From 8d2ee6bf84373bfdd580d586753251674086005e Mon Sep 17 00:00:00 2001 From: Quentin Gabriele Date: Sun, 14 Jan 2024 13:34:28 +0100 Subject: [PATCH] support zipping media --- composer.json | 1 + src/MediaZipper.php | 78 +++++++++++++++++++++++++++++++ tests/Feature/MediaZipperTest.php | 30 ++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 src/MediaZipper.php create mode 100644 tests/Feature/MediaZipperTest.php diff --git a/composer.json b/composer.json index 75b8697..590f19f 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "require": { "php": "^8.1", "illuminate/contracts": "^10.0", + "maennchen/zipstream-php": "^3.1", "pbmedia/laravel-ffmpeg": "^8.3", "spatie/image": "^3.0.0", "spatie/laravel-package-tools": "^1.14.0", diff --git a/src/MediaZipper.php b/src/MediaZipper.php new file mode 100644 index 0000000..8072ee1 --- /dev/null +++ b/src/MediaZipper.php @@ -0,0 +1,78 @@ + $media + */ + public function __construct( + public Collection $media = new Collection(), + public string $fileName = 'media.zip', + public array $zipStreamOptions = [], + ) { + $this->zipStreamOptions['outputName'] = $fileName; + } + + public function toFile(Filesystem $storage, string $path, array $options = []): string|false + { + $tempStream = fopen('php://memory', 'w+'); + + $zipStream = $this->getZipStream([ + 'outputStream' => $tempStream, + ]); + + $success = $storage->writeStream($path, $tempStream, $options); + + fclose($tempStream); + + return $success ? $path : false; + } + + public function getZipStream(array $options = []) + { + $zip = new ZipStream( + ...$this->zipStreamOptions, + ...$options, + ); + + foreach ($this->media as $item) { + $stream = $item->readStream(); + + $zip->addFileFromStream( + fileName: $item->file_name, + stream: $stream + ); + + if (is_resource($stream)) { + fclose($stream); + } + } + + $zip->finish(); + + return $zip; + } + + /** + * Create an HTTP response that represents the object. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + */ + public function toResponse($request): StreamedResponse + { + return new StreamedResponse(fn () => $this->getZipStream(), 200, [ + 'Content-Disposition' => "attachment; filename=\"{$this->fileName}\"", + 'Content-Type' => 'application/octet-stream', + ]); + } +} diff --git a/tests/Feature/MediaZipperTest.php b/tests/Feature/MediaZipperTest.php new file mode 100644 index 0000000..80b8f19 --- /dev/null +++ b/tests/Feature/MediaZipperTest.php @@ -0,0 +1,30 @@ +make(), + MediaFactory::new()->make(), + ])->each(function (Media $media) { + $media->storeFile( + file: UploadedFile::fake()->image('foo.jpg'), + collection_name: 'avatar', + name: 'avatar', + disk: 'media' + ); + }); + + $zipper = new MediaZipper($media); + + $zipper->toFile($storage, $zipper->fileName); + + Storage::disk('media')->assertExists($zipper->fileName); + +});