Rev 142 | 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 commande
if ($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ées
ES_CHEMIN_CONFIG.'commun.ini', // Paramêtres communs aux différents projets
$this->getModuleChemin().DS.'configurations'.DS.'config.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);
}
}
}
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.
* @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 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;
}
}
}
?>