Phar archives are similar in concept to Java JAR archives, but are tailored to the needs and to the flexibility of PHP applications. A Phar archive is used to distribute a complete PHP application or library in a single file. A Phar archive application is used exactly like any other PHP application:
php coolapplication.phar
Using a Phar archive library is identical to using any other PHP library:
<?phpinclude 'coollibrary.phar';?>
The phar
stream wrapper provides the core of the phar extension, and
is explained in detail here.
The phar stream wrapper allows accessing the files within a phar archive using
PHP's standard file functions fopen(), opendir(), and
others that work on regular files. The phar
stream wrapper supports all
read/write operations on both files and directories.
<?phpinclude 'phar://coollibrary.phar/internal/file.php';header('Content-type: image/jpeg');// phars can be accessed by full path or by aliasecho file_get_contents('phar:///fullpath/to/coollibrary.phar/images/wow.jpg');?>
The Phar class implements advanced functionality for accessing files and for creating phar archives. The Phar class is explained in detail here.
<?phptry { // open an existing phar $p = new Phar('coollibrary.phar', 0); // Phar extends SPL's DirectoryIterator class foreach (new RecursiveIteratorIterator($p) as $file) { // $file is a PharFileInfo class, and inherits from SplFileInfo echo $file->getFileName() . "\n"; echo file_get_contents($file->getPathName()) . "\n"; // display contents; } if (isset($p['internal/file.php'])) { var_dump($p['internal/file.php']->getMetadata()); } // create a new phar - phar.readonly must be 0 in php.ini // phar.readonly is enabled by default for security reasons. // On production servers, Phars need never be created, // only executed. if (Phar::canWrite()) { $p = new Phar('newphar.tar.phar', 0, 'newphar.tar.phar'); // make this a tar-based phar archive, compressed with gzip compression (.tar.gz) $p = $p->convertToExecutable(Phar::TAR, Phar::GZ); // create transaction - nothing is written to newphar.phar // until stopBuffering() is called, although temporary storage is needed $p->startBuffering(); // add all files in /path/to/project, saving in the phar with the prefix "project" $p->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator('/path/to/project')), '/path/to/'); // add a new file via the array access API $p['file1.txt'] = 'Information'; $fp = fopen('hugefile.dat', 'rb'); // copy all data from the stream $p['data/hugefile.dat'] = $fp; if (Phar::canCompress(Phar::GZ)) { $p['data/hugefile.dat']->compress(Phar::GZ); } $p['images/wow.jpg'] = file_get_contents('images/wow.jpg'); // any value can be saved as file-specific meta-data $p['images/wow.jpg']->setMetadata(array('mime-type' => 'image/jpeg')); $p['index.php'] = file_get_contents('index.php'); $p->setMetadata(array('bootstrap' => 'index.php')); // save the phar archive to disk $p->stopBuffering(); }} catch (Exception $e) { echo 'Could not open Phar: ', $e;}?>
In addition, verification of phar file contents can be done using any of the supported symmetric hash algorithms (MD5, SHA1, SHA256 and SHA512 if ext/hash is enabled) and using asymmetric public/private key signing using OpenSSL. To take advantage of OpenSSL signing, you need to generate a public/private key pair, and use the private key to set the signature using Phar::setSignatureAlgorithm(). In addition, the public key as extracted using this code:
<?php$public = openssl_get_publickey(file_get_contents('private.pem'));$pkey = '';openssl_pkey_export($public, $pkey);?>
/path/to/my.phar
, the public key must be saved
as /path/to/my.phar.pubkey
, or phar will be unable to verify
the OpenSSL signature.
The Phar class also provides 3 static methods, Phar::webPhar(), Phar::mungServer() and Phar::interceptFileFuncs() that are crucial to packaging up PHP applications designed for usage on regular filesystems and for web-based applications. Phar::webPhar() implements a front controller that routes HTTP calls to the correct location within the phar archive. Phar::mungServer() is used to modify the values of the $_SERVER array to trick applications that process these values. Phar::interceptFileFuncs() instructs Phar to intercept calls to fopen(), file_get_contents(), opendir(), and all of the stat-based functions (file_exists(), is_readable() and so on) and route all relative paths to locations within the phar archive.
As an example, packaging up a release of the popular phpMyAdmin application for use as a phar archive requires
only this simple script and then phpMyAdmin.phar.tar.php
can be accessed as a regular file
from your web server after modifying the user/password:
<?php@unlink('phpMyAdmin.phar.tar.php');copy('phpMyAdmin-2.11.3-english.tar.gz', 'phpMyAdmin.phar.tar.php');$a = new Phar('phpMyAdmin.phar.tar.php');$a->startBuffering();$a["phpMyAdmin-2.11.3-english/config.inc.php"] = '<?php/* Servers configuration */$i = 0;/* Server localhost (config:root) [1] */$i++;$cfg[\'Servers\'][$i][\'host\'] = \'localhost\';$cfg[\'Servers\'][$i][\'extension\'] = \'mysqli\';$cfg[\'Servers\'][$i][\'connect_type\'] = \'tcp\';$cfg[\'Servers\'][$i][\'compress\'] = false;$cfg[\'Servers\'][$i][\'auth_type\'] = \'config\';$cfg[\'Servers\'][$i][\'user\'] = \'root\';$cfg[\'Servers\'][$i][\'password\'] = \'\';/* End of servers configuration */if (strpos(PHP_OS, \'WIN\') !== false) { $cfg[\'UploadDir\'] = getcwd();} else { $cfg[\'UploadDir\'] = \'/tmp/pharphpmyadmin\'; @mkdir(\'/tmp/pharphpmyadmin\'); @chmod(\'/tmp/pharphpmyadmin\', 0777);}';$a->setStub('<?phpPhar::interceptFileFuncs();Phar::webPhar("phpMyAdmin.phar", "phpMyAdmin-2.11.3-english/index.php");echo "phpMyAdmin is intended to be executed from a web browser\n";exit -1;__HALT_COMPILER();');$a->stopBuffering();?>