无尘阁日记

无尘阁日记

别再被坑!PHP7.1 下 ZipArchive 根本不能加密 zip,多文件加密正确姿势在这里
2025-09-29

一、问题背景

在业务开发中,我们经常需要对文件进行 压缩打包并加密,比如用户上传的文件需要打包成 zip 后再提供下载,或者在 API 里生成带密码的压缩包,提升安全性。

一开始,很多人(包括我)都会自然想到:
👉 PHP 自带的 ZipArchive,调用 $zip->setPassword('xxx') 不就行了吗?

结果实际跑下来,压缩包生成了,但用 WinRAR / 7-Zip 打开时 完全不提示输入密码,文件还是明文的!

于是,我开始了一场 “为什么 PHP7.1 的 ZipArchive 不加密” 的踩坑之旅。

二、第一次尝试:ZipArchive + setPassword()

我最初写的代码大概长这样:

$zip = new \ZipArchive(); $zip->open($zipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); foreach ($files as $file) {     $zip->addFile($file, basename($file)); } $zip->setPassword('123456'); $zip->close();

结果:

  • zip 文件能打开;

  • 但完全没加密!

后来查文档才发现:

  • setPassword() 只是设置密码上下文,不会自动加密文件

  • 真正加密要配合 setEncryptionName()setEncryptionIndex()

  • 而这两个方法是 PHP7.2+ 才有的

👉 坑点 #1:PHP7.1 的 ZipArchive 根本不支持加密写入,只能解密已有压缩包。

三、第二次尝试:setEncryptionName()

我升级到新环境测试:

$zip->setPassword('123456'); $zip->setEncryptionName('test.txt', \ZipArchive::EM_AES_256);

这才发现 AES-256 加密是真正可用的。但坏消息是:在 PHP7.1 里完全没有这个方法

👉 坑点 #2:AES 加密必须 PHP7.2+ + 新版 libzip,7.1 压根没有。

四、退而求其次:系统命令 zip -P

既然 PHP7.1 自带的 ZipArchive 不行,我只能换思路:
利用系统里的 zip 命令来完成加密。

改造后的代码:

$fileList = implode(' ', array_map('escapeshellarg', $files)); $cmd = "LANG=en_US.UTF-8 zip -j -P " . escapeshellarg($password) . " " . escapeshellarg($zipFile) . " " . $fileList; exec($cmd, $output, $resultCode); if ($resultCode === 0) {     echo "压缩成功"; } else {     echo "压缩失败"; }

效果:

  • 多文件压缩 ✅

  • 打开 zip 时提示输入密码 ✅

  • 兼容 WinRAR/7-Zip ✅

这里我也踩到一个小坑:
👉 文件路径或密码里可能带空格/特殊符号,如果直接拼接字符串,命令会出错甚至被注入。

所以要用 escapeshellarg() 包裹参数,才能安全可靠。

五、最终结论

  1. PHP7.1 里:

    • ZipArchive::setPassword() 只能用来 解密,不会加密;

    • 没有 setEncryptionName() 方法,无法开启 AES 加密;

    • 👉 别再幻想用 ZipArchive 来加密 zip 文件了!

  2. 解决方案:

    • 能升级 PHP → 上到 7.2+,用 setEncryptionName(),支持 AES-128/192/256;

    • 不能升级 PHP → 用系统命令 zip -P,简单粗暴;

    • 更高需求 → 引入第三方库 nelexa/php-zip,支持 AES。

  3. 实践建议:

    • 多文件加密 → 推荐直接用系统命令(配合 escapeshellarg 避免注入);

    • 生产环境安全性要求高 → 升级到支持 AES 的 PHP;

    • 千万别再被 $zip->setPassword() 迷惑了,以为它能加密。

六、踩坑经验总结

  • 看到文档≠能用,要注意不同 PHP 版本和 libzip 版本差异;

  • setPassword() 在 PHP7.1 根本不会加密,它只是“解密密码”;

  • 多文件加密最靠谱的方法就是调用系统命令 zip -P

  • 安全性更高的 AES 加密,需要 PHP7.2+ 或第三方库。

📢 一句话总结

在 PHP7.1 下,ZipArchive 根本无法实现真正的加密压缩,唯一稳妥的办法是调用系统 zip -P 命令,或者升级到支持 AES 的 PHP7.2+。