chumper/zipper
Chumper/Zipper is a simple Laravel wrapper around PHP's ZipArchive that makes creating, extracting, and manipulating ZIP archives easy. Add files or folders, extract contents, and manage entries through a clean, fluent API. A lightweight, popular choice for bundling downloads and archiving files.
composer require chumper/zipper
zip extension is enabled (php -m | grep zip). This package is a thin wrapper around ZipArchive; without ext-zip it will fail immediately.config/app.php:'providers' => [
Chumper\Zipper\ZipperServiceProvider::class,
],
'aliases' => [
'Zipper' => Chumper\Zipper\Facades\Zipper::class,
],
Laravel 5.5+ may auto-discover it, but verify before relying on the facade alias.
vendor/chumper/zipper/src/Chumper/Zipper/Zipper.php for the actual API. The README is old; the class is the source of truth.use Chumper\Zipper\Facades\Zipper;
use Illuminate\Support\Facades\File;
$dir = storage_path('app/exports');
File::ensureDirectoryExists($dir);
$zipPath = $dir.'/orders-'.now()->format('YmdHis').'.zip';
Zipper::make($zipPath)
->add([storage_path('app/exports/orders.csv')])
->close();
return response()->download($zipPath)->deleteFileAfterSend(true);
If you only need a one-off zip, native ZipArchive is usually clearer. Use this package when you want its chained API or already have legacy code depending on it.
final class OrderArchive
{
public function build(array $files, string $zipPath): string
{
Zipper::make($zipPath)
->add($files)
->close();
return $zipPath;
}
}
close() explicitly, even when chaining:Zipper::make($zipPath)
->folder('reports')
->add($reportPath)
->folder('invoices')
->add($invoicePaths)
->close();
addString() rather than writing temporary files:Zipper::make($zipPath)
->addString('manifest.json', json_encode($manifest, JSON_PRETTY_PRINT))
->close();
$tmp = storage_path('app/tmp/'.Str::uuid());
File::ensureDirectoryExists($tmp);
Zipper::make($uploadedZipPath)->extractTo($tmp);
Zipper expects filesystem paths, not Storage URLs or S3 keys:$local = Storage::disk('local')->path('exports/orders.csv');
Zipper::make($zipPath)->add($local)->close();
For remote disks, download to a temp local path, build the archive, upload it, then delete the temp files.
Queue large archive jobs. Zipping hundreds of files in a request is a common timeout source; use a job, write the zip to storage/app, and notify or expose a download route when finished.
In tests, use Storage::fake() and inspect the generated archive with native ZipArchive rather than only asserting the file exists:
$zip = new ZipArchive();
$zip->open($zipPath);
$this->assertNotFalse($zip->locateName('reports/orders.csv'));
$zip->close();
ZipArchive, nelexa/zip, maennchen/zipstream-php for streaming, or a maintained fork such as zanysoft/laravel-zip.close(). Forgetting it can leave the archive incomplete or leave file handles open, especially on Windows.folder() and verify with listFiles() in a test.../ traversal after extraction.ZipArchive failures. Check that the zip exists, inspect listFiles(), and validate extracted files. Wrap archive operations in try/finally for temp cleanup.max_execution_time. Queue the work and set sensible limits.php artisan config:cache. Facade alias conflicts are possible in apps that already define Zipper.composer.lock and avoid broad constraints. Plan a replacement path before the next Laravel/PHP upgrade.How can I help you explore Laravel packages today?