在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目錄下還原完整結構,並進一步處理內容,如生成縮略圖、掃描病毒或做備份。
通過這種方式,可以極大簡化內容上傳及文件初始化的工作流程,提高開發效率。