44
55use frictionlessdata \datapackage \Datapackages \BaseDatapackage ;
66use frictionlessdata \datapackage \Resources \BaseResource ;
7+ use Alchemy \Zippy \Zippy ;
78
89/**
910 * datapackage and resource have different classes depending on the corresponding profile
@@ -23,6 +24,7 @@ class Factory
2324 * - JSON encoded object
2425 * - URL (must be in either 'http' or 'https' schemes)
2526 * - local filesystem (POSIX) path.
27+ * - local or remote zip file
2628 *
2729 * @param mixed $source
2830 * @param null|string $basePath optional, required only if you want to use relative paths
@@ -269,37 +271,45 @@ protected static function loadSource($source, $basePath)
269271 );
270272 }
271273 } elseif (static ::isHttpSource ($ source )) {
272- try {
273- $ descriptor = json_decode (file_get_contents (static ::normalizeHttpSource ($ source )));
274- } catch (\Exception $ e ) {
275- throw new Exceptions \DatapackageInvalidSourceException (
276- 'Failed to load source: ' .json_encode ($ source ).': ' .$ e ->getMessage ()
277- );
274+ if (static ::isHttpZipSource ($ source )) {
275+ return static ::loadHttpZipSource ($ source );
276+ } else {
277+ try {
278+ $ descriptor = json_decode (file_get_contents (static ::normalizeHttpSource ($ source )));
279+ } catch (\Exception $ e ) {
280+ throw new Exceptions \DatapackageInvalidSourceException (
281+ 'Failed to load source: ' .json_encode ($ source ).': ' .$ e ->getMessage ()
282+ );
283+ }
284+ // http sources don't allow relative paths, hence basePath should remain null
285+ $ basePath = null ;
278286 }
279- // http sources don't allow relative paths, hence basePath should remain null
280- $ basePath = null ;
281287 } else {
282288 // not a json string and not a url - assume it's a file path
283- if (empty ($ basePath )) {
284- // no basePath
285- // - assume source is the absolute path of the file
286- // - set it's directory as the basePath
287- $ basePath = dirname ($ source );
289+ if (static ::isFileZipSource ($ source )) {
290+ return static ::loadFileZipSource ($ source );
288291 } else {
289- // got a basePath
290- // - try to prepend it to the source and see if such a file exists
291- // - if not - assume it's an absolute path
292- $ absPath = $ basePath .DIRECTORY_SEPARATOR .$ source ;
293- if (file_exists ($ absPath )) {
294- $ source = $ absPath ;
292+ if (empty ($ basePath )) {
293+ // no basePath
294+ // - assume source is the absolute path of the file
295+ // - set it's directory as the basePath
296+ $ basePath = dirname ($ source );
297+ } else {
298+ // got a basePath
299+ // - try to prepend it to the source and see if such a file exists
300+ // - if not - assume it's an absolute path
301+ $ absPath = $ basePath .DIRECTORY_SEPARATOR .$ source ;
302+ if (file_exists ($ absPath )) {
303+ $ source = $ absPath ;
304+ }
305+ }
306+ try {
307+ $ descriptor = json_decode (file_get_contents ($ source ));
308+ } catch (\Exception $ e ) {
309+ throw new Exceptions \DatapackageInvalidSourceException (
310+ 'Failed to load source: ' .json_encode ($ source ).': ' .$ e ->getMessage ()
311+ );
295312 }
296- }
297- try {
298- $ descriptor = json_decode (file_get_contents ($ source ));
299- } catch (\Exception $ e ) {
300- throw new Exceptions \DatapackageInvalidSourceException (
301- 'Failed to load source: ' .json_encode ($ source ).': ' .$ e ->getMessage ()
302- );
303313 }
304314 }
305315 } else {
@@ -310,4 +320,38 @@ protected static function loadSource($source, $basePath)
310320
311321 return (object ) ['descriptor ' => $ descriptor , 'basePath ' => $ basePath ];
312322 }
323+
324+ protected static function isHttpZipSource ($ source )
325+ {
326+ return (strtolower (substr ($ source , -4 )) == '.zip ' );
327+ }
328+
329+ protected static function isFileZipSource ($ source )
330+ {
331+ return (strtolower (substr ($ source , -4 )) == '.zip ' );
332+ }
333+
334+ protected static function loadHttpZipSource ($ source )
335+ {
336+ $ tempfile = tempnam (sys_get_temp_dir (), 'datapackage-php ' );
337+ unlink ($ tempfile );
338+ $ tempfile .='.zip ' ;
339+ stream_copy_to_stream (fopen ($ source , 'r ' ), fopen ($ tempfile , 'w ' ));
340+ register_shutdown_function (function () use ($ tempfile ) {unlink ($ tempfile );});
341+ return self ::loadFileZipSource ($ tempfile );
342+ }
343+
344+ protected static function loadFileZipSource ($ source )
345+ {
346+ $ zippy = Zippy::load ();
347+ $ tempdir = tempnam (sys_get_temp_dir (), 'datapackage-php ' );
348+ unlink ($ tempdir );
349+ mkdir ($ tempdir );
350+ register_shutdown_function (function () use ($ tempdir ) {Utils::removeDir ($ tempdir );});
351+ $ zippy ->open ($ source )->extract ($ tempdir );
352+ if (!file_exists ($ tempdir ."/datapackage.json " )) {
353+ throw new Exceptions \DatapackageInvalidSourceException ("zip file must contain a datappackage.json file " );
354+ }
355+ return static ::loadSource ($ tempdir ."/datapackage.json " , $ tempdir );
356+ }
313357}
0 commit comments