Subversion Repositories Applications.referentiel

Rev

Rev 30 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
// Encodage : UTF-8
// +-------------------------------------------------------------------------------------------------------------------+
/**
* ScriptCommande
*
* Description : classe abstraite des scripts
* Fichier d'origine jelix-scripts par Jouanneau Laurent
* copyright             2005-2007 Jouanneau laurent
* link                  http://www.jelix.org
* 
//Auteur original :
* @author               Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright    Tela-Botanica 1999-2008
* @licence              GPL v3 & CeCILL v2
* @version              $Id: ScriptCommande.class.php 1948 2009-09-03 14:12:02Z Jean-Pascal MILCENT $
*/
// +-------------------------------------------------------------------------------------------------------------------+
// TODO : supprimer les classe getStaticIni(), getStaticParam() et getStaticNom(). Utiliser une seule méthode qui gère les deux méthodes d'appel.
/**
* classe representant une commande
*/
abstract class ScriptCommande {

        public $nom;
        public $parametres;
        
        
        /**
         * Paramêtres disponible pour la ligne de commande
         * le tableau se construit de la forme suivnate :       
         * - clé =  nom du paramêtre '-foo'
         * - value = contient un nouveau tableau composé de cette façaon :
         *  - booléen: true si le paramêtre est obligatoire
         *  - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
         *  - string: description du contenu du paramêtre
         * Les paramêtres optionels devraient être déclaré à la fin du tableau.
         * Le dernier parametre du tableau peut avoir la valeur '...',
         * il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
         * @var array
         */
        private $_parametres_autorises = array( '-p' => array(true, true, 'Projet, le nom utiliser pour le fichier ini'),
                                                                                        '-a' => array(true, true, 'Action à réaliser'),
                                                                                        '-v' => array(false, '1', 'Mode verbeux : 1 ou 2'),
                                                                                        '-t' => array(false, '', 'Test sur un nombre de ligne...'));
        /**
         * Contient les valeurs des paramêtres récupérés de la ligne de commande :
         * le tableau se construit de la forme suivnate :       
         * - clé =  nom du paramêtre '-foo'
         * - valeur = la valeur récupérée sur la ligne de commande
         * @var array
         */
        private $_parametres;

        private static $_static_nom;
        private static $_static_parametres;
        private static $_static_ini;
        private static $log = '';
        private static $log_fichier;
        private static $log_resource;
        private static $log_fichier_ecraser = false;

        public $syntaxhelp = '';
        public $help = 'Aucune aide pour cette commande';

        function __construct($commande_nom) {
                $this->setNom($commande_nom);
        }
        
        public function __destruct() {
                if (isset(self::$log_resource)) {
                        if (fclose(self::$log_resource)) {
                                self::$log_resource = null;
                        }
                }       
        }
        
        public function getNom() {
                return $this->nom;
        }
        
        public static function getStaticNom() {
                return self::$_static_nom;
        }
        
        private function setNom($script_nom) {
                $this->nom = $script_nom;
                self::$_static_nom = $script_nom;
        }
        
        public static function getLog() {
                return self::$log;
        }
        
        public static function setLog($l) {
                self::$log .= $l;
        }
        
        public function initialiser($plc) {
                // Récupération des paramêtres autorisés par le script
                $this->setParamAutorises($this->parametres);
                
                // Vérification et récupération des paramêtres de la ligne de commande
                if ($parametres = $this->verifierParametres($plc, $this->getParamAutorises())) {
                        $this->setParam($parametres);
                }
                
                // Tableaux des emplacements des fichiers ini à rechercher et à charger dans l'ordre du tableau
                $projet_prefixe = '';
                if (preg_match('/^([^_]+)/', $this->getParam('p'), $match)) {
                        $projet_prefixe = $match[1];
                }
                $tab_fichiers_ini = array(      ES_CHEMIN_CONFIG.'bdd.ini', // Paramêtres de la base de données
                                                                        ES_CHEMIN_CONFIG.'commun.ini', // Paramêtres communs aux différents projets
                                                                        ES_CHEMIN_CONFIG.$this->getParam('p').'.ini',// Ancien emplacement du fichier ini du projet, dans le dossier configuration global
                                                                        $this->getModuleChemin().$this->getParam('p').'.ini',
                                                                        $this->getModuleChemin().DS.'configurations'.DS.$this->getParam('p').'.ini');
                
                // Chargement des fichiers ini généraux 
                for ($i = 0; $i < 2 ; $i++) {
                        if (!$this->parserFichierIni($tab_fichiers_ini[$i])) {
                                $e = "Le fichier $tab_fichiers_ini[$i] est introuvable\n";
                                trigger_error($e, E_USER_WARNING);
                        }
                }
                // Chargement du fichier ini du projet
                $erreur_ini_projet = true; 
                for ($i = 2; $i < 7 ; $i++) {
                        if ($this->parserFichierIni($tab_fichiers_ini[$i])) {
                                $erreur_ini_projet = false;
                        }
                }
                if ($erreur_ini_projet) {
                        $e = "Le fichier .ini du projet est introuvable : \n".$tab_fichiers_ini[2]."\n".$tab_fichiers_ini[3]."\n";
                        trigger_error($e, E_USER_WARNING);
                }
        }

        abstract public function executer();

        protected function getModuleChemin($shouldexist = true) {
                $chemin = ES_CHEMIN_MODULE.$this->getNom().DS;
                if (!file_exists($chemin) && $shouldexist) {
                        trigger_error("Erreur: le module '".$this->getNom()."' n'existe pas ($chemin)\n", E_USER_ERROR);
                }
                return $chemin;
        }
        
        private function verifierParametres($p_ligne, $p_autorise) {
        
                //print_r($p_ligne);
                // Récupération des paramêtres
                foreach ($p_autorise as $p_nom => $p_val) {
                        if (count($p_ligne) == 0) {
                                if ($p_val[0]) {
                                        trigger_error("Erreur: paramêtre manquant '".$p_nom."' \n", E_USER_WARNING);
                                }
                        }
                        if ($p_nom == '...') {
                                $parametres['...'] = array();
                                foreach($p_ligne as $arg) {
                                        $parametres['...'][] = $arg;
                                }
                                $p_ligne = array();
                                break;
                        } else {
                                if (isset($p_ligne[$p_nom])) {
                                        // Attribution de la valeur issue de la ligne de commande
                                        $parametres[ltrim($p_nom, '-')] = $p_ligne[$p_nom];
                                        unset($p_ligne[$p_nom]);
                                } else {
                                        // Attribution de la valeur par défaut
                                        if ($p_val[1] !== true) {
                                                $parametres[ltrim($p_nom, '-')] = $p_val[1];
                                        }
                                }
                        }
                }
                
                // Gestion de l'excédant de paramêtres
                if (count($p_ligne)) {
                        trigger_error("Erreur: trop de paramêtres\n", E_USER_ERROR);
                }
                
                return $parametres;
        }
        
        protected function setParamAutorises($param) {
                if (!is_null($param)) {
                        foreach ($param as $c => $v) {
                                if (isset($this->_parametres_autorises[$c])) {
                                        trigger_error("Erreur: le module '".$this->getNom()."' ne peut définir le paramêtre '$c' car il existe déjà\n", E_USER_ERROR);
                                } else {
                                        $this->_parametres_autorises[$c] = $v;
                                }
                        }
                }
        }
        
        protected function getParamAutorises($param = null) {
                
                if (!is_null($param)) {
                        if (isset($this->_parametres_autorises['-'.$param])) {
                                return $this->_parametres_autorises['-'.$param];
                        } else if (isset($this->_parametres_autorises[$param])) {
                                return $this->_parametres_autorises[$param];
                        } else {
                                trigger_error("Erreur: le module '".$this->getNom()."' n'a pas défini le paramêtre '$param'\n", E_USER_WARNING);
                                return false;
                        }
                } else {
                        return $this->_parametres_autorises;
                }
        }
        
        protected function setParam($params = array(), $val = null) {
                
                if (is_array($params)) {
                        $this->_parametres = $params;
                        self::$_static_parametres = $params;
                } else if (!is_array($params) && !is_null($val)) {
                        $this->_parametres[$params] = $val;
                        self::$_static_parametres[$params] = $val;
                } else {
                        return false;
                }
        }
        
        protected function getParam($param = null) {
                
                if (!is_null($param)) {
                        if (isset($this->_parametres['-'.$param])) {
                                return $this->_parametres['-'.$param];
                        } else if (isset($this->_parametres[$param])) {
                                return $this->_parametres[$param];
                        } else {
                                trigger_error("Erreur: la ligne de commande ne contenait pas le paramêtre '$param'\n", E_USER_WARNING);
                                return false;
                        }
                } else {
                        return $this->_parametres;
                }
        }
        
        protected static function getStaticParam($param = null) {
                
                if (!is_null($param)) {
                        if (isset(self::$_static_parametres['-'.$param])) {
                                return self::$_static_parametres['-'.$param];
                        } else if (isset(self::$_static_parametres[$param])) {
                                return self::$_static_parametres[$param];
                        } else {
                                trigger_error("Erreur: la ligne de commande ne contenait pas le paramêtre '$param'\n", E_USER_WARNING);
                                return false;
                        }
                } else {
                        return self::$_static_parametres;
                }
        }
        
        protected function getIni($nom) {
                if (isset($this->_ini[$nom])) {
                         return $this->_ini[$nom];
                 } else {
                         return false;
                 }
        }
        
        protected static function getStaticIni($nom) {
                if (isset(self::$_static_ini[$nom])) {
                         return self::$_static_ini[$nom];
                 } else {
                         return false;
                 }
        }
        
        protected function parserFichierIni($fichier_ini) {
        if (file_exists($fichier_ini)) {
                        $aso_ini = parse_ini_file($fichier_ini);
                foreach ($aso_ini as $cle => $val) {
                        if (preg_match('/^php:(.+)$/', $val, $correspondances)) {
                                eval('$this->$cle = '.$correspondances[1].';');
                                eval('$this->_ini[$cle] = '.$correspondances[1].';');
                        } else if (preg_match('/^php-static:(.+)$/', $val, $correspondances)) {
                                eval('self::$'.$cle.' = '.$correspondances[1].';');
                                eval('$this->_ini[$cle] = '.$correspondances[1].';');
                        } else {
                                // Ancienne forme : compatibilité avec les anciens scripts...
                                $this->$cle = $val;
                                // Nouvelle forme : utilisation de la méthode getInit().
                                $this->_ini[$cle] = $val;
                        }
                }
                self::$_static_ini = $this->_ini;
                return true;
        } else {
                return false;
        }
        }
        
        // Log Resource
        /**
        * Lit la valeur de l'attribut Log Resource.
        * Utilise le motif de conception (= design pattern) Singleton.
        * 
        * @access public
        * @param string le préfixe du nom de fichier à créer.
        * @return string retourne le Log Resource.
        */
        public static function getLogResource() {
                if (!isset(self::$log_resource)) {
                        if (file_exists(self::getLogFichier()) && !self::$log_fichier_ecraser) {
                                // Ouvre en écriture seule ; place le pointeur de fichier à la fin du fichier. Si le fichier 
                                // n'existe pas, on tente de le créer.
                                self::$log_resource = fopen(self::getLogFichier(), 'a');
                        } else {
                                //Ouvre en écriture seule ; place le pointeur de fichier au début du fichier et réduit la taille 
                                // du fichier à 0. Si le fichier n'existe pas, on tente de le créer.
                                self::$log_resource = fopen(self::getLogFichier(), 'w');
                                $entete_utf8 = "\xEF\xBB\xBF";
                                if (!fwrite(self::$log_resource, $entete_utf8)) {
                                        echo "Erreur écriture dans le fichier de log lors de l'ajout de l'entête UTF8.\n";
                                }
                        }
                }
                return self::$log_resource;
        }

        // Log Fichier
        /**
        * Lit la valeur de l'attribut Log Fichier.
        * Utilise le motif de conception (= design pattern) Singleton.
        * 
        * @access public
        * @return string retourne le nom du fichier de log.
        */
        public static function getLogFichier() {
                if (!isset(self::$log_fichier)) {
                        if (self::getStaticIni('projet_nom') && self::getStaticIni('version') && self::getStaticIni('sous_version')) {
                                $fichier =      self::getStaticIni('projet_nom').'_'.
                                                        self::getStaticNom().'_'.
                                                        self::getStaticParam('a').'_'.
                                                        'v'.self::getStaticIni('version').'_'.self::getStaticIni('sous_version');
                        } else {
                                $fichier = self::getStaticNom().'_'.self::getStaticParam('a');
                        }
                        
                        if (!self::$log_fichier_ecraser) {
                                $fichier .= '_'.date('Y-m-j_H:i:s', time());
                        }
                        $fichier .= '.log';
                        // Ajout du chemin vers le fichier de log et stockage dans variable static
                        self::$log_fichier = self::getStaticIni('log_chemin').$fichier;
                }
                return self::$log_fichier;
        }
        
        /** 
         * Retourne un message d'avertissement formaté.
         * 
         * @param string le message d'erreur avec des %s.
         * @param array le tableau des paramêtres à insérer dans le message d'erreur.
         * @param int le niveau de verbosité à dépasser pour afficher les messages.
         * @return string le message d'erreur formaté.
         */
        private function traiterMessage($message, $tab_arguments = array(), $niveau = 0) {
                // Nous ajoutons dans le texte les infos provenant de la BDD (déjà encodées en UTF-8).
                $texte = vsprintf($message, $tab_arguments);
                if ($this->getParam('v') >= $niveau) {
                        $prefixe = '';
                        if ($this->getIni('projet_nom') && $this->getIni('version') && $this->getIni('sous_version')) {
                                $prefixe = $this->getIni('projet_nom').'v'.$this->getIni('version').'.'.$this->getIni('sous_version').'. ';
                        } else {
                                $prefixe = date('Y-m-j_H:i:s', time()).' - '.Script::getCode($niveau).' : ';
                        }
                        $log = $prefixe.$texte."\n";
                        echo $log;
                        self::setLog($log);
                        
                        if (!fwrite($this->getLogResource(), $log)) {
                                trigger_error('Erreur écriture dans le fichier de log.'."\n", E_USER_WARNING);
                        }
                }
                return "\t".$texte."\n";
        }
        
        /** 
         * Retourne un message d'erreur après avoir écrit le message danns le fichier de log.
         * Si le mode verbeux est inactivé, écrit le message dans le fichier de log.
         * Si le mode verbeux de niveau 1 ou plus est activé, écrit le message dans le fichier de log et dans la console.
         *  
         * @param string le message d'erreur avec des %s.
         * @param array le tableau des paramêtres à insérer dans le message d'erreur.
         * @return string le message d'erreur formaté.
         */
        protected function traiterErreur($message, $tab_arguments = array()) {
                $niveau = Script::ERREUR;
                return $this->traiterMessage($message, $tab_arguments, $niveau);
        }
        
        /** 
         * Retourne un message d'avertissement formaté.
         * Si le mode verbeux de niveau 1 est activé, écrit le message dans le fichier de log.
         * Si le mode verbeux de niveau 2 est activé, écrit le message dans le fichier de log et dans la console.
         * 
         * @param string le message d'erreur avec des %s.
         * @param array le tableau des paramêtres à insérer dans le message d'erreur.
         * @return string le message d'erreur formaté.
         */
        protected function traiterAttention($message, $tab_arguments = array()) {
                $niveau = Script::AVERTISSEMENT;
                return $this->traiterMessage($message, $tab_arguments, $niveau);
        }
        
        /** 
         * Retourne un message d'information formaté.
         * Si le mode verbeux de niveau 2 est activé, écrit le message dans le fichier de log.
         * Si le mode verbeux de niveau 3 est activé, écrit le message dans le fichier de log et dans la console.
         * 
         * @param string le message d'information avec des %s.
         * @param array le tableau des paramêtres à insérer dans le message d'erreur.
         * @param int le niveau de verbosité à dépasser pour afficher les messages.
         * @return string le message d'erreur formaté.
         */
        protected function afficher($message, $tab_arguments = array(), $niveau = null) {
                if (is_null($niveau)) {
                        $niveau = Script::INFO;
                }
                $msg = $this->traiterMessage($message, $tab_arguments, $niveau);
                return $msg ;
        }
        
        /**
         * Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,
         * en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
         *
         * @param String $fichier       le chemin du fichier du squelette
         * @param Array  $donnees       un tableau associatif contenant les variables a injecter dans le squelette.
         *
         * @return boolean false si le squelette n'existe pas, sinon la chaine résultat.
         */
        public static function traiterSquelettePhp($fichier, Array $donnees = array()) {
                $sortie = false;
                if (file_exists($fichier)) {
                        // Extraction des variables du tableau de données
                        extract($donnees);
                        // Démarage de la bufferisation de sortie
                        ob_start();
                        // Si les tags courts sont activés
                        if ((bool) @ini_get('short_open_tag') === true) {
                                // Simple inclusion du squelette
                                include $fichier;
                        } else {
                                // Sinon, remplacement des tags courts par la syntaxe classique avec echo
                                $html_et_code_php = self::traiterTagsCourts($fichier);
                                // Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval
                                $html_et_code_php = '?>'.$html_et_code_php;
                                // Interprétation du html et du php dans le buffer
                                echo eval($html_et_code_php);
                        }
                        // Récupèration du contenu du buffer
                        $sortie = ob_get_contents();
                        // Suppression du buffer
                        @ob_end_clean();
                } else {
                        $msg = "Le fichier du squelette '$fichier' n'existe pas.";
                        trigger_error($msg, E_USER_WARNING);
                }
                // Retourne le contenu
                return $sortie;
        }
        
        /**
         * Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.
         *
         * @param String $chemin_squelette le chemin du fichier du squelette
         *
         * @return string le contenu du fichier du squelette php avec les tags courts remplacés.
         */
        private static function traiterTagsCourts($chemin_squelette) {
                $contenu = file_get_contents($chemin_squelette);
                // Remplacement de tags courts par un tag long avec echo
                $contenu = str_replace('<?=', '<?php echo ',  $contenu);
                // Ajout systématique d'un point virgule avant la fermeture php
                $contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);
                return $contenu;
        }
        
        /** 
         * Créer et stocke du contenu dans un fichier.
         * 
         * @param string le chemin et le nom du fichier.
         * @param string le contenu à stocker dans le fichier.
         * @return string le message d'erreur formaté.
         */
        protected function creerFichier($fichier, $contenu, $compression = false) {
                $e = null;
                if ($compression) {
                        // Ajout de l'extension gz
                        if (substr($fichier, -3) != '.gz') {
                                $fichier = $fichier.'.gz';
                        }
                        // Début de l'écriture du fichier compressé
                        if ($resource = gzopen($fichier, 'w9')) {
                                if (!gzwrite($resource, $contenu)) {
                                        $e = "Le contenu texte n'a pas pu être écrit dans le fichier compressé '$fichier'.";
                                }
                                if (!gzclose($resource)) {
                                        $e = "Le fichier compressé '$fichier' n'a pas pu être fermé.";
                                }
                        } else {
                                $e = "Le fichier compressé '$fichier' n'a pas pu être ouvert.";
                        }
                } else {
                        if ($resource = fopen($fichier, 'w')) {
                                if (!fwrite($resource, $contenu)) {
                                        $e = "Le contenu texte n'a pas pu être écrit dans le fichier '$fichier'.";
                                }
                                if (!fclose($resource)) {
                                        $e = "Le fichier '$fichier' n'a pas pu être fermé.";
                                }
                        } else {
                                $e = "Le fichier '$fichier' n'a pas pu être ouvert.";
                        }
                }
                if (is_null($e)) {
                        return true;
                } else {
                        trigger_error($e, E_USER_WARNING);
                        return false;
                }
        }
        
        /**
         * Méthode permettant d'encoder de l'iso-8859-15 vers utf-8 un tableau de variables.
         *
         * @param mixed la chaine ou le tableau à encoder en utf-8 depuis l'iso-8859-15.
         * @param string l'encodage d'origine si ce n'est pas ISO-8859-15.
         * @return mixed la chaine ou le tableau encodé en utf-8.
         * @access protected
         */
        protected function encoderUtf8( &$val, $encodage = 'ISO-8859-15') {
                //echo print_r($val, true)."\n";
                if (is_array($val)) {
                        foreach ($val as $c => $v) {
                                $val[$c] = $this->encoderUtf8($v);
                        }
                } else {
                        // Nous vérifions si nous avons un bon encodage UTF-8
                        if (!is_numeric($val) && !empty($val) && !$this->detecterUtf8($val)) { 
                                // Les nombres, les valeurs vides et ce qui est déjà en UTF-8 ne sont pas encodés.
                                $val = mb_convert_encoding($val, 'UTF-8', $encodage);
                        }
                }
                return $val;
        }
        
        /**
         * Méthode permettant de détecter réellement l'encodage utf8.
         * mb_detect_encoding plante si la chaine de caractère se termine par un caractère accentué.
         * Provient de  PHPDIG.
         * 
         * @param string la chaine à vérifier.
         * @return bool true si c'est de l'utf8, sinon false.
         * @access private
         */
        private function detecterUtf8($str) {
                if ($str === mb_convert_encoding(mb_convert_encoding($str, 'UTF-32', 'UTF-8'), 'UTF-8', 'UTF-32')) {
                        return true;
                } else {
                        return false;
                }
        }
}
?>