--with-zip 編譯或安裝 php-zip 擴充 (Ubuntu: apt install php-zip, Windows: php.ini 啟用 extension=zip)<?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}";
$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();
ZipArchive 需將整個 ZIP 結構讀入記憶體。超大檔案 (GB 級) 建議:
memory_limitexec('unzip -q large.zip -d out/') 避免 PHP 記憶體限制zip -s 100m) 單卷處理$zip->extractTo($extractTo);
// ZipArchive 會嘗試還原 mtime,權限依賴作業系統/檔案系統支援
// Windows 環境權限資訊通常遺失
// 惡意 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_OK | 0 | 無錯誤 |
ZipArchive::ER_MULTIDISK | 1 | 多磁碟 ZIP 不支援 |
ZipArchive::ER_RENAME | 2 | 重命名失敗 |
ZipArchive::ER_CLOSE | 3 | 關閉失敗 |
ZipArchive::ER_SEEK | 4 | Seek 錯誤 |
ZipArchive::ER_READ | 5 | 讀取錯誤 |
ZipArchive::ER_WRITE | 6 | 寫入錯誤 |
ZipArchive::ER_CRC | 7 | CRC 校驗失敗 |
ZipArchive::ER_ZIPCLOSED | 8 | ZIP 已關閉 |
ZipArchive::ER_NOENT | 9 | 檔案不存在 |
ZipArchive::ER_EXISTS | 10 | 檔案已存在 |
ZipArchive::ER_OPEN | 11 | 無法開啟 |
ZipArchive::ER_TMPOPEN | 12 | 臨時檔開啟失敗 |
ZipArchive::ER_ZLIB | 13 | Zlib 錯誤 |
ZipArchive::ER_MEMORY | 14 | 記憶體不足 |
ZipArchive::ER_CHANGED | 15 | 內容已變更 |
ZipArchive::ER_COMPNOTSUPP | 16 | 壓縮方式不支援 |
ZipArchive::ER_EOF | 17 | 過早 EOF |
ZipArchive::ER_INVAL | 18 | 無效參數 |
ZipArchive::ER_NOZIP | 19 | 非 ZIP 檔案 |
ZipArchive::ER_INTERNAL | 20 | 內部錯誤 |
ZipArchive::ER_INCONS | 21 | 資料不一致 |
ZipArchive::ER_REMOVE | 22 | 移除失敗 |
ZipArchive::ER_DELETED | 23 | 項目已刪除 |
$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();