stechstudio/laravel-zipstream

为 Laravel 的高效简单的流式压缩文件下载器。

5.0.2 2024-07-13 01:31 UTC

This package is auto-updated.

Last update: 2024-09-13 17:50:48 UTC


README

Latest Version on Packagist Total Downloads Software License Build Status

为 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 中。

  1. 安装 aws/aws-sdk-php

  2. 设置一个具有 s3:GetObject 权限的 AWS IAM 用户,用于您打算压缩的 S3 存储桶和对象。

  3. 将凭证作为 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_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禁用。

配置压缩

默认情况下,此包使用压缩。为什么?

  1. 这使得构建zip超级快,并且对CPU的负担很小
  2. 这使得可以预测上述的最终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)。有关更多信息,请参阅许可文件