Subversion Repositories Applications.annuaire

Rev

Rev 561 | Rev 571 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
69 aurelien 1
<?php
2
/**
3
 * Classe mère abstraite contenant les méthodes génériques des services.
4
 * Encodage en entrée : utf8
5
 * Encodage en sortie : utf8
6
 *
7
 * @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
8
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
9
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
10
 * @version $Id$
11
 * @copyright 2009
12
 */
13
abstract class JRestService {
14
 
15
	public $config;
16
	protected $bdd;
331 jpm 17
	protected $ressources;
69 aurelien 18
	protected $log = array();
19
	protected $messages = array();
20
	protected $debug = array();
21
	protected $distinct = false;
22
	protected $orderby = null;
23
	protected $formatRetour = 'objet';
24
	protected $start = 0;
25
	protected $limit = 150;
26
 
519 mathias 27
	/** pour l'envoi de XML : éventuelle balise dans laquelle placer tout le contenu */
28
	protected $baliseMaitresse;
29
 
69 aurelien 30
	public function __construct($config, $demarrer_session = true) {
31
		// Tableau contenant la config de Jrest
32
		$this->config = $config;
33
 
34
		// Connection à la base de données
35
		$this->bdd = $this->connecterPDO($this->config, 'appli');
36
 
37
		// Nettoyage du $_GET (sécurité)
38
		if (isset($_GET)) {
39
			$get_params = array('orderby', 'distinct', 'start', 'limit', 'formatRetour');
40
			foreach ($get_params as $get) {
41
				$verifier = array('NULL', "\n", "\r", "\\", "'", '"', "\x00", "\x1a", ';');
538 mathias 42
				if (isset($_GET[$get])) {
43
					$_GET[$get] = str_replace($verifier, '', $_GET[$get]);
44
					if ($_GET[$get] != '') {
45
						$this->$get = $_GET[$get];
46
					}
69 aurelien 47
				} else {
48
					$_GET[$get] = null;
49
				}
50
			}
51
		}
52
	}
53
 
54
	/**
55
	 * Méthode appelée quand aucun paramètre n'est passé dans l'url et avec une requête de type GET.
56
	 */
57
	public function getRessource() {
58
		$this->getElement(array());
59
	}
60
 
331 jpm 61
	//+----------------------------------------------------------------------------------------------------------------+
536 mathias 62
	// GESTION de l'ENVOI au NAVIGATEUR pas la PEINE de CRIER
331 jpm 63
 
64
	protected function envoyerJson($donnees, $encodage = 'utf-8') {
65
		$contenu = json_encode($donnees);
66
		$this->envoyer($contenu, 'application/json', $encodage, false);
67
	}
390 jpm 68
 
519 mathias 69
	/** à l'arrache pour rétrocompatibilité avec le service "annuaire_tela" de eFlore_chatin */
70
	protected function envoyerXml($donnees, $encodage = 'utf-8') {
71
		$xml = '<?xml version="1.0" encoding="' . strtoupper($encodage) . '"?>';
72
		if ($this->baliseMaitresse) {
73
			$xml .= '<' . $this->baliseMaitresse . '>';
74
		}
75
		$xml .= $this->genererXmlAPartirDeTableau($donnees);
76
		if ($this->baliseMaitresse) {
77
			$xml .= '</' . $this->baliseMaitresse . '>';
78
		}
79
		$this->envoyer($xml, 'application/xml', $encodage, false);
80
	}
81
 
82
	/**
83
	 * Génère un XML minimaliste à partir d'un tableau associatif
84
	 * Note : gère mal les indices numériques
85
	 * @TODO utiliser une vraie lib
86
	 */
87
	protected function genererXmlAPartirDeTableau($tableau) {
88
		$xml = '';
89
		foreach ($tableau as $balise => $donnee) {
90
			$xml .= '<' . $balise . '>';
91
			if (is_array($donnee)) {
92
				// récurer, balayer, que ce soit toujours pimpant
93
				$xml .= $this->genererXmlAPartirDeTableau($donnee);
94
			} else {
95
				$xml .= $donnee;
96
			}
97
			$xml .= '</' . $balise . '>';
98
		}
99
		return $xml;
100
	}
101
 
331 jpm 102
	protected function envoyerJsonVar($variable, $donnees = null, $encodage = 'utf-8') {
103
		$contenu = "var $variable = ".json_encode($donnees);
104
		$this->envoyer($contenu, 'text/html', $encodage, false);
105
	}
390 jpm 106
 
331 jpm 107
	protected function envoyerJsonp($donnees = null, $encodage = 'utf-8') {
108
		$contenu = $_GET['callback'].'('.json_encode($donnees).');';
109
		$this->envoyer($contenu, 'text/html', $encodage, false);
110
	}
390 jpm 111
 
331 jpm 112
	protected function envoyerTxt($donnees, $encodage = 'utf-8') {
113
		$this->envoyer($contenu, 'text/html', $encodage, false);
114
	}
115
 
69 aurelien 116
	protected function envoyer($donnees = null, $mime = 'text/html', $encodage = 'utf-8', $json = true) {
117
		// Traitements des messages d'erreurs et données
118
		if (count($this->messages) != 0) {
119
			header('HTTP/1.1 500 Internal Server Error');
120
			$mime = 'text/html';
121
			$encodage = 'utf-8';
122
			$json = true;
123
			$sortie = $this->messages;
124
		} else {
125
			$sortie = $donnees;
126
			if (is_null($donnees)) {
127
				$sortie = 'OK';
128
			}
129
		}
130
 
131
		// Gestion de l'envoie du déboguage
132
		$this->envoyerDebogage();
133
 
134
		// Encodage au format et JSON et envoie sur la sortie standard
135
		$contenu = $json ? json_encode($sortie) : $sortie;
136
		$this->envoyerContenu($encodage, $mime, $contenu);
137
	}
138
 
331 jpm 139
	private function envoyerDebogage() {
69 aurelien 140
		if (!is_array($this->debug)) {
141
			$this->debug[] = $this->debug;
142
		}
143
		if (count($this->debug) != 0) {
144
			foreach ($this->debug as $cle => $val) {
145
				if (is_array($val)) {
146
					$this->debug[$cle] = print_r($val, true);
147
				}
148
			}
149
			header('X-DebugJrest-Data:'.json_encode($this->debug));
150
		}
151
	}
152
 
331 jpm 153
	private function envoyerContenu($encodage, $mime, $contenu) {
154
		if (!is_null($mime) && !is_null($encodage)) {
155
			header("Content-Type: $mime; charset=$encodage");
156
		} else if (!is_null($mime) && is_null($encodage)) {
157
			header("Content-Type: $mime");
158
		}
69 aurelien 159
		print $contenu;
160
	}
390 jpm 161
 
331 jpm 162
	private function envoyerAuth($message_accueil, $message_echec) {
163
		header('HTTP/1.0 401 Unauthorized');
164
		header('WWW-Authenticate: Basic realm="'.mb_convert_encoding($message_accueil, 'ISO-8859-1', 'UTF-8').'"');
165
		header('Content-type: text/plain; charset=UTF-8');
166
		print $message_echec;
167
		exit(0);
168
	}
390 jpm 169
 
473 jpm 170
	protected function envoyerMessageErreur($msg, $code) {
171
		$textHttp = $this->getCodeHttpText($code);
172
		header("HTTP/1.0 $code $textHttp");
173
		header("Content-Type: text/plain; charset=utf-8");
174
		die($msg);
175
	}
176
 
177
	private function getCodeHttpText($code) {
178
		$text = '';
179
		switch ($code) {
180
			case 100: $text = 'Continue'; break;
181
			case 101: $text = 'Switching Protocols'; break;
182
			case 200: $text = 'OK'; break;
183
			case 201: $text = 'Created'; break;
184
			case 202: $text = 'Accepted'; break;
185
			case 203: $text = 'Non-Authoritative Information'; break;
186
			case 204: $text = 'No Content'; break;
187
			case 205: $text = 'Reset Content'; break;
188
			case 206: $text = 'Partial Content'; break;
189
			case 300: $text = 'Multiple Choices'; break;
190
			case 301: $text = 'Moved Permanently'; break;
191
			case 302: $text = 'Moved Temporarily'; break;
192
			case 303: $text = 'See Other'; break;
193
			case 304: $text = 'Not Modified'; break;
194
			case 305: $text = 'Use Proxy'; break;
195
			case 400: $text = 'Bad Request'; break;
196
			case 401: $text = 'Unauthorized'; break;
197
			case 402: $text = 'Payment Required'; break;
198
			case 403: $text = 'Forbidden'; break;
199
			case 404: $text = 'Not Found'; break;
200
			case 405: $text = 'Method Not Allowed'; break;
201
			case 406: $text = 'Not Acceptable'; break;
202
			case 407: $text = 'Proxy Authentication Required'; break;
203
			case 408: $text = 'Request Time-out'; break;
204
			case 409: $text = 'Conflict'; break;
205
			case 410: $text = 'Gone'; break;
206
			case 411: $text = 'Length Required'; break;
207
			case 412: $text = 'Precondition Failed'; break;
208
			case 413: $text = 'Request Entity Too Large'; break;
209
			case 414: $text = 'Request-URI Too Large'; break;
210
			case 415: $text = 'Unsupported Media Type'; break;
211
			case 500: $text = 'Internal Server Error'; break;
212
			case 501: $text = 'Not Implemented'; break;
213
			case 502: $text = 'Bad Gateway'; break;
214
			case 503: $text = 'Service Unavailable'; break;
215
			case 504: $text = 'Gateway Time-out'; break;
216
			case 505: $text = 'HTTP Version not supported'; break;
217
			default:
218
				exit('Unknown http status code "' . htmlentities($code) . '"');
219
			break;
220
		}
221
		return $text;
222
	}
223
 
331 jpm 224
	//+----------------------------------------------------------------------------------------------------------------+
225
	// GESTION de la BASE de DONNÉES
390 jpm 226
 
69 aurelien 227
	private function connecterPDO($config, $base = 'database') {
390 jpm 228
  		$cfg = $config[$base];
473 jpm 229
		// ATTENTION : la connexin à la bdd peut échouer si l'host vaut localhost. Utiliser 127.0.0.1 à la place.
69 aurelien 230
		$dsn = $cfg['phptype'].':dbname='.$cfg['database'].';host='.$cfg['hostspec'];
231
		try {
473 jpm 232
		// Création de la connexion en UTF-8 à la BDD
390 jpm 233
			$PDO = new PDO($dsn, $cfg['username'], $cfg['password'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
69 aurelien 234
		} catch (PDOException $e) {
473 jpm 235
			echo 'La connexion à la base de donnée via PDO a échouée : ' .$dsn. $e->getMessage();
69 aurelien 236
		}
237
		// Affiche les erreurs détectées par PDO (sinon mode silencieux => aucune erreur affiché)
238
		$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
473 jpm 239
		return $PDO;
69 aurelien 240
	}
241
 
242
	protected function getTxt($id) {
243
		$sortie = '';
244
		switch ($id) {
245
			case 'sql_erreur' : $sortie = 'Requête echec. Fichier : "%s". Ligne : "%s". Message : %s'; break;
246
			default : $sortie = $id;
247
		}
248
		return $sortie;
249
	}
250
 
331 jpm 251
	//+----------------------------------------------------------------------------------------------------------------+
252
	// TRAITEMENT des URLs et des PARAMÊTRES
390 jpm 253
 
331 jpm 254
	protected function traiterNomMethodeGet($nom) {
255
		$methode = 'get';
256
		$methode .= str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($nom))));
257
		return $methode;
258
	}
390 jpm 259
 
347 jpm 260
	protected function traiterNomMethodePost($nom) {
261
		$methode = 'update';
262
		$methode .= str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($nom))));
263
		return $methode;
264
	}
390 jpm 265
 
430 aurelien 266
	protected function traiterNomMethodePut($nom) {
267
		$methode = 'create';
268
		$methode .= str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($nom))));
269
		return $methode;
394 jpm 270
	}
271
 
69 aurelien 272
	protected function traiterParametresUrl($params_attendu, $params, $pourBDD = true) {
273
		$sortie = array();
274
		foreach ($params_attendu as $num => $nom) {
275
			if (isset($params[$num]) && $params[$num] != '*') {
276
				if ($pourBDD) {
277
					$params[$num] = $this->bdd->quote($params[$num]);
278
				}
279
				$sortie[$nom] = $params[$num];
280
			}
281
		}
282
		return $sortie;
283
	}
284
 
285
	protected function traiterParametresPost($params) {
286
		$sortie = array();
287
		foreach ($params as $cle => $valeur) {
288
			$sortie[$cle] = $this->bdd->quote($valeur);
289
		}
290
		return $sortie;
291
	}
292
 
331 jpm 293
	//+----------------------------------------------------------------------------------------------------------------+
294
	// GESTION DE L'IDENTIFICATION
390 jpm 295
 
473 jpm 296
	public function controlerIpAutorisees() {
297
		$ipsAutorisees = $this->config['jrest_admin']['ip_autorisees'];
298
 
299
		$remoteIp = filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP);
300
		$serverIp = filter_input(INPUT_SERVER, 'SERVER_ADDR', FILTER_VALIDATE_IP);
301
		if (in_array($remoteIp, $ipsAutorisees) == false) {
302
			if ($remoteIp != $serverIp) {// ATTENTION : maintenir ce test à l'intérieur du précédent
303
				$message = "Accès interdit. \n".
304
					"Vous n'êtes pas autorisé à accéder à ce service depuis '$remoteIp' !\n";
305
				$this->envoyerMessageErreur($message, 401);
306
			}
307
		}
308
		return true;
309
	}
310
 
430 aurelien 311
	protected function getIdentification(&$params) {
312
		// Initialisation des variables
313
		$utilisateur = array(0, session_id());
314
 
315
		// L'id utilisateur est soit passé par le POST soit dans l'url
316
		if (is_array($params) && isset($params['cmhl_ce_modifier_par'])) {
317
		   	$utilisateur[0] = $params['cmhl_ce_modifier_par'];
318
			unset($params['cmhl_ce_modifier_par']);
319
		} else if (is_string($params)) {
320
			$utilisateur[0] = $params;
321
		}
322
 
323
		return $utilisateur;
324
	}
325
 
326
	protected function etreAutorise($id_utilisateur) {
327
		$autorisation = false;
328
		if (($_SESSION['coel_utilisateur'] != '') && $_SESSION['coel_utilisateur']['id'] != $id_utilisateur) {
329
			$this->messages[] = 'Accès interdit.';
330
		} else if ($_SESSION['coel_utilisateur'] == '') {
331
			$this->messages[] = 'Veuillez vous identifiez pour accéder à cette fonction.';
332
		} else {
333
			$autorisation = true;
334
		}
335
		return $autorisation;
336
	}
337
 
536 mathias 338
	// WTF coel en dur ??
430 aurelien 339
	private function gererIdentificationPermanente() {
340
		// Pour maintenir l'utilisateur tjrs réellement identifié nous sommes obligé de recréer une SESSION et de le recharger depuis la bdd
341
		if ($this->getUtilisateur() == ''
342
				&& isset($_COOKIE['coel_login'])
343
				&& ($utilisateur = $this->chargerUtilisateur($_COOKIE['coel_login'], $_COOKIE['coel_mot_de_passe']))) {
344
			$this->setUtilisateur($utilisateur, $_COOKIE['coel_permanence']);
345
		}
346
	}
347
 
536 mathias 348
	// WTF coel en dur ??
430 aurelien 349
	protected function getUtilisateur() {
350
		return (isset($_SESSION['coel_utilisateur']) ? $_SESSION['coel_utilisateur'] : '');
351
	}
352
 
331 jpm 353
	protected function authentifier() {
565 mathias 354
		// @TODO @WARNING @ACHTUNG @ ALARM enlever le patch CGI quand on aura mis à jour Apache/PHP !!
561 mathias 355
		if (JRest::$cgi === false) { // si on est en CGI, accès libre pour tous (pas trouvé mieux)
356
			if (!isset($_SERVER['PHP_AUTH_USER'])) {
331 jpm 357
				header('WWW-Authenticate: Basic realm="www.tela-botanica.org"');
358
				header('HTTP/1.0 401 Unauthorized');
359
				header('Content-type: text/html; charset=UTF-8');
360
				echo 'Accès interdit';
561 mathias 361
				exit;
362
			} else {
363
				if ($this->verifierAcces()) {
364
					return ;
365
				} else {
366
					header('WWW-Authenticate: Basic realm="www.tela-botanica.org"');
367
					header('HTTP/1.0 401 Unauthorized');
368
					header('Content-type: text/html; charset=UTF-8');
369
					echo 'Accès interdit';
370
					exit ;
371
				}
331 jpm 372
			}
373
		}
374
	}
69 aurelien 375
 
565 mathias 376
	/**
377
	 * Vérifie l'accès en se basant sur $id et $mdp si ceux-ci sont fournis; sinon,
378
	 * lit les valeurs transmises par l'authentification HTTP BASIC AUTH
379
	 */
394 jpm 380
	protected function verifierAcces($id = null, $mdp = null) {
565 mathias 381
		$basicAuth = false;
382
		if ($id == null && $mdp == null) {
561 mathias 383
			$id = is_null($id) ? $_SERVER['PHP_AUTH_USER'] : $id;
384
			$mdp = is_null($mdp) ? $_SERVER['PHP_AUTH_PW'] : $mdp;
565 mathias 385
			$basicAuth = true;
386
		}
387
		if ($basicAuth === false || JRest::$cgi === false) { // en mode non-CGI ou pour une identification $id / $mdp
388
 
561 mathias 389
			$requete = 'SELECT '.$this->config['database_ident']['ann_id'].' AS courriel '.
390
				'FROM '.$this->config['database_ident']['database'].'.'.$this->config['database_ident']['annuaire'].' '.
391
				'WHERE '.$this->config['database_ident']['ann_id'].' = '.$this->bdd->quote($id).' '.
392
				'	AND '.$this->config['database_ident']['ann_pwd'].' = '.$this->config['database_ident']['pass_crypt_funct'].'('.$this->bdd->quote($mdp).')' ;
565 mathias 393
 
561 mathias 394
			$resultat = $this->bdd->query($requete)->fetch();
395
 
396
			$identifie = false;
397
			if (isset($resultat['courriel'])) {
398
				$identifie = true;
399
			}
400
			return $identifie;
565 mathias 401
		} else { // si on est en CGI, accès libre pour tous (pas trouvé mieux)
561 mathias 402
			return true; // ça fait un peu mal...
331 jpm 403
		}
394 jpm 404
	}
331 jpm 405
 
521 mathias 406
	/**
407
	 * Envoie une demande d'authentification HTTP puis compare le couple
408
	 * login / mot de passe envoyé par l'utilisateur, à ceux définis dans
409
	 * la config (section database_ident).
410
	 * En cas d'erreur, sort du programme avec un entête HTTP 401
411
	 * @TODO redondant avec les trucs du dessus :'(
412
	 */
413
	protected function authentificationHttpSimple() {
414
		$autorise = true;
565 mathias 415
		// contrôle d'accès @TODO @WARNING @ACHTUNG @ ALARM enlever le patch CGI quand on aura mis à jour Apache/PHP !!
561 mathias 416
		if (JRest::$cgi === false) { // si on est en CGI, accès libre pour tous (pas trouvé mieux)
417
			$nomUtil = $_SERVER['PHP_AUTH_USER'];
418
			$mdp = $_SERVER['PHP_AUTH_PW'];
419
			$autorise = (($nomUtil == $this->config['database_ident']['username']) && ($mdp == $this->config['database_ident']['password']));
420
		}
521 mathias 421
		// entêtes HTTP
422
		if (! $autorise) {
423
			header('WWW-Authenticate: Basic realm="Annuaire de Tela Botanica"');
424
			header('HTTP/1.0 401 Unauthorized');
425
			echo 'Veuillez vous authentifier pour utiliser ce service';
426
			exit;
427
		}
428
	}
429
 
396 jpm 430
	protected function creerCookiePersistant($duree = null, $id = null, $mdp = null) {
430 aurelien 431
		$id = is_null($id) ? $_SERVER['PHP_AUTH_USER'] : $id;
394 jpm 432
		$mdp = is_null($mdp) ? $_SERVER['PHP_AUTH_PW'] : $mdp;
396 jpm 433
		$duree = (int) is_null($duree) ? time()+3600*24*30 : $duree;
331 jpm 434
 
394 jpm 435
		$nomCookie = $this->config['database_ident']['nom_cookie_persistant'];
430 aurelien 436
		$valeurCookie = md5($mdp).$id;
437
 
396 jpm 438
		setcookie($nomCookie, $valeurCookie, $duree, '/');
331 jpm 439
	}
390 jpm 440
 
430 aurelien 441
	protected function creerCookieUtilisateur($duree = null, $id = null, $mdp = null) {
400 jpm 442
		$id = is_null($id) ? $_SERVER['PHP_AUTH_USER'] : $id;
430 aurelien 443
		$mdp = is_null($mdp) ? $_SERVER['PHP_AUTH_PW'] : $mdp;
396 jpm 444
		$duree = (int) is_null($duree) ? 0 : $duree;
430 aurelien 445
 
446
		$nomCookie = $this->config['database_ident']['nom_cookie_utilisateur'];
400 jpm 447
		$valeurCookie = md5($mdp).$id;
430 aurelien 448
 
449
		setcookie($nomCookie, $valeurCookie, $duree, '/');
394 jpm 450
	}
532 aurelien 451
 
452
	protected function supprimerCookieUtilisateur() {
453
		session_destroy();
454
		setcookie($this->config['database_ident']['nom_cookie_utilisateur'], "", time()-7200, "/");
455
		setcookie($this->config['database_ident']['nom_cookie_persistant'], "", time()-7200, "/");
456
	}
394 jpm 457
 
388 aurelien 458
	protected function estAutoriseMessagerie($adresse) {
459
		$utilisateurs_messagerie = explode(',', $this->config['messagerie']['utilisateurs_autorises']);
460
		return in_array($adresse, $utilisateurs_messagerie);
461
	}
394 jpm 462
 
331 jpm 463
	//+----------------------------------------------------------------------------------------------------------------+
464
	// GESTION DES SQUELETTES PHP
390 jpm 465
 
69 aurelien 466
	/**
467
	 * Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,
468
	 * en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
469
	 *
470
	 * @param String $fichier	le chemin du fichier du squelette
471
	 * @param Array  $donnees	un tableau associatif contenant les variables a injecter dans le squelette.
472
	 *
473
	 * @return boolean false si le squelette n'existe pas, sinon la chaine résultat.
474
	 */
475
	public static function traiterSquelettePhp($fichier, Array $donnees = array()) {
476
		$sortie = false;
477
		if (file_exists($fichier)) {
478
			// Extraction des variables du tableau de données
479
			extract($donnees);
480
			// Démarage de la bufferisation de sortie
481
			ob_start();
482
			// Si les tags courts sont activés
483
			if ((bool) @ini_get('short_open_tag') === true) {
484
				// Simple inclusion du squelette
485
				include $fichier;
486
			} else {
487
				// Sinon, remplacement des tags courts par la syntaxe classique avec echo
488
				$html_et_code_php = self::traiterTagsCourts($fichier);
489
				// Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval
490
				$html_et_code_php = '?>'.$html_et_code_php;
491
				// Interprétation du html et du php dans le buffer
492
				echo eval($html_et_code_php);
493
			}
494
			// Récupèration du contenu du buffer
495
			$sortie = ob_get_contents();
496
			// Suppression du buffer
497
			@ob_end_clean();
498
		} else {
499
			$msg = "Le fichier du squelette '$fichier' n'existe pas.";
500
			trigger_error($msg, E_USER_WARNING);
501
		}
502
		// Retourne le contenu
503
		return $sortie;
504
	}
505
 
506
	/**
507
	 * Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.
508
	 *
509
	 * @param String $chemin_squelette le chemin du fichier du squelette
510
	 *
511
	 * @return string le contenu du fichier du squelette php avec les tags courts remplacés.
512
	 */
513
	private static function traiterTagsCourts($chemin_squelette) {
514
		$contenu = file_get_contents($chemin_squelette);
515
		// Remplacement de tags courts par un tag long avec echo
516
		$contenu = str_replace('<?=', '<?php echo ',  $contenu);
517
		// Ajout systématique d'un point virgule avant la fermeture php
518
		$contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);
519
		return $contenu;
520
	}
521
}
522
?>