您的位置:首頁技術文章
文章詳情頁

PHP擴展之壓縮與歸檔擴展2——Phar

瀏覽:78日期:2022-09-15 15:12:13

Phar 歸檔的概念來自 Java? 技術的 JAR 歸檔,它允許使用單個文件打包應用程序,這個文件中包含運行應用程序所需的所有東西。該文件不同于單個可執行文件,后者通常由編程語言生成,比如 C,因為該文件實際上是一個歸檔文件而非編譯過的應用程序。因此 JAR 文件實際上包含組成應用程序的文件,但是考慮到安全性,不對這些文件進行仔細區分。Phar 擴展正是基于類似的理念,但是在設計時主要針對 PHP 的 Web 環境。同樣,與 JAR 歸檔不同的是,Phar 歸檔可由 PHP 本身處理,因此不需要使用額外的工具來創建或使用。

Phar 擴展對 PHP 來說并不是一個新鮮的概念。它最初使用 PHP 編寫并被命名為 PHP_Archive,然后在 2005 年被添加到 PEAR 庫。然而在實際中,解決這一問題的純 PHP 解決方案非常緩慢,因此 2007 年重新編寫為純 C 語言擴展,同時添加了使用 SPL 的ArrayAccess?對象遍歷 Phar 歸檔的支持。自那時起,人們做了大量工作來改善 Phar 歸檔的性能。

創建 Phar

創建 Phar 文件需要執行若干步驟。所有步驟需要用到某種形式的 PHP 命令完成創建,因為不存在用于創建歸檔的獨立工具。此外,要創建和修改 Phar 文件,php.ini 設置 phar.readonly 必須被設置為 0。在 PHP 的 Phar 歸檔內打開和引用文件時不需要使用到該設置。

讓我們看一看創建可用于驅動應用程序的 Phar 文件需要哪些步驟。應用程序的設計目標是從 Web 瀏覽器或命令提示符直接加載。第一步是創建 Phar 文件,因此我們將創建清單 1 所示的?Phar?對象。對象引用將允許您控制 Phar 歸檔的所有方面。

示例 1. 創建?Phar?對象

$p = new Phar(’/path/to/my.phar’, CURRENT_AS_FILEINFO | KEY_AS_FILENAME, ’my.phar’);$p->startBuffering();

構造函數的第一個參數表示保存 Phar 文件的位置。第二個參數將所有參數都傳遞給?RecursiveDirectoryIterator?父類。第三個參數是在流上下文中引用 Phar 歸檔的別名。因此對于清單 1,可以在這個 Phar 歸檔中使用 phar://my.phar 引用文件。您還可以發出Phar::startBuffering()?方法調用來緩沖對歸檔做出的修改,直到發出?Phar::stopBuffering()?命令為止。盡管不一定要執行上述操作,但是這樣做確實改善了創建或修改歸檔的性能,因為它避免了每次在腳本中修改歸檔時對做出的修改進行保存。

默認情況下,創建的 Phar 將使用原生的基于 Phar 的歸檔格式。還可以按照清單 2 所示將格式轉換為 ZIP 格式,從而對 Phar 文件使用 ZIP 或 TAR 格式。示例 2. 將存儲格式轉換為 ZIP 格式

$p = $p->convertToExecutable(Phar::ZIP);

轉換歸檔格式有利也有弊。主要優點就是能夠使用任何處理 ZIP 或 TAR 文件的工具查看歸檔的內容。然而,如果 Phar 歸檔沒有使用原生的基于 Phar 的歸檔格式,那么它不需要使用 Phar 擴展加載歸檔,而使用 ZIP 或 TAR 格式的 Phar 歸檔則需要如此。

接下來,將需要定義文件存根(stub),這是在加載 Phar 文件時首先調用的代碼。

Phar 文件存根

文件存根僅僅是在加載 Phar 文件時最初運行的代碼的一小部分,并且始終以一個?__HALT_COMPILER()?標記作為結束。清單 3 展示了一個典型的文件存根。示例 3. Phar 文件存根

<?php Phar::mapPhar(); include ’phar://myphar.phar/index.php’; __HALT_COMPILER();

上面所示的?Phar::mapPhar()?方法調用通過讀取清單文件(manifest)對 Phar 歸檔執行初始化。您需要在歸檔內引用文件之前使用 phar:// 流包裝器執行初始化。初始加載的文件將是應用程序首次加載時的文件;在本例中為 index.php。

如何將這個文件存根 Phar 添加到 Phar 歸檔取決于所使用的歸檔的格式。對于基于 Phar 的歸檔,使用?Phar::setStub()?方法,它將接受 PHP 代碼的惟一參數,并以字符串形式放入存根中。清單 4 演示了這一方法。示例 4. 使用?Phar::setStub()?創建文件存根

$p->setStub(’<?php Phar::mapPhar(); include ’phar://myphar.phar/index.php’; __HALT_COMPILER(); ?>’);

如果您計劃使用存根而不是重定向到 index.php 頁面來完成操作,可以使用 helper 方法?Phar::createDefaultStub()?構建文件存根。因此,只需要傳遞您希望包含在文件存根的文件的名稱。在清單 5 中,將重寫?Phar::setStub()?方法調用來使用 helper 方法。

示例 5. 使用?Phar::createDefaultStub()?創建文件存根

$p->setStub($p-> createDefaultStub(’index.php’));

如果從 Web 服務器加載 Phar,Phar::createDefaultStub()?方法的第二個可選參數允許包含一個不同的文件。這對于設計用于命令行或 Web 瀏覽器上下文的應用程序非常方便。

對于基于 ZIP 和 TAR 的實現,將以上存根的內容存儲到 .phar/stub.php 文件內,而不是使用?setStub()?命令。

將文件添加到歸檔

Phar?對象使用?ArrayAccess?SPL 對象,允許以數組的形式訪問歸檔內容,因此提供了許多方法來向歸檔添加文件。最簡單的方法是直接使用?ArrayAccess?接口。示例 6. 向歸檔添加文件

$p[’file.txt’] = ’This is a text file’;$p[’index.php’] = file_get_contents(’index.php’);

示例 6 表明文件名被指定為數組鍵,將內容指定為值??梢允褂?file_get_contents()?函數獲得現有文件的內容,然后將內容設為值。這樣可以更加靈活地向歸檔添加文件,可以通過引用現有文件或動態構建文件實現。后一種方法可以作為應用程序構建腳本的一部分。

如果存儲在 Phar 歸檔中的文件非常大,可以分別通過?PharFileInfo::setCompressedGZ()?或PharFileInfo::setCompressedBZIP2()?方法使用 gzip 或 bzip2 壓縮有選擇地壓縮歸檔中的文件。在清單 7 中,您將使用 bzip2 壓縮文件。示例 7. 使用 bzip2 壓縮 Phar 歸檔中的文件

$p[’big.txt’] = ’This is a big text file’;$p[’big.txt’]->setCompressedBZIP2();

要壓縮文件或使用包含壓縮文件的歸檔,必須在 PHP 安裝中支持 bzip2 或 zlib(用于 gz 壓縮文件)擴展。

假設您需要將許多文件加入到歸檔中。使用?ArrayAccess?接口逐一添加文件是一項非常單調的工作,因此可以使用一些便捷的方法。一種方法就是使用?Phar::buildFromDirectory()?方法,該方法將遍歷指定的目錄并添加其中的文件。它還支持對添加的文件進行過濾,方法是使用文件的正則表達式模式傳遞第二個參數,以匹配文件并添加到歸檔中。清單 8 展示了這一過程。示例 8. 使用?Phar::buildFromDirectory()?向歸檔添加文件

$p->buildFromDirectory(’/path/to/files’,’./.php$/’);

示例 8 將指定目錄中的 PHP 文件添加到 Phar 歸檔。如果需要對添加的文件執行任何修改,比如將文件壓縮,那么可以使用ArrayAccess?接口返回。

可以使用一個迭代器(iterator)通過?Phar::buildFromIterator()?方法添加文件。支持兩種風格的迭代器:一種是將 Phar 中的文件名映射到磁盤文件的名稱,另一種是返回?SplFileInfo?對象。RecursiveDirectoryIterator?是一種兼容的迭代器,下面展示如何使用它向歸檔添加目錄文件。示例 9. 使用?Phar::buildFromIterator()?向歸檔添加目錄文件

$p->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(’/path/to/files’)),’/path/to/files’);

Phar::buildFromIterator()?方法接受迭代器對象本身作為惟一的參數。在上例中,您已經使用RecursiveIteratorIterator?對象包裝了?RecursiveDirectoryIterator?對象,RecursiveIteratorIterator?對象提供了Phar::buildFromIterator()?方法所需的兼容型迭代器。

我們現在已經創建了一個 Phar 歸檔,它可以用于任何 PHP 應用程序。讓我們看一看如何方便地使用這個歸檔。

使用 Phar 歸檔

Phar 歸檔的一個優點就是可以非常方便地集成到任何應用程序中。如果使用的是原生的基于 Phar 的歸檔格式,這一點尤其明顯。在這種情況下,您甚至不需要安裝 Phar 擴展,因為 PHP 天生就可以加載文件并提取文件內容?;?ZIP 和 TAR 的歸檔需要加載 Phar 擴展。

Phar 歸檔在設計時被包括到應用程序中,跟普通的 PHP 文件一樣,這使得已經熟悉如何包含其他第三方代碼的應用程序開發人員可以非常方便地使用 Phar 歸檔。讓我們看一看在應用程序中集成 Phar 有多么容易。

在應用程序中集成 Phar 歸檔代碼

在 Phar 歸檔中集成代碼的最簡單方法就是包含 Phar 歸檔,然后在 Phar 文件中包含需要使用的文件。phar:// 流包裝器可以用來訪問已加載 Phar 歸檔中的文件,如下所示。示例 10. 在 Phar 歸檔中加載代碼

include ’myphar.phar’; include ’phar://myphar.phar/file.php’;

第一個 include 將加載 myphar.phar 歸檔,包含文件存根中指定的代碼。第二個 include 使用流包裝器打開 Phar 歸檔并且僅在歸檔中包括指定的文件。注意在歸檔中包含文件之前,您不需要包含 Phar 歸檔本身,如清單 10 所示。

從 Phar 歸檔運行 PHP 應用程序

Phar 歸檔的一個出色特性就是可以使用一個 Phar 歸檔打包整個應用程序并進行發布。這種方法的優點就是簡化應用程序部署并且不會降低性能,它主要得益于 PHP V5.3 中新增的若干 Phar 增強。然而,設計在 Phar 中運行的應用程序時應當考慮以下幾點:

任何需要創建的特定于應用程序實例的文件,比如 config 文件,都不能作為歸檔的一部分,因此需要將它們寫入到獨立但是可訪問的位置。如果應用程序創建構成擴展的緩存文件,那么這些文件也要采用相同的做法。您應當始終使用基于 Phar 的歸檔格式,并且不對歸檔中的文件進行壓縮,從而獲得最大的靈活性?;?ZIP 和 TAR 的歸檔要求在 PHP 中安裝 Phar 擴展,而基于 Phar 的歸檔甚至可用于未安裝 Phar 擴展的情況。應用程序中的任何文件引用都需要修改為同時使用 phar:// 流包裝器和歸檔名,如前面小節所示。

PHPMyAdmin 是一種流行的 PHP 應用程序,它一直使用 Phar 打包,演示出使用 Phar 歸檔的簡便性。它一直以來被設計為從 Phar 歸檔文件運行,但是仍然能夠在 Phar 歸檔之外存儲配置文件。

標簽: PHP
相關文章:
国产综合久久一区二区三区