Utiliser Phar pour packager un projet
Sommaire
Construire son archive Phar
Script de construction
Créer un make-archive.php comme suit :
<?php $path = $_SERVER['argv'][2].'e-venement.phar.php'; if ( file_exists($path) ) unlink($path); $phar = new Phar($path, NULL, 'e-venement.phar.php'); $phar->buildFromDirectory($_SERVER['argv'][1]); $phar->setStub("<?php Phar::mapPhar('e-venement.phar.php'); Phar::webPhar(); Phar::mungServer(); Phar::interceptFileFuncs(); __HALT_COMPILER(); ?>"); $phar->stopBuffering();
Et appelez-le via la commande :
$ php -d phar.readonly=0 make-archive.php [RÉPERTOIRE À PACKAGER]
Si vous avez des répertoires où vous aurez à écrire des données
Utiliser la commande :
Phar::mount('/writable/path/cache/', 'phar://e-venement.phar.php/cache/');
Ainsi, toutes les écritures dans ./cache (dans l'archive) seront envoyées dans /writable/path/cache/ (équivalent d'un mount UNIX).
Placez cette commande (au choix) :
- dans un fichier chargé en début d'exécution de votre application
- dans un fichier que vous aurez créé spécialement et qui sera chargé avant (ou au tout début de) chaque exécution de votre application
- dans un stub de votre archive Phar
Les commandes à oublier / remplacer
glob()
/**#@+ * Extra GLOB constant for glob2() */ define('GLOB_NODIR',256); define('GLOB_PATH',512); define('GLOB_NODOTS',1024); define('GLOB_RECURSE',2048); /**#@-*/ /** * A safe empowered glob(). * * Function glob() is prohibited on some server (probably in safe mode) * (Message "Warning: glob() has been disabled for security reasons in * (script) on line (line)") for security reasons as stated on: * http://seclists.org/fulldisclosure/2005/Sep/0001.html * * safe_glob() intends to replace glob() using readdir() & fnmatch() instead. * Supported flags: GLOB_MARK, GLOB_NOSORT, GLOB_ONLYDIR * Additional flags: GLOB_NODIR, GLOB_PATH, GLOB_NODOTS, GLOB_RECURSE * (not original glob() flags) * @author BigueNique AT yahoo DOT ca * @updates * - 080324 Added support for additional flags: GLOB_NODIR, GLOB_PATH, * GLOB_NODOTS, GLOB_RECURSE */ function glob2($pattern, $flags=GLOB_PATH) { $pattern = preg_replace('!/$!', , $pattern); $split=explode('/',str_replace('\\','/',$pattern)); $mask=array_pop($split); $path=implode('/',$split); if ( is_dir($path) ) if (($dir=opendir($path))!==false) { $glob=array(); while(($file=readdir($dir))!==false) { // Recurse subdirectories (GLOB_RECURSE) if( ($flags&GLOB_RECURSE) && is_dir($file) && (!in_array($file,array('.','..'))) ) $glob = array_merge($glob, array_prepend(safe_glob($path.'/'.$file.'/'.$mask, $flags), ($flags&GLOB_PATH?:$file.'/'))); // Match file mask if (fnmatch($mask,$file)) { if ( ( (!($flags&GLOB_ONLYDIR)) || is_dir("$path/$file") ) && ( (!($flags&GLOB_NODIR)) || (!is_dir($path.'/'.$file)) ) && ( (!($flags&GLOB_NODOTS)) || (!in_array($file,array('.','..'))) ) ) $glob[] = ($flags&GLOB_PATH?$path.'/':) . $file . ($flags&GLOB_MARK?'/':); } } closedir($dir); if (!($flags&GLOB_NOSORT)) sort($glob); return $glob; } else { return false; } }
realpath()
À remplacer par la fonction suivante :
function realpath2($path) { // whether $path is unix or not $unipath = strlen($path)==0 || $path{0}!='/'; $unc = substr($path,0,2)=='\\\\'?true:false; // attempts to detect if path is relative in which case, add cwd if(strpos($path,':') === false && $unipath && !$unc){ $path=getcwd().DIRECTORY_SEPARATOR.$path; if($path{0}=='/'){ $unipath = false; } } // resolve path parts (single dot, double dot and double delimiters) $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part){ continue; } if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } $path = implode(DIRECTORY_SEPARATOR, $absolutes); // resolve any symlinks if( function_exists('readlink') && file_exists($path) && linkinfo($path)>0 ){ $path = readlink($path); } // put initial separator that could have been lost $path = !$unipath ? '/'.$path : $path; $path = $unc ? '\\\\'.$path : $path; // TODO $path = str_replace('phar:', 'phar://', $path); return $path; }
getcwd()
Utiliser la constante __DIR__ à la place.
e-venement ou un autre projet Symfony1
Se dotter d'un script make-archive.php adapté
Symfony1 requiert la possibilité de lancer des tâches depuis la ligne de commande "CLI". Il faut donc se permettre de lancer ces commandes depuis l'extérieur de la Phar.
Rajoutez donc ces éléments dans votre fichier make-archive.php :
// ... Phar::mapPhar('e-venement.phar.php'); if ( isset(\$_SERVER['argv']) ) if ( \$_SERVER['argv'][1] == './symfony' ) { \$php = 'phar://e-venement.phar.php/'.\$_SERVER['argv'][1]; foreach ( \$_SERVER['argv'] as \$i => \$arg ) if ( \$i > 1 ) \$_SERVER['argv'][\$i-1] = \$arg; array_pop(\$_SERVER['argv']); require \$php; die(); } Phar::webPhar(); // ...
Se créer une instance initiale
Prendre un déploiement fonctionnel d'e-venement (fichiers de configuration inclus) et le recopier ainsi :
$ cp -Lr [REPSOURCE] [REPDESTINATION]
Cela élimine tous les problèmes liés aux liens symboliques...
Les problèmes de path
- Remplacer tous les appels à realpath() par realpath2()
- Remplacer tous les appels à getcwd() par __DIR__
- Retirer la première ligne du fichier ./symfony (#!/usr/bin/php)
- Attention au fichier lib/vendor/symfony/lib/util/sfToolkit.class.php et sa méthode sfToolkit::isPathAbsolute() ; remplacer sa 1ère ligne par :
if ($path[0] == '/' || $path[0] == '\\' || preg_match('!\w+://!', $path) === 1 ||
Répertoires cache et log
Rajouter un paramétrage particulier pour les répertoires de cache, de log, etc... dans votre fichier config/ProjectConfiguration.php :
public function setup() { $this->setCacheDir('/tmp/myproject/cache'); $this->setLogDir('/tmp/myproject/log'); // ... }
À la recherche du WebRoot
Dans le fichier lib/vendor/symfony/lib/request/sfWebRequest.class.php, modifier la méthode sfWebRequest::getScriptName() de la manière suivante :
public function getScriptName() { $pathArray = $this->getPathInfoArray(); if ( isset($pathArray['PHAR_PATH_INFO']) && isset($pathArray['PATH_TRANSLATED']) ) return preg_replace('!phar://!', , str_replace($pathArray['DOCUMENT_ROOT'], '/', $pathArray['PATH_TRANSLATED'])); return isset($pathArray['SCRIPT_NAME']) ? $pathArray['SCRIPT_NAME'] : (isset($pathArray['ORIG_SCRIPT_NAME']) ? $pathArray['ORIG_SCRIPT_NAME'] : ); }