goletter/hyperf-archive

Multi-file archive (ZIP) builder for Hyperf with sync download and storage upload support.

Maintainers

Package info

github.com/goletter/hyperf-archive

pkg:composer/goletter/hyperf-archive

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-27 16:48 UTC

This package is auto-updated.

Last update: 2026-08-27 16:53:54 UTC


README

Hyperf 多文件 ZIP 打包扩展,支持本地文件、内存内容、filesystem 磁盘,以及直接下载 / 上传存储。

安装

composer require goletter/hyperf-archive
php bin/hyperf.php vendor:publish goletter/hyperf-archive

配置文件发布到 config/autoload/archive.php

依赖 PHP 扩展:ext-zip

配置

return [
    'temp_dir' => BASE_PATH . '/runtime/archive',
    'max_files' => 500,
    'max_total_size' => 500 * 1024 * 1024,
    'temp_ttl' => 3600,
    'compression_level' => -1,
];

使用

链式 API(推荐)

use Goletter\Archive\Archive;

return Archive::make()
    ->addFile('/data/uploads/a.pdf')
    ->addFile('/data/uploads/b.jpg', 'images/b.jpg')
    ->addFromStorage('s3', 'exports/report.xlsx', 'report.xlsx')
    ->addContents('hello', 'readme.txt')
    ->download('bundle.zip');

辅助函数:

return archive()
    ->addFile('/path/a.pdf')
    ->download('files.zip');

打包整个文件夹

// ZIP 内保留顶层目录名:project-docs/a.pdf, project-docs/sub/b.jpg
return Archive::make()
    ->addDirectory('/data/uploads/project-docs')
    ->download('project-docs.zip');

// 自定义 ZIP 内顶层目录名
return Archive::make()
    ->addDirectory('/data/uploads/project-docs', 'exports')
    ->download('exports.zip');

// 不保留顶层目录,直接按相对路径写入 ZIP 根目录
return Archive::make()
    ->addDirectory('/data/uploads/project-docs', '')
    ->download('flat.zip');

// 包含隐藏文件(默认会跳过 .git、.DS_Store 等)
return Archive::make()
    ->addDirectory('/data/uploads/project-docs', null, true)
    ->download('all.zip');

通过 ArchiverInterface 也可以直接传目录数组:

return $this->archiver->download([
    ['dir' => '/data/uploads/project-docs'],
    ['dir' => '/data/uploads/assets', 'prefix' => 'assets'],
], 'bundle.zip');

注入 ArchiverInterface

use Goletter\Archive\Contract\ArchiverInterface;
use Hyperf\Di\Annotation\Inject;

#[Inject]
protected ArchiverInterface $archiver;

// 直接下载
return $this->archiver->download([
    '/path/a.pdf',
    ['path' => '/path/b.jpg', 'name' => 'photos/b.jpg'],
    ['disk' => 's3', 'path' => 'docs/c.pdf', 'name' => 'c.pdf'],
], 'export.zip');

// 仅生成临时 ZIP 路径
$path = $this->archiver->create($entries, 'export.zip');

// 打包后上传到磁盘
$remote = $this->archiver->upload($entries, 'exports/bundle.zip', 's3');

// 打包后返回下载地址(推荐)
$result = Archive::make()
    ->addDirectory('/data/uploads/project-docs')
    ->store(disk: 'oss');

return [
    'download_url' => $result->url,
    'path' => $result->path,
    'disk' => $result->disk,
];

// 指定远端路径
$result = Archive::make()
    ->addEntries($files)
    ->store('exports/bundle.zip', 'oss');

// 返回 JSON 给前端
return $result->toArray();
// ['path' => 'exports/bundle.zip', 'url' => 'https://...', 'disk' => 'oss', 'expires_at' => null]

下载地址配置

config/autoload/archive.php

return [
    'default_disk' => 'oss',
    'upload_path' => 'archives/{Ymd}/{uuid}.zip',
    'disks' => [
        'local' => [
            'url' => env('APP_URL') . '/uploads/{path}',
        ],
        'oss' => [
            'url' => 'https://your-bucket.oss-cn-hangzhou.aliyuncs.com/{path}',
        ],
    ],
];

{path} 会被替换为上传后的远端路径。如需 OSS 签名链接,可在业务中实现 ArchiveUrlResolverInterface 并绑定到容器。

Controller 示例

use Goletter\Archive\Archive;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\PostMapping;
use Psr\Http\Message\ResponseInterface;

#[Controller(prefix: '/files')]
class FileController
{
    #[PostMapping('download-zip')]
    public function downloadZip(): ResponseInterface
    {
        // 先按业务做权限校验,再收集可访问文件路径
        $files = $this->fileService->getAccessibleFiles($this->request->input('ids', []));

        return Archive::make()
            ->addEntries($files)
            ->download('files_' . date('YmdHis') . '.zip');
    }
}

$files 可为本地路径字符串,或:

[
    ['path' => '/local/a.pdf'],
    ['path' => '/local/b.jpg', 'name' => 'images/b.jpg'],
    ['disk' => 'oss', 'path' => 'remote/c.png', 'name' => 'c.png'],
    ['contents' => 'meta', 'name' => 'info.txt'],
]

输出方式

方法 说明
download() 设置 Content-Disposition: attachment 直接下载
create() 返回本地临时 ZIP 绝对路径
upload() 上传到 hyperf/filesystem 磁盘并返回远端路径
store() 上传后返回 ArchiveResult(含 url 下载地址)

goletter/hyperf-serverResponseFormatMiddleware 兼容:attachment 响应会透传,不会被包装成 JSON。

安全说明

  • ZIP 内路径会过滤 ../,避免目录穿越
  • 目录打包会跳过符号链接指向目录外的文件
  • 默认跳过隐藏文件/目录(以 . 开头)
  • 请在业务层校验用户对每个文件的访问权限,不要直接信任前端传入的绝对路径
  • 通过 max_files / max_total_size 限制单次打包规模

License

MIT