Subversion Repositories Applications.framework

Rev

Rev 229 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 229 Rev 232
Line 1... Line 1...
1
<?php
1
<?php
2
/**
2
/**
-
 
3
 * Classe principale gérant les services web de type (@link(REST, http://fr.wikipedia.org/wiki/Rest).
-
 
4
 * 
-
 
5
 * Elle contient  :
-
 
6
 *  - les constantes indiquant les différentes (@link(méthode HTTP, http://fr.wikipedia.org/wiki/Http) prises en compte.
-
 
7
 *  - les @link(codes HTTP des réponses, http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP)
-
 
8
 * 
-
 
9
 * Ce serveur REST accepte 4 types de méthodes HTTP : GET, PUT, POST, DELETE.
-
 
10
 * 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
 * Vous pouvez donc pour réaliser :
-
 
12
 *  - DELETE : utiliser la méthode POST avec action=DELETE dans le corps de la requête.
-
 
13
 *  - PUT : utiliser la méthode POST avec une url ne contenant aucune indication de ressource.
-
 
14
 * Une autre solution consiste à utiliser n'importe quelle méthode et à ajouter l'entête "X_HTTP_METHOD_OVERRIDE" avec pour 
-
 
15
 * valeur le nom de la méthode que vous souhaitez utiliser. Exemple d'entête : "X_HTTP_METHOD_OVERRIDE: PUT".
-
 
16
 * Exemple : <code>curl -v -v -H "X_HTTP_METHOD_OVERRIDE: DELETE" "http://www.mondomaine.org/services/apiVersion/[mon-service]/"</code>
3
 * Classe principale gérant les services.
17
 * Cela fonctionne avec Apache.
-
 
18
 * 
-
 
19
 * 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
 * en minuscule où les mots sont séparés par des tirets "mon-service".
-
 
21
 * 
4
 * Paramètres liés dans config.ini :
22
 * Paramètres liés dans config.ini :
5
 *  - serveur.baseURL
23
 *  - serveur.baseURL
6
 * 
24
 *  
7
 * Encodage en entrée : utf8
25
 * Encodage en entrée : utf8
8
 * Encodage en sortie : utf8
26
 * Encodage en sortie : utf8
9
 * 
27
 * 
10
 * @category	Php 5.2
28
 * @category	Php 5.2
11
 * @package		JRest
29
 * @package	Framework
12
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
30
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
-
 
31
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
13
 * @license		GPL v3 <http://www.gnu.org/licenses/gpl.txt>
32
 * @license	GPL v3 <http://www.gnu.org/licenses/gpl.txt>
14
 * @license		CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
33
 * @license	CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
15
 * @copyright	2010 Tela-Botanica
-
 
16
 * @version		$Id$
34
 * @version	$Id$
-
 
35
 * @link		/doc/framework/
17
 */
36
 */
18
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
37
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
19
class Serveur {
38
class Serveur {
Line 20... Line 39...
20
	
39
	
21
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
40
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
Line 22... Line 41...
22
	const METHODE_GET = 'getElement';
41
	const METHODE_GET = 'consulter';
23
	
42
	
Line 24... Line 43...
24
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type POST. */
43
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type POST. */
25
	const METHODE_POST = 'getElement';
44
	const METHODE_POST = 'modifier';
Line 26... Line 45...
26
	
45
	
27
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type DELETE. */
46
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type DELETE. */
Line -... Line 47...
-
 
47
	const METHODE_DELETE = 'supprimer';
-
 
48
	
-
 
49
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type PUT. */
-
 
50
	const METHODE_PUT = 'ajouter';
-
 
51
	
-
 
52
	/** Code HTTP 200 indiquant le succès de l'accès à un service web par la méthode GET.
-
 
53
	 * L'utiliser lors d'une requète de type GET (consulter) pour indiquer le succès de l'opération.
-
 
54
	 * Sera renvoyée par défaut par PHP. */
-
 
55
	const HTTP_CODE_OK = '200';
-
 
56
	
-
 
57
	/** 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é.
-
 
58
	 * L'utiliser lors d'une requète de type PUT (ajouter) ou POST (modifier) pour indiquer le succès de l'opération. */
-
 
59
	const HTTP_CODE_CREATION_OK = '201';
-
 
60
	
-
 
61
	/** 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.
-
 
62
	 * L'utiliser lors d'une requète de type DELETE (supprimer) pour indiquer le succès de l'opération. */
-
 
63
	const HTTP_CODE_SUPPRESSION_OK = '204';
-
 
64
	
-
 
65
	/** Code HTTP 400 indique que les paramètres envoyés au service contiennent des erreurs.
-
 
66
	 * L'utiliser pour indiquer l'échec de l'accès au service. La réponse pourra contenir un message expliquant la source 
-
 
67
	 * de l'erreur. */
-
 
68
	const HTTP_CODE_MAUVAISE_REQUETE = '400';
-
 
69
	
-
 
70
	/** Code HTTP 401 indiquant que l'accès à un service web est refusé car l'authentification (obligatoire) a échoué pour
-
 
71
	 * accéder à la ressource. */
-
 
72
	const HTTP_CODE_ACCES_NON_AUTORISE = '401';
-
 
73
	
-
 
74
	/** Code HTTP 404 indiquant que la ressource indiquée par l'url est introuvable. */
-
 
75
	const HTTP_CODE_RESSOURCE_INTROUVABLE = '404';
-
 
76
	
-
 
77
	/** Code HTTP 405 indiquant soit :
-
 
78
	 *  - que le service web ne possède pas d'accès la ressource correspondant à la méthode HTTP employée.
-
 
79
	 *  - que la méthode HTTP enployée n'est pas en accord avec la ressource indiquée par l'url. */
-
 
80
	const HTTP_CODE_METHODE_NON_AUTORISE = '405';
-
 
81
	
-
 
82
	/** Code d'erreur HTTP 409 indiquant qu'un conflit est survenu vis à vis de la ressource.
-
 
83
	 * 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 
-
 
84
	 * ailleurs. */
-
 
85
	const HTTP_CODE_CONFLIT = '409';
-
 
86
	
-
 
87
	/** Code HTTP 411 indiquant que des paramètres passés dans le contenu de la requête sont nécessaires au service. */
-
 
88
	const HTTP_CODE_CONTENU_REQUIS = '411';
28
	const METHODE_DELETE = 'getElement';
89
	
-
 
90
	/** Code d'erreur HTTP 500 Internal Server Error.
29
	
91
	 * L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
Line 30... Line 92...
30
	/** Nom de la méthode appelée dans un service pour éxécuter une requête de type PUT. */
92
	const HTTP_CODE_ERREUR = '500';
-
 
93
	
31
	const METHODE_PUT = 'getElement';
94
	/** Les paramètres de configuration dynamiques internes au serveur. 
Line 32... Line 95...
32
	
95
	 * @var array */
-
 
96
	private static $config = array();
33
	/** Les paramètres de configuration dynamiques internes au serveur. */
97
	
-
 
98
	/** La méthode de la requête HTTP utilisée. 
-
 
99
	 * @var string */
-
 
100
	private $methode = 'GET';
-
 
101
 
Line 34... Line 102...
34
	private static $config;
102
	/** Le contenu brut du corps de la requête HTTP (s'il y en a).
35
	
-
 
36
	/** La méthode de la requête HTTP utilisée. */
103
	 * @var array */
-
 
104
	private $requeteDonnees = null;
37
	private $methode = 'GET';
105
	
38
 
106
	/** Le contenu sous forme de tableau de paires clés-valeurs du corps de la requête HTTP (s'il y en a). 
Line 39... Line 107...
39
	/** Le contenu de la requête HTTP (s'il y en a). */
107
	 * @var array */
40
	private $requeteDonnees = null;//requestData
108
	private $requeteDonneesParsees = null;
-
 
109
 
41
 
110
	/** Version de l'API demandée.
42
	/** Version de l'API demandée.
111
	 * Ex. http://www.mondomaine.org/services/[apiVersion]/mon-service/
Line 43... Line 112...
43
	 * Généralement deux nombres séparés par un point. Ex. : 1.0 
112
	 * @var mixed Généralement deux nombres séparés par un point. Ex. : 1.0
44
	 * Ex. http://www.mondomaine.org/services/[apiVersion]/monService/
113
	 */
-
 
114
	private $apiVersion = null;
45
	 */
115
 
46
	private $apiVersion = null;
116
	/** Nom du service demandé. 
Line 47... Line 117...
47
 
117
	 * Ex. http://www.mondomaine.org/services/apiVersion/[mon-service]/
48
	/** Nom du service demandé. 
118
	 * @var string par défaut vaut null.
-
 
119
	 */
49
	 * Ex. http://www.mondomaine.org/services/apiVersion/[monService]/ 
120
	private $service = null;
50
	 */
121
	
Line 51... Line 122...
51
	private $service = null;// $ressource
122
	/** Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
52
	
123
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service/[maRessource/maSousResource...]
-
 
124
	 * @var array
53
	/** Morceaux de l'url servant à préciser la ressource concerné pour service demandé.
125
	 */
54
	 * Ex. http://www.mondomaine.org/services/apiVersion/monService/[maRessource/maSousResource...]
126
	private $ressources = array();
55
	 */
127
	
56
	private $ressources = array();// $uid
128
	/** Partie de l'url situé après le '?' servant à paramétrer le service demandé.
57
	
129
	 * Ex. http://www.mondomaine.org/services/apiVersion/mon-service?monParametre1=maValeur1&monParametre2=maValeur2
58
	/** Partie de l'url servant à paramétrer le service demandé.
130
	 * @var array
59
	 * Ex. http://www.mondomaine.org/services/apiVersion/monService?monParametre1=maValeur1&monParametre2=maValeur2
131
	 */
60
	 */
132
	private $parametres = array();
61
	private $parametres = array();
133
	
62
	
134
	/** Codes HTTP. */
Line 63... Line 135...
63
	/** Codes HTTP. */
135
	private static $http10 = array(
64
	private static $http10 = array(
136
		self::HTTP_CODE_OK => 'OK',	
65
		'201' => 'Created',
137
		self::HTTP_CODE_CREATION_OK => 'Created',
66
		'204' => 'No Content',
138
		self::HTTP_CODE_SUPPRESSION_OK => 'No Content',
67
		'400' => 'Bad Request',
139
		self::HTTP_CODE_MAUVAISE_REQUETE => 'Bad Request',
68
		'401' => 'Unauthorized',
140
		self::HTTP_CODE_ACCES_NON_AUTORISE => 'Unauthorized',
69
		'404' => 'Not Found',
-
 
70
		'405' => 'Method Not Allowed',
141
		self::HTTP_CODE_RESSOURCE_INTROUVABLE => 'Not Found',
71
		'406' => 'Not Acceptable',
-
 
72
		'411' => 'Length Required',
-
 
73
		'500' => 'Internal Server Error'
142
		self::HTTP_CODE_METHODE_NON_AUTORISE => 'Method Not Allowed',
74
	);
-
 
75
 
-
 
76
	/**
-
 
77
	 * Analyse les données envoyées au serveur, enregistre la méthode HTTP utilisée pour appeler le serveur et parse
-
 
78
	 * l'url appelée pour trouver le service demandé.
-
 
79
	 */
-
 
80
	public function __construct() {
-
 
81
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
-
 
82
			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
-
 
83
				$this->requeteDonnees = '';
-
 
84
				$httpContent = fopen('php://input', 'r');
-
 
85
				while ($data = fread($httpContent, 1024)) {
-
 
86
					$this->requeteDonnees .= $data;
-
 
87
				}
-
 
88
				fclose($httpContent);
-
 
89
			}
-
 
90
			if (strlen($_SERVER['QUERY_STRING']) == 0) {
-
 
91
				$tailleURL = strlen($_SERVER['REQUEST_URI']);
-
 
92
			} else {
-
 
93
				$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
-
 
94
			}
-
 
95
			$urlString = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseURL')), $tailleURL);
-
 
96
 
-
 
97
			$urlParts = explode('/', $urlString);
-
 
98
			if (isset($urlParts[0]) && !empty($urlParts[0])) {
-
 
Line 99... Line 143...
99
				$this->apiVersion = $urlParts[0];
143
		self::HTTP_CODE_CONFLIT => 'Conflict',
100
				self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
144
		self::HTTP_CODE_CONTENU_REQUIS => 'Length Required',
101
			} else {
145
		self::HTTP_CODE_ERREUR => 'Internal Server Error'
102
				$e = "Aucune version d'API n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
-
 
103
				trigger_error($e, E_USER_ERROR);
-
 
104
			}
146
	);
105
			
-
 
106
			if (isset($urlParts[1]) && !empty($urlParts[1])) {
-
 
107
				$this->service = $this->traiterNomService($urlParts[1]);
-
 
108
			} else {
-
 
109
				$e = "Aucun service n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
-
 
110
				trigger_error($e, E_USER_ERROR);
-
 
111
			}
-
 
112
			
-
 
Line -... Line 147...
-
 
147
 
-
 
148
	/**
113
			if (count($urlParts) > 2 && $urlParts[2] != '') {
149
	 * Analyse les données envoyées au serveur, enregistre la méthode HTTP utilisée pour appeler le serveur et parse
114
				array_shift($urlParts);
150
	 * l'url appelée pour trouver le service demandé.
115
				array_shift($urlParts);
151
	 */
116
				foreach ($urlParts as $ressource) {
152
	public function __construct() {
117
					if ($ressource != '') {
153
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
118
						$this->ressources[] = urldecode($ressource);
154
			$this->initialiserMethode();
119
					}
155
			$this->initialiserRequeteDonnees();
Line -... Line 156...
-
 
156
			
-
 
157
			$urlParts = $this->decouperUrlChemin();
-
 
158
			$this->initialiserApiVersion(array_shift($urlParts));
-
 
159
			$this->initialiserServiceNom(array_shift($urlParts));
-
 
160
			$this->initialiserRessource($urlParts);
-
 
161
			
-
 
162
			$this->initialiserParametres();
-
 
163
			Debug::printr($this);
-
 
164
			// Enregistrement en première position des autoload de la méthode gérant les classes des services 
-
 
165
			spl_autoload_register(array(get_class(), 'chargerClasse'));
-
 
166
		} else {
-
 
167
			$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
-
 
168
			trigger_error($e, E_USER_ERROR);
-
 
169
		}
-
 
170
	}
-
 
171
	
-
 
172
	private function initialiserMethode() {
-
 
173
		if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']) && count(trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) > 0) {
-
 
174
			$this->methode = trim($_SERVER['X_HTTP_METHOD_OVERRIDE']);
-
 
175
		} else {
-
 
176
			$this->methode = $_SERVER['REQUEST_METHOD'];
-
 
177
		}
-
 
178
	}
-
 
179
	
-
 
180
	private function initialiserRequeteDonnees() {
-
 
181
		if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
-
 
182
			$this->requeteDonnees = '';
-
 
183
			$httpContent = fopen('php://input', 'r');
-
 
184
			while ($data = fread($httpContent, 1024)) {
-
 
185
				$this->requeteDonnees .= $data;
-
 
186
			}
-
 
187
			fclose($httpContent);
-
 
188
		}
-
 
189
	}
-
 
190
	
-
 
191
	private function decouperUrlChemin() {
-
 
192
		if (strlen($_SERVER['QUERY_STRING']) == 0) {
-
 
193
			$tailleURL = strlen($_SERVER['REQUEST_URI']);
-
 
194
		} else {
-
 
195
			$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
-
 
196
		}
-
 
197
		$urlChaine = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseURL')), $tailleURL);
-
 
198
		return explode('/', $urlChaine);
-
 
199
	}
-
 
200
	
-
 
201
	private function initialiserApiVersion($apiVersion) {
-
 
202
		if (isset($apiVersion) && !empty($apiVersion)) {
-
 
203
			$this->apiVersion = $apiVersion;
120
				}
204
			self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
121
			}
205
		} else {
122
			
206
			$e = "Aucune version d'API n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
Line -... Line 207...
-
 
207
			trigger_error($e, E_USER_ERROR);
-
 
208
		}
-
 
209
	}
-
 
210
	
-
 
211
	private function initialiserServiceNom($serviceNom) {
-
 
212
		if (isset($serviceNom) && !empty($serviceNom)) {
-
 
213
			$this->service = $this->traiterNomService($serviceNom);
-
 
214
		} else {
-
 
215
			$e = "Aucun service n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
-
 
216
			trigger_error($e, E_USER_ERROR);
-
 
217
		}
-
 
218
	}
-
 
219
	
-
 
220
	private function traiterNomService($serviceNom) {
-
 
221
		return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
-
 
222
	}
123
			$this->nettoyerGet();
223
	
-
 
224
	private function initialiserRessource($urlParts) {
124
			$this->parametres = $_GET;
225
		if (is_array($urlParts) && count($urlParts) > 0) {
125
 
226
			foreach ($urlParts as $ressource) {
126
			$this->methode = $_SERVER['REQUEST_METHOD'];
227
				// Ne pas utiliser empty() car valeur 0 acceptée
127
			
228
				if ($ressource != '') {
128
			// Enregistrement en première position des autoload de la méthode gérant les classes des services 
229
					$this->ressources[] = urldecode($ressource);
Line 180... Line 281...
180
				break;
281
				break;
181
			case 'DELETE':
282
			case 'DELETE':
182
				$this->delete();
283
				$this->delete();
183
				break;
284
				break;
184
			case 'PUT':
285
			case 'PUT':
185
				$this->add();
286
				$this->put();
186
				break;
287
				break;
-
 
288
			default :
-
 
289
				$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.";
-
 
290
				trigger_error($e, E_USER_WARNING);
187
		}
291
		}
188
		// 	Affichage des exceptions et erreurs générées par les services
292
		// 	Affichage des exceptions et erreurs générées par les services
189
		echo GestionnaireException::getExceptions();
293
		$this->gererErreurs();
190
	}
294
	}
Line 191... Line 295...
191
 
295
 
192
	/**
296
	/**
193
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
297
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
194
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
298
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
195
	 * database contents.
299
	 * database contents.
196
	 */
300
	 */
197
	private function get() {
301
	private function get() {
198
		Debug::printr($this);
302
		if ($this->service != null) {
199
		$Service = new $this->service(self::$config);
303
			$Service = new $this->service(self::$config);
200
		if (method_exists($Service, self::METHODE_GET)) {
304
			if (method_exists($Service, self::METHODE_GET)) {
201
			$methodeGet = self::METHODE_GET;
305
				$methodeGet = self::METHODE_GET;
202
			$Service->$methodeGet($this->ressources, $this->parametres);
306
				$Service->$methodeGet($this->ressources, $this->parametres);
203
		} else {
307
			} else {
-
 
308
				$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
204
			$e = "La classe '{$this->service}' ne contient pas de méthode '".self::METHODE_GET."'.";
309
					"lors de l'appel du service via la méthode HTTP GET.";
-
 
310
				trigger_error($e, E_USER_ERROR);
205
			trigger_error($e, E_USER_ERROR);
311
			}
206
		}
312
		}
Line 207... Line 313...
207
	}
313
	}
208
 
-
 
209
	private function post() {
-
 
210
	   	$pairs = array();
-
 
211
		// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
314
 
212
	   	if ($this->requestData) {
-
 
Line 213... Line -...
213
			$pairs = $this->parserDonneesRequete();
-
 
214
		}
315
	private function post() {
215
 
-
 
216
		// Ajout des informations concernant l'upload de fichier passées dans la variable $_FILE
-
 
217
		if(isset($_FILES)) {
-
 
218
			foreach ($_FILES as $v) {
-
 
219
				$pairs[$v['name']] = $v;
-
 
220
			}
-
 
221
 
-
 
222
			// Ne pas effacer cette ligne ! Elle est indispensable pour les services du Carnet en ligne
-
 
223
			// qui n'utilisent que le tableau pairs dans les posts
-
 
224
			$pairs = array_merge($pairs, $_POST);
-
 
225
		}
-
 
226
 
-
 
227
		// Gestion du contenu du post
-
 
228
		if(isset($_POST))
316
		$paires = $this->parserDonneesRequete();
229
		{
-
 
230
			// Safari ne sait pas envoyer des DELETE avec gwt...
317
 
231
			// Nous utilisons le parametre "action" passé dans le POST qui doit contenir DELETE pour lancer la supression
-
 
232
			if ($pairs['action'] == 'DELETE') {
-
 
233
				$this->delete();
-
 
234
				return;
-
 
235
			}
318
		if (count($paires) != 0) {
236
 
-
 
237
			if (count($pairs) != 0) {
319
			if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
238
				if ($this->uid) { // get a resource element
320
				$this->delete();
239
					$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
-
 
240
					$resource_class = $this->ressource;
321
			} else if (count($this->ressources) == 0) {// Altnative à l'utilisation de PUT
241
					if (file_exists($resource_file)) {
322
				$this->add();
242
						include_once $resource_file;
323
			} else {
243
						if (class_exists($resource_class)) {
324
				if ($this->service != null) {
244
							$service = new $resource_class(self::$config);
325
					$Service = new $this->service(self::$config);
245
							if (method_exists($service,'updateElement')) { // Update element
326
					if (method_exists($Service, self::METHODE_POST)) {
246
								// TODO : a voir le retour ...
-
 
247
								if ($service->updateElement($this->uid, $pairs)) {
-
 
248
									$this->envoyerEnteteHttp(201);// Created
327
						$methodePost = self::METHODE_POST;
-
 
328
						if ($Service->$methodePost($this->ressources, $paires)) {
-
 
329
							$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
-
 
330
						}
-
 
331
					} else {
249
								}
332
						$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
250
							}
-
 
251
						}
-
 
252
					}
333
							"lors de l'appel du service via la méthode HTTP POST.";
-
 
334
						trigger_error($e, E_USER_ERROR);
253
				} else { // get all elements of a ressource
335
					}
254
					$this->add($pairs);
336
				}
255
				}
-
 
256
			} else {
337
			} 
257
				$this->envoyerEnteteHttp(411);// Length required
338
		} else {
Line 258... Line 339...
258
			}
339
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
259
		}
-
 
260
	}
340
		}
-
 
341
	}
261
 
342
 
262
	private function delete() {
-
 
263
		$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
343
	private function put() {
264
		$resource_class = $this->ressource;
344
		$paires = $this->parserDonneesRequete();
265
		if (file_exists($resource_file)) {
345
 
266
			include_once $resource_file;
346
		if (count($paires) != 0) {
267
			if (class_exists($resource_class)) {
347
			if ($this->service != null) {
268
				$service = new $resource_class(self::$config);
348
				$Service = new $this->service(self::$config);
269
				if ($this->uid) { // get a resource element
349
				if (method_exists($Service, self::METHODE_PUT)) {
270
		 			if (method_exists($service, 'deleteElement')) { // Delete element
350
					$methodePut = self::METHODE_PUT;
-
 
351
					if ($Service->$methodePut($this->ressources, $paires)) {
-
 
352
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
-
 
353
					}
271
						if ($service->deleteElement($this->uid)) {
354
				} else {
272
							$this->envoyerEnteteHttp(204);// No Content
355
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
-
 
356
						"lors de l'appel du service via la méthode HTTP PUT (ou équivalant).";
-
 
357
					trigger_error($e, E_USER_ERROR);
273
						}
358
				}
274
	 				}
359
			}
Line 275... Line 360...
275
				}
360
		} else {
276
			}
-
 
277
		}
-
 
278
	}
-
 
279
 
-
 
280
	private function add($pairs = null) {
361
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
281
		if (is_null($pairs)) {
-
 
282
			$pairs = array();
-
 
283
			// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
-
 
284
			// FIXME : vérifier que l'on récupère bien les données passées par PUT
-
 
285
		   	if ($this->requestData) {
362
		}
286
				$pairs = $this->parserDonneesRequete();
-
 
287
			}
363
	}
288
		}
364
 
289
 
365
	private function delete() {
290
		if (count($pairs) != 0) {
366
		if (count($this->ressources) != 0) {
291
			$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
367
			if ($this->service != null) {
292
			$resource_class = $this->ressource;
-
 
293
			if (file_exists($resource_file)) {
368
				$Service = new $this->service(self::$config);
294
				include_once $resource_file;
369
				if (method_exists($Service, self::METHODE_DELETE)) {
295
				if (class_exists($resource_class)) {
-
 
296
					$service = new $resource_class(self::$config);
370
					$methodeDelete = self::METHODE_DELETE;
-
 
371
					if ($Service->$methodeDelete($this->ressources, $paires)) {
-
 
372
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
-
 
373
					} else {
-
 
374
						$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
297
					if (method_exists($service,'createElement')) { // Create a new element
375
					}
298
						if ($service->createElement($pairs)) {
376
				} else {
299
							$this->envoyerEnteteHttp(201);// Created
377
					$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
300
						}
378
						"lors de l'appel du service via la méthode HTTP DELETE (ou équivalant).";
301
					}
379
					trigger_error($e, E_USER_ERROR);
302
				}
380
				}
303
			}
381
			}
304
		} else {
382
		} else {
305
			$this->envoyerEnteteHttp(411);// Length required
383
			$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
-
 
384
		}
-
 
385
	}
-
 
386
	
306
		}
387
	/**
307
	}
388
	 * Parse les données contenu dans le corps de la requête HTTP (= POST) en :
308
 
389
	 *  - décodant les clés et valeurs.
309
	/**
390
	 *  - supprimant les espaces en début et fin des clés et des valeurs.
-
 
391
	 * 
-
 
392
	 * @return array Tableau de paires clé et valeur.
-
 
393
	 */
310
	 * Parse les données de la requête HTTP.
394
	private function parserDonneesRequete() {
311
	 * @return str[] Array of name value pairs
395
		$donnees = array();
312
	 */
396
		if ($this->$requeteDonneesParsees != null) {
313
	private function parserDonneesRequete() {
397
			$donnees = $this->$requeteDonneesParsees;
314
		$values = array();
398
		} else if ($this->requeteDonnees != null) {
315
		$pairs = explode('&', $this->requeteDonnees);
399
			$paires = explode('&', $this->requeteDonnees);
316
		foreach ($pairs as $pair) {
400
			foreach ($paires as $paire) {
-
 
401
				list($cle, $valeur) = explode('=', $paire);
317
			$parts = explode('=', $pair);
402
				$cle = (isset($cle)) ? trim(urldecode($cle)) : '';
318
			if (isset($parts[0]) && isset($parts[1])) {
403
				$valeur = (isset($valeur)) ? trim(urldecode($valeur)) : '';
319
				$parts[1] = rtrim(urldecode($parts[1]));
404
				$donnees[$cle] = $valeur;
Line 320... Line 405...
320
				$values[$parts[0]] = $parts[1];
405
			}
321
			}
406
			$this->$requeteDonneesParsees = $donnees;
-
 
407
		}
322
		}
408
		return $donnees;
323
		return $values;
409
	}
324
	}
410
	
325
	
411
	/**
326
	/**
412
	 * Envoyer un entête HTTP (version 1.0) de statut.
327
	 * Envoyer un entête HTTP.
413
	 * Il remplacera systématiquement tout entête HTTP de statut précédement envoyé.
-
 
414
	 * @param int $code entier indiquant le code du statut de l'entête HTTP à envoyer. 
-
 
415
	 */
-
 
416
	public static function envoyerEnteteStatutHttp($code) {
-
 
417
		if (isset(self::$http10[$code])) {
-
 
418
			$txt = self::$http10[$code];
-
 
419
			header("HTTP/1.0 $code $txt", true);
-
 
420
		}
-
 
421
	}
-
 
422
	
-
 
423
	/**
-
 
424
	 * Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode. 
-
 
425
	 */
-
 
426
	public static function gererErreurs() {
-
 
427
		if (Config::get('fw_debogage') && GestionnaireException::getExceptionsNbre() > 0) {
-
 
428
			$exceptionsTriees = GestionnaireException::getExceptionsTriees();
-
 
429
			reset($exceptionsTriees);
-
 
430
			if (! (count($exceptionsTriees) == 1 && key($exceptionsTriees) == E_USER_NOTICE)) {
-
 
431
				self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
328
	 * @param int $code entier indiquant le code de l'entête http à envoyer 
432
			}
329
	 */
433
			foreach ($exceptionsTriees as $exceptions) {
330
	public static function envoyerEnteteHttp($code) {
434
				foreach ($exceptions as $e) {
331
		if (isset(self::$http10[$code])) {
435
					echo GestionnaireException::formaterExceptionXhtml($e);
332
			$txt = self::$http[$code];
436
				}