文字

Using Phar Archives: Introduction

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:

<?php
include  '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.

<?php
include  'phar://coollibrary.phar/internal/file.php' ;
header ( 'Content-type: image/jpeg' );
// phars can be accessed by full path or by alias
echo  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.

<?php
try {
    
// 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  DirectoryIterator ( '/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 (new in Phar 2.0.0). 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 );
?>
must be saved adjacent to the phar archive it verifies. If the phar archive is saved as /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.

As of version 2.0.0, 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

$i = 0;


$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\'] = \'\';



if (strpos(PHP_OS, \'WIN\') !== false) {
    $cfg[\'UploadDir\'] = getcwd();
} else {
    $cfg[\'UploadDir\'] = \'/tmp/pharphpmyadmin\';
    @mkdir(\'/tmp/pharphpmyadmin\');
    @chmod(\'/tmp/pharphpmyadmin\', 0777);
}'
;
$a -> setStub ( '<?php
Phar::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 ();
?>

用户评论:

[#1] ch1902 [2014-03-27 13:14:09]

If you are going to be running a webPhar from the browser, for example http://localhost/myphar.phar then you will probably have to associate the .phar extension with PHP in your webserver to interpret the PHP code. In Apache modify httpd.conf to include

AddType application/x-httpd-php .php .phar

[#2] frame86 at live dot com [2013-06-29 23:46:20]

The openssl example is completely wrong. The public key must be extracted from certificate and openssl_pkey_export() is for private key only.

Working example:
<?php
$publicKey 
openssl_get_publickey(file_get_contents('certificate.pem'));
$details openssl_pkey_get_details($publicKey);
file_put_contents('my.phar.pubkey'$details['key']);
?>


No need to say that the best and strongest encryption of my.phar/.phar/signature.bin is useless if the consumer does not check against a valid fingerprint or certificate of public key as anybody can open, read, recreate and sign a new archive with new key. Do you do? Think about it.

[#3] shaun at shaunfreeman dot co dot uk [2010-09-27 03:06:33]

If you are trying to use Phar for a web application and just getting a blank screen, if you have enabled suhosin as well you have to add:

suhosin.executor.include.whitelist="phar"

to "/etc/php5/conf.d/suhosin.ini" file or your "php.ini" file.

once done everything works fine and dandy.

上一篇: 下一篇: