總算到了PHP 的拿手好戲上場了,前面我們學習過Bzip2 、 LZF 、 Phar 和rar 這些壓縮相關擴展在PHP 的使用,不過它們要么是太冷門,要么就是很多功能不支援。而 Zip 則是在 PHP 中得到最大幅度功能支援的熱門壓縮格式,或者說是通用常見的一種壓縮格式。當然,也主要得益於 Zip 也是事實上的 Linux 環境中的通用壓縮格式。
安裝
對於PHP 來說,Zip 擴充功能已經整合在了PHP 的安裝包中,在Configure 的時候可以直接加上--with-zip ,如果在安裝的時候沒有加上這個參數,我們也可以在源碼包的ext/zip 下找到源碼,然後透過擴充安裝的方式來安裝。
建立一個壓縮包
$zip = new ZipArchive(); $filename = './test_zip.zip'; if($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE){ exit('cannot open ' . $filename .'\n'); } // 加入文字类型的文件 $zip->addFromString('testfile1.txt' . time(), "#1"); $zip->addFromString('testfile2.txt' . time(), "#2"); // 加入已存在的文件 $zip->addFile('rar.php', 'newrar.php'); echo $zip->numFiles, PHP_EOL; // 文件数量 echo $zip->status, PHP_EOL; // 压缩包状态 $zip->close(); // 使用操作系统的 unzip 查看 // # unzip -l test_zip.zip // Archive: test_zip.zip // Length Date Time Name // --------- ---------- ----- ---- // 2 07-08-2020 08:57 testfile1.txt1594169845 // 2 07-08-2020 08:57 testfile2.txt1594169845 // 2178 07-07-2020 08:55 newrar2.php // --------- ------- // 2182 3 files
之前學習過的rar 擴充功能是無法打包檔案或是建立新的壓縮包的,而Zip 一上來我們就學習的是建立一個新的壓縮包。透過實例化一個 ZipArchive 物件後,我們就可以使用 open() 函數開啟或建立一個壓縮包檔案。接著,我們使用了兩種添加內容的方式。 addFromString() 是加入文字類型的文件,也就是將一段文字轉換成文字檔案保存在這個壓縮包中。另外,我們透過 addFile() 來將外部的檔案加入到這個壓縮包中。
【推薦學習:PHP影片教學】
numFiles 和status 屬性可以分別查看到壓縮包檔案裡面的檔案數量及目前這個壓縮包的狀態資訊。最後直接使用 close() 關閉句柄即可。這樣,一個簡單的 Zip 壓縮包檔案就創建完成了。我們可以直接使用作業系統的 unzip 指令來查看壓縮包的內容。
讀取壓縮包內容及資訊
$zip = new ZipArchive(); $zip->open('./test_zip.zip'); print_r($zip); // 压缩包信息 // ZipArchive Object // ( // [status] => 0 // [statusSys] => 0 // [numFiles] => 40 // [filename] => /data/www/blog/test_zip.zip // [comment] => // ) var_dump($zip); // object(ZipArchive)#2 (5) { // ["status"]=> // int(0) // ["statusSys"]=> // int(0) // ["numFiles"]=> // int(40) // ["filename"]=> // string(27) "/data/www/blog/test_zip.zip" // ["comment"]=> // string(0) "" // } echo $zip->numFiles, PHP_EOL; echo $zip->status, PHP_EOL; echo $zip->statusSys, PHP_EOL; echo $zip->filename, PHP_EOL; echo $zip->comment, PHP_EOL; echo $zip->count(), PHP_EOL; for ($i=0; $i<$zip->numFiles;$i++) { echo "index: $i\n"; // 打印每个文件实体信息 print_r($zip->statIndex($i)); // index: 0 // Array // ( // [name] => testfile1.txt1594169845 // [index] => 0 // [crc] => 2930664868 // [size] => 2 // [mtime] => 1594169844 // [comp_size] => 2 // [comp_method] => 0 // [encryption_method] => 0 // ) // …… $entry = $zip->statIndex($i); if($entry['name'] == 'newrar.php'){ // 仅解压 newrar.php 文件到指定目录 $zip->extractTo('./test_zip_single', $entry['name']); } } // 修改压缩包内的文件名 $zip->renameName('newrar.php', 'newrar2.php'); print_r($zip->getFromIndex(2)); // 获取第二个文件的内容 print_r($zip->getFromName('newrar2.php')); // 获取指定文件名的文件内容 $zip->extractTo('./test_zip'); // 解压整个压缩包到指定目录 $zip->close();
其實讀取也是同樣的步驟,實例化一個 ZipArchive 類,然後 open() 開啟一個壓縮套件檔案句柄。接著就可以直接輸出一些壓縮包的屬性資訊。我們可以透過循環並透過 statIndex() 方法獲取每個檔案實體的資訊。這裡要注意的是 statIndex() 取得的是檔案的訊息,而不是這個檔案的內容。
當然,我們也可以透過 getFromIndex() 或 getFromName() 直接取得指定的檔案。透過 renameName() 直接將壓縮包內部的檔案改名,透過 extractTo() 將指定的檔案或整個壓縮包解壓縮到指定的目錄中。 extractTo() 方法的第二個參數如果指定了內容,則只會解壓縮指定的這個檔案。
壓縮目錄,設定說明以及流、偽協定方式讀取檔案
既然是壓縮包工具,那麼我們最常用的也就是直接將多個檔案或目錄進行打包。同時,也有很多壓縮包可以設定一些說明、密碼什麼的。另外,我們也可以透過專屬的 zip:// 偽協定來直接取得壓縮包內某個檔案的內容。這些功能,在 PHP 的 Zip 擴充功能中都能夠非常簡單方便地使用。
壓縮目錄
// 压缩目录 $zip = new ZipArchive(); $zip->open('./test_zip2.zip', ZIPARCHIVE::CREATE); $zip->addFile('rar.php', 'newrar.php'); $zip->addGlob('./test_zip/*.{php,txt}', GLOB_BRACE, ['add_path'=> 'new_path/']);
直接使用 addGlob 就可以幫助我們完成對某個檔案目錄下的所有檔案的內容打包。同時,它的第三個參數也可以指定這些檔案在壓縮包內部的路徑位址。
設定說明及密碼
// 设置注释、密码 $zip->setArchiveComment('This is rar Comment!'); $zip->setPassword('123'); $zip->close(); // 使用操作系统 unzip 查看 // # unzip -l test_zip2.zip // Archive: test_zip2.zip // This is rar Comment! // Length Date Time Name // --------- ---------- ----- ---- // 2178 07-07-2020 08:55 newrar.php // 2178 07-08-2020 10:36 new_path/./test_zip/newrar.php // 2178 07-08-2020 10:36 new_path/./test_zip/newrar2.php // --------- ------- // 6534 3 files
設定壓縮包的說明註解以及密碼都是有現成的函數方法直接使用的。我們再次通過作業系統的 unzip 指令,就可以查看到這個壓縮包的註解資訊以及打包的目錄內容。原本測試的 test_zip/ 目錄下的內容被放在了 new_path/ 目錄下,這就是我們自定的一個壓縮套件內部的路徑位址。
流、偽協定方式讀取檔案
// 流、伪协议方法读取压缩包内容 $zip = new ZipArchive(); $zip->open('./test_zip2.zip'); // 获取文件流 $fp = $zip->getStream('newrar.php'); while(!feof($fp)){ echo fread($fp, 2); } fclose($fp); // 使用伪协议 $fp = fopen('zip://' . dirname(__FILE__) . '/test_zip2.zip#newrar.php', 'r'); while(!feof($fp)){ echo fread($fp, 2); } fclose($fp); // file_get_contents 使用伪协议 echo file_get_contents('zip://' . dirname(__FILE__) . '/test_zip2.zip#newrar.php'); // 直接使用伪协议将文件拷贝出来 copy('zip://' . dirname(__FILE__) . '/test_zip2.zip#newrar.php', './newrar2.php');
首先,我們透過getStream() 方法直接取得壓縮包中某個檔案的流,這種方式幾乎是所有壓縮類別擴充都會提供的一種讀取文件的方式。而下面的方式則是透過 zip:// 偽協定直接使用 fopen() 、 file_get_contents() 函數來讀取壓縮包內部的某個檔案。既然有了這麼方便的一個偽協議,那麼我們要簡單的取得並解壓縮某個文件也就變得十分容易了,直接使用 copy() 函數將這個文件拷貝出來就可以了。
总结
是不是感觉比 rar 的操作强大了许多。都说了这是 PHP 主力支持的一种通用压缩格式,所以当然功能会丰富许多,而且还有很多的函数方法我们并没有全部列出来,如果全列出来的话还不如大家自己去看手册呢。这里就是以一些简单的例子让大家看到这类扩展功能的操作,方便大家在业务选型的时候能够快速的联想到我们 PHP 就已经提供了这些现成的扩展。需要了解 Zip 其它内容的同学可以移步最下方的链接直接进入手册中查阅。
测试代码: https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84zip%E5%8E%8B%E7%BC%A9%E5%B7%A5%E5%85%B7%E6%89%A9%E5%B1%95%E5%8C%85%E5%AD%A6%E4%B9%A0.php 参考文档:https://www.php.net/manual/zh/book.zip.php