如何无需base64编码从文件内容字符串而非本地文件加载ZipArchive
问题说明
PHP官方文档给出的本地文件加载ZipArchive的示例代码如下:
$zip = new \ZipArchive(); $zip->open('file.zip');
当使用抽象层封装的外部文件存储时,没有可直接访问的本地文件路径,仅能获取到zip文件的二进制内容,期望实现类似$zip->fromString($fileContent)的调用效果,同时要避免base64中转带来的大文件内存占用过高问题。
解决方案
原生ZipArchive没有提供直接从字符串内容加载实例的内置方法,最优实现是借助PHP内置的php://temp临时流包装器,无需生成实体本地文件、无需编码转码,内存占用远低于base64中转方案,处理大文件时会自动将超出内存阈值的内容写入系统临时文件,不会出现内存溢出问题。
实现代码如下:
$zip = new \ZipArchive(); // 打开临时流:读写模式、二进制安全、内存中最多保留2MB内容,超出自动落临时磁盘 $stream = fopen('php://temp/maxmemory:2097152', 'r+b'); // 将zip二进制内容写入临时流 fwrite($stream, $fileContent); // 重置流指针到起始位置 rewind($stream); // 直接从流加载ZipArchive,不需要落地为实体文件 $zip->open(stream_get_meta_data($stream)['uri'], \ZipArchive::RDONLY); // 后续正常操作zip即可,比如读取内部文件、解压等 // $content = $zip->getFromIndex(0); // 操作完成后关闭资源 fclose($stream); $zip->close();
方案优势
- 无base64编解码开销,内存占用仅和临时流配置的阈值相关,处理GB级大文件也不会内存溢出
- 不会在业务目录生成残留临时文件,流关闭后系统会自动回收临时资源
- 全程使用PHP内置能力,无需安装第三方扩展
- 二进制安全,不会出现zip内容损坏的问题
如果PHP版本 >= 8.0,还可以使用更简洁的写法,直接给open方法传入流资源:
$zip = new \ZipArchive(); $stream = fopen('php://temp/maxmemory:2097152', 'r+b'); fwrite($stream, $fileContent); rewind($stream); // PHP8.0+ 支持直接传入resource参数 $zip->open($stream, \ZipArchive::RDONLY);
注意:不要使用
php://memory流,该流会将所有内容全量存在内存中,处理大文件时依然会出现内存溢出问题,php://temp的自动落盘机制可以完美规避这个问题。
内容的提问来源于stack exchange,提问作者Christian Kolb
相关产品推荐
相关产品推荐

