PHP技术求助:HTTP响应二进制ASCII转ZIP文件及多附件POST请求ZIP解析失败问题
我来帮你梳理下排查方向和解决方案,你遇到的问题大概率是数据提取错误或者代码逻辑的小疏漏,咱们一步步拆解:
一、先排查提取的ZIP二进制数据是否准确
你是手动拆分MIME请求的,这一步很容易踩坑:
- 有没有误把MIME边界、头部字段(比如
Content-Type: application/zip这类行)包含进了$zipBinary里?正常ZIP文件的开头是十六进制504B0304(对应ASCII的PK..),你可以用bin2hex(substr($zipBinary, 0, 4))输出开头字符,对比下是不是这个值——如果前面有换行、空格或者其他字符,说明数据提取错了。 - 检查数据完整性:用
strlen($zipBinary)对比原始test.zip文件的大小,如果长度不一致,说明数据被截断了。另外正常ZIP文件的结尾是十六进制504B0506,你可以检查下数据尾部有没有这个标记。
二、修复代码里的两个关键问题
你的unzip函数有两个容易忽略的错误,哪怕数据是对的,也会导致ZIP无法读取:
1. 错误的ZIP打开模式
你用了ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE,这两个参数是用来创建/覆盖ZIP文件的,不是读取已有文件!用这个模式打开已存在的ZIP,会清空原文件内容,自然numFiles会返回0。
正确的姿势是用只读模式打开:
$res = $zip->open($file, ZIPARCHIVE::RDONLY);
甚至可以省略第二个参数,默认就是只读模式。
2. 文件写入的模式问题
file_put_contents在Windows环境下可能会把二进制字符(比如0x0A)转成换行符0x0D0A,破坏ZIP的二进制结构。建议换成明确的二进制写入模式:
// 替换原来的file_put_contents $handle = fopen($file, 'wb'); fwrite($handle, $zipBinary); fclose($handle);
'wb'模式确保完全按二进制写入,不会做任何字符转换,跨平台更稳妥。
三、优化临时文件路径
你用tempnam("tmp", "zip")的相对路径,可能存在权限问题或者找不到目录的情况,换成系统临时目录更可靠:
$file = tempnam(sys_get_temp_dir(), "zip");
sys_get_temp_dir()会返回系统默认的临时目录,权限一般都是没问题的。
调试小技巧
- 先注释掉
unlink($file),把生成的临时文件保留下来,用7-Zip/WinRAR打开试试,或者在Unix系统下用file 临时文件名命令查看文件类型——如果输出不是Zip archive data,说明数据肯定有问题。 - 在
$zip->open失败时,可以输出错误码(ZipArchive有ER_*系列常量),比如error_log("ZIP打开失败,错误码:{$res}"),能帮你快速定位问题(比如ER_NOZIP就是文件不是有效的ZIP)。
修改后的完整函数示例
public static function unzip($zipBinary) { $zip = new ZipArchive; // 使用系统临时目录创建临时文件 $file = tempnam(sys_get_temp_dir(), "zip"); // 二进制模式写入数据 $handle = fopen($file, 'wb'); fwrite($handle, $zipBinary); fclose($handle); // 只读模式打开已有ZIP文件 $res = $zip->open($file, ZIPARCHIVE::RDONLY); if ($res === TRUE) { $files = []; for ($i = 0; $i < $zip->numFiles; $i++) { $files[$zip->getNameIndex($i)] = $zip->getFromIndex($i); } $zip->close(); unlink($file); return $files; } else { error_log("ZIP文件打开失败,错误码:{$res}"); unlink($file); return false; } }
内容的提问来源于stack exchange,提问作者lsg93
相关产品推荐
相关产品推荐

