ziparchive不支持分卷zip和流式解压;分卷需用zip命令合并为单文件再处理,大文件应逐个提取+及时释放内存或调用unzip/7z等系统命令。

PHP 的 ZipArchive 类原生不支持分卷 ZIP(如 archive.z01, archive.zip)的直接读取,也不支持流式解压(即边读边解、不全量加载到内存)。这是它的设计限制——它要求 ZIP 文件结构完整、可随机访问,而分卷 ZIP 需要先合并或由专用工具识别,流式解压则需底层支持 deflate 流解析,ZipArchive 封装过深,无法暴露中间流。
但实际业务中遇到超大 ZIP(几十 GB)或分卷包时,仍有可行路径。关键不是“强行用 ZipArchive 做”,而是选对工具 + 合理分层处理。
分卷 ZIP 包怎么读取?
分卷 ZIP(如 data.zip, data.z01, data.z02…)本质是将一个逻辑 ZIP 拆成多个物理文件,需先还原为单个完整 ZIP 才能被标准工具识别。
-
✅ 可靠做法:用系统命令预合并
在 Linux/macOS 上,zip命令本身支持分卷包识别:zip -s 0 data.zip --out data-full.zip
这会把所有
.z??和.zip合并为data-full.zip。PHP 中调用:$output = []; $return = 0; exec('zip -s 0 data.zip --out data-full.zip 2>&1', $output, $return); if ($return === 0 && file_exists('data-full.zip')) { // 再用 ZipArchive 打开 data-full.zip }⚠️ 注意:确保
zip命令可用、有读写权限、磁盘空间充足;Windows 下需安装 Info-ZIP 或 7-Zip 并调用其7z x命令。 ❌ 不推荐:手动拼接二进制文件
分卷格式有头部校验和跨卷元数据,简单cat *.z* > full.zip极易损坏结构,导致ZipArchive::open()失败或解压乱码。
大 ZIP 文件如何“流式”解压(不爆内存)?
ZipArchive::extractTo() 是原子操作,会一次性读取整个中央目录并分配内存,对百 MB 以上 ZIP 易触发 memory_limit 错误。所谓“流式”,实际指:
-
✅ 逐个文件提取 + 即时处理:遍历条目 → 校验路径 →
getFromIndex()读内容 → 处理/写磁盘 → 释放变量
不解压全部,只按需加载单个文件内容:$zip = new ZipArchive(); if ($zip->open('big.zip') !== TRUE) die('打开失败'); for ($i = 0; $i numFiles; $i++) { $name = $zip->getNameIndex($i); if (!$name || str_starts_with($name, '/') || str_contains($name, '..')) continue; $content = $zip->getFromIndex($i); // 只加载当前文件内容到内存 if ($content !== false) { file_put_contents("extracted/$name", $content); unset($content); // 主动释放 } } $zip->close(); -
✅ 配合临时文件 +
fopen流写入(适合超大单文件)
若某 ZIP 内含一个几 GB 的日志文件,getFromIndex()仍可能撑爆内存。此时改用fopen('php://temp')或临时文件中转:$fp = fopen('/tmp/temp_extract.bin', 'w'); $zip->extractTo('/tmp/', [$name]); // 仅解压该文件到临时目录 fclose($fp); // 再用 fgets() 逐行处理 /tmp/$name,处理完 unlink() ❌
ZipArchive无法实现真正流式(如gzdecode(fread($fp, 8192))那种),因其依赖 ZIP 中央目录定位,必须先加载索引。
替代方案:绕过 ZipArchive,用更底层或外部工具
| 场景 | 推荐方式 | 说明 |
|---|---|---|
纯 deflate 流解压(已知是单个 .gz 或 ZIP 内单文件流) |
zlib.inflate_filter() + stream_filter_append()
|
适用于 HTTP 响应体、日志流等,不涉及 ZIP 结构 |
| 大 ZIP + 高性能需求 | 调用 unzip -p 输出到 pipe |
proc_open('unzip -p archive.zip "path/in/zip"', ...),从 stdout 读流 |
| 需要密码、分卷、修复等高级功能 |
7z 或 unzip 命令行 |
功能全、稳定、内存可控,加 escapeshellarg() 防注入 |
? 提示:用
exec()时务必校验输入路径、过滤空格和特殊字符,优先用escapeshellarg()包裹用户可控参数。
总结要点
-
ZipArchive不能直接读分卷 ZIP,必须先合并为单文件; - 它不支持流式解压,但可通过
getFromIndex()+ 循环 + 及时unset()模拟低内存占用; - 百 MB 以上 ZIP,优先考虑系统命令(
unzip,7z,zip -s),更稳更快; - 所有路径操作必须做安全校验(防
../路径遍历),解压目标目录需realpath()约束范围; - 大文件场景记得调整 PHP 配置:
ini_set('memory_limit', '1G')、set_time_limit(0),但不如交给系统命令可靠。
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











