Pour diffuser du code sous la forme d'une archive phar
, il faut commencer par la générer.
Cela n'a rien de très compliqué en soit, d'autant que Pascal a réalisé un excellent travail de vulgarisation sur le sujet.
Dans le cas de sparkline, la méthode la plus simple consiste :
- À créer une instance de la classe
\Phar
en indiquant l'emplacement final du fichierphar
. - À demander à cette instance de lire le contenu du répertoire de sparkline et d'inclure dans le fichier
phar
tous les fichiers se terminant par.php
.
Ceci revient donc à écrire dans le fichier phar.php
le code suivant :
<?php
$phar = new \Phar('path/to/sparkline.phar');
$phar->buildFromDirectory('path/to/sparkline/directory', '/\.php$/');
?>
Il suffit ensuite d'effectuer en ligne de commande l'instruction qui suit pour obtenir l'archive désirée à l'emplacement path/to/phar
:
# php -d phar.readonly=0 phar.php
Évidement, pour les projets plus complexes que sparkline, PHP 5.3 dispose d'une méthode plus puissante pour sélectionner les fichiers à mettre dans une archive phar
.
Notre archive obtenue, nous pouvons l'intégrer directement dans du code PHP, de la manière suivante :
<?php
\Phar::loadPhar(__DIR__ . '/mageekguy.sparkline.phar');
require('phar://mageekguy.sparkline.phar/autoloader.php');
use mageekguy\sparkline;
use mageekguy\sparkline\writers;
use mageekguy\sparkline\layer\linechart;
$data = array(1, 5, 6, -9, 10, -4, 8, 10, 11, 34, 3, 1, -7, -23, 38, 21, 10, 8, 6);
$sparkline = new sparkline(100, 20, $data);
$sparkline
->setPadding(4)
->addLayer(new linechart\curves\line(3, 40, 50, 255))
->addWriter(new writers\png(__DIR__ . '/sparkline.png'))
->write()
;
?>
Nous avons donc une archive qu'il est possible d'intégrer directement dans un script PHP, mais cela nécessite que le développeur écrive un code spécifique à cette tâche.
Pour palier à cet inconvénient, il est possible d'indiquer à l'archive phar
le code qui doit être exécuté lorsqu'elle est incluse dans un script PHP à l'aide de la méthode \Phar::setStub().
Ainsi, il est par exemple possible d'indiquer à PHP la méthode d'auto-chargement de classes qui doit être utilisée :
<?php
$phar = new \Phar('/path/to/sparkline.phar');
$phar->buildFromDirectory('/path/to/sparkline/directory', '/\.php$/');
$phar->setStub('<?php Phar::mapPhar(\'mageekguy.sparkline.phar\'); require(\'phar://' . self::phar . '/autoloader.php\'); __HALT_COMPILER(); ?>');
?>
De cette manière, l'utilisation de l'archive est considérablement simplifiée, puisqu'il suffit de l'inclure d'une manière tout à fait classique :
<?php
...
require(__DIR__ . '/mageekguy.sparkline.phar');
use mageekguy\sparkline;
use mageekguy\sparkline\writers;
use mageekguy\sparkline\layer\linechart;
$data = array(1, 5, 6, -9, 10, -4, 8, 10, 11, 34, 3, 1, -7, -23, 38, 21, 10, 8, 6);
$sparkline = new sparkline(100, 20, $data);
...
?>
Nous avons donc maintenant une archive phar
qui permet la diffusion de sparkline sous la forme d'un fichier unique et qui de plus facilite son utilisation par le développeur, puisqu'il n'a plus qu'à inclure le fichier phar
dans son code pour pouvoir utiliser son contenu.
Nous allons maintenant voir qu'il est possible d'aller plus loin, avec la définition de méta-données, qui s'effectue de la manière suivante :
<?php
$phar = new \Phar('/path/to/sparkline.phar');
$phar->setMetadata(array(
'version' => \mageekguy\sparkline::version,
'author' => 'Frederic Hardy',
'support' => 'sparkline[AT]mageekbox.net,
'description' => file_get_contents(\mageekguy\sparkline::directory . DIRECTORY_SEPARATOR . 'ABOUT'),
'licence' => file_get_contents(\mageekguy\sparkline::directory . DIRECTORY_SEPARATOR . 'COPYING')
)
);
$phar->setStub('<?php Phar::mapPhar(\'mageekguy.sparkline.phar\'); require(\'phar://mageekguy.sparkline.phar/autoloader.php\'); __HALT_COMPILER(); ?>');$phar->buildFromDirectory('/path/to/sparkline/directory', '/\.php$/');
?>
Bien évidement, il est possible de consulter ces méta-données à l'aide de la méthode \Phar::getMetaData()
, mais nous allons voir qu'il est possible de le faire d'une manière beaucoup plus pratique.
En effet, il est possible d'éxécuter une archive phar
, soit via un navigateur, soit en ligne de commande, et dans les deux cas, l'archive accepte des arguments, tout comme un script PHP traditionnel.
Il est donc tout à fait possible de définir la gestion de ces arguments dans le code de démarrage de l'archive, défini comme nous l'avons vu précédemment à l'aide de la méthode \Phar::setStub() :
<?php
...
$phar->setStub('<?php Phar::mapPhar(\'mageekguy.sparkline.phar\'); require(\'phar://mageekguy.sparkline.phar/autoloader.php\'); $stub = new \mageekguy\sparkline\phar\stub(); $stub->run(); __HALT_COMPILER(); ?>');
...
?>
Ainsi, il devient possible d'obtenir cela en ligne de commande :
# php mageekguy.sparkline.phar -i
Infos:
Compressed: Yes
version: 0.0.1
author: Frederic Hardy
support: sparkline@mageekbox.net
description: Sparkline generator.
: Sparklines are "data-intense, design-simple, word-sized graphics".
: See http://en.wikipedia.org/wiki/Sparkline for more informations.
licence: * Copyright (c) 1998, Regents of the University of California
: * All rights reserved.
: * Redistribution and use in source and binary forms, with or without
: * modification, are permitted provided that the following conditions are met:
...
Nous avons donc maintenant une archive capable de renseigner un utilisateur sur son contenu à l'aide de méta-données, lorqu'elle est appelée en ligne de commande avec le bon argument.
De plus, les plus attentifs d'entre vous auront peut être remarqué la ligne
dans la sortie ci-dessus, qui ne fait pas partie des méta-données.Compressed: Yes
Il est en effet possible de compresser une archive phar
, ou bien uniquement une partie de son contenu.
Dans le cas de sparkline, j'ai décidé de compresser l'ensemble des fichiers de l'archive, de la façon suivante :
<?php
...
$phar->compressFiles(\Phar::GZ);
$phar->setSignatureAlgorithm(\Phar::SHA1);
...
?>
Le code ci-dessus demande également que la signature de l'archive soit générée à l'aide de l'algorithme sha1
.
Cette signature permet de vérifier l'intégrité de l'archive en la comparant avec celle fourni par son créateur, ce qui peut être intéressant dans un contexte sensible en terme de sécurité, d'autant qu'il est possible d'utiliser différents algorithmes pour la générer.
Il est à noter que les méthodes \Phar::compressFiles()
et \Phar::setSignatureAlgorithm()
accepte respectivement plusieurs algorithmes de compression et de
génération de signature.
L'archive phar
jointe à ce billet utilise toutes ses notions et elle contient le code qui a permis de la réaliser, ainsi que le code de son fichier de démarrage.
Sa signature, visible en utilisant la commande php mageekguy.sparkline.phar -s
, est 42C41AA718BBF9E32A46931AF39B190DDCC9B1AD
.
L'archive a été générée à l'aide de la commande
, éxecutée à partir du répertoire de sparkline, que vous pourrez créer à l'aide de la commande php -d phar.readonly=0 phar.php -d ..
.php -d phar.readonly=0 mageekguy.sparkline.phar -e path/to/directory
Pour ceux qui s'inquiéteraient des performances d'une archive compressée, l'archive est capable de s'auto-décompresser en ligne de commande.
Je vous invite à découvrir les arguments nécéssaires pour tout cela en éxecutant la commande
, qui permet d'obtenir plus de détails sur le fonctionnement de l'archive.php mageekguy.sparkline.phar --help
J'espère que cela vous a donné envie d'en savoir plus sur le format phar
, voir même de l'utiliser, d'autant que nous n'avons pas exploré l'intégralité de ses possibilités.
8 réactions
1 De oxman - 23/05/2010, 23:46
Tout simplement génial merci
Au passage j'ai découvert ton blog récemment via une amie et je m'y suis tout de suite inscrit au flux RSS.
Continue comme ça bon travail
2 De desfrenes - 24/05/2010, 00:16
Parce que ça ne serait pas vraiment du PHP si ça marchait partout de la même façon, il faut encore que la directive phar.readonly du php.ini soit à Off, sinon on ne passe pas le premier niveau de ton tuto.
3 De Éric Rogé - 24/05/2010, 00:48
Merci pour cette introduction, je n'ai pas eu le courage jusqu'ici de me pencher sur cette nouvelle fonctionnalité.
En fait, au-delà de l'aspect technique, c'est même le genre d'usages prévu qui est encore flou pour moi.
Dans quel genre de scenarii les utilisateurs java utilisent ils les .jar ?
La première idée d'utilisation qui me vient pour les .phar est la gestion de plugins (par exemple, les futur plugins/bundles Symfony 2 ?), mais y'en a-t'il d'autres ?
4 De mageekguy - 24/05/2010, 08:44
@desfrenes : Rien à voir avec PHP qui ne fonctionne pas partout de la même manière.
J'ai juste oublié l'option
-d phar.readonly=0
lorsque j'ai copié/collé la commande permettant la génération duphar
, cette directive étant à 0 au niveau de monphp.ini
.j'ai corrigé, merci du retour.
5 De mageekguy - 24/05/2010, 09:20
@Éric Rogé : Les applications sont multiples.
Diffusion de projets du type de sparkline, outil en ligne de commande, application compléte encapsulée, plug-in, etc, il y a plein d'applications possibles.
Le mieux est à mon avis de ne pas se brider en se basant sur l'utilisation qui est faite des
.jar
et de laisser aller son imagination.Ainsi, les métas-données, si elle était un minimum normalisées, permettraient la création de dépôts capable d'indexer automatiquement le code contenu dans les
phar
.Personnellement, je trouve que les possibilités de ce format justifient amplement son utilisation pour la diffusion de code.
6 De Jean-Marc Fontaine - 28/05/2010, 10:15
Juste une précision, PHP 5.3 n'est pas obligatoire. Cette extension est incluse en standard depuis la version 5.3 mais il est possible de l'installer via PECL à partir de la version 5.2.1.
J'ai utilisé la version 1 il y a quelques années avec succès bien avant que PHP 5.3 ne pointe le bout de son nez.
Sinon, Fred il faut vraiment que tu t'occupes. Les titres de tes billets sont de plus en plus barrés.
(et oui, j'ai compris la référence)
7 De mageekguy - 28/05/2010, 14:37
@Jean-Marc Fontaine : Pour le titre, j'avais hésité entre l'actuel et "Plein phar !".
Et puis de toute façon, l'auteur du titre, c'est bastnic.
Sinon, pour en revenir au sujet de l'article, je connais l'extension, depuis longtemps, mais c'est une extension, et en tant que telle, elle est rarement disponible.
D'ailleurs, tu connais beaucoup de projet qui l'utilise (en natif ou via pecl) ? Parce qu'à part PHPUnit... et encore...
PHP 5.3 va, je l'espère, permettre la démocratisation du .phar.
8 De Jean-Marc Fontaine - 31/05/2010, 10:53
@mageekguy: Le manque de disponibilité de l'extension est un faux argument à mon sens car soit on est un vrai développeur, on travaille sur un serveur dédié où l'on peut l'installer, soit on travaille sur du serveur mutualisé et on fait probablement du paramétrage de CMS ou du script "à la PHP 4", dans ce cas on n'a pas besoin de Phar.
J'ai conscience que ce point de vue est un peu radical mais je distingue vraiment le développeur du bidouilleur. Pour moi, ce sont deux populations très différentes avec des besoins et des moyens (compétences, budget, contraintes, etc.) différents.
Quant à l'usage de Phar dans un projet connu, malheureusement comme toi je n'en connais pas vraiment à part quelques expérimentations de ci de là.