stechstudio / laravel-zipstream
为 Laravel 的高效简单的流式压缩文件下载器。
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
- guzzlehttp/psr7: ^2.6
- illuminate/support: ^10.0|^11.0
- league/flysystem-path-prefixing: ^3.28
- maennchen/zipstream-php: ^v3.0
- psr/http-message: ^2.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- league/flysystem-aws-s3-v3: ^3.28
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^9.0|^10.0
README
为 Laravel 的高效简单的流式压缩文件下载器。
- 从本地或 S3 文件源,或任何其他 PSR7 流构建 zip 文件。
- 提供直接下载流到您的用户。即使 zip 正在创建中,zip 下载也会立即开始。无需首先将 zip 保存到磁盘。
- 预先计算 zip 文件大小以便于
Content-Length
标头。用户会在他们的浏览器中获得准确的下载时间估计。 - 基于出色的 ZipStream-PHP 库构建。
升级
从版本 4 升级?请确保查看版本 5 的发行说明。有一些破坏性更改。
https://github.com/stechstudio/laravel-zipstream/releases/tag/5.0
快速入门
1. 安装包
composer require stechstudio/laravel-zipstream
服务提供者和外观将自动连接。
2. 在控制器方法中,调用 Zip
外观的 create
方法
use STS\ZipStream\Facades\Zip; class ZipController { public function build() { return Zip::create("package.zip", [ "/path/to/Some File.pdf", "/path/to/Export.xlsx" ]); } }
就是这样!将返回 StreamedResponse
,zip 内容将构建并流式传输出来。用户的浏览器将立即开始下载 package.zip
文件。
自定义文件内部 zip 路径
默认情况下,您添加的任何文件都将存储在 zip 的根目录中,并保留其原始文件名。
您可以通过提供包含键/值对的文件数组来自定义文件名,甚至在 zip 中创建子文件夹
Zip::create("package.zip", [ // Will be stored as `Some File.pdf` in the zip "/path/to/Some File.pdf", // Will be stored as `Export.xlsx` in the zip "/path/to/data.xlsx" => 'Export.xlsx', // Will create a `log` subfolder in the zip and be stored as `log/details.txt` "/path/to/log.txt" => "log/details.txt" ]);
流畅用法
您也可以一次提供一个文件
Zip::create("package.zip") ->add("/path/to/Some File.pdf") ->add("/path/to/data.xlsx", 'Export.xlsx') ->add("/path/to/log.txt", "log/details.txt");
添加 HTTP 文件源
您可以将 HTTP URL 作为源文件路径添加。请注意,如果 HTTP 源提供了 Content-Length
标头,则可以预先计算 zip 文件大小,并非所有 URL 都这样做。
Zip::create("package.zip") ->add("https://...", "myfile.pdf");
添加原始文件数据
您可以提供原始数据而不是文件路径
Zip::create("package.zip") ->addRaw("...file contents...", "hello.txt");
从存储磁盘添加
您可以从存储磁盘添加文件。使用 addFromDisk
并提供磁盘名称或磁盘实例作为第一个参数
Zip::create("package.zip") ->addFromDisk("local", "file.txt", "My File.txt") ->addFromDisk(Storage::disk("tmp"), "important.txt")
S3 支持
安装 AWS sdk 并配置 S3
您可以将 S3 中的文件流式传输到您的 zip 中。
-
安装
aws/aws-sdk-php
包 -
设置一个具有
s3:GetObject
权限的 AWS IAM 用户,用于您打算压缩的 S3 存储桶和对象。 -
将凭证作为
AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
和AWS_DEFAULT_REGION
存储在您的 .env 文件中。
将 S3 文件添加到您的 zip 中
在创建 zip 时提供 s3://
路径
Zip::create("package.zip") ->add("s3://bucket-name/path/to/object.pdf", "Something.pdf");
默认情况下,此包将尝试使用 Laravel 使用的相同 .env 文件凭证创建 S3 客户端。如果需要,您可以连接一个自定义 S3 客户端到 zipstream.s3client
容器键。或者,您甚至可以在将文件添加到 zip 时传递自己的 S3 客户端。为此,您需要自己创建一个 S3File
模型实例,以便您可以提供客户端,如下所示
use STS\ZipStream\Models\S3File; // Create your own client however necessary $s3 = new Aws\S3\S3Client(); Zip::create("package.zip")->add( S3File::make("s3://bucket-name/path/to/object.pdf")->setS3Client($s3) );
而不是指定绝对 s3://
路径,您可以使用 addFromDisk
并指定一个使用 s3
驱动程序的磁盘
Zip::create("package.zip") ->addFromDisk("s3", "object.pdf", "Something.pdf");
在这种情况下,存储磁盘的 S3 客户端将被使用。
指定自己的文件大小
对于一些文件源,如S3或HTTP,检索文件大小可能会很昂贵。这需要专用调用,如果您正在压缩多个文件,这可能会花费大量时间。如果您在数据库中存储文件大小并且可以访问它们,通过在添加文件时提供文件大小,您可以显著提高性能。您需要自己创建文件模型,而不是直接将路径添加到zip中。
假设您有一组Eloquent $files
,正在循环并构建一个zip。如果您有一个filesize
属性可用,它将看起来像这样
use STS\ZipStream\Models\File; // Retrieve file records from the database $files = ...; $zip = Zip::create("package.zip"); foreach($files AS $file) { $zip->add( File::make($file->path, $file->name)->setFilesize($file->size) ); }
或者如果您是从S3磁盘添加
$zip->add( File::makeFromDisk('s3', $file->key, $file->name)->setFilesize($file->size) );
Zip大小预测
默认情况下,此包尝试预测最终zip大小,并在前端发送Content-Length
标题。这意味着用户将在zip创建的同时看到准确的下载进度!
这仅适用于未压缩的文件。
如果您在zip大小预测方面遇到问题,可以在.env文件中将ZIPSTREAM_PREDICT_SIZE=false
禁用。
配置压缩
默认情况下,此包使用无压缩。为什么?
- 这使得构建zip超级快,并且对CPU的负担很小
- 这使得可以预测上述的最终zip大小。
如果您想压缩zip文件,请在.env文件中将ZIPSTREAM_COMPRESSION_METHOD=deflate
设置。只需注意,这将禁用Content-Length
标题。
将Zip保存到磁盘
尽管此包的主要目标是启用无需保存到磁盘的zip下载,但有时您可能还需要在磁盘上生成zip。您可以使用此包来实现这一点。
使用saveTo
方法立即将整个zip写入磁盘。注意,这需要一个文件夹路径,zip名称将被追加。
Zip::create("package.zip") // ... add files ... ->saveTo("/path/to/folder");
是的,如果您已正确设置并配置了S3,您甚至可以将文件保存到S3桶/路径。
Zip::create("package.zip") // ... add files ... ->saveTo("s3://bucket-name/path/to/folder");
或者您可以将文件保存到磁盘
Zip::create("package.zip") // ... add files ... ->saveToDisk("s3", "folder");
在流式下载的同时缓存zip
如果您有大量用户请求相同的zip有效负载,那么在流式输出zip的同时将其缓存到磁盘可能会很方便。
使用cache
方法提供缓存路径。注意,这应该包括文件名的完整路径。
Zip::create("package.zip") // ... add files ... ->cache("/path/to/folder/some-unique-cache-name.zip");
或者您可以将缓存到磁盘
Zip::create("package.zip") // ... add files ... ->cacheToDisk("s3", "folder/some-unique-cache-name.zip");
您可能使用内部DB ID作为缓存名称,这样当用户再次请求zip下载时,您可以确定是否已构建了一个,并将其直接返回。
事件
STS\ZipStream\Events\ZipStreaming
:在新的zip流开始处理时触发STS\ZipStream\Events\ZipStreamed
:在zip完成流式传输时触发
文件名净化
默认情况下,此包将尝试将文件名或文件夹名中的任何非ASCII字符转换为ASCII。例如,如果您的文件名为中文_にほんご_Ч_Ɯ_☺_someascii.txt
,它将使用Laravel的Str::ascii($path)
变为__C___someascii.txt
。
如果您需要保留非ASCII字符,可以禁用此功能。
ZIPSTREAM_ASCII_FILENAMES=false
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。