goletter / hyperf-archive
Multi-file archive (ZIP) builder for Hyperf with sync download and storage upload support.
v1.0.0
2026-08-27 16:48 UTC
Requires
- php: >=8.1
- ext-zip: *
- hyperf/context: ~3.1.0
- hyperf/contract: ~3.1.0
- hyperf/coroutine: ~3.1.0
- hyperf/filesystem: ~3.1.0
- hyperf/http-server: ~3.1.0
- hyperf/support: ~3.1.0
- psr/container: ^1.0 || ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.0
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^10.0
- swoole/ide-helper: dev-master
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-server 的 ResponseFormatMiddleware 兼容:attachment 响应会透传,不会被包装成 JSON。
安全说明
- ZIP 内路径会过滤
../,避免目录穿越 - 目录打包会跳过符号链接指向目录外的文件
- 默认跳过隐藏文件/目录(以
.开头) - 请在业务层校验用户对每个文件的访问权限,不要直接信任前端传入的绝对路径
- 通过
max_files/max_total_size限制单次打包规模
License
MIT