在 PHP 中处理 ZIP 文件是一项常见的任务,特别是当我们需要从压缩包中提取内容或读取文件结构时。zip_read() 函数是 ZipArchive 类之外的另一种处理 ZIP 文件的方式,它常与 zip_open() 和 zip_entry_read() 等函数配合使用。尽管这些函数比较底层,但对于想深入掌控 ZIP 文件结构的开发者来说,它们依然具有重要意义,特别是在处理包含多层嵌套目录的 ZIP 文件时。
首先,我们需要用 zip_open() 打开 ZIP 文件,并使用 zip_read() 遍历每一个条目。以下是基本的结构:
$zip = zip_open("nested_directories.zip");
if (is_resource($zip)) {
while ($entry = zip_read($zip)) {
$entryName = zip_entry_name($entry);
echo "Entry: $entryName\n";
}
zip_close($zip);
}
该代码段能够列出 ZIP 文件中所有的条目(包括目录和文件),但仅仅列出还不够,我们需要更深入地处理嵌套的结构。
ZIP 文件中的嵌套目录并不像真实的文件系统那样具备“树状”的结构。每一个目录或文件,都是以路径字符串的方式表现,例如:
photos/
photos/vacation/
photos/vacation/beach.jpg
documents/report.docx
因此,我们需要根据 / 来判断文件路径的深度。通过简单的 explode() 可以分析每一层:
$depth = substr_count($entryName, '/');
这在我们需要根据目录层级执行特定操作时非常有用。
要将 ZIP 文件中的内容提取到指定目录并保留其目录结构,我们可以结合 zip_entry_read() 和 file_put_contents() 来完成。如下所示:
$zip = zip_open("nested_directories.zip");
$extractPath = "extracted/";
if (is_resource($zip)) {
while ($entry = zip_read($zip)) {
if (zip_entry_open($zip, $entry, "r")) {
$entryName = zip_entry_name($entry);
$fullPath = $extractPath . $entryName;
// 如果是目录,确保创建
if (substr($entryName, -1) === '/') {
if (!is_dir($fullPath)) {
mkdir($fullPath, 0755, true);
}
} else {
// 如果是文件,确保上级目录存在
$dir = dirname($fullPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$content = zip_entry_read($entry, zip_entry_filesize($entry));
file_put_contents($fullPath, $content);
}
zip_entry_close($entry);
}
}
zip_close($zip);
}
上述代码实现了完整的嵌套结构提取功能,处理目录创建和文件写入,并保证原始结构不变。
设想你开发了一个网站(比如 https://m66.net/upload)提供 ZIP 上传功能,用户上传的 ZIP 文件中可能含有复杂的多层嵌套目录。为了安全地解压这些文件到临时目录供进一步处理,你可以先用上面的代码提取内容,再遍历目标文件夹进行处理。
为了避免路径穿越漏洞(如恶意 ZIP 包含 ../../etc/passwd),你还应在路径拼接后进行安全校验:
$realBase = realpath($extractPath);
$realUserPath = realpath($fullPath);
if (strpos($realUserPath, $realBase) !== 0) {
// 非法路径,跳过
continue;
}
避免不必要的文件读取:只处理需要的目录或特定扩展名文件。
按需加载:对于大型文件,不使用 zip_entry_read($entry, zip_entry_filesize($entry)) 一次性加载,而是使用流式读取。
批处理操作:如果最终操作涉及数据库或外部服务,考虑缓冲处理结果,批量提交。
使用 zip_read() 函数处理 ZIP 文件虽然不如 ZipArchive 直观,但在某些对结构控制要求较高的场景中依然非常实用。通过分析路径字符串,我们可以有效地处理多层嵌套目录,并将内容安全地提取到服务器指定路径下。结合适当的安全和性能优化措施,这种方式依然是构建复杂 ZIP 文件处理逻辑的有力工具。