當使用者上傳 ZIP 壓縮檔(如大量圖片),後端需對檔案進行耗時處理。若使用者再次上傳更新後的 ZIP,比對兩個 ZIP 內容差異,僅處理變動檔案,可大幅節省資源。本文提供 ZipCompare 類別,呼叫系統 unzip -v 解析 ZIP 目錄,比對檔案名、大小、CRC32,回傳新增、刪除、相同三類清單。
compare($zipfile1, $zipfile2):回傳陣列 ['add'=>[], 'del'=>[], 'match'=>[]]unzip 指令(Linux 環境)<?php
class ZipCompare {
public function compare($zipfile1, $zipfile2) {
if(!$this->check_handler()) throw new Exception('unzip not install');
if(!$this->check($zipfile1) || !$this->check($zipfile2)) throw new Exception('zipfile not exists or error');
$zipinfo1 = $this->getInfo($zipfile1);
$zipinfo2 = $this->getInfo($zipfile2);
return $this->parse($zipinfo1, $zipinfo2);
}
private function getInfo($zipfile) {
$fields = array('Length','Method','Size','Cmpr','Date','Time','CRC-32','Name');
$verbose = shell_exec(sprintf("unzip -v %s | sed '\$d' | sed '\$d' | sed -n '4,\$p'", $zipfile));
$zipinfo = array();
foreach(explode("\n", $verbose) as $row) {
if(!$row) continue;
$row = preg_replace('/[ ]{2,}/', ' ', $row);
$tmp = array_slice(explode(' ', $row), 1);
$file = array_combine($fields, $tmp);
$zipinfo[$file['Name']] = $file['Length'].'_'.$file['CRC-32'];
}
return $zipinfo;
}
private function parse($zipinfo1, $zipinfo2) {
$result = array('add'=>array(), 'del'=>array(), 'match'=>array());
if($zipinfo1 && $zipinfo2) {
$result['add'] = array_values(array_diff(array_keys($zipinfo1), array_keys($zipinfo2)));
$result['del'] = array_values(array_diff(array_keys($zipinfo2), array_keys($zipinfo1)));
$match_file = array_values(array_diff(array_keys($zipinfo1), $result['add']));
foreach($match_file as $f) {
if($zipinfo1[$f]==$zipinfo2[$f]) $result['match'][]=$f;
else $result['add'][]=$f; // 同名但內容不同視為新增
}
}
return $result;
}
private function check($zipfile) { return file_exists($zipfile) && shell_exec(sprintf('unzip -v %s | wc -l', $zipfile))>1; }
private function check_handler() { return strstr(shell_exec('unzip -v'), 'version')!==false; }
}
?>
<?php
require "ZipCompare.class.php";
$obj = new ZipCompare();
$result = $obj->compare('test1.zip','test2.zip');
print_r($result);
Array
(
[add] => Array ( [0] => 9.jpg )
[del] => Array ( [0] => 5.jpg [1] => 6.jpg [2] => 7.jpg [3] => 8.jpg )
[match] => Array ( [0] => 1.jpg [1] => 10.jpg ... [12] => 4.jpg )
)
shell_exec 效能較低ZipArchive 類別可純 PHP 解析 ZIP,支援多層目錄,適合跨平台需求ZipArchive 移除外部指令相依ZipCompare 以系統指令快速實現 ZIP 內容差異比對,適合 Linux 環境下的批次處理前置過濾。若需跨平台或處理複雜目錄結構,建議改用 ZipArchive 純 PHP 實作。