Das Konzept des Phar-Archivs stammt aus dem JAR-Archiv der Java™-Technologie, das es ermöglicht, Anwendungen in einer einzigen Datei zu packen, die alles enthält, was zum Ausführen der Anwendung erforderlich ist. Diese Datei unterscheidet sich von einer einzelnen ausführbaren Datei, die normalerweise von einer Programmiersprache wie C generiert wird, darin, dass es sich bei der Datei tatsächlich um eine Archivdatei und nicht um eine kompilierte Anwendung handelt. Die JAR-Datei enthält also tatsächlich die Dateien, aus denen die Anwendung besteht, diese Dateien werden jedoch aus Sicherheitsgründen nicht sorgfältig differenziert. Die Phar-Erweiterung basiert auf einem ähnlichen Konzept, ist jedoch hauptsächlich für die Webumgebung von PHP konzipiert. Außerdem können Phar-Archive im Gegensatz zu JAR-Archiven von PHP selbst verarbeitet werden, sodass keine zusätzlichen Tools erforderlich sind, um sie zu erstellen oder zu verwenden.
Phar-Erweiterungen sind kein neues Konzept für PHP. Es wurde ursprünglich in PHP geschrieben und hieß PHP_Archive, bevor es 2005 zur PEAR-Bibliothek hinzugefügt wurde. In der Praxis waren reine PHP-Lösungen für dieses Problem jedoch sehr langsam, weshalb es 2007 als reine C-Spracherweiterung umgeschrieben wurde und Unterstützung für das Durchlaufen von Phar-Archiven mithilfe der ArrayAccess-Objekte von SPL hinzugefügt wurde. Seitdem wurde viel daran gearbeitet, die Leistung der Phar-Archive zu verbessern.
Eine Phar-Datei erstellen
Die Erstellung einer Phar-Datei erfordert mehrere Schritte. Für alle Schritte ist ein PHP-Befehl erforderlich, um die Erstellung abzuschließen, da es kein eigenständiges Tool zum Erstellen von Archiven gibt. Um Phar-Dateien zu erstellen und zu ändern, muss außerdem die php.ini-Einstellung phar.readonly auf 0 gesetzt werden. Diese Einstellung ist nicht erforderlich, wenn Dateien im Phar-Archiv von PHP geöffnet und referenziert werden.
Sehen wir uns die Schritte an, die zum Erstellen einer Phar-Datei erforderlich sind, die zum Ansteuern einer Anwendung verwendet werden kann. Die Anwendung ist so konzipiert, dass sie direkt über einen Webbrowser oder eine Eingabeaufforderung geladen werden kann. Der erste Schritt besteht darin, eine Phar-Datei zu erstellen, also erstellen wir das in Listing 1 gezeigte Phar-Objekt. Mit Objektverweisen können Sie alle Aspekte der Phar-Archivierung steuern.
Beispiel 1. Erstellen Sie ein Phar-Objekt
$p = new Phar('/path/to/my.phar', CURRENT_AS_FILEINFO | KEY_AS_FILENAME, 'my.phar'); $p->startBuffering();
Der erste Parameter des -Konstruktors gibt den Speicherort der Phar-Datei an. Der zweite Parameter übergibt alle Parameter an die übergeordnete Klasse RecursiveDirectoryIterator. Der dritte Parameter ist ein Alias, der im Stream-Kontext auf das Phar-Archiv verweist. Für Listing 1 können Sie also phar://my.phar verwenden, um auf die Datei in diesem Phar-Archiv zu verweisen. Sie können auch einen Phar::startBuffering()-Methodenaufruf ausgeben, um Änderungen am Archiv zu puffern, bis ein Phar::stopBuffering()-Befehl ausgegeben wird. Obwohl dies nicht notwendig ist, verbessert sich dadurch die Leistung beim Erstellen oder Ändern von Archiven, da die Änderungen nicht jedes Mal gespeichert werden müssen, wenn das Archiv in einem Skript geändert wird.
Standardmäßig verwendet das erstellte Phar das native Phar-basierte Archivformat. Sie können auch das ZIP- oder TAR-Format mit Phar-Dateien verwenden, indem Sie das Format wie in Listing 2 gezeigt in das ZIP-Format konvertieren.
Beispiel 2. Speicherformat in ZIP-Format konvertieren
$p = $p->convertToExecutable(Phar::ZIP);
Das Konvertieren des Archivformats hat Vor- und Nachteile. Der Hauptvorteil ist die Möglichkeit, den Inhalt des Archivs mit jedem Tool anzuzeigen, das ZIP- oder TAR-Dateien verarbeitet. Wenn ein Phar-Archiv jedoch kein natives Phar-basiertes Archivformat verwendet, muss es nicht die Phar-Erweiterung zum Laden des Archivs verwenden, wie dies für Phar-Archive im ZIP- oder TAR-Format erforderlich ist.
Als nächstes müssen Sie den Datei-Stub definieren. Dabei handelt es sich um den Code, der beim Laden einer Phar-Datei zuerst aufgerufen wird.
Phar-Datei-Stub
Ein Datei-Stub ist nur ein kleiner Teil des Codes, der zunächst ausgeführt wird, wenn eine Phar-Datei geladen wird, und endet immer mit einem __HALT_COMPILER()-Tag. Listing 3 zeigt einen typischen Datei-Stub.
Beispiel 3. Phar-Datei-Stub
<?php Phar::mapPhar(); include 'phar://myphar.phar/index.php'; __HALT_COMPILER();
Der oben gezeigte Methodenaufruf Phar::mapPhar() führt die Initialisierung des Phar-Archivs durch, indem er die Manifestdatei liest. Sie müssen den Stream-Wrapper phar:// verwenden, um die Initialisierung durchzuführen, bevor Sie auf die Datei im Archiv verweisen. Die Datei, die zunächst geladen wird, ist die Datei, die die Anwendung zum ersten Mal lädt. In diesem Fall handelt es sich um index.php.
Wie man diesen Datei-Stub Phar zu einem Phar-Archiv hinzufügt, hängt vom Format des verwendeten Archivs ab. Verwenden Sie für Phar-basierte Archive die Methode Phar::setStub(), die ein einzelnes Argument des PHP-Codes akzeptiert und es als Zeichenfolge in den Stub einfügt. Listing 4 demonstriert diesen Ansatz.
Beispiel 4. Erstellen Sie einen Datei-Stub mit Phar::setStub()
$p->setStub('<?php Phar::mapPhar(); include 'phar://myphar.phar/index.php'; __HALT_COMPILER(); ?>');
Wenn Sie vorhaben, einen Stub zu verwenden, anstatt zur Seite index.php umzuleiten, um den Vorgang abzuschließen, können Sie Folgendes verwenden: Die Hilfsmethode Phar::createDefaultStub() erstellt einen Datei-Stub. Übergeben Sie einfach den Namen der Datei, die Sie in den Datei-Stub aufnehmen möchten. In Listing 5 wird der Methodenaufruf Phar::setStub() überschrieben, um die Hilfsmethode zu verwenden.
Beispiel 5. Verwenden Sie Phar::createDefaultStub(), um einen Datei-Stub zu erstellen
$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 应用程序
Eine großartige Funktion von Phar-Archiven besteht darin, dass eine gesamte Anwendung mit einem einzigen Phar-Archiv gepackt und verteilt werden kann. Der Vorteil dieses Ansatzes besteht darin, dass er die Anwendungsbereitstellung ohne Leistungseinbußen vereinfacht und vor allem von mehreren Phar-Verbesserungen profitiert, die in PHP V5.3 hinzugefügt wurden. Beim Entwerfen von Anwendungen für die Ausführung in Phar sollten jedoch die folgenden Punkte berücksichtigt werden:
Alle anwendungsinstanzspezifischen Dateien, die erstellt werden müssen, wie z. B. Konfigurationsdateien, können nicht Teil des Archivs sein und müssen daher vorhanden sein Schreiben Sie an einen separaten, aber zugänglichen Ort. Wenn die Anwendung Cache-Dateien erstellt, die Erweiterungen darstellen, gilt das Gleiche auch für diese Dateien.
Für maximale Flexibilität sollten Sie immer das Phar-basierte Archivformat verwenden und die Dateien im Archiv nicht komprimieren. ZIP- und TAR-basierte Archive erfordern die Installation der Phar-Erweiterung in PHP, während Phar-basierte Archive auch ohne installierte Phar-Erweiterung verwendet werden können.
Alle Dateiverweise in der Anwendung müssen geändert werden, um sowohl den Stream-Wrapper phar:// als auch den Archivnamen zu verwenden, wie im vorherigen Abschnitt gezeigt.
PHPMyAdmin ist eine beliebte PHP-Anwendung, die mit Phar gepackt wurde, was die Benutzerfreundlichkeit der Phar-Archivierung demonstriert. Es wurde für die Ausführung aus Phar-Archiven entwickelt, ist jedoch weiterhin in der Lage, Konfigurationsdateien außerhalb von Phar-Archiven zu speichern.