ZipArchive扩展遇到的问题

近期已经遇到了两个关于php扩展zip压缩的问题,而且问题都属于比较难以排查的,因为都跟环境有关系,所以这里总结记录一下。

问题1:php版本问题

1
2
3
4
5
$zip = new \ZipArchive;
$res = $zip->open($destination, \ZIPARCHIVE::OVERWRITE);
if ($res == true) {
// todo
}

在php5.5下,以上代码是可以正常运行,当$destination这个文件路径不存在的时候会创建,如果存在则重新生成并覆盖。我们线上的部署环境是用php5.5,我本机使用php5.6,然而这段代码在php5.6下运行就会报错,当$destination不存在时候它无法生成新文件!
stackoverflow一番之后,顺利找到问题的根源,php5.6已经不再支持这个特性,为了解决这个问题必须使用下面的代码:

1
2
3
4
5
6
$zip = new \ZipArchive;
// 同时指定\ZIPARCHIVE::CREATE 解决php5.6的不兼容问题
$res = $zip->open($destination, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE);
if ($res == true) {
// todo
}

问题2:zip扩展版本问题

1
2
3
4
5
6
7
$zip = new \ZipArchive;
$res = $zip->open($destination, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE);
if ($res === true) {
$fileName = iconv("UTF-8", "GBK//IGNORE", $fileName);
$zip->addFile($exportFilePath, $fileName);
$zip->close();
}

这里可以看到fileName变量做了一次编码转换,因为当文件名称为中文的时候,压缩包解压出来的文件名会变为乱码,所以这里做了一次特殊转码。
然而,同样的代码到了另外一台服务器上运行,会发现压缩包下载下来双击打开里面的文件会被隐藏了!一步一步调试代码后,发现只要移除那一句对fileName变量的编码转换,压缩就会变得正常了,中文也不会出现乱码,但是有些环境不转码又会出现乱码,这让人非常怀疑是扩展版本问题。执行php –ri zip命令查看扩展的版本,确实也发现了两个环境的扩展版本不一样,乱码的环境zip版本是1.11.0,而另一个环境是1.13.0,这样就基本定位到问题了,1.11.0版本的zip扩展对中文的文件名称支持地不好,在1.13.0版本就修复了这个问题,然而如果代码中对文件名称做了特殊转码,在1.13.0版本又会引发新的问题,压缩包打开不显示文件。
最终的解决方案是升级所有环境的zip扩展到1.13.0版本,然后移除掉对file转码的代码。