在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 文件處理邏輯的有力工具。