早期 PHP 無內建 ZIP 支援,開發者常用第三方類(如 PHPZip、PclZip)純 PHP 實現壓縮。現代 PHP (5.2+) 內建 ZipArchive 類(需編譯 --enable-zip),效能遠超純 PHP 實現。本文介紹 PHPZip 類用法(歷史參考),並重點推薦 ZipArchive 及第三方庫 chumper/zipper、maennchen/zipstream-php 的現代最佳實踐。
<?php
require_once 'phpzip.class.php';
$zip = new PHPZip();
// 方法一:壓縮整個目錄(含子目錄)
$zip->Zip('', 'backup_full.zip'); // 當前目錄
// 方法二:壓縮指定文件列表
$files = ['1.txt', 'gb.txt', '5.txt'];
$zip->Zip($files, 'backup_files.zip');
// 方法三:壓縮指定目錄
$zip->Zip('/usr/local/sext/', 'backup_dir.zip');
?>
缺點:純 PHP 實現、大文件極慢、記憶體佔用高、不支援加密、停止維護。
# Ubuntu/Debian
apt-get install php-zip
# 或編譯 PHP 時添加 --enable-zip (PHP 7.3 前) / --with-zip (PHP 7.4+)
# PHP 8.0+ 內建,無需額外編譯參數
<?php
$zip = new ZipArchive();
$filename = 'backup.zip';
// 創建新壓縮包
if ($zip->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
die('無法創建壓縮包');
}
// 添加文件(保留相對路徑)
$zip->addFile('data/report.pdf', 'report.pdf');
$zip->addFile('images/logo.png', 'assets/logo.png');
// 添加目錄遞歸
function addDir(ZipArchive $zip, string $dir, string $prefix = '') {
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($items as $item) {
$localPath = $prefix . $item->getPathname();
$relativePath = $prefix . substr($item->getPathname(), strlen($dir) + 1);
if ($item->isDir()) {
$zip->addEmptyDir($relativePath);
} else {
$zip->addFile($localPath, $relativePath);
}
}
}
addDir($zip, '/var/www/html/uploads', 'uploads/');
// 設置註釋
$zip->setArchiveComment('備份於 ' . date('Y-m-d H:i:s'));
// 關閉並寫入磁盤
$zip->close();
echo "壓縮完成: $filename";
?>
<?php
$zip = new ZipArchive();
if ($zip->open('backup.zip') === true) {
$zip->extractTo('/var/www/html/restore/');
$zip->close();
echo '解壓完成';
} else {
echo '打開失敗';
}
?>
<?php
$zip = new ZipArchive();
$zip->open('secure.zip', ZipArchive::CREATE);
$zip->addFile('secret.txt');
$zip->setEncryptionName('secret.txt', ZipArchive::EM_AES_256, 'strong_password_123');
$zip->close();
?>
注意:PHP 7.2 前需 --with-libzip,且僅支援 ZipCrypto(弱)。AES-256 需較新 libzip。
ZipArchive 需將整個壓縮包寫入磁盤再輸出,大文件佔用磁盤 IO。使用 maennchen/zipstream-php 直接輸出到 HTTP 響應流:
<?php
require 'vendor/autoload.php';
use ZipStream\ZipStream;
$zip = new ZipStream('large-export.zip', [
'content_type' => 'application/zip',
'enable_zip64' => true,
]);
// 動態添加大文件(如資料庫導出 CSV)
$zip->addFileFromPath('export-1.csv', '/data/exports/part1.csv');
$zip->addFileFromPath('export-2.csv', '/data/exports/part2.csv');
// ... 可持續添加,邊壓縮邊輸出
$zip->finish();
// 自動發送 Header 並輸出流,無需佔用伺服器磁盤空間
?>
<?php
require 'vendor/autoload.php';
use Chumper\Zipper\Zipper;
$zipper = new Zipper();
$zipper->make('backup.zip')
->add('uploads/')
->add('database.sql')
->close();
// 或鏈式
Zipper::make('backup.zip')->folder('app')->add('config/')->close();
?>
| 方案 | 100MB 文件壓縮 | 記憶體峰值 | 支援加密 | 流式輸出 |
|---|---|---|---|---|
| PHPZip (純 PHP) | ~120 秒 | ~200MB | 否 | 否 |
| ZipArchive (C 擴展) | ~3 秒 | ~10MB | AES-256 (PHP 7.2+) | 否 |
| ZipStream (流式) | ~3 秒 | ~2MB | 否 | 是 |
| 問題 | 原因 | 解決 |
|---|---|---|
| Class 'ZipArchive' not found | 未安裝 php-zip 擴展 | 安裝 php-zip 或重新編譯 PHP |
| 添加文件失敗 | 路徑錯誤、權限不足、文件不存在 | 用絕對路徑、檢查 is_readable() |
| 中文文件名亂碼 | Zip 標準早期不支援 UTF-8 | PHP 8.0+ / libzip 1.7+ 自動處理,舊版需轉編碼 |
| 壓縮包超過 2GB/4GB | Zip64 支援 | ZipArchive::OVERWRITE | ZipArchive::CREATE (PHP 5.6+ 自動 Zip64) |
放棄純 PHP 的 PHPZip 類,首選內建 ZipArchive,功能完整、效能高、零依賴。大文件導出、低記憶體環境用 ZipStream 流式輸出。Laravel 專案可用 chumper/zipper 享受優雅 API。所有方案均基於 C 擴展,效能比純 PHP 快 1-2 個數量級。