首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP ZipArchive 解壓縮 ZIP 檔案完整實作與坑點避雷

     編輯:PHP 相關知識

環境需求

  • PHP --with-zip 編譯或安裝 php-zip 擴充 (Ubuntu: apt install php-zip, Windows: php.ini 啟用 extension=zip)
  • ZIP 檔案需為標準格式,支援 Zip64 (大於 4GB)、AES-256 加密 (PHP 7.2+)

基礎解壓縮代碼

<?php
header('Content-Type: text/html; charset=UTF-8');
set_time_limit(0); // 大檔案防止超時

$zipPath = __DIR__ . '/uploads/package.zip';
$extractTo = __DIR__ . '/extracted/';

if (!file_exists($zipPath)) {
    die("檔案不存在: {$zipPath}");
}

$zip = new ZipArchive();
$res = $zip->open($zipPath);
if ($res !== true) {
    die("開啟失敗,錯誤碼: {$res}"); // 參考 ZipArchive::ER_* 常數
}

// 可選:檢查內容清單
for ($i = 0; $i < $zip->numFiles; $i++) {
    $stat = $zip->statIndex($i);
    echo "{$stat['name']} ({$stat['size']} bytes, CRC32: {$stat['crc']})\n";
}

// 解壓縮 (可指定特定檔案)
$zip->extractTo($extractTo); // 全部
// $zip->extractTo($extractTo, ['file1.txt', 'dir/file2.php']); // 指定檔案

$zip->close();
echo "解壓縮完成至: {$extractTo}";

進階功能與常見需求

1. 密碼保護的 ZIP (PHP 7.2+)

$zip->setPassword('secret123'); // 解壓縮前設定
// 或建立加密 ZIP
$zip->open('secure.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->setPassword('secret123');
$zip->setEncryptionName('data.sql', ZipArchive::EM_AES_256);
$zip->addFile('data.sql');
$zip->close();

2. 記憶體優化:串流處理大檔案

ZipArchive 需將整個 ZIP 結構讀入記憶體。超大檔案 (GB 級) 建議:

  • CLI 模式執行,調大 memory_limit
  • 系統命令 exec('unzip -q large.zip -d out/') 避免 PHP 記憶體限制
  • 分卷壓縮 (zip -s 100m) 單卷處理

3. 保留檔案權限與時間戳

$zip->extractTo($extractTo);
// ZipArchive 會嘗試還原 mtime,權限依賴作業系統/檔案系統支援
// Windows 環境權限資訊通常遺失

4. 避免路徑遍歷攻擊 (Zip Slip)

// 惡意 ZIP 含 ../../etc/passwd 導致任意寫入
// 解壓縮前掃描檔名
for ($i = 0; $i < $zip->numFiles; $i++) {
    $name = $zip->getNameIndex($i);
    // 正規化路徑並檢查是否嘗試跳出目標目錄
    $fullPath = realpath($extractTo . DIRECTORY_SEPARATOR . $name);
    if ($fullPath === false || strpos($fullPath, realpath($extractTo)) !== 0) {
        die("偵測到路徑遍歷攻擊: {$name}");
    }
}
$zip->extractTo($extractTo);

錯誤碼對照表

常數值含義
ZipArchive::ER_OK0無錯誤
ZipArchive::ER_MULTIDISK1多磁碟 ZIP 不支援
ZipArchive::ER_RENAME2重命名失敗
ZipArchive::ER_CLOSE3關閉失敗
ZipArchive::ER_SEEK4Seek 錯誤
ZipArchive::ER_READ5讀取錯誤
ZipArchive::ER_WRITE6寫入錯誤
ZipArchive::ER_CRC7CRC 校驗失敗
ZipArchive::ER_ZIPCLOSED8ZIP 已關閉
ZipArchive::ER_NOENT9檔案不存在
ZipArchive::ER_EXISTS10檔案已存在
ZipArchive::ER_OPEN11無法開啟
ZipArchive::ER_TMPOPEN12臨時檔開啟失敗
ZipArchive::ER_ZLIB13Zlib 錯誤
ZipArchive::ER_MEMORY14記憶體不足
ZipArchive::ER_CHANGED15內容已變更
ZipArchive::ER_COMPNOTSUPP16壓縮方式不支援
ZipArchive::ER_EOF17過早 EOF
ZipArchive::ER_INVAL18無效參數
ZipArchive::ER_NOZIP19非 ZIP 檔案
ZipArchive::ER_INTERNAL20內部錯誤
ZipArchive::ER_INCONS21資料不一致
ZipArchive::ER_REMOVE22移除失敗
ZipArchive::ER_DELETED23項目已刪除

建立 ZIP 檔案補充

$zip = new ZipArchive();
$zip->open('backup.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);

// 新增檔案
$zip->addFile('/var/log/nginx/access.log', 'logs/access.log');

// 新增字串內容
$zip->addFromString('README.txt', "建立時間: " . date('c'));

// 新增空目錄
$zip->addEmptyDir('empty_dir/');

$zip->close();
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved