2
votes

The documentation illustrates how to integrate the dropbox flysystem adapter, but does not show you how to integrate with the ZipArchive Adapter or similar.

https://laravel.com/docs/5.4/filesystem#custom-filesystems

https://github.com/thephpleague/flysystem-ziparchive

I tried reading over the methods on the FilesystemManager.php which is the class containing the extend method used in the docs example. I found a method called adapt which looks like it might be the ticket.

I tried calling this method from the Storage facade like so:

return $storage_with_zip = Storage::adapt(new \League\Flysystem\ZipArchive\ZipArchiveAdapter($file->getRealPath()));

but I'm getting this error:

BadMethodCallException Call to undefined method League\Flysystem\Filesystem::adapt

Has anyone had success integrating the Laravel Filesystem with the ZipArchiveAdapter? I know I can just use the PHP native ZipArchive, but I'd like to have everything in the filesystem use Laravels wrapper.

Thanks!

***Update

My ultimate goal is to be able to unzip uploaded zips to the storage/ directory or to s3.

Example 1) $file = Storage::disk('local')->extractTo('unzipped/', $file);

instead of this:

$zip = new ZipArchive(); 
$zip->open($file->getRealPath()); 
$zip->extractTo(storage_path('app') . 'unzipped');

Example 2) $file = Storage::disk('s3')->extractTo('unzipped/', $file);

1

1 Answers

6
votes

For what you want to do, it would better to create a plugin for League\Flyststem. I'm not sure if there is a "clean" way to add a plugin to Laravel-Flyststem which is a bridge between League\Flyststem and Laravel. One of the workaround is to register a custom driver for local/s3 which will extend embedded driver with injection of zip plugin.

There are few steps to achive it:

1) Create ZipExtractTo plugin inside App/Filesystem/Plugins

ZipExtractTo

namespace App\Filesystem\Plugins;

use League\Flysystem\Plugin\AbstractPlugin;
use ZipArchive;

class ZipExtractTo extends AbstractPlugin
{
    /**
     * @inheritdoc
     */
    public function getMethod()
    {
        return 'extractTo';
    }

    /**
     * Extract zip file into destination directory.
     *
     * @param string $path Destination directory
     * @param string $zipFilePath The path to the zip file.
     *
     * @return bool True on success, false on failure.
     */
    public function handle($path, $zipFilePath)
    {
        $path = $this->cleanPath($path);

        $zipArchive = new ZipArchive();
        if ($zipArchive->open($zipFilePath) !== true) 
        {
            return false;
        }

        for ($i = 0; $i < $zipArchive->numFiles; ++$i) 
        {
            $zipEntryName = $zipArchive->getNameIndex($i);
            $destination = $path . DIRECTORY_SEPARATOR . $this->cleanPath($zipEntryName);
            if ($this->isDirectory($zipEntryName)) 
            {
                $this->filesystem->createDir($destination);
                continue;
            }
            $this->filesystem->putStream($destination, $zipArchive->getStream($zipEntryName));
        }

        return true;
    }

    private function isDirectory($zipEntryName) 
    {
        return substr($zipEntryName, -1) ===  '/';
    }

    private function cleanPath($path)
    {
        return str_replace('/', DIRECTORY_SEPARATOR, $path);
    }

}

2) Create providers for local/s3:

ExtendedLocalServiceProvider

namespace App\Providers;

use Storage;
use Illuminate\Support\ServiceProvider;
use App\Filesystem\Plugins\ZipExtractTo;

class ExtendedLocalServiceProvider extends ServiceProvider 
{
    public function boot()
    {
        Storage::extend('local', function($app, $config) {
            return Storage::createLocalDriver($config)->addPlugin(new ZipExtractTo());
        });
    }
}

ExtendedS3ServiceProvider

namespace App\Providers;

use Storage;
use Illuminate\Support\ServiceProvider;
use App\Filesystem\Plugins\ZipExtractTo;

class ExtendedS3ServiceProvider extends ServiceProvider 
{
    public function boot()
    {
        Storage::extend('s3', function($app, $config) {
            return Storage::createS3Driver($config)->addPlugin(new ZipExtractTo());
        });        
    }
}

3) Register providers inside app.php

'providers' => [
 ...
 App\Providers\ExtendedLocalServiceProvider::class,
 App\Providers\ExtendedS3ServiceProvider::class,
],

4) Now you're able to do something like this:

Storage::disk('local')->extractTo('unzipped/', $zipPath);
Storage::disk('s3')->extractTo('unzipped/', $zipPath);