SunshinePHP Developer Conference 2015

Utilizar Archivos Phar: Introduction

Los archivos phar son similares en concepto a los archivo JAR de Java, pero están adaptados a las necesidades y a la flexibilidad de apliciones de PHP. Un archivo Phar se usa para distribuir una aplicación o biblioteca PHP completa en un único fichero. Una aplicación de un archivo Phar se utiliza exactamente de la misma manera que otra aplicación PHP:

php aplicacion.phar
  

Utilizar una biblioteca de archivo Phar es idéntico a usar cualquier otra biblioteca de PHP:

<?php
include 'biblioteca.phar';
?>

La envoltura de flujos phar proporciona el núcleo de la extensión Phar, y está explicada en detalle aquí. La envoltura de flujos phar permite el acceso a los ficheros dentro de un archivo phar utilizando las funciones estándar de ficheros de PHP fopen(), opendir(), y y otras que trabajan sobre ficheros normales. La envoltura de flujos phar soporta todas las operaciones de lectura/escritura tanto en ficheros como en directorios.

<?php
include 'phar://biblioteca.phar/fichero/interno.php';
header('Content-type: image/jpeg');
// a los phar se puede acceder con la ruta completa o mediante un alias
echo file_get_contents('phar:///ruta_completa/a/biblioteca.phar/imagenes/wow.jpg');
?>

La clase Phar implementa una funcionalidad avanzada para acceder a ficheros y crear arhivos phar. La clas Phar está explicada en detalle aquí.

<?php
try {
    
// abrir un phar existente
    
$p = new Phar('biblioteca.phar'0);
    
// Phar extiende la clase DirectoryIterator de SPL
    
foreach (new RecursiveIteratorIterator($p) as $fichero) {
        
// $fichero en una clase PharFileInfo, y hereda de SplFileInfo
        
echo $fichero->getFileName() . "\n";
        echo 
file_get_contents($fichero->getPathName()) . "\n"// mostrar el contenido;
    
}
    if (isset(
$p['fichero/interno.php'])) {
        
var_dump($p['fichero/interno.php']->getMetadata());
    }

    
// crear un nuevo phar - phar.readonly debe ser 0 en php.ini
    // phar.readonly está habilitado por omisión por motivos de seguridad.
    // En servidores de producción, los archivos Phar nunca se crean,
    // sólo se ejecutan.
    
if (Phar::canWrite()) {
        
$p = new Phar('nuevo_phar.tar.phar'0'nuevo_phar.tar.phar');
        
// hacerlo un archivo phar basado en tar, comprimido con gzip (.tar.gz)
        
$p $p->convertToExecutable(Phar::TARPhar::GZ);

        
// crear una transacción -  no se escribe nada en nuevo_phar.phar
        // hasta que stopBuffering() sea llamado, aunque se necesita almacenamiento temporal
        
$p->startBuffering();
        
// añadir todos los ficheros de /ruta/del/proyecto, guardándolos en el phar con el prefijo "proyecto"
        
$p->buildFromIterator(new RecursiveIteratorIterator(new DirectoryIterator('/ruta/del/proyecto')), '/ruta/del/');

        
// añadir un nuevo fichero mediante la API de acceso a arrays
        
$p['fichero1.txt'] = 'Información';
        
$fp fopen('fichero_enorme.dat''rb');
        
// copiar toda la información del flujo
        
$p['datos/fichero_enorme.dat'] = $fp;

        if (
Phar::canCompress(Phar::GZ)) {
            
$p['datos/fichero_enorme.dat']->compress(Phar::GZ);
        }

        
$p['imagenes/wow.jpg'] = file_get_contents('imagenes/wow.jpg');
        
// cualquier valor se puede guardar como metainformación específica del fichero
        
$p['imagenes/wow.jpg']->setMetadata(array('mime-type' => 'image/jpeg'));
        
$p['index.php'] = file_get_contents('index.php');
        
$p->setMetadata(array('bootstrap' => 'index.php'));

        
// cuardar el archivo phar en el disco
        
$p->stopBuffering();
    }
} catch (
Exception $e) {
    echo 
'No se pudo abrir Phar: '$e;
}
?>

Además, la verificación del contenido de ficheros phar se puede realizar utilizando cualquiera de los algoritmos hash simétricos soportados (MD5, SHA1, SHA256 y SHA512 si la extensión Hash está habilitada) y utilizando firmas de clave pública/privada asimétricas de OpenSSL (nuevo en Phar 2.0.0). Para aprovechar la firmas de OpenSSL, se necesita generar una pareja de claves pública/privada, y utilizar la clave privada para establecer la firma usando Phar::setSignatureAlgorithm(). Además, la clave pública se extrae usando este código:

<?php
$public 
openssl_get_publickey(file_get_contents('private.pem'));
$pkey '';
openssl_pkey_export($public$pkey);
?>
debe ser guardada junto al archivo phar que verifica. Si el archivo phar es guardado como /ruta/a/mi.phar, la clave pública debe guardarse como /ruta/a/mi.phar.pubkey, o phar no será capaz de verificar la firma OpenSSL.

A partir de la verisón 2.0.0, la clase Phar también proporciona tres métodos estáticos, Phar::webPhar(), Phar::mungServer() y Phar::interceptFileFuncs(), los cuales son cruiciales para empaquetar aplicaciones PHP diseñadas para un uso en sistemas de ficheros normales y aplicación basadas en web. Phar::webPhar() implementa un controlador principal que direcciona llamadas HTTP a la ubicación correcta dentro del archivo phar. Phar::mungServer() se utiliza para modificar los valores del array $_SERVER para hacer que las aplicaciones procesen estos valores. Phar::interceptFileFuncs() ordena a Phar que intercepte llamdas a fopen(), file_get_contents(), opendir(), y a todas las funciones basadas en estadísticas (file_exists(), is_readable(), etc.) y direccione todas las rutas relativas a las ubicaciones dentro del archivo phar.

Como ejemplo, empaquetar una versión de la popular aplicación phpMyAdmin para usarla cono un archivo phar, requiere solamente este sencillo script, y después se puede acceder a phpMyAdmin.phar.tar.php como un fichero normal desde el servidor web después de modificar el usuario/contraseña:

<?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('<?php
Phar::interceptFileFuncs();
Phar::webPhar("phpMyAdmin.phar", "phpMyAdmin-2.11.3-english/index.php");
echo "phpMyAdmin está intentando ejecutarse desde un navegador web\n";
exit -1;
__HALT_COMPILER();
'
);
$a->stopBuffering();
?>

add a note add a note

User Contributed Notes 3 notes

up
3
shaun at shaunfreeman dot co dot uk
4 years ago
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.
up
1
ch1902
6 months ago
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
up
0
frame86 at live dot com
1 year ago
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.
To Top