我在 PHP 中遇到了一个奇怪的错误,我遍历了很多目录并通过压缩文件夹来归档旧的内容,然后删除包含其中所有文件的文件夹。这在大多数情况下都很好,但对于一些条目,我收到此错误:
警告:ZipArchive::close():创建临时文件失败: 未知错误 myfile.php 上 132号线
我有这个 PHP 代码,直接取自 https://stackoverflow.com/a/4914807/2028935 但我插入了一个
exit()
以确保捕获错误:
// Get real path for our folder
$rootPath = realpath("/myfolder/pathX");
// Initialize archive object
$zip = new ZipArchive();
$zip->open("/myfolder/myfile.zip", ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file) {
// Skip directories (they would be added automatically)
if (!$file->isDir()) {
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
if(!$zip->close()) {
exit();
}
错误在第 132 行触发,即这一行,
if(!$zip->close()) {
我没有文件夹或文件权限问题,因为文件夹和文件确实被删除了(另一个代码),但我无法弄清楚 ZIP 中的
Unknown error
是什么?
我在 Windows Server 上使用 PHP 7.4。
### 更新###
未知错误似乎是由于ZIP文件路径太长造成的,但我不明白为什么。如果
$zip->open("/myfolder/myfile.zip", ZipArchive::CREATE | ZipArchive::OVERWRITE);
中的路径长度大于或等于 250 个字符,则会出现此错误!?
我可以理解是否会有 256 或 260 个字符的限制,因为我可以看到那里可能有一些限制,但为什么是 250 个?
目前我正在研究是否可以通过使用 DOS 命令
SUBST
或通过注册表进行本地驱动器/文件夹映射来减少路径长度,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices
经过更多分析,我发现
Unknown error
是由于 ZIP 文件路径太长 - 它长于 250 个字符,这似乎是 Windows 限制,尽管我看到此限制上的数字波动,任何东西从 247 到 260。
我尝试过的一个可能的解决方案是在 DOS 命令中执行
SUBST
命令,该命令为长路径创建一个驱动器 - 就像这样 subst O: D:\very\long\..\path
。这将给出一个 O:\
,我可以直接连接,但这仅适用于我的本地用户帐户,也无法在重新启动后继续存在。
我发现有效的解决方案是在注册表中向
REG_SZ
添加新的 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices
。我添加了这个REG_SZ
(字符串):
O: => \DosDevices\D: ery\long...\path
重新启动 Windows Server(2019)后,我现在有了 O 驱动器,我可以在 IIS 中使用它(然后是 PHP),我的问题已经解决了:-)
在我的例子中,我执行的用户没有目录的访问权限:
# ls -ld foo
drwxrwxr-x 4 root root 4096 Apr 11 14:40 foo
通过将
$user = posix_getpwuid(posix_geteuid())['name'];
添加到脚本中来检查运行 php 脚本的用户。
在我的例子中,脚本是通过
www-data
用户执行的,因此我将目录的所有权更改为 www-data
:
chown -R www-data:www-data foo
这解决了我的问题。
(如果您因为安全原因认为这不好,可以通过评论联系我根据反馈编辑答案)