在PHP中处理ZIP压缩文件时,zip_read() 函数可以帮助我们逐条读取压缩包内的内容。而配合 scandir() 函数进行递归文件夹操作,我们可以方便地在服务器端实现一个自动解压ZIP文件并保留其目录结构的功能。本文将详细介绍如何通过这两个函数构建这样的脚本。
确保你的PHP环境已经开启了 zip 扩展。如果没有开启,可以通过编辑 php.ini 文件,找到如下配置行并取消注释:
extension=zip
然后重启你的Web服务器。
打开ZIP文件;
遍历ZIP中的每一个条目;
判断条目是否为目录或文件;
使用 scandir() 结合自定义函数递归创建目录结构;
将ZIP中的文件写入目标路径。
<?php
function createDirRecursive($path) {
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
}
function unzipWithStructure($zipFilePath, $destination) {
$zip = zip_open($zipFilePath);
if (is_resource($zip)) {
while ($zip_entry = zip_read($zip)) {
$entryName = zip_entry_name($zip_entry);
$fullPath = $destination . '/' . $entryName;
// 如果是目录,则创建
if (substr($entryName, -1) === '/') {
createDirRecursive($fullPath);
} else {
// 确保文件所在目录存在
$dirPath = dirname($fullPath);
createDirRecursive($dirPath);
if (zip_entry_open($zip, $zip_entry)) {
$fileContent = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
file_put_contents($fullPath, $fileContent);
zip_entry_close($zip_entry);
}
}
}
zip_close($zip);
} else {
echo "无法打开ZIP文件: $zipFilePath";
}
}
// 使用示例
$zipPath = '/var/www/html/uploads/sample.zip';
$extractTo = '/var/www/html/extracted';
// 调用函数进行解压
unzipWithStructure($zipPath, $extractTo);
?>
使用 scandir() 可进一步验证目标目录结构是否被正确创建。例如:
function listAllFiles($dir) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file === '.' || $file === '..') continue;
$path = $dir . '/' . $file;
if (is_dir($path)) {
echo "目录: $path\n";
listAllFiles($path);
} else {
echo "文件: $path\n";
}
}
}
listAllFiles('/var/www/html/extracted');
执行上述代码后,可以输出所有被解压出来的文件和文件夹,方便调试和验证。
所有路径应使用绝对路径以避免权限或路径错误;
在生产环境中,应注意ZIP文件的来源,防止目录穿越攻击(例如 ZIP 中含有 ../../);
可结合 realpath() 对路径进行规范化处理;
如果文件较大,建议使用流式读取方式处理,防止内存溢出。
这个脚本适用于上传压缩文件并自动解压的功能,如用户上传一个包含多层目录结构的ZIP文件到 m66.net/upload,后台可直接通过以上脚本在 m66.net/storage 目录下还原完整结构,并进一步处理内容,如生成缩略图、扫描病毒或做备份。
通过这种方式,可以极大简化内容上传及文件初始化的工作流程,提高开发效率。