總算到了咱們壓縮相關擴展的最後一篇文章了,最後咱們要學習的也是 Linux 下很是經常使用的一種壓縮格式:.gz 的壓縮擴展。做爲 PHP 的自帶擴展,就像 zip 同樣,zlib 擴展是隨着 PHP 的安裝包一塊兒發佈的,因此咱們在編譯的時候直接加上 --with-zlib 就能夠了,若是沒法找到對應的軟件包的話,使用 yum 安裝相應的軟件包便可。php
// 建立壓縮包 $zp = gzopen('./gztest.gz', "w9"); gzwrite($zp, "Only test, test, test, test, test, test!\n"); gzclose($zp);
壓縮包的建立很是地簡單,不過 PHP 的這個擴展中,只能使用 gzwrite() 來建立這種字符串類型的壓縮包,沒法直接將某些目錄或者文件進行打包。html
建立壓縮包成功後,咱們就能夠經過系統的 tar 命令來解壓或者查看文件了。git
// 讀取壓縮包 $zp = gzopen('./gztest.gz', "r"); echo gzread($zp, 3); gzpassthru($zp); // 輸出 gz 文件指針中的全部剩餘數據 // Only test, test, test, test, test, test! echo PHP_EOL; gzpassthru($zp); // gzrewind($zp); // 將 gz 指針的遊標返回到最開始的位置 gzpassthru($zp); // Only test, test, test, test, test, test! echo PHP_EOL; gzclose($zp);
讀取操做其實也很是簡單,直接使用 gzpassthru() 就能夠輸出當前壓縮包裏面的內容,而且是直接打印出來。固然,它也是以相似於文件指針的形式進行輸出的,因此若是咱們輸出過一次以後,就必需要使用 gzrewind() 將指針的遊標還原到句柄最開始的位置。程序員
對於 zlib 的壓縮包來講,咱們還有不少其它的方式能夠進行文件內容的讀取。github
// 讀取壓縮包二 $gz = gzopen('./gztest.gz', 'r'); while (!gzeof($gz)) { echo gzgetc($gz); } gzclose($gz); // Only test, test, test, test, test, test! echo PHP_EOL; // 讀取壓縮包三 echo readgzfile("./gztest.gz"); // Only test, test, test, test, test, test! echo PHP_EOL; // 讀取壓縮包四 print_r(gzfile("./gztest.gz")); // Array // ( // [0] => Only test, test, test, test, test, test! // ) echo PHP_EOL;
這裏一口氣就提供了三種讀取的方式。首先固然仍是咱們最熟悉的文件操做形式的讀取,使用的是 zlib 爲咱們提供的 gzeof() 和 gzgetc() 函數。除了 gzgetc() 以外,也提供了包括 gzgets() 和 gzgetss() ,分別是按行和按 HTML 格式行的讀取。其次,咱們可使用 readgzfile() 來直接讀取整個壓縮文件的內容,連 gzopen() 均可以省了,與它相似的是 gzfile() 函數,這個函數與 readgzfile() 的區別就是它讀取的內容是以數組形式返回的,對於多文件的壓縮包更有用。算法
既然 zlib 所壓縮的格式是 .gz 類型,並且還只能作字符串形式的壓縮,那麼很多小夥伴確定有疑問了,它和 gzip 有什麼關係呢?其實,zlib 除了是能夠作爲壓縮打包工具以外,也能夠作爲 gzip 工具應用到咱們的服務器中。固然,如今大多數狀況下咱們只須要開啓 Nginx 或者 Apache 的 gzip 壓縮功能就能夠了,不須要咱們再到 PHP 中進行處理了。不過作爲一名合格的 PHP 程序員,相關的操做函數咱們仍是須要學習的,說不定哪天就用上了呢。數組
// 壓縮類型及相關操做 // gzcompress 默認使用ZLIB_ENCODING_DEFLATE編碼,使用zlib壓縮格式,其實是用 deflate 壓縮數據,而後加上 zlib 頭和 CRC 校驗 $compressed = gzcompress('Compress me', 9); echo $compressed; // x�s��-(J-.V�M�? echo PHP_EOL; echo gzuncompress($compressed); // Compress me echo PHP_EOL; // gzencode 默認使用ZLIB_ENCODING_GZIP編碼,使用gzip壓縮格式,其實是使用defalte 算法壓縮數據,而後加上文件頭和adler32校驗 $compressed = gzencode('Compress me', 9); echo $compressed; // s��-(J-.V�M�jM4 echo PHP_EOL; echo gzdecode($compressed); // Compress me echo PHP_EOL; // gzdeflate 默認使用ZLIB_ENCODING_RAW編碼方式,使用deflate數據壓縮算法,其實是先用 LZ77 壓縮,而後用霍夫曼編碼壓縮 $compressed = gzdeflate('Compress me', 9); echo $compressed; // s��-(J-.V�M echo PHP_EOL; echo gzinflate($compressed); // Compress me echo PHP_EOL;
其實註釋中已經寫得很清晰了,不止是 PHP ,Nginx 也是會提供這三種編碼格式的,並且咱們從瀏覽器中就能夠看出當前訪問的網站使用的是哪一種壓縮編碼格式。好比咱們訪問 PHP 的官方網站所返回的內容:瀏覽器
從性能的維度看:deflate 好於 gzip 好於 zlib,而從文本文件默認壓縮率壓縮後體積的維度看:deflate 好於 zlib 好於 gzip 。也就是說,deflate 格式無論在性能仍是壓縮率來講都是如今比較好的選擇。固然,這樣好的格式對於 CPU 的硬件性能的影響就不清楚了,畢竟咱們沒有大型的功能頁面來進行測試,起碼對於普通的網站頁面來講,已經綽綽有餘了。服務器
另外,就像其它的壓縮工具同樣,可以對於字符串進行編碼的工具咱們均可以擴展一個應用場景,那就是數據的加密能力,這個在前面 Bzip2 、 LZF 相關的這些文章已經說過了,就再也不多說了。函數
最後,咱們還有一個通用的函數經過預約義的常量直接能夠操做這三種類型的編碼及解碼。
// 通用壓縮函數 $compressed = zlib_encode('Compress me', ZLIB_ENCODING_GZIP, 9); echo $compressed; // ZLIB_ENCODING_RAW:s��-(J-.V�M // ZLIB_ENCODING_DEFLATE:x�s��-(J-.V�M�? // ZLIB_ENCODING_GZIP:s��-(J-.V�M�jM4 echo PHP_EOL; echo zlib_get_coding_type(); echo PHP_EOL; echo zlib_decode($compressed); // Compress me echo PHP_EOL;
zlib_encode() 函數的第二個參數就是須要指定一個編碼的類型,這裏 zlib 擴展已經爲咱們準備好了 ZLIB_ENCODING_RAW 、 ZLIB_ENCODING_DEFLATE 、 ZLIB_ENCODING_GZIP 這三個類型的常量。而解壓 zlib_decode() 則不須要再進行指定了,它會直接根據文件頭自動選擇相應的編碼格式對內容進行解碼。
在 PHP7 中,zlib 擴展爲咱們增長一種能夠增量壓縮編碼的操做函數,就是能夠在不使用對象句柄的狀況下,使用函數直接增長內容。
// PHP7 新增的增量壓縮操做函數 $deflateContext = deflate_init(ZLIB_ENCODING_GZIP); $compressed = deflate_add($deflateContext, "數據壓縮", ZLIB_NO_FLUSH); $compressed .= deflate_add($deflateContext, ",更多數據", ZLIB_NO_FLUSH); $compressed .= deflate_add($deflateContext, ",繼續添加更多數據!", ZLIB_FINISH); // ZLIB_FINISH 終止 echo $compressed, PHP_EOL; // {6uó�uO����Y�~Oϳ�[�.�� // �>߽���϶�~ڵU�h�9 $inflateContext = inflate_init(ZLIB_ENCODING_GZIP); $uncompressed = inflate_add($inflateContext, $compressed, ZLIB_NO_FLUSH); $uncompressed .= inflate_add($inflateContext, NULL, ZLIB_FINISH); echo $uncompressed; // 數據壓縮,更多數據,繼續添加更多數據!
就像例子中展現的那樣,deflate_add() 用於增量的添加內容到編碼文件中,當標誌爲 ZLIB_FINISH 時結束操做的寫入。deflate_init() 和 inflate_init() 分別是編碼和反編碼對應的初始化操做。
關於壓縮解壓相關的擴展咱們已經介紹了 Bzip2 、 LZF 、 Phar 、 rar 、 zip 和 zlib 這些官方的擴展,在實際的生產中咱們其實會比較經常使用到的是 zip 和 zlib ,固然,對於其它的格式也有了必定的學習瞭解,剩下的就是咱們本身在用到的時候再次的深度研究了。這一個系列的內容讓我對這些壓縮格式也有了更一步的瞭解,但願你們也能從中獲益。
測試代碼:
參考文檔:
https://www.php.net/manual/zh/book.zlib.php
各自媒體平臺都可搜索【硬核項目經理】