Utiliser Phar pour packager un projet : Différence entre versions

De e-glop
(Les problèmes de path)
(Les commandes à oublier / remplacer)
Ligne 43 : Ligne 43 :
  
 
== Les commandes à oublier / remplacer ==
 
== 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() ===
 
=== realpath() ===

Version du 15 janvier 2016 à 20:10

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');
   // ...
 }