Rev 30 | 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 extends Controleur {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( '-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);parent::__construct();}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 commandeif ($parametres = $this->verifierParametres($plc, $this->getParamAutorises())) {$this->setParam($parametres);}$tab_fichiers_ini = array( ES_CHEMIN_CONFIG.'bdd.ini', // Paramêtres de la base de donnéesES_CHEMIN_CONFIG.'commun.ini', // Paramêtres communs aux différents projets$this->getModuleChemin().DS.'configurations'.DS.'config.ini');// Chargement des fichiers ini générauxfor ($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);}}}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êtresforeach ($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éfautif ($p_val[1] !== true) {$parametres[ltrim($p_nom, '-')] = $p_val[1];}}}}// Gestion de l'excédant de paramêtresif (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 staticself::$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éesextract($donnees);// Démarage de la bufferisation de sortieob_start();// Si les tags courts sont activésif ((bool) @ini_get('short_open_tag') === true) {// Simple inclusion du squeletteinclude $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 bufferecho 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 contenureturn $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.* @param boolean true pour compresser (gz) le fichier. Par défaut vaut false.* @return string le message d'erreur formaté.*/protected function creerFichier($fichier, $contenu, $compression = false) {$e = null;if ($compression) {// Ajout de l'extension gzif (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-8if (!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;}}}?>