Subversion Repositories Applications.framework

Rev

Rev 366 | Rev 383 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 366 Rev 382
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
 * Classe principale gérant les services web de type (@link(REST, http://fr.wikipedia.org/wiki/Rest).
4
 * Classe principale gérant les services web de type (@link(REST, http://fr.wikipedia.org/wiki/Rest).
5
 * 
5
 * 
6
 * Elle contient  :
6
 * Elle contient  :
7
 *  - les constantes indiquant les différentes (@link(méthode HTTP, http://fr.wikipedia.org/wiki/Http) prises en compte.
7
 *  - les constantes indiquant les différentes (@link(méthode HTTP, http://fr.wikipedia.org/wiki/Http) prises en compte.
8
 *  - les @link(codes HTTP des réponses, http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP)
8
 *  - les @link(codes HTTP des réponses, http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP)
9
 * 
9
 * 
10
 * Ce serveur REST accepte 4 types de méthodes HTTP : GET, PUT, POST, DELETE.
10
 * Ce serveur REST accepte 4 types de méthodes HTTP : GET, PUT, POST, DELETE.
11
 * GET et POST ne pose généralement pas de problème pour les clients HTTP mais ce n'est pas forcément le cas pour PUT et DELETE.
11
 * GET et POST ne pose généralement pas de problème pour les clients HTTP mais ce n'est pas forcément le cas pour PUT et DELETE.
12
 * Vous pouvez donc pour réaliser :
12
 * Vous pouvez donc pour réaliser :
13
 *  - DELETE : utiliser la méthode POST avec action=DELETE dans le corps de la requête.
13
 *  - DELETE : utiliser la méthode POST avec action=DELETE dans le corps de la requête.
14
 *  - PUT : utiliser la méthode POST avec une url ne contenant aucune indication de ressource.
14
 *  - PUT : utiliser la méthode POST avec une url ne contenant aucune indication de ressource.
15
 * Une autre solution consiste à utiliser n'importe quelle méthode et à ajouter l'entête "X_HTTP_METHOD_OVERRIDE" avec pour 
15
 * Une autre solution consiste à utiliser n'importe quelle méthode et à ajouter l'entête "X_HTTP_METHOD_OVERRIDE" avec pour 
16
 * valeur le nom de la méthode que vous souhaitez utiliser. Exemple d'entête : "X_HTTP_METHOD_OVERRIDE: PUT".
16
 * valeur le nom de la méthode que vous souhaitez utiliser. Exemple d'entête : "X_HTTP_METHOD_OVERRIDE: PUT".
17
 * Exemple : <code>curl -v -v -H "X_HTTP_METHOD_OVERRIDE: DELETE" "http://www.mondomaine.org/services/apiVersion/[mon-service]/"</code>
17
 * Exemple : <code>curl -v -v -H "X_HTTP_METHOD_OVERRIDE: DELETE" "http://www.mondomaine.org/services/apiVersion/[mon-service]/"</code>
18
 * Cela fonctionne avec Apache.
18
 * Cela fonctionne avec Apache.
19
 * 
19
 * 
20
 * Les classes des services web doivent avoir un nom au format ChatMot "MonService" et être appelée dans l'url par le même nom
20
 * Les classes des services web doivent avoir un nom au format ChatMot "MonService" et être appelée dans l'url par le même nom
21
 * en minuscule où les mots sont séparés par des tirets "mon-service".
21
 * en minuscule où les mots sont séparés par des tirets "mon-service".
22
 * 
22
 * 
23
 * Paramètres liés dans config.ini :
23
 * Paramètres liés dans config.ini :
24
 *  - serveur.baseURL : morceau de l'url pour appeler le serveur relative au domaine. Exemple : pour http://www.tela-botanica.org/mon_serveur/
24
 *  - serveur.baseURL : morceau de l'url pour appeler le serveur relative au domaine. Exemple : pour http://www.tela-botanica.org/mon_serveur/
25
 *  	mettre : "/mon_serveur/"
25
 *  	mettre : "/mon_serveur/"
26
 *  - serveur.baseAlternativeURL : sur le même principe que ci-dessus permet d'affecter une deuxième url (pour gérer des raccourci via htaccess)
26
 *  - serveur.baseAlternativeURL : sur le même principe que ci-dessus permet d'affecter une deuxième url (pour gérer des raccourci via htaccess)
27
 *  
27
 *  
28
 * Encodage en entrée : utf8
28
 * Encodage en entrée : utf8
29
 * Encodage en sortie : utf8
29
 * Encodage en sortie : utf8
30
 * 
30
 * 
31
 * @category	Php 5.2
31
 * @category	Php 5.2
32
 * @package		Framework
32
 * @package		Framework
33
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
33
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
34
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
34
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
35
 * @license		GPL v3 <http://www.gnu.org/licenses/gpl.txt>
35
 * @license		GPL v3 <http://www.gnu.org/licenses/gpl.txt>
36
 * @license		CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
36
 * @license		CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
37
 * @since 		0.3
37
 * @since 		0.3
38
 * @version		$Id: RestServeur.php 366 2011-09-30 08:20:45Z jpm $
38
 * @version		$Id: RestServeur.php 382 2011-10-14 10:36:41Z jpm $
39
 * @link		/doc/framework/
39
 * @link		/doc/framework/
40
 */
40
 */
41
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
41
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
42
class RestServeur {
42
class RestServeur {
43
	
43
	
44
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
44
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
45
	const METHODE_GET = 'consulter';
45
	const METHODE_GET = 'consulter';
46
	
46
	
47
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type POST. */
47
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type POST. */
48
	const METHODE_POST = 'modifier';
48
	const METHODE_POST = 'modifier';
49
	
49
	
50
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type DELETE. */
50
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type DELETE. */
51
	const METHODE_DELETE = 'supprimer';
51
	const METHODE_DELETE = 'supprimer';
52
	
52
	
53
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type PUT. */
53
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type PUT. */
54
	const METHODE_PUT = 'ajouter';
54
	const METHODE_PUT = 'ajouter';
55
	
55
	
56
	/** Code HTTP 200 indiquant le succès de l'accès à un service web par la méthode GET.
56
	/** Code HTTP 200 indiquant le succès de l'accès à un service web par la méthode GET.
57
	 * L'utiliser lors d'une requète de type GET (consulter) pour indiquer le succès de l'opération.
57
	 * L'utiliser lors d'une requète de type GET (consulter) pour indiquer le succès de l'opération.
58
	 * Sera renvoyée par défaut par PHP. */
58
	 * Sera renvoyée par défaut par PHP. */
59
	const HTTP_CODE_OK = '200';
59
	const HTTP_CODE_OK = '200';
60
	
60
	
61
	/** Code HTTP 201 indiquant que l'accès à un service web est un succès et que la ressource a été créée ou modifié.
61
	/** Code HTTP 201 indiquant que l'accès à un service web est un succès et que la ressource a été créée ou modifié.
62
	 * L'utiliser lors d'une requète de type PUT (ajouter) ou POST (modifier) pour indiquer le succès de l'opération. */
62
	 * L'utiliser lors d'une requète de type PUT (ajouter) ou POST (modifier) pour indiquer le succès de l'opération. */
63
	const HTTP_CODE_CREATION_OK = '201';
63
	const HTTP_CODE_CREATION_OK = '201';
64
	
64
	
65
	/** Code HTTP 204 indique que l'accès à un service web est un succès et qu'il n'y a pas de contenu à renvoyer.
65
	/** Code HTTP 204 indique que l'accès à un service web est un succès et qu'il n'y a pas de contenu à renvoyer.
66
	 * L'utiliser lors d'une requète de type DELETE (supprimer) pour indiquer le succès de l'opération. */
66
	 * L'utiliser lors d'une requète de type DELETE (supprimer) pour indiquer le succès de l'opération. */
67
	const HTTP_CODE_SUPPRESSION_OK = '204';
67
	const HTTP_CODE_SUPPRESSION_OK = '204';
68
	
68
	
69
	/** Code HTTP 400 indique que les paramètres envoyés au service contiennent des erreurs.
69
	/** Code HTTP 400 indique que les paramètres envoyés au service contiennent des erreurs.
70
	 * L'utiliser pour indiquer l'échec de l'accès au service. La réponse pourra contenir un message expliquant la source 
70
	 * L'utiliser pour indiquer l'échec de l'accès au service. La réponse pourra contenir un message expliquant la source 
71
	 * de l'erreur. */
71
	 * de l'erreur. */
72
	const HTTP_CODE_MAUVAISE_REQUETE = '400';
72
	const HTTP_CODE_MAUVAISE_REQUETE = '400';
73
	
73
	
74
	/** Code HTTP 401 indiquant que l'accès à un service web est refusé car l'authentification (obligatoire) a échoué pour
74
	/** Code HTTP 401 indiquant que l'accès à un service web est refusé car l'authentification (obligatoire) a échoué pour
75
	 * accéder à la ressource. */
75
	 * accéder à la ressource. */
76
	const HTTP_CODE_ACCES_NON_AUTORISE = '401';
76
	const HTTP_CODE_ACCES_NON_AUTORISE = '401';
77
	
77
	
78
	/** Code HTTP 404 indiquant que la ressource indiquée par l'url est introuvable. */
78
	/** Code HTTP 404 indiquant que la ressource indiquée par l'url est introuvable. */
79
	const HTTP_CODE_RESSOURCE_INTROUVABLE = '404';
79
	const HTTP_CODE_RESSOURCE_INTROUVABLE = '404';
80
	
80
	
81
	/** Code HTTP 405 indiquant soit :
81
	/** Code HTTP 405 indiquant soit :
82
	 *  - que le service web ne possède pas d'accès la ressource correspondant à la méthode HTTP employée.
82
	 *  - que le service web ne possède pas d'accès la ressource correspondant à la méthode HTTP employée.
83
	 *  - que la méthode HTTP enployée n'est pas en accord avec la ressource indiquée par l'url. */
83
	 *  - que la méthode HTTP enployée n'est pas en accord avec la ressource indiquée par l'url. */
84
	const HTTP_CODE_METHODE_NON_AUTORISE = '405';
84
	const HTTP_CODE_METHODE_NON_AUTORISE = '405';
85
	
85
	
86
	/** Code d'erreur HTTP 409 indiquant qu'un conflit est survenu vis à vis de la ressource.
86
	/** Code d'erreur HTTP 409 indiquant qu'un conflit est survenu vis à vis de la ressource.
87
	 * Par exemple, essayer de créer deux fois la même ressource ou bien tenter de modifier une ressource qui a été modifiée par 
87
	 * Par exemple, essayer de créer deux fois la même ressource ou bien tenter de modifier une ressource qui a été modifiée par 
88
	 * ailleurs. */
88
	 * ailleurs. */
89
	const HTTP_CODE_CONFLIT = '409';
89
	const HTTP_CODE_CONFLIT = '409';
90
	
90
	
91
	/** Code HTTP 411 indiquant que des paramètres passés dans le contenu de la requête sont nécessaires au service. */
91
	/** Code HTTP 411 indiquant que des paramètres passés dans le contenu de la requête sont nécessaires au service. */
92
	const HTTP_CODE_CONTENU_REQUIS = '411';
92
	const HTTP_CODE_CONTENU_REQUIS = '411';
93
	
93
	
94
	/** Code d'erreur HTTP 500 Internal Server Error.
94
	/** Code d'erreur HTTP 500 Internal Server Error.
95
	 * L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
95
	 * L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
96
	const HTTP_CODE_ERREUR = '500';
96
	const HTTP_CODE_ERREUR = '500';
97
	
97
	
98
	/** Motif de l'epression régulière vérfiant la version de l'API. */
98
	/** Motif de l'epression régulière vérfiant la version de l'API. */
99
	const MOTIF_API_VERSION = '/^[0-9]+(?:[.][0-9]+)*$/';
99
	const MOTIF_API_VERSION = '/^[0-9]+(?:[.][0-9]+)*$/';
100
	
100
	
101
	/** Motif de l'epression régulière vérfiant le nom du service. */
101
	/** Motif de l'epression régulière vérfiant le nom du service. */
102
	const MOTIF_SERVICE_NOM = '/^[a-z0-9]+(?:[-][a-z0-9]+)*$/';
102
	const MOTIF_SERVICE_NOM = '/^[a-z0-9]+(?:[-][a-z0-9]+)*$/';
103
	
103
	
104
	/** Mettre à true pour activer l'affichage des messages d'erreurs et de débogage. 
104
	/** Mettre à true pour activer l'affichage des messages d'erreurs et de débogage. 
105
	 * @var boolean */
105
	 * @var boolean */
106
	private static $debogageActivation = false;
106
	private static $debogageActivation = false;
107
	
107
	
108
	/** Indiquer le mode de débogage à utiliser (@see Debug). 
108
	/** Indiquer le mode de débogage à utiliser (@see Debug). 
109
	 * @var string */
109
	 * @var string */
110
	private static $debogageMode = '';
110
	private static $debogageMode = '';
111
	
111
	
112
	/** La méthode de la requête HTTP utilisée. 
112
	/** La méthode de la requête HTTP utilisée. 
113
	 * @var string */
113
	 * @var string */
114
	private $methode = 'GET';
114
	private $methode = 'GET';
115
 
115
 
116
	/** Le contenu brut du corps de la requête HTTP (s'il y en a).
116
	/** Le contenu brut du corps de la requête HTTP (s'il y en a).
117
	 * @var array */
117
	 * @var array */
118
	private $requeteDonnees = null;
118
	private $requeteDonnees = null;
119
	
119
	
120
	/** Le contenu sous forme de tableau de paires clés-valeurs du corps de la requête HTTP (s'il y en a). 
120
	/** Le contenu sous forme de tableau de paires clés-valeurs du corps de la requête HTTP (s'il y en a). 
121
	 * @var array */
121
	 * @var array */
122
	private $requeteDonneesParsees = null;
122
	private $requeteDonneesParsees = null;
123
 
123
 
124
	/** Version de l'API demandée.
124
	/** Version de l'API demandée.
125
	 * Ex. http://www.mondomaine.org/services/[apiVersion]/mon-service/
125
	 * Ex. http://www.mondomaine.org/services/[apiVersion]/mon-service/
126
	 * @var mixed Généralement deux nombres séparés par un point. Ex. : 1.0
126
	 * @var mixed Généralement deux nombres séparés par un point. Ex. : 1.0
127
	 */
127
	 */
128
	private $apiVersion = null;
128
	private $apiVersion = null;
129
 
129
 
130
	/** Nom du service demandé. 
130
	/** Nom du service demandé. 
131
	 * Ex. http://www.mondomaine.org/services/apiVersion/[mon-service]/
131
	 * Ex. http://www.mondomaine.org/services/apiVersion/[mon-service]/
132
	 * @var string par défaut vaut null.
132
	 * @var string par défaut vaut null.
133
	 */
133
	 */
134
	private $service = null;
134
	private $service = null;
135
	
135
	
136
	/** Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
136
	/** Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
137
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service/[maRessource/maSousResource...]
137
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service/[maRessource/maSousResource...]
138
	 * @var array
138
	 * @var array
139
	 */
139
	 */
140
	private $ressources = array();
140
	private $ressources = array();
141
	
141
	
142
	/** Partie de l'url situé après le '?' servant à paramétrer le service demandé.
142
	/** Partie de l'url situé après le '?' servant à paramétrer le service demandé.
-
 
143
	 * Les données proviennent de $_GET où les caractères suivant ont été transformé en '_' undescrore dans les clés :
-
 
144
	 * - chr(32) ( ) (space)
-
 
145
	 * - chr(46) (.) (dot)
-
 
146
	 * - chr(91) ([) (open square bracket)
-
 
147
	 * - chr(128) - chr(159) (various)
-
 
148
	 * En outre nous appliquons la méthode nettoyerGet() qui effectue d'autres remplacement dans les valeurs.
143
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service?monParametre1=maValeur1&monParametre2=maValeur2
149
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service?monParametre1=maValeur1&monParametre2=maValeur2
-
 
150
	 * @see parametresBruts
144
	 * @var array
151
	 * @var array
145
	 */
152
	 */
146
	private $parametres = array();
153
	private $parametres = array();
-
 
154
	
-
 
155
	/** Partie de l'url situé après le '?' servant à paramétrer le service demandé.
-
 
156
	 * Les données proviennent de $_SERVER['QUERY_STRING'] et n'ont subies aucune transformation au niveau des clés.
-
 
157
	 * Cependant nous appliquons la méthode nettoyerGet() qui effectue d'autres remplacement dans les valeurs.
-
 
158
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service?monParametre1=maValeur1&monParametre2=maValeur2
-
 
159
	 * @see parametres
-
 
160
	 * @var array
-
 
161
	 */
-
 
162
	private $parametresBruts = array();
147
	
163
	
148
	/** Tableau contenant les paramètres de configuration du serveur.
164
	/** Tableau contenant les paramètres de configuration du serveur.
149
	 * @var array
165
	 * @var array
150
	 */
166
	 */
151
	private static $config = array();
167
	private static $config = array();
152
 
168
 
153
	/** Tableau contenant les messages d'erreur et/ou d'avertissement du Serveur.
169
	/** Tableau contenant les messages d'erreur et/ou d'avertissement du Serveur.
154
	 * @var array
170
	 * @var array
155
	 * */
171
	 * */
156
	private static $messages = array();
172
	private static $messages = array();
157
	
173
	
158
	/** Codes HTTP. */
174
	/** Codes HTTP. */
159
	private static $http10 = array(
175
	private static $http10 = array(
160
		self::HTTP_CODE_OK => 'OK',	
176
		self::HTTP_CODE_OK => 'OK',	
161
		self::HTTP_CODE_CREATION_OK => 'Created',
177
		self::HTTP_CODE_CREATION_OK => 'Created',
162
		self::HTTP_CODE_SUPPRESSION_OK => 'No Content',
178
		self::HTTP_CODE_SUPPRESSION_OK => 'No Content',
163
		self::HTTP_CODE_MAUVAISE_REQUETE => 'Bad Request',
179
		self::HTTP_CODE_MAUVAISE_REQUETE => 'Bad Request',
164
		self::HTTP_CODE_ACCES_NON_AUTORISE => 'Unauthorized',
180
		self::HTTP_CODE_ACCES_NON_AUTORISE => 'Unauthorized',
165
		self::HTTP_CODE_RESSOURCE_INTROUVABLE => 'Not Found',
181
		self::HTTP_CODE_RESSOURCE_INTROUVABLE => 'Not Found',
166
		self::HTTP_CODE_METHODE_NON_AUTORISE => 'Method Not Allowed',
182
		self::HTTP_CODE_METHODE_NON_AUTORISE => 'Method Not Allowed',
167
		self::HTTP_CODE_CONFLIT => 'Conflict',
183
		self::HTTP_CODE_CONFLIT => 'Conflict',
168
		self::HTTP_CODE_CONTENU_REQUIS => 'Length Required',
184
		self::HTTP_CODE_CONTENU_REQUIS => 'Length Required',
169
		self::HTTP_CODE_ERREUR => 'Internal Server Error'
185
		self::HTTP_CODE_ERREUR => 'Internal Server Error'
170
	);
186
	);
171
	
187
	
172
	/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
188
	/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
173
	private $parametres_obligatoires = array('debogage', 'debogage_mode', 'serveur.baseURL', 'chemin_modules');
189
	private $parametres_obligatoires = array('debogage', 'debogage_mode', 'serveur.baseURL', 'chemin_modules');
174
 
190
 
175
	/**
191
	/**
176
	 * Analyse les données envoyées au serveur, enregistre la méthode HTTP utilisée pour appeler le serveur et parse
192
	 * Analyse les données envoyées au serveur, enregistre la méthode HTTP utilisée pour appeler le serveur et parse
177
	 * l'url appelée pour trouver le service demandé.
193
	 * l'url appelée pour trouver le service demandé.
178
	 */
194
	 */
179
	public function __construct() {
195
	public function __construct() {
180
		Config::verifierPresenceParametres($this->parametres_obligatoires);
196
		Config::verifierPresenceParametres($this->parametres_obligatoires);
181
		
197
		
182
		self::$debogageActivation = Config::get('debogage');
198
		self::$debogageActivation = Config::get('debogage');
183
		self::$debogageMode = Config::get('debogage_mode');
199
		self::$debogageMode = Config::get('debogage_mode');
184
 
200
 
185
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
201
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
186
			$this->initialiserMethode();
202
			$this->initialiserMethode();
187
			$this->initialiserRequeteDonnees();
203
			$this->initialiserRequeteDonnees();
188
			
204
			
189
			$urlParts = $this->decouperUrlChemin();
205
			$urlParts = $this->decouperUrlChemin();
190
			
206
			
191
			$this->initialiserApiVersion(array_shift($urlParts));
207
			$this->initialiserApiVersion(array_shift($urlParts));
192
			$this->initialiserServiceNom(array_shift($urlParts));
208
			$this->initialiserServiceNom(array_shift($urlParts));
193
			$this->initialiserRessource($urlParts);
209
			$this->initialiserRessource($urlParts);
194
			
210
			
195
			$this->initialiserParametres();
211
			$this->initialiserParametres();
196
			// Enregistrement en première position des autoload de la méthode gérant les classes des services 
212
			// Enregistrement en première position des autoload de la méthode gérant les classes des services 
197
			spl_autoload_register(array(get_class(), 'chargerClasse'));
213
			spl_autoload_register(array(get_class(), 'chargerClasse'));
198
		} else {
214
		} else {
199
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
215
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
200
			$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
216
			$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
201
			self::ajouterMessage($e);
217
			self::ajouterMessage($e);
202
		}
218
		}
203
	}
219
	}
204
	
220
	
205
	private function initialiserMethode() {
221
	private function initialiserMethode() {
206
		if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']) && count(trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) > 0) {
222
		if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']) && count(trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) > 0) {
207
			$this->methode = trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
223
			$this->methode = trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
208
		} else {
224
		} else {
209
			$this->methode = $_SERVER['REQUEST_METHOD'];
225
			$this->methode = $_SERVER['REQUEST_METHOD'];
210
		}
226
		}
211
	}
227
	}
212
	
228
	
213
	private function initialiserRequeteDonnees() {
229
	private function initialiserRequeteDonnees() {
214
		if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
230
		if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
215
			$this->requeteDonnees = '';
231
			$this->requeteDonnees = '';
216
			$httpContent = fopen('php://input', 'r');
232
			$httpContent = fopen('php://input', 'r');
217
			while ($data = fread($httpContent, 1024)) {
233
			while ($data = fread($httpContent, 1024)) {
218
				$this->requeteDonnees .= $data;
234
				$this->requeteDonnees .= $data;
219
			}
235
			}
220
			fclose($httpContent);
236
			fclose($httpContent);
221
		}
237
		}
222
	}
238
	}
223
	
239
	
224
	private function decouperUrlChemin() {
240
	private function decouperUrlChemin() {
225
		if (isset($_SERVER['REDIRECT_URL']) && $_SERVER['REDIRECT_URL'] != '') {
241
		if (isset($_SERVER['REDIRECT_URL']) && $_SERVER['REDIRECT_URL'] != '') {
226
			if (isset($_SERVER['REDIRECT_QUERY_STRING']) && !empty($_SERVER['REDIRECT_QUERY_STRING'])) {
242
			if (isset($_SERVER['REDIRECT_QUERY_STRING']) && !empty($_SERVER['REDIRECT_QUERY_STRING'])) {
227
				$url = $_SERVER['REDIRECT_URL'].'?'.$_SERVER['REDIRECT_QUERY_STRING'];
243
				$url = $_SERVER['REDIRECT_URL'].'?'.$_SERVER['REDIRECT_QUERY_STRING'];
228
			} else {
244
			} else {
229
				$url = $_SERVER['REDIRECT_URL'];
245
				$url = $_SERVER['REDIRECT_URL'];
230
			}
246
			}
231
		} else {
247
		} else {
232
			$url = $_SERVER['REQUEST_URI'];
248
			$url = $_SERVER['REQUEST_URI'];
233
		}
249
		}
234
		
250
		
235
		if (strlen($_SERVER['QUERY_STRING']) == 0) {
251
		if (strlen($_SERVER['QUERY_STRING']) == 0) {
236
			$tailleURL = strlen($url);
252
			$tailleURL = strlen($url);
237
		} else {
253
		} else {
238
			$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
254
			$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
239
		}
255
		}
240
		
256
		
241
		$urlChaine = '';
257
		$urlChaine = '';
242
		if (strpos($url, Config::get('serveur.baseURL')) !== false) {
258
		if (strpos($url, Config::get('serveur.baseURL')) !== false) {
243
			$urlChaine = substr($url, strlen(Config::get('serveur.baseURL')), $tailleURL);
259
			$urlChaine = substr($url, strlen(Config::get('serveur.baseURL')), $tailleURL);
244
		} else if (strpos($url, Config::get('serveur.baseAlternativeURL')) !== false) {
260
		} else if (strpos($url, Config::get('serveur.baseAlternativeURL')) !== false) {
245
			$urlChaine = substr($url, strlen(Config::get('serveur.baseAlternativeURL')), $tailleURL);
261
			$urlChaine = substr($url, strlen(Config::get('serveur.baseAlternativeURL')), $tailleURL);
246
		}
262
		}
247
		return explode('/', $urlChaine);
263
		return explode('/', $urlChaine);
248
	}
264
	}
249
	
265
	
250
	private function initialiserApiVersion($apiVersion) {
266
	private function initialiserApiVersion($apiVersion) {
251
		if ($this->verifierApiVersion($apiVersion)) {
267
		if ($this->verifierApiVersion($apiVersion)) {
252
			$this->apiVersion = $apiVersion;
268
			$this->apiVersion = $apiVersion;
253
			self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
269
			self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
254
		} else {
270
		} else {
255
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
271
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
256
			$e = "Aucune version d'API n'a été spécifiée.\n".
272
			$e = "Aucune version d'API n'a été spécifiée.\n".
257
				"La version doit respecter l'expression régulière suivante : ".self::MOTIF_API_VERSION.".\n".
273
				"La version doit respecter l'expression régulière suivante : ".self::MOTIF_API_VERSION.".\n".
258
			  	"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
274
			  	"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
259
			self::ajouterMessage($e);
275
			self::ajouterMessage($e);
260
			self::cloreAccesServeur();
276
			self::cloreAccesServeur();
261
		}
277
		}
262
	}
278
	}
263
	
279
	
264
	private function verifierApiVersion($apiVersion) {
280
	private function verifierApiVersion($apiVersion) {
265
		$apiOk = false;
281
		$apiOk = false;
266
		if (isset($apiVersion) && !empty($apiVersion) && preg_match(self::MOTIF_API_VERSION, $apiVersion)) {
282
		if (isset($apiVersion) && !empty($apiVersion) && preg_match(self::MOTIF_API_VERSION, $apiVersion)) {
267
			$apiOk = true;
283
			$apiOk = true;
268
		}
284
		}
269
		return $apiOk;
285
		return $apiOk;
270
	}
286
	}
271
	
287
	
272
	private function initialiserServiceNom($serviceNom) {
288
	private function initialiserServiceNom($serviceNom) {
273
		if ($this->verifierServiceNom($serviceNom)) {
289
		if ($this->verifierServiceNom($serviceNom)) {
274
			$this->service = $this->traiterNomService($serviceNom);
290
			$this->service = $this->traiterNomService($serviceNom);
275
		} else {
291
		} else {
276
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
292
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
277
			$e = "Aucune nom de service n'a été spécifié.\n".
293
			$e = "Aucune nom de service n'a été spécifié.\n".
278
				"La nom du service doit respecter l'expression régulière suivante : ".self::MOTIF_SERVICE_NOM.".\n".
294
				"La nom du service doit respecter l'expression régulière suivante : ".self::MOTIF_SERVICE_NOM.".\n".
279
			  	"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
295
			  	"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
280
			self::ajouterMessage($e);
296
			self::ajouterMessage($e);
281
			self::cloreAccesServeur();
297
			self::cloreAccesServeur();
282
		}
298
		}
283
	}
299
	}
284
	
300
	
285
	private function verifierServiceNom($serviceNom) {
301
	private function verifierServiceNom($serviceNom) {
286
		$serviceNomOk = false;
302
		$serviceNomOk = false;
287
		if (isset($serviceNom) && !empty($serviceNom) && preg_match(self::MOTIF_SERVICE_NOM, $serviceNom)) {
303
		if (isset($serviceNom) && !empty($serviceNom) && preg_match(self::MOTIF_SERVICE_NOM, $serviceNom)) {
288
			$serviceNomOk = true;
304
			$serviceNomOk = true;
289
		}
305
		}
290
		return $serviceNomOk;
306
		return $serviceNomOk;
291
	}
307
	}
292
	
308
	
293
	private function traiterNomService($serviceNom) {
309
	private function traiterNomService($serviceNom) {
294
		return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
310
		return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
295
	}
311
	}
296
	
312
	
297
	private function initialiserRessource($urlParts) {
313
	private function initialiserRessource($urlParts) {
298
		if (is_array($urlParts) && count($urlParts) > 0) {
314
		if (is_array($urlParts) && count($urlParts) > 0) {
299
			foreach ($urlParts as $ressource) {
315
			foreach ($urlParts as $ressource) {
300
				// Ne pas utiliser empty() car valeur 0 acceptée
316
				// Ne pas utiliser empty() car valeur 0 acceptée
301
				if ($ressource != '') {
317
				if ($ressource != '') {
302
					$this->ressources[] = urldecode($ressource);
318
					$this->ressources[] = urldecode($ressource);
303
				}
319
				}
304
			}
320
			}
305
		}
321
		}
306
	}
322
	}
307
	
323
	
308
	private function initialiserParametres() {
324
	private function initialiserParametres() {
-
 
325
		$this->parametres = $this->recupererParametresGet();
-
 
326
		$this->parametresBruts = $this->recupererParametresBruts();
-
 
327
	}
-
 
328
	
-
 
329
	private function recupererParametresGet() {
309
		$this->nettoyerGet();
330
		$_GET = $this->nettoyerParametres($_GET);
310
		$this->parametres = $_GET;
331
		return $_GET;
311
	}
332
	}
312
	
333
	
313
	private function nettoyerGet() {
334
	private function nettoyerParametres(Array $parametres) {
314
		// Pas besoin d'utiliser urldecode car déjà fait par php pour les clés et valeur de $_GET 
335
		// Pas besoin d'utiliser urldecode car déjà fait par php pour les clés et valeur de $_GET 
315
		if (isset($_GET) && count($_GET) > 0) {
336
		if (isset($parametres) && count($parametres) > 0) {
316
			foreach ($_GET as $cle => $valeur) {
337
			foreach ($parametres as $cle => $valeur) {
317
				$verifier = array('NULL', "\n", "\r", "\\", "'", '"', "\x00", "\x1a", ';');
338
				$verifier = array('NULL', "\n", "\r", "\\", "'", '"', "\x00", "\x1a", ';');
318
				$_GET[$cle] = strip_tags(str_replace($verifier, '', $valeur));
339
				$parametres[$cle] = strip_tags(str_replace($verifier, '', $valeur));
319
			}
340
			}
-
 
341
		}
320
		}
342
		return $parametres;
-
 
343
	}
-
 
344
	
-
 
345
	private function recupererParametresBruts() {
-
 
346
		$paires = explode('&', $_SERVER['QUERY_STRING']);
-
 
347
		$parametres_bruts = array();
-
 
348
		foreach ($paires as $paire) {
-
 
349
			$nv = explode('=', $paire);
-
 
350
			$nom = urldecode($nv[0]);
-
 
351
			$valeur = urldecode($nv[1]);
-
 
352
			$parametres_bruts[$nom] = $valeur;
-
 
353
		}
-
 
354
		$parametres_bruts = $this->nettoyerParametres($parametres_bruts);
-
 
355
		return $parametres_bruts;
321
	}
356
	}	
322
	
357
	
323
	/**
358
	/**
324
	* La méthode __autoload() charge dynamiquement les classes trouvées dans le code.
359
	* La méthode __autoload() charge dynamiquement les classes trouvées dans le code.
325
	* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
360
	* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
326
	*
361
	*
327
	*@param string le nom de la classe appelée.
362
	*@param string le nom de la classe appelée.
328
	*@return void le fichier contenant la classe doit être inclu par la fonction.
363
	*@return void le fichier contenant la classe doit être inclu par la fonction.
329
	*/
364
	*/
330
	public static function chargerClasse($classe) {
365
	public static function chargerClasse($classe) {
331
		if (class_exists($classe)) {
366
		if (class_exists($classe)) {
332
			return null;
367
			return null;
333
		}
368
		}
334
		$classeTrouvee = false;
369
		$classeTrouvee = false;
335
		$chemins = array('', self::$config['chemins']['api']);
370
		$chemins = array('', self::$config['chemins']['api']);
336
		foreach ($chemins as $chemin) {
371
		foreach ($chemins as $chemin) {
337
			$chemin = $chemin.$classe.'.php';
372
			$chemin = $chemin.$classe.'.php';
338
			if (file_exists($chemin)) {
373
			if (file_exists($chemin)) {
339
				require_once $chemin;
374
				require_once $chemin;
340
				$classeTrouvee = true;
375
				$classeTrouvee = true;
341
			}
376
			}
342
		}
377
		}
343
		if ($classeTrouvee === false) {
378
		if ($classeTrouvee === false) {
344
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
379
			self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
345
			$e = "La classe '$classe' du service n'a pas été trouvée par le serveur.\n".
380
			$e = "La classe '$classe' du service n'a pas été trouvée par le serveur.\n".
346
				"Cela peut signifier que le nom du service saisi comporte une erreur.";
381
				"Cela peut signifier que le nom du service saisi comporte une erreur.";
347
			self::ajouterMessage($e);
382
			self::ajouterMessage($e);
348
			self::cloreAccesServeur();
383
			self::cloreAccesServeur();
349
		}
384
		}
350
	}
385
	}
351
	
386
	
352
	/**
387
	/**
353
	 * Execute la requête.
388
	 * Execute la requête.
354
	 */
389
	 */
355
	public function executer() {
390
	public function executer() {
356
		$retour = '';
391
		$retour = '';
357
		switch ($this->methode) {
392
		switch ($this->methode) {
358
			case 'GET':
393
			case 'GET':
359
				$retour = $this->get();
394
				$retour = $this->get();
360
				break;
395
				break;
361
			case 'POST':
396
			case 'POST':
362
				$this->post();
397
				$this->post();
363
				break;
398
				break;
364
			case 'DELETE':
399
			case 'DELETE':
365
				$this->delete();
400
				$this->delete();
366
				break;
401
				break;
367
			case 'PUT':
402
			case 'PUT':
368
				$retour = $this->put();
403
				$retour = $this->put();
369
				break;
404
				break;
370
			default :
405
			default :
371
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_METHODE_NON_AUTORISE);
406
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_METHODE_NON_AUTORISE);
372
				header('Allow: GET, POST, DELETE, PUT');
407
				header('Allow: GET, POST, DELETE, PUT');
373
				$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.\n".
408
				$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.\n".
374
					"Consulter l'entête Allow pour connaître les méthodes autorisées.";
409
					"Consulter l'entête Allow pour connaître les méthodes autorisées.";
375
				self::ajouterMessage($e);
410
				self::ajouterMessage($e);
376
		}
411
		}
377
		$this->cloreAccesServeur($retour);
412
		$this->cloreAccesServeur($retour);
378
	}
413
	}
379
 
414
 
380
	/**
415
	/**
381
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
416
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
382
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
417
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
383
	 * database contents.
418
	 * database contents.
384
	 */
419
	 */
385
	private function get() {
420
	private function get() {
386
		$retour = '';
421
		$retour = '';
387
		if ($this->service != null) {
422
		if ($this->service != null) {
388
			$Service = new $this->service(self::$config);
423
			$Service = new $this->service(self::$config);
389
			if (method_exists($Service, self::METHODE_GET)) {
424
			if (method_exists($Service, self::METHODE_GET)) {
390
				$methodeGet = self::METHODE_GET;
425
				$methodeGet = self::METHODE_GET;
-
 
426
				$parametres = $Service->utiliserParametresBruts() ? $this->parametresBruts : $this->parametres;
391
				$retour = $Service->$methodeGet($this->ressources, $this->parametres);
427
				$retour = $Service->$methodeGet($this->ressources, $parametres);
392
			} else {
428
			} else {
393
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
429
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
394
				$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
430
				$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
395
					"lors de l'appel du service via la méthode HTTP GET.";
431
					"lors de l'appel du service via la méthode HTTP GET.";
396
				self::ajouterMessage($e);
432
				self::ajouterMessage($e);
397
			}
433
			}
398
		}
434
		}
399
		return $retour;
435
		return $retour;
400
	}
436
	}
401
 
437
 
402
	private function post() {
438
	private function post() {
403
		$paires = $this->parserDonneesRequete();
439
		$paires = $this->parserDonneesRequete();
404
		if (count($paires) != 0) {
440
		if (count($paires) != 0) {
405
			if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
441
			if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
406
				$retour = $this->delete();
442
				$retour = $this->delete();
407
			} else if (count($this->ressources) == 0) {// Altnative à l'utilisation de PUT
443
			} else if (count($this->ressources) == 0) {// Altnative à l'utilisation de PUT
408
				$retour = $this->put();
444
				$retour = $this->put();
409
			} else {
445
			} else {
410
				if ($this->service != null) {
446
				if ($this->service != null) {
411
					$Service = new $this->service(self::$config);
447
					$Service = new $this->service(self::$config);
412
					if (method_exists($Service, self::METHODE_POST)) {
448
					if (method_exists($Service, self::METHODE_POST)) {
413
						$methodePost = self::METHODE_POST;
449
						$methodePost = self::METHODE_POST;
414
						$info = $Service->$methodePost($this->ressources, $paires);
450
						$info = $Service->$methodePost($this->ressources, $paires);
415
						if ($info === true) {
451
						if ($info === true) {
416
							$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
452
							$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
417
						}
453
						}
418
					} else {
454
					} else {
419
						self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
455
						self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
420
						$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
456
						$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
421
							"lors de l'appel du service via la méthode HTTP GET.";
457
							"lors de l'appel du service via la méthode HTTP GET.";
422
						self::ajouterMessage($e);
458
						self::ajouterMessage($e);
423
					}
459
					}
424
				}
460
				}
425
			} 
461
			} 
426
		} else {
462
		} else {
427
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
463
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
428
			$e = "Le service '{$this->service}' requiert de fournir le contenu à modifier dans le corps ".
464
			$e = "Le service '{$this->service}' requiert de fournir le contenu à modifier dans le corps ".
429
				"de la requête avec la méthode HTTP POST.";
465
				"de la requête avec la méthode HTTP POST.";
430
			self::ajouterMessage($e);
466
			self::ajouterMessage($e);
431
		}
467
		}
432
	}
468
	}
433
 
469
 
434
	private function put() {
470
	private function put() {
435
		$paires = $this->parserDonneesRequete();
471
		$paires = $this->parserDonneesRequete();
436
		if (count($paires) != 0) {
472
		if (count($paires) != 0) {
437
			if ($this->service != null) {
473
			if ($this->service != null) {
438
				$Service = new $this->service(self::$config);
474
				$Service = new $this->service(self::$config);
439
				if (method_exists($Service, self::METHODE_PUT)) {
475
				if (method_exists($Service, self::METHODE_PUT)) {
440
					$methodePut = self::METHODE_PUT;
476
					$methodePut = self::METHODE_PUT;
441
					$info = $Service->$methodePut($this->ressources, $paires);
477
					$info = $Service->$methodePut($this->ressources, $paires);
442
					if ($info === true) {
478
					if ($info === true) {
443
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
479
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
444
					}
480
					}
445
				} else {
481
				} else {
446
					self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
482
					self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
447
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
483
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
448
						"lors de l'appel du service via la méthode HTTP GET.";
484
						"lors de l'appel du service via la méthode HTTP GET.";
449
					self::ajouterMessage($e);
485
					self::ajouterMessage($e);
450
				}
486
				}
451
			}
487
			}
452
		} else {
488
		} else {
453
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
489
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
454
			$e = "Il est nécessaire de fournir du contenu dans le corps de la requête pour créer une nouvelle ressource.";
490
			$e = "Il est nécessaire de fournir du contenu dans le corps de la requête pour créer une nouvelle ressource.";
455
			self::ajouterMessage($e);
491
			self::ajouterMessage($e);
456
		}
492
		}
457
	}
493
	}
458
 
494
 
459
	private function delete() {
495
	private function delete() {
460
		if (count($this->ressources) != 0) {
496
		if (count($this->ressources) != 0) {
461
			if ($this->service != null) {
497
			if ($this->service != null) {
462
				$Service = new $this->service(self::$config);
498
				$Service = new $this->service(self::$config);
463
				if (method_exists($Service, self::METHODE_DELETE)) {
499
				if (method_exists($Service, self::METHODE_DELETE)) {
464
					$methodeDelete = self::METHODE_DELETE;
500
					$methodeDelete = self::METHODE_DELETE;
465
					$info = $Service->$methodeDelete($this->ressources);
501
					$info = $Service->$methodeDelete($this->ressources);
466
					if ($info === true) {
502
					if ($info === true) {
467
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
503
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
468
					} else if ($info === false) {
504
					} else if ($info === false) {
469
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
505
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
470
						$e = "La ressource à supprimer est introuvable. Il se peut qu'elle ait été préalablement supprimé.";
506
						$e = "La ressource à supprimer est introuvable. Il se peut qu'elle ait été préalablement supprimé.";
471
						self::ajouterMessage($e);
507
						self::ajouterMessage($e);
472
					}
508
					}
473
				} else {
509
				} else {
474
					self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
510
					self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
475
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
511
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
476
						"lors de l'appel du service via la méthode HTTP GET.";
512
						"lors de l'appel du service via la méthode HTTP GET.";
477
					self::ajouterMessage($e);
513
					self::ajouterMessage($e);
478
				}
514
				}
479
			}
515
			}
480
		} else {
516
		} else {
481
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
517
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
482
			$e = "Il est nécessaire d'indiquer dans l'url la ressource à supprimer.";
518
			$e = "Il est nécessaire d'indiquer dans l'url la ressource à supprimer.";
483
			self::ajouterMessage($e);
519
			self::ajouterMessage($e);
484
		}
520
		}
485
	}
521
	}
486
	
522
	
487
	/**
523
	/**
488
	 * Parse les données contenu dans le corps de la requête HTTP (= POST) en :
524
	 * Parse les données contenu dans le corps de la requête HTTP (= POST) en :
489
	 *  - décodant les clés et valeurs.
525
	 *  - décodant les clés et valeurs.
490
	 *  - supprimant les espaces en début et fin des clés et des valeurs.
526
	 *  - supprimant les espaces en début et fin des clés et des valeurs.
491
	 * 
527
	 * 
492
	 * @return array Tableau de paires clé et valeur.
528
	 * @return array Tableau de paires clé et valeur.
493
	 */
529
	 */
494
	private function parserDonneesRequete() {
530
	private function parserDonneesRequete() {
495
		$donnees = array();
531
		$donnees = array();
496
		if ($this->requeteDonneesParsees != null) {
532
		if ($this->requeteDonneesParsees != null) {
497
			$donnees = $this->requeteDonneesParsees;
533
			$donnees = $this->requeteDonneesParsees;
498
		} else if ($this->requeteDonnees != null) {
534
		} else if ($this->requeteDonnees != null) {
499
			$paires = explode('&', $this->requeteDonnees);
535
			$paires = explode('&', $this->requeteDonnees);
500
			foreach ($paires as $paire) {
536
			foreach ($paires as $paire) {
501
				list($cle, $valeur) = explode('=', $paire);
537
				list($cle, $valeur) = explode('=', $paire);
502
				$cle = (isset($cle)) ? trim(urldecode($cle)) : '';
538
				$cle = (isset($cle)) ? trim(urldecode($cle)) : '';
503
				$valeur = (isset($valeur)) ? trim(urldecode($valeur)) : '';
539
				$valeur = (isset($valeur)) ? trim(urldecode($valeur)) : '';
504
				$donnees[$cle] = $valeur;
540
				$donnees[$cle] = $valeur;
505
			}
541
			}
506
			$this->requeteDonneesParsees = $donnees;
542
			$this->requeteDonneesParsees = $donnees;
507
		}
543
		}
508
		return $donnees;
544
		return $donnees;
509
	}
545
	}
510
	
546
	
511
	/**
547
	/**
512
	 * Envoyer un entête HTTP (version 1.0) de statut.
548
	 * Envoyer un entête HTTP (version 1.0) de statut.
513
	 * Il remplacera systématiquement tout entête HTTP de statut précédement envoyé.
549
	 * Il remplacera systématiquement tout entête HTTP de statut précédement envoyé.
514
	 * @param int $code entier indiquant le code du statut de l'entête HTTP à envoyer. 
550
	 * @param int $code entier indiquant le code du statut de l'entête HTTP à envoyer. 
515
	 */
551
	 */
516
	public static function envoyerEnteteStatutHttp($code) {
552
	public static function envoyerEnteteStatutHttp($code) {
517
		if (isset(self::$http10[$code])) {
553
		if (isset(self::$http10[$code])) {
518
			$txt = self::$http10[$code];
554
			$txt = self::$http10[$code];
519
			header("HTTP/1.0 $code $txt", true);
555
			header("HTTP/1.0 $code $txt", true);
520
		}
556
		}
521
	}
557
	}
522
	
558
	
523
	/**
559
	/**
524
	 * Termine l'accès au serveur après envoir envoyer les messages.
560
	 * Termine l'accès au serveur après envoir envoyer les messages.
525
	 */
561
	 */
526
	private static function cloreAccesServeur($retour) {
562
	private static function cloreAccesServeur($retour) {
527
		// 	Gestion des exceptions et erreurs générées par les services
563
		// 	Gestion des exceptions et erreurs générées par les services
528
		$retour .= self::gererErreurs();
564
		$retour .= self::gererErreurs();
529
		
565
		
530
		// Envoie des messages d'erreur et d'avertissement du serveur
566
		// Envoie des messages d'erreur et d'avertissement du serveur
531
		$retour .= self::envoyerMessages();
567
		$retour .= self::envoyerMessages();
532
		
568
		
533
		// Envoie sur la sortie standard le contenu de la réponse HTTP
569
		// Envoie sur la sortie standard le contenu de la réponse HTTP
534
		print $retour;
570
		print $retour;
535
		
571
		
536
		// Nous terminons le script
572
		// Nous terminons le script
537
		exit(0);
573
		exit(0);
538
	}
574
	}
539
	
575
	
540
	/**
576
	/**
541
	 * Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode.
577
	 * Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode.
542
	 * Si nous avec des erreurs d'un type différent d'E_USER_NOTICE (réservé au débogage), elle sont renvoyées sur la sortie 
578
	 * Si nous avec des erreurs d'un type différent d'E_USER_NOTICE (réservé au débogage), elle sont renvoyées sur la sortie 
543
	 * standard (via echo).
579
	 * standard (via echo).
544
	 * Si seulement des erreurs de type E_USER_NOTICE, sont présentes, elle sont envoyées en fonction du contenu du paramètre de 
580
	 * Si seulement des erreurs de type E_USER_NOTICE, sont présentes, elle sont envoyées en fonction du contenu du paramètre de 
545
	 * config "debogage_mode" :
581
	 * config "debogage_mode" :
546
	 *  - Debug::MODE_ECHO : les messages sont affichés en utilisant echo au moment où ils sont déclenchés dans le code. 
582
	 *  - Debug::MODE_ECHO : les messages sont affichés en utilisant echo au moment où ils sont déclenchés dans le code. 
547
	 *  - Debug::MODE_NOTICE : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type 
583
	 *  - Debug::MODE_NOTICE : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type 
548
	 *  E_USER_NOTICE et sont renvoyés sur la sortie standard à la fin de l'execution du programme (via echo).
584
	 *  E_USER_NOTICE et sont renvoyés sur la sortie standard à la fin de l'execution du programme (via echo).
549
	 *  - Debug::MODE_ENTETE_HTTP : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type 
585
	 *  - Debug::MODE_ENTETE_HTTP : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type 
550
	 *  E_USER_NOTICE et sont renvoyés dans un entête HTTP (X_REST_DEBOGAGE_MESSAGES) à la fin de l'execution du programme.
586
	 *  E_USER_NOTICE et sont renvoyés dans un entête HTTP (X_REST_DEBOGAGE_MESSAGES) à la fin de l'execution du programme.
551
	 *  - Autre valeur : les messages sont formatés puis retournés par la fonction de débogage (à vous de les afficher).
587
	 *  - Autre valeur : les messages sont formatés puis retournés par la fonction de débogage (à vous de les afficher).
552
	 */
588
	 */
553
	public static function gererErreurs() {
589
	public static function gererErreurs() {
554
		$retour = '';
590
		$retour = '';
555
		if (self::$debogageActivation && GestionnaireException::getExceptionsNbre() > 0) {
591
		if (self::$debogageActivation && GestionnaireException::getExceptionsNbre() > 0) {
556
			
592
			
557
			$exceptionsTriees = GestionnaireException::getExceptionsTriees();
593
			$exceptionsTriees = GestionnaireException::getExceptionsTriees();
558
			reset($exceptionsTriees);
594
			reset($exceptionsTriees);
559
			$debogageSeulement = true;
595
			$debogageSeulement = true;
560
			if (array_key_exists(E_USER_ERROR, $exceptionsTriees)) {
596
			if (array_key_exists(E_USER_ERROR, $exceptionsTriees)) {
561
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
597
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
562
				$debogageSeulement = false;
598
				$debogageSeulement = false;
563
			}
599
			}
564
			
600
			
565
			$exceptionsFormatees = array();
601
			$exceptionsFormatees = array();
566
			foreach ($exceptionsTriees as $exceptions) {
602
			foreach ($exceptionsTriees as $exceptions) {
567
				foreach ($exceptions as $e) {
603
				foreach ($exceptions as $e) {
568
					if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
604
					if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
569
						$exceptionsFormatees[] = GestionnaireException::formaterExceptionDebug($e);
605
						$exceptionsFormatees[] = GestionnaireException::formaterExceptionDebug($e);
570
					} else {
606
					} else {
571
						$retour = GestionnaireException::formaterExceptionXhtml($e);
607
						$retour = GestionnaireException::formaterExceptionXhtml($e);
572
					}
608
					}
573
				}
609
				}
574
			}
610
			}
575
			
611
			
576
			if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
612
			if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
577
				header('X_REST_DEBOGAGE_MESSAGES: '.json_encode($exceptionsFormatees));
613
				header('X_REST_DEBOGAGE_MESSAGES: '.json_encode($exceptionsFormatees));
578
			}
614
			}
579
		}
615
		}
580
		return $retour;
616
		return $retour;
581
	}
617
	}
582
	
618
	
583
	
619
	
584
	/**
620
	/**
585
	 * Permet d'ajouter un message d'erreur ou d'avertissement qui sera envoyé au client.
621
	 * Permet d'ajouter un message d'erreur ou d'avertissement qui sera envoyé au client.
586
	 * Le message doit être au format texte et en UTF-8.
622
	 * Le message doit être au format texte et en UTF-8.
587
	 * @param string $message le message à envoyer. 
623
	 * @param string $message le message à envoyer. 
588
	 */
624
	 */
589
	public static function ajouterMessage($message) {
625
	public static function ajouterMessage($message) {
590
		if (isset($message) && !empty($message)) {
626
		if (isset($message) && !empty($message)) {
591
			self::$messages[] = $message;
627
			self::$messages[] = $message;
592
		}
628
		}
593
	}
629
	}
594
	
630
	
595
	/**
631
	/**
596
	 * Envoie au client les éventuels messages d'erreur et d'avertissement du Serveur.
632
	 * Envoie au client les éventuels messages d'erreur et d'avertissement du Serveur.
597
	 * Le format d'envoie est text/plain encodé en UTF-8.
633
	 * Le format d'envoie est text/plain encodé en UTF-8.
598
	 */
634
	 */
599
	private static function envoyerMessages() {
635
	private static function envoyerMessages() {
600
		if (count(self::$messages) > 0) {
636
		if (count(self::$messages) > 0) {
601
			header("Content-Type: text/plain; charset=utf-8");
637
			header("Content-Type: text/plain; charset=utf-8");
602
			return implode("\n", self::$messages);
638
			return implode("\n", self::$messages);
603
		}
639
		}
604
	}
640
	}
605
}
641
}
606
?>
642
?>