Subversion Repositories Applications.referentiel

Rev

Rev 26 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
20 jpm 1
<?php
2
// Encodage : UTF-8
3
// +-------------------------------------------------------------------------------------------------------------------+
4
/**
5
* ScriptCommande
6
*
7
* Description : classe abstraite des scripts
8
* Fichier d'origine jelix-scripts par Jouanneau Laurent
9
* copyright		2005-2007 Jouanneau laurent
10
* link			http://www.jelix.org
11
*
12
//Auteur original :
13
* @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
14
* @copyright	Tela-Botanica 1999-2008
15
* @licence		GPL v3 & CeCILL v2
16
* @version		$Id: ScriptCommande.class.php 1948 2009-09-03 14:12:02Z Jean-Pascal MILCENT $
17
*/
18
// +-------------------------------------------------------------------------------------------------------------------+
19
// TODO : supprimer les classe getStaticIni(), getStaticParam() et getStaticNom(). Utiliser une seule méthode qui gère les deux méthodes d'appel.
20
/**
21
* classe representant une commande
22
*/
23
abstract class ScriptCommande {
24
 
25
	public $nom;
26
	public $parametres;
27
 
28
 
29
	/**
30
	 * Paramêtres disponible pour la ligne de commande
31
	 * le tableau se construit de la forme suivnate :
32
	 * - clé =  nom du paramêtre '-foo'
33
	 * - value = contient un nouveau tableau composé de cette façaon :
34
	 *  - booléen: true si le paramêtre est obligatoire
35
	 *  - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
36
	 *  - string: description du contenu du paramêtre
37
	 * Les paramêtres optionels devraient être déclaré à la fin du tableau.
38
	 * Le dernier parametre du tableau peut avoir la valeur '...',
39
	 * il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
40
	 * @var array
41
	 */
42
	private $_parametres_autorises = array(	'-p' => array(true, true, 'Projet, le nom utiliser pour le fichier ini'),
43
											'-a' => array(true, true, 'Action à réaliser'),
44
											'-v' => array(false, '1', 'Mode verbeux : 1 ou 2'),
45
											'-t' => array(false, '', 'Test sur un nombre de ligne...'));
46
	/**
47
	 * Contient les valeurs des paramêtres récupérés de la ligne de commande :
48
	 * le tableau se construit de la forme suivnate :
49
	 * - clé =  nom du paramêtre '-foo'
50
	 * - valeur = la valeur récupérée sur la ligne de commande
51
	 * @var array
52
	 */
53
	private $_parametres;
54
 
55
	private static $_static_nom;
56
	private static $_static_parametres;
57
	private static $_static_ini;
58
	private static $log = '';
59
	private static $log_fichier;
60
	private static $log_resource;
61
	private static $log_fichier_ecraser = false;
62
 
63
	public $syntaxhelp = '';
64
	public $help = 'Aucune aide pour cette commande';
65
 
66
	function __construct($commande_nom) {
67
		$this->setNom($commande_nom);
68
	}
69
 
70
	public function __destruct() {
71
		if (isset(self::$log_resource)) {
72
			if (fclose(self::$log_resource)) {
73
				self::$log_resource = null;
74
			}
75
		}
76
	}
77
 
78
	public function getNom() {
79
		return $this->nom;
80
	}
81
 
82
	public static function getStaticNom() {
83
		return self::$_static_nom;
84
	}
85
 
86
	private function setNom($script_nom) {
87
		$this->nom = $script_nom;
88
		self::$_static_nom = $script_nom;
89
	}
90
 
91
	public static function getLog() {
92
		return self::$log;
93
	}
94
 
95
	public static function setLog($l) {
96
		self::$log .= $l;
97
	}
98
 
99
	public function initialiser($plc) {
100
		// Récupération des paramêtres autorisés par le script
101
		$this->setParamAutorises($this->parametres);
102
 
103
		// Vérification et récupération des paramêtres de la ligne de commande
104
		if ($parametres = $this->verifierParametres($plc, $this->getParamAutorises())) {
105
			$this->setParam($parametres);
106
		}
107
 
108
		// Tableaux des emplacements des fichiers ini à rechercher et à charger dans l'ordre du tableau
109
		$projet_prefixe = '';
110
		if (preg_match('/^([^_]+)/', $this->getParam('p'), $match)) {
111
			$projet_prefixe = $match[1];
112
		}
113
		$tab_fichiers_ini = array(	ES_CHEMIN_CONFIG.'bdd.ini', // Paramêtres de la base de données
114
									ES_CHEMIN_CONFIG.'commun.ini', // Paramêtres communs aux différents projets
115
									ES_CHEMIN_CONFIG.$this->getParam('p').'.ini',// Ancien emplacement du fichier ini du projet, dans le dossier configuration global
116
									$this->getModuleChemin().$this->getParam('p').'.ini',
117
									$this->getModuleChemin().DS.'configurations'.DS.$this->getParam('p').'.ini');
118
 
119
		// Chargement des fichiers ini généraux
120
		for ($i = 0; $i < 2 ; $i++) {
121
			if (!$this->parserFichierIni($tab_fichiers_ini[$i])) {
122
				$e = "Le fichier $tab_fichiers_ini[$i] est introuvable\n";
123
				trigger_error($e, E_USER_WARNING);
124
			}
125
		}
126
		// Chargement du fichier ini du projet
127
		$erreur_ini_projet = true;
128
		for ($i = 2; $i < 7 ; $i++) {
129
			if ($this->parserFichierIni($tab_fichiers_ini[$i])) {
130
				$erreur_ini_projet = false;
131
			}
132
		}
133
		if ($erreur_ini_projet) {
134
			$e = "Le fichier .ini du projet est introuvable : \n".$tab_fichiers_ini[2]."\n".$tab_fichiers_ini[3]."\n";
135
			trigger_error($e, E_USER_WARNING);
136
		}
137
	}
138
 
139
	abstract public function executer();
140
 
141
	protected function getModuleChemin($shouldexist = true) {
142
		$chemin = ES_CHEMIN_MODULE.$this->getNom().DS;
143
		if (!file_exists($chemin) && $shouldexist) {
144
			trigger_error("Erreur: le module '".$this->getNom()."' n'existe pas ($chemin)\n", E_USER_ERROR);
145
		}
146
		return $chemin;
147
	}
148
 
149
	private function verifierParametres($p_ligne, $p_autorise) {
150
 
151
		//print_r($p_ligne);
152
		// Récupération des paramêtres
153
		foreach ($p_autorise as $p_nom => $p_val) {
154
			if (count($p_ligne) == 0) {
155
				if ($p_val[0]) {
156
					trigger_error("Erreur: paramêtre manquant '".$p_nom."' \n", E_USER_WARNING);
157
				}
158
			}
159
			if ($p_nom == '...') {
160
				$parametres['...'] = array();
161
				foreach($p_ligne as $arg) {
162
					$parametres['...'][] = $arg;
163
				}
164
				$p_ligne = array();
165
				break;
166
			} else {
167
				if (isset($p_ligne[$p_nom])) {
168
					// Attribution de la valeur issue de la ligne de commande
169
					$parametres[ltrim($p_nom, '-')] = $p_ligne[$p_nom];
170
					unset($p_ligne[$p_nom]);
171
				} else {
172
					// Attribution de la valeur par défaut
173
					if ($p_val[1] !== true) {
174
						$parametres[ltrim($p_nom, '-')] = $p_val[1];
175
					}
176
				}
177
			}
178
		}
179
 
180
		// Gestion de l'excédant de paramêtres
181
		if (count($p_ligne)) {
182
			trigger_error("Erreur: trop de paramêtres\n", E_USER_ERROR);
183
		}
184
 
185
		return $parametres;
186
	}
187
 
188
	protected function setParamAutorises($param) {
189
		if (!is_null($param)) {
190
			foreach ($param as $c => $v) {
191
				if (isset($this->_parametres_autorises[$c])) {
192
					trigger_error("Erreur: le module '".$this->getNom()."' ne peut définir le paramêtre '$c' car il existe déjà\n", E_USER_ERROR);
193
				} else {
194
					$this->_parametres_autorises[$c] = $v;
195
				}
196
			}
197
		}
198
	}
199
 
200
	protected function getParamAutorises($param = null) {
201
 
202
		if (!is_null($param)) {
203
			if (isset($this->_parametres_autorises['-'.$param])) {
204
				return $this->_parametres_autorises['-'.$param];
205
			} else if (isset($this->_parametres_autorises[$param])) {
206
				return $this->_parametres_autorises[$param];
207
			} else {
208
				trigger_error("Erreur: le module '".$this->getNom()."' n'a pas défini le paramêtre '$param'\n", E_USER_WARNING);
209
				return false;
210
			}
211
		} else {
212
			return $this->_parametres_autorises;
213
		}
214
	}
215
 
216
	protected function setParam($params = array(), $val = null) {
217
 
218
		if (is_array($params)) {
219
			$this->_parametres = $params;
220
			self::$_static_parametres = $params;
221
		} else if (!is_array($params) && !is_null($val)) {
222
			$this->_parametres[$params] = $val;
223
			self::$_static_parametres[$params] = $val;
224
		} else {
225
			return false;
226
		}
227
	}
228
 
229
	protected function getParam($param = null) {
230
 
231
		if (!is_null($param)) {
232
			if (isset($this->_parametres['-'.$param])) {
233
				return $this->_parametres['-'.$param];
234
			} else if (isset($this->_parametres[$param])) {
235
				return $this->_parametres[$param];
236
			} else {
237
				trigger_error("Erreur: la ligne de commande ne contenait pas le paramêtre '$param'\n", E_USER_WARNING);
238
				return false;
239
			}
240
		} else {
241
			return $this->_parametres;
242
		}
243
	}
244
 
245
	protected static function getStaticParam($param = null) {
246
 
247
		if (!is_null($param)) {
248
			if (isset(self::$_static_parametres['-'.$param])) {
249
				return self::$_static_parametres['-'.$param];
250
			} else if (isset(self::$_static_parametres[$param])) {
251
				return self::$_static_parametres[$param];
252
			} else {
253
				trigger_error("Erreur: la ligne de commande ne contenait pas le paramêtre '$param'\n", E_USER_WARNING);
254
				return false;
255
			}
256
		} else {
257
			return self::$_static_parametres;
258
		}
259
	}
260
 
261
	protected function getIni($nom) {
262
		if (isset($this->_ini[$nom])) {
263
			 return $this->_ini[$nom];
264
		 } else {
265
			 return false;
266
		 }
267
	}
268
 
269
	protected static function getStaticIni($nom) {
270
		if (isset(self::$_static_ini[$nom])) {
271
			 return self::$_static_ini[$nom];
272
		 } else {
273
			 return false;
274
		 }
275
	}
276
 
277
	protected function parserFichierIni($fichier_ini) {
278
    	if (file_exists($fichier_ini)) {
279
			$aso_ini = parse_ini_file($fichier_ini);
280
	    	foreach ($aso_ini as $cle => $val) {
281
	    		if (preg_match('/^php:(.+)$/', $val, $correspondances)) {
282
	    			eval('$this->$cle = '.$correspondances[1].';');
283
	    			eval('$this->_ini[$cle] = '.$correspondances[1].';');
284
	    		} else if (preg_match('/^php-static:(.+)$/', $val, $correspondances)) {
285
	    			eval('self::$'.$cle.' = '.$correspondances[1].';');
286
	    			eval('$this->_ini[$cle] = '.$correspondances[1].';');
287
	    		} else {
288
	    			// Ancienne forme : compatibilité avec les anciens scripts...
289
	    			$this->$cle = $val;
290
	    			// Nouvelle forme : utilisation de la méthode getInit().
291
	    			$this->_ini[$cle] = $val;
292
	    		}
293
	    	}
294
	    	self::$_static_ini = $this->_ini;
295
	    	return true;
296
    	} else {
297
    		return false;
298
    	}
299
	}
300
 
301
	// Log Resource
302
	/**
303
	* Lit la valeur de l'attribut Log Resource.
304
	* Utilise le motif de conception (= design pattern) Singleton.
305
	*
306
	* @access public
307
	* @param string le préfixe du nom de fichier à créer.
308
	* @return string retourne le Log Resource.
309
	*/
310
	public static function getLogResource() {
311
		if (!isset(self::$log_resource)) {
312
			if (file_exists(self::getLogFichier()) && !self::$log_fichier_ecraser) {
313
				// Ouvre en écriture seule ; place le pointeur de fichier à la fin du fichier. Si le fichier
314
				// n'existe pas, on tente de le créer.
315
				self::$log_resource = fopen(self::getLogFichier(), 'a');
316
			} else {
317
				//Ouvre en écriture seule ; place le pointeur de fichier au début du fichier et réduit la taille
318
				// du fichier à 0. Si le fichier n'existe pas, on tente de le créer.
319
				self::$log_resource = fopen(self::getLogFichier(), 'w');
320
				$entete_utf8 = "\xEF\xBB\xBF";
321
				if (!fwrite(self::$log_resource, $entete_utf8)) {
322
					echo "Erreur écriture dans le fichier de log lors de l'ajout de l'entête UTF8.\n";
323
				}
324
			}
325
		}
326
		return self::$log_resource;
327
	}
328
 
329
	// Log Fichier
330
	/**
331
	* Lit la valeur de l'attribut Log Fichier.
332
	* Utilise le motif de conception (= design pattern) Singleton.
333
	*
334
	* @access public
335
	* @return string retourne le nom du fichier de log.
336
	*/
337
	public static function getLogFichier() {
338
		if (!isset(self::$log_fichier)) {
339
			if (self::getStaticIni('projet_nom') && self::getStaticIni('version') && self::getStaticIni('sous_version')) {
340
				$fichier =	self::getStaticIni('projet_nom').'_'.
341
							self::getStaticNom().'_'.
342
							self::getStaticParam('a').'_'.
343
							'v'.self::getStaticIni('version').'_'.self::getStaticIni('sous_version');
344
			} else {
345
				$fichier = self::getStaticNom().'_'.self::getStaticParam('a');
346
			}
347
 
348
			if (!self::$log_fichier_ecraser) {
349
				$fichier .= '_'.date('Y-m-j_H:i:s', time());
350
			}
351
			$fichier .= '.log';
352
			// Ajout du chemin vers le fichier de log et stockage dans variable static
353
			self::$log_fichier = self::getStaticIni('log_chemin').$fichier;
354
		}
355
		return self::$log_fichier;
356
	}
357
 
358
	/**
359
	 * Retourne un message d'avertissement formaté.
360
	 *
361
	 * @param string le message d'erreur avec des %s.
362
	 * @param array le tableau des paramêtres à insérer dans le message d'erreur.
363
	 * @param int le niveau de verbosité à dépasser pour afficher les messages.
364
	 * @return string le message d'erreur formaté.
365
	 */
366
	private function traiterMessage($message, $tab_arguments = array(), $niveau = 0) {
367
		// Nous ajoutons dans le texte les infos provenant de la BDD (déjà encodées en UTF-8).
368
		$texte = vsprintf($message, $tab_arguments);
369
		if ($this->getParam('v') >= $niveau) {
370
			$prefixe = '';
371
			if ($this->getIni('projet_nom') && $this->getIni('version') && $this->getIni('sous_version')) {
372
				$prefixe = $this->getIni('projet_nom').'v'.$this->getIni('version').'.'.$this->getIni('sous_version').'. ';
373
			} else {
374
				$prefixe = date('Y-m-j_H:i:s', time()).' - '.Script::getCode($niveau).' : ';
375
			}
376
			$log = $prefixe.$texte."\n";
377
			echo $log;
378
			self::setLog($log);
379
 
380
			if (!fwrite($this->getLogResource(), $log)) {
381
				trigger_error('Erreur écriture dans le fichier de log.'."\n", E_USER_WARNING);
382
			}
383
		}
384
		return "\t".$texte."\n";
385
	}
386
 
387
	/**
388
	 * Retourne un message d'erreur après avoir écrit le message danns le fichier de log.
389
	 * Si le mode verbeux est inactivé, écrit le message dans le fichier de log.
390
	 * Si le mode verbeux de niveau 1 ou plus est activé, écrit le message dans le fichier de log et dans la console.
391
	 *
392
	 * @param string le message d'erreur avec des %s.
393
	 * @param array le tableau des paramêtres à insérer dans le message d'erreur.
394
	 * @return string le message d'erreur formaté.
395
	 */
396
	protected function traiterErreur($message, $tab_arguments = array()) {
397
		$niveau = Script::ERREUR;
398
		return $this->traiterMessage($message, $tab_arguments, $niveau);
399
	}
400
 
401
	/**
402
	 * Retourne un message d'avertissement formaté.
403
	 * Si le mode verbeux de niveau 1 est activé, écrit le message dans le fichier de log.
404
	 * Si le mode verbeux de niveau 2 est activé, écrit le message dans le fichier de log et dans la console.
405
	 *
406
	 * @param string le message d'erreur avec des %s.
407
	 * @param array le tableau des paramêtres à insérer dans le message d'erreur.
408
	 * @return string le message d'erreur formaté.
409
	 */
410
	protected function traiterAttention($message, $tab_arguments = array()) {
411
		$niveau = Script::AVERTISSEMENT;
412
		return $this->traiterMessage($message, $tab_arguments, $niveau);
413
	}
414
 
415
	/**
416
	 * Retourne un message d'information formaté.
417
	 * Si le mode verbeux de niveau 2 est activé, écrit le message dans le fichier de log.
418
	 * Si le mode verbeux de niveau 3 est activé, écrit le message dans le fichier de log et dans la console.
419
	 *
420
	 * @param string le message d'information avec des %s.
421
	 * @param array le tableau des paramêtres à insérer dans le message d'erreur.
422
	 * @param int le niveau de verbosité à dépasser pour afficher les messages.
423
	 * @return string le message d'erreur formaté.
424
	 */
425
	protected function afficher($message, $tab_arguments = array(), $niveau = null) {
426
		if (is_null($niveau)) {
427
			$niveau = Script::INFO;
428
		}
429
		$msg = $this->traiterMessage($message, $tab_arguments, $niveau);
430
		return $msg ;
431
	}
432
 
433
	/**
434
	 * Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,
435
	 * en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
436
	 *
437
	 * @param String $fichier	le chemin du fichier du squelette
438
	 * @param Array  $donnees	un tableau associatif contenant les variables a injecter dans le squelette.
439
	 *
440
	 * @return boolean false si le squelette n'existe pas, sinon la chaine résultat.
441
	 */
442
	public static function traiterSquelettePhp($fichier, Array $donnees = array()) {
443
		$sortie = false;
444
		if (file_exists($fichier)) {
445
			// Extraction des variables du tableau de données
446
			extract($donnees);
447
			// Démarage de la bufferisation de sortie
448
			ob_start();
449
			// Si les tags courts sont activés
450
			if ((bool) @ini_get('short_open_tag') === true) {
451
				// Simple inclusion du squelette
452
				include $fichier;
453
			} else {
454
				// Sinon, remplacement des tags courts par la syntaxe classique avec echo
455
				$html_et_code_php = self::traiterTagsCourts($fichier);
456
				// Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval
457
				$html_et_code_php = '?>'.$html_et_code_php;
458
				// Interprétation du html et du php dans le buffer
459
				echo eval($html_et_code_php);
460
			}
461
			// Récupèration du contenu du buffer
462
			$sortie = ob_get_contents();
463
			// Suppression du buffer
464
			@ob_end_clean();
465
		} else {
466
			$msg = "Le fichier du squelette '$fichier' n'existe pas.";
467
			trigger_error($msg, E_USER_WARNING);
468
		}
469
		// Retourne le contenu
470
		return $sortie;
471
	}
472
 
473
	/**
474
	 * Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.
475
	 *
476
	 * @param String $chemin_squelette le chemin du fichier du squelette
477
	 *
478
	 * @return string le contenu du fichier du squelette php avec les tags courts remplacés.
479
	 */
480
	private static function traiterTagsCourts($chemin_squelette) {
481
		$contenu = file_get_contents($chemin_squelette);
482
		// Remplacement de tags courts par un tag long avec echo
483
		$contenu = str_replace('<?=', '<?php echo ',  $contenu);
484
		// Ajout systématique d'un point virgule avant la fermeture php
485
		$contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);
486
		return $contenu;
487
	}
488
 
489
	/**
490
	 * Créer et stocke du contenu dans un fichier.
491
	 *
492
	 * @param string le chemin et le nom du fichier.
493
	 * @param string le contenu à stocker dans le fichier.
494
	 * @return string le message d'erreur formaté.
495
	 */
496
	protected function creerFichier($fichier, $contenu, $compression = false) {
497
		$e = null;
498
		if ($compression) {
499
			// Ajout de l'extension gz
500
			if (substr($fichier, -3) != '.gz') {
501
				$fichier = $fichier.'.gz';
502
			}
503
			// Début de l'écriture du fichier compressé
504
			if ($resource = gzopen($fichier, 'w9')) {
505
				if (!gzwrite($resource, $contenu)) {
506
					$e = "Le contenu texte n'a pas pu être écrit dans le fichier compressé '$fichier'.";
507
				}
508
				if (!gzclose($resource)) {
509
					$e = "Le fichier compressé '$fichier' n'a pas pu être fermé.";
510
				}
511
			} else {
512
				$e = "Le fichier compressé '$fichier' n'a pas pu être ouvert.";
513
			}
514
		} else {
515
			if ($resource = fopen($fichier, 'w')) {
516
				if (!fwrite($resource, $contenu)) {
517
					$e = "Le contenu texte n'a pas pu être écrit dans le fichier '$fichier'.";
518
				}
519
				if (!fclose($resource)) {
520
					$e = "Le fichier '$fichier' n'a pas pu être fermé.";
521
				}
522
			} else {
523
				$e = "Le fichier '$fichier' n'a pas pu être ouvert.";
524
			}
525
		}
526
		if (is_null($e)) {
527
			return true;
528
		} else {
529
			trigger_error($e, E_USER_WARNING);
530
			return false;
531
		}
532
	}
533
 
534
	/**
535
	 * Méthode permettant d'encoder de l'iso-8859-15 vers utf-8 un tableau de variables.
536
	 *
537
	 * @param mixed la chaine ou le tableau à encoder en utf-8 depuis l'iso-8859-15.
538
	 * @param string l'encodage d'origine si ce n'est pas ISO-8859-15.
539
	 * @return mixed la chaine ou le tableau encodé en utf-8.
540
	 * @access protected
541
	 */
542
	protected function encoderUtf8( &$val, $encodage = 'ISO-8859-15') {
543
		//echo print_r($val, true)."\n";
544
		if (is_array($val)) {
545
			foreach ($val as $c => $v) {
546
				$val[$c] = $this->encoderUtf8($v);
547
			}
548
		} else {
549
			// Nous vérifions si nous avons un bon encodage UTF-8
550
			if (!is_numeric($val) && !empty($val) && !$this->detecterUtf8($val)) {
551
				// Les nombres, les valeurs vides et ce qui est déjà en UTF-8 ne sont pas encodés.
552
				$val = mb_convert_encoding($val, 'UTF-8', $encodage);
553
			}
554
		}
555
		return $val;
556
	}
557
 
558
	/**
559
	 * Méthode permettant de détecter réellement l'encodage utf8.
560
	 * mb_detect_encoding plante si la chaine de caractère se termine par un caractère accentué.
561
	 * Provient de  PHPDIG.
562
	 *
563
	 * @param string la chaine à vérifier.
564
	 * @return bool true si c'est de l'utf8, sinon false.
565
	 * @access private
566
	 */
567
	private function detecterUtf8($str) {
568
		if ($str === mb_convert_encoding(mb_convert_encoding($str, 'UTF-32', 'UTF-8'), 'UTF-8', 'UTF-32')) {
569
			return true;
570
		} else {
571
			return false;
572
		}
573
	}
574
}
575
?>