Subversion Repositories Applications.referentiel

Rev

Rev 38 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 38 Rev 50
1
<?php
1
<?php
2
// In : utf8 url_encoded (get et post)
2
// In : utf8 url_encoded (get et post)
3
// Out : utf8
3
// Out : utf8
4
 
4
 
5
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
5
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
6
class JRest {
6
class JRest {
7
 
7
 
8
 	/** Parsed configuration file */
8
 	/** Parsed configuration file */
9
    private static $config;
9
    private static $config;
10
 
10
 
11
	/** The HTTP request method used. */
11
	/** The HTTP request method used. */
12
	private $method = 'GET';
12
	private $method = 'GET';
13
 
13
 
14
	/** The HTTP request data sent (if any). */
14
	/** The HTTP request data sent (if any). */
15
	private $requestData = NULL;
15
	private $requestData = NULL;
16
 
16
 
17
	/** Nom resource. */
17
	/** Nom resource. */
18
	private $resource = NULL;
18
	private $resource = NULL;
19
 
19
 
20
	/** Identifiant unique resource. */
20
	/** Identifiant unique resource. */
21
	private $uid = NULL;
21
	private $uid = NULL;
22
 
22
 
23
	/**
23
	/**
24
	 * Constructor. Parses the configuration file "JRest.ini", grabs any request data sent, records the HTTP
24
	 * Constructor. Parses the configuration file "JRest.ini", grabs any request data sent, records the HTTP
25
	 * request method used and parses the request URL to find out the requested resource
25
	 * request method used and parses the request URL to find out the requested resource
26
	 * @param str iniFile Configuration file to use
26
	 * @param str iniFile Configuration file to use
27
	 */
27
	 */
28
	public function JRest($iniFile = 'jrest.ini.php') {
28
	public function JRest($iniFile = 'jrest.ini.php') {
29
		// Chargement de la configuration
29
		// Chargement de la configuration
30
		self::$config = parse_ini_file($iniFile, TRUE);
30
		self::$config = parse_ini_file($iniFile, TRUE);
31
		
31
		
32
		// Gestion de la mémoire maximum allouée aux services
32
		// Gestion de la mémoire maximum allouée aux services
33
		ini_set('memory_limit', self::$config['settings']['memoryLimit']);
33
		ini_set('memory_limit', self::$config['settings']['memoryLimit']);
34
		
34
		
35
		// Gestion des erreurs
35
		// Gestion des erreurs
36
		error_reporting(self::$config['settings']['erreurNiveau']);
36
		error_reporting(self::$config['settings']['erreurNiveau']);
37
		
37
		
38
		// Enregistrement de la méthode gérant l'autoload des classes
38
		// Enregistrement de la méthode gérant l'autoload des classes
39
		spl_autoload_register(array('JRest', 'chargerClasse'));
39
		spl_autoload_register(array('JRest', 'chargerClasse'));
40
		
40
		
41
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
41
		if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
42
			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
42
			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
43
				$this->requestData = '';
43
				$this->requestData = '';
44
				$httpContent = fopen('php://input', 'r');
44
				$httpContent = fopen('php://input', 'r');
45
				while ($data = fread($httpContent, 1024)) {
45
				while ($data = fread($httpContent, 1024)) {
46
					$this->requestData .= $data;
46
					$this->requestData .= $data;
47
				}
47
				}
48
				fclose($httpContent);
48
				fclose($httpContent);
49
			}
49
			}
50
			if (strlen($_SERVER['QUERY_STRING']) == 0) {
50
			if (strlen($_SERVER['QUERY_STRING']) == 0) {
51
				$len = strlen($_SERVER['REQUEST_URI']);
51
				$len = strlen($_SERVER['REQUEST_URI']);
52
			} else {
52
			} else {
53
				$len = -(strlen($_SERVER['QUERY_STRING']) + 1);
53
				$len = -(strlen($_SERVER['QUERY_STRING']) + 1);
54
			}
54
			}
55
			$urlString = substr($_SERVER['REQUEST_URI'], strlen(self::$config['settings']['baseURL']), $len);
55
			$urlString = substr($_SERVER['REQUEST_URI'], strlen(self::$config['settings']['baseURL']), $len);
56
 
56
 
57
			$urlParts = explode('/', $urlString);
57
			$urlParts = explode('/', $urlString);
58
 
58
 
59
			if (isset($urlParts[0])) $this->resource = $urlParts[0];
59
			if (isset($urlParts[0])) $this->resource = $urlParts[0];
60
			if (count($urlParts) > 1 && $urlParts[1] != '') {
60
			if (count($urlParts) > 1 && $urlParts[1] != '') {
61
				array_shift($urlParts);
61
				array_shift($urlParts);
62
				foreach ($urlParts as $uid) {
62
				foreach ($urlParts as $uid) {
63
					if ($uid != '') {
63
					if ($uid != '') {
64
						$this->uid[] = urldecode($uid);
64
						$this->uid[] = urldecode($uid);
65
					}
65
					}
66
				}
66
				}
67
			}
67
			}
68
 
68
 
69
			$this->method = $_SERVER['REQUEST_METHOD'];
69
			$this->method = $_SERVER['REQUEST_METHOD'];
70
		} else {
70
		} else {
71
			trigger_error('I require the server variables REQUEST_URI, REQUEST_METHOD and QUERY_STRING to work.', E_USER_ERROR);
71
			trigger_error('I require the server variables REQUEST_URI, REQUEST_METHOD and QUERY_STRING to work.', E_USER_ERROR);
72
		}
72
		}
73
	}
73
	}
74
 
74
 
75
	/**
75
	/**
76
	* La méthode __autoload() charge dynamiquement les classes trouvées dans le code.
76
	* La méthode __autoload() charge dynamiquement les classes trouvées dans le code.
77
	* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
77
	* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
78
	*
78
	*
79
	*@param string le nom de la classe appelée.
79
	*@param string le nom de la classe appelée.
80
	*@return void le fichier contenant la classe doit être inclu par la fonction.
80
	*@return void le fichier contenant la classe doit être inclu par la fonction.
81
	*/
81
	*/
82
	public static function chargerClasse($classe) {
82
	public static function chargerClasse($classe) {
83
		if (class_exists($classe)) {
83
		if (class_exists($classe)) {
84
			return null;
84
			return null;
85
		}
85
		}
86
		
86
		
87
		$chemins = array('', self::$config['settings']['servicesDir']);
87
		$chemins = array('', self::$config['settings']['servicesDir']);
88
		foreach ($chemins as $chemin) {
88
		foreach ($chemins as $chemin) {
89
			$chemin = $chemin.$classe.'.php';
89
			$chemin = $chemin.$classe.'.php';
90
			if (file_exists($chemin)) {
90
			if (file_exists($chemin)) {
91
				require_once $chemin;
91
				require_once $chemin;
92
			}
92
			}
93
		}
93
		}
94
	}
94
	}
95
	
95
	
96
	
96
	
97
	/**
97
	/**
98
	 * Execute the request.
98
	 * Execute the request.
99
	 */
99
	 */
100
	function exec() {
100
	function exec() {
101
		switch ($this->method) {
101
		switch ($this->method) {
102
			case 'GET':
102
			case 'GET':
103
				$this->get();
103
				$this->get();
104
				break;
104
				break;
105
			case 'POST':
105
			case 'POST':
106
				$this->post();
106
				$this->post();
107
				break;
107
				break;
108
			case 'DELETE':
108
			case 'DELETE':
109
				$this->delete();
109
				$this->delete();
110
				break;
110
				break;
111
			case 'PUT':
111
			case 'PUT':
112
				$this->add();
112
				$this->add();
113
				break;
113
				break;
114
		}
114
		}
115
	}
115
	}
116
 
116
 
117
	/**
117
	/**
118
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
118
	 * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
119
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
119
	 * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
120
	 * database contents.
120
	 * database contents.
121
	 */
121
	 */
122
	private function get() {
122
	private function get() {
123
		if ($this->resource) {
123
		if ($this->resource) {
124
			$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
124
			$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
125
			$resource_class = ucfirst($this->resource);
125
			$resource_class = ucfirst($this->resource);
126
			if (file_exists($resource_file))  {
126
			if (file_exists($resource_file))  {
127
				include_once $resource_file;
127
				include_once $resource_file;
128
				if (class_exists($resource_class)) {
128
				if (class_exists($resource_class)) {
129
					$service = new $resource_class(self::$config);
129
					$service = new $resource_class(self::$config);
130
					if ($this->uid) { // get a resource element
130
					if ($this->uid) { // get a resource element
131
						if (method_exists($service, 'getElement')) {
131
						if (method_exists($service, 'getElement')) {
132
							$service->getElement($this->uid);
132
							$service->getElement($this->uid);
133
						}
133
						}
134
					} elseif (method_exists($service, 'getRessource')) { // get all elements of a ressource
134
					} elseif (method_exists($service, 'getRessource')) { // get all elements of a ressource
135
						$service->getRessource();
135
						$service->getRessource();
136
					}
136
					}
137
				}
137
				}
138
			}
138
			}
139
		} else { // get resources
139
		} else { // get resources
140
			// include set.jrest.php, instanticiation et appel
140
			// include set.jrest.php, instanticiation et appel
141
		}
141
		}
142
	}
142
	}
143
 
143
 
144
	private function post() {
144
	private function post() {
145
	   	$pairs = array();
145
	   	$pairs = array();
146
		// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
146
		// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
147
	   	if ($this->requestData) {
147
	   	if ($this->requestData) {
148
			$pairs = $this->parseRequestData();
148
			$pairs = $this->parseRequestData();
149
		}
149
		}
150
 
150
 
151
		// Ajout des informations concernant l'upload de fichier passées dans la variable $_FILE
151
		// Ajout des informations concernant l'upload de fichier passées dans la variable $_FILE
152
		if(isset($_FILES)) {
152
		if(isset($_FILES)) {
153
			foreach ($_FILES as $v) {
153
			foreach ($_FILES as $v) {
154
				$pairs[$v['name']] = $v;
154
				$pairs[$v['name']] = $v;
155
			}
155
			}
156
 
156
 
157
			// Ne pas effacer cette ligne ! Elle est indispensable pour les services du Carnet en ligne
157
			// Ne pas effacer cette ligne ! Elle est indispensable pour les services du Carnet en ligne
158
			// qui n'utilisent que le tableau pairs dans les posts
158
			// qui n'utilisent que le tableau pairs dans les posts
159
			$pairs = array_merge($pairs, $_POST);
159
			$pairs = array_merge($pairs, $_POST);
160
		}
160
		}
161
 
161
 
162
		// gestion du contenu du post
162
		// gestion du contenu du post
163
		if(isset($_POST))
163
		if(isset($_POST)) {
164
		{
-
 
165
			// Safari ne sait pas envoyer des DELETE avec gwt...
164
			// Safari ne sait pas envoyer des DELETE avec gwt...
166
			// Nous utilisons le parametre "action" passé dans le POST qui doit contenir DELETE pour lancer la supression
165
			// Nous utilisons le parametre "action" passé dans le POST qui doit contenir DELETE pour lancer la supression
167
			if ($pairs['action'] == 'DELETE') {
166
			if (isset($pairs['action']) && $pairs['action'] == 'DELETE') {
168
				$this->delete();
167
				$this->delete();
169
				return;
168
				return;
170
			}
169
			}
171
 
170
 
172
			if (count($pairs) != 0) {
171
			if (count($pairs) != 0) {
173
				if ($this->uid) { // get a resource element
172
				if ($this->uid) { // get a resource element
174
					$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
173
					$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
175
					$resource_class = ucfirst($this->resource);
174
					$resource_class = ucfirst($this->resource);
176
					if (file_exists($resource_file)) {
175
					if (file_exists($resource_file)) {
177
						include_once $resource_file;
176
						include_once $resource_file;
178
						if (class_exists($resource_class)) {
177
						if (class_exists($resource_class)) {
179
							$service = new $resource_class(self::$config);
178
							$service = new $resource_class(self::$config);
180
							if (method_exists($service,'updateElement')) { // Update element
179
							if (method_exists($service,'updateElement')) { // Update element
181
								// TODO : a voir le retour ...
180
								// TODO : a voir le retour ...
182
								if ($service->updateElement($this->uid, $pairs)) {
181
								if ($service->updateElement($this->uid, $pairs)) {
183
									$this->created();
182
									$this->created();
184
								}
183
								}
185
							}
184
							}
186
						}
185
						}
187
					}
186
					}
188
				} else { // get all elements of a ressource
187
				} else { // get all elements of a ressource
189
					$this->add($pairs);
188
					$this->add($pairs);
190
				}
189
				}
191
			} else {
190
			} else {
192
				$this->lengthRequired();
191
				$this->lengthRequired();
193
			}
192
			}
194
		}
193
		}
195
	}
194
	}
196
 
195
 
197
	private function delete() {
196
	private function delete() {
198
		$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
197
		$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
199
		$resource_class = ucfirst($this->resource);
198
		$resource_class = ucfirst($this->resource);
200
		if (file_exists($resource_file)) {
199
		if (file_exists($resource_file)) {
201
			include_once $resource_file;
200
			include_once $resource_file;
202
			if (class_exists($resource_class)) {
201
			if (class_exists($resource_class)) {
203
				$service = new $resource_class(self::$config);
202
				$service = new $resource_class(self::$config);
204
				if ($this->uid) { // get a resource element
203
				if ($this->uid) { // get a resource element
205
		 			if (method_exists($service, 'deleteElement')) { // Delete element
204
		 			if (method_exists($service, 'deleteElement')) { // Delete element
206
						if ($service->deleteElement($this->uid)) {
205
						if ($service->deleteElement($this->uid)) {
207
							$this->noContent();
206
							$this->noContent();
208
						}
207
						}
209
	 				}
208
	 				}
210
				}
209
				}
211
			}
210
			}
212
		}
211
		}
213
	}
212
	}
214
 
213
 
215
	private function add($pairs = null) {
214
	private function add($pairs = null) {
216
		if (is_null($pairs)) {
215
		if (is_null($pairs)) {
217
			$pairs = array();
216
			$pairs = array();
218
			// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
217
			// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
219
			// FIXME : vérifier que l'on récupère bien les données passées par PUT
218
			// FIXME : vérifier que l'on récupère bien les données passées par PUT
220
		   	if ($this->requestData) {
219
		   	if ($this->requestData) {
221
				$pairs = $this->parseRequestData();
220
				$pairs = $this->parseRequestData();
222
			}
221
			}
223
		}
222
		}
224
 
223
 
225
		if (count($pairs) != 0) {
224
		if (count($pairs) != 0) {
226
			$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
225
			$resource_file = self::$config['settings']['servicesDir'].ucfirst($this->resource).'.php';
227
			$resource_class = ucfirst($this->resource);
226
			$resource_class = ucfirst($this->resource);
228
			if (file_exists($resource_file)) {
227
			if (file_exists($resource_file)) {
229
				include_once $resource_file;
228
				include_once $resource_file;
230
				if (class_exists($resource_class)) {
229
				if (class_exists($resource_class)) {
231
					$service = new $resource_class(self::$config);
230
					$service = new $resource_class(self::$config);
232
					if (method_exists($service,'createElement')) { // Create a new element
231
					if (method_exists($service,'createElement')) { // Create a new element
233
						if ($service->createElement($pairs)) {
232
						if ($service->createElement($pairs)) {
234
							$this->created();
233
							$this->created();
235
						}
234
						}
236
					}
235
					}
237
				}
236
				}
238
			}
237
			}
239
		} else {
238
		} else {
240
			$this->lengthRequired();
239
			$this->lengthRequired();
241
		}
240
		}
242
	}
241
	}
243
 
242
 
244
	/**
243
	/**
245
	 * Parse the HTTP request data.
244
	 * Parse the HTTP request data.
246
	 * @return str[] Array of name value pairs
245
	 * @return str[] Array of name value pairs
247
	 */
246
	 */
248
	private function parseRequestData() {
247
	private function parseRequestData() {
249
		$values = array();
248
		$values = array();
250
		$pairs = explode(self::$config['settings']['argSeparatorInput'], $this->requestData);
249
		$pairs = explode(self::$config['settings']['argSeparatorInput'], $this->requestData);
251
		foreach ($pairs as $pair) {
250
		foreach ($pairs as $pair) {
252
			$parts = explode('=', $pair);
251
			$parts = explode('=', $pair);
253
			if (isset($parts[0]) && isset($parts[1])) {
252
			if (isset($parts[0]) && isset($parts[1])) {
254
				$parts[1] = rtrim(urldecode($parts[1]));
253
				$parts[1] = rtrim(urldecode($parts[1]));
255
				$values[$parts[0]] = $parts[1];
254
				$values[$parts[0]] = $parts[1];
256
			}
255
			}
257
		}
256
		}
258
		return $values;
257
		return $values;
259
	}
258
	}
260
 
259
 
261
	/**
260
	/**
262
	 * Send a HTTP 201 response header.
261
	 * Send a HTTP 201 response header.
263
	 */
262
	 */
264
	private function created($url = FALSE) {
263
	private function created($url = FALSE) {
265
		header('HTTP/1.0 201 Created');
264
		header('HTTP/1.0 201 Created');
266
		if ($url) {
265
		if ($url) {
267
			header('Location: '.$url);
266
			header('Location: '.$url);
268
		}
267
		}
269
	}
268
	}
270
 
269
 
271
	/**
270
	/**
272
	 * Send a HTTP 204 response header.
271
	 * Send a HTTP 204 response header.
273
	 */
272
	 */
274
	private function noContent() {
273
	private function noContent() {
275
		header('HTTP/1.0 204 No Content');
274
		header('HTTP/1.0 204 No Content');
276
	}
275
	}
277
 
276
 
278
	/**
277
	/**
279
	 * Send a HTTP 400 response header.
278
	 * Send a HTTP 400 response header.
280
	 */
279
	 */
281
	private function badRequest() {
280
	private function badRequest() {
282
		header('HTTP/1.0 400 Bad Request');
281
		header('HTTP/1.0 400 Bad Request');
283
	}
282
	}
284
 
283
 
285
	/**
284
	/**
286
	 * Send a HTTP 401 response header.
285
	 * Send a HTTP 401 response header.
287
	 */
286
	 */
288
	private function unauthorized($realm = 'JRest') {
287
	private function unauthorized($realm = 'JRest') {
289
		if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
288
		if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
290
			header('WWW-Authenticate: Basic realm="'.$realm.'"');
289
			header('WWW-Authenticate: Basic realm="'.$realm.'"');
291
		}
290
		}
292
		header('HTTP/1.0 401 Unauthorized');
291
		header('HTTP/1.0 401 Unauthorized');
293
	}
292
	}
294
 
293
 
295
	/**
294
	/**
296
	 * Send a HTTP 404 response header.
295
	 * Send a HTTP 404 response header.
297
	 */
296
	 */
298
	private function notFound() {
297
	private function notFound() {
299
		header('HTTP/1.0 404 Not Found');
298
		header('HTTP/1.0 404 Not Found');
300
	}
299
	}
301
 
300
 
302
	/**
301
	/**
303
	 * Send a HTTP 405 response header.
302
	 * Send a HTTP 405 response header.
304
	 */
303
	 */
305
	private function methodNotAllowed($allowed = 'GET, HEAD') {
304
	private function methodNotAllowed($allowed = 'GET, HEAD') {
306
		header('HTTP/1.0 405 Method Not Allowed');
305
		header('HTTP/1.0 405 Method Not Allowed');
307
		header('Allow: '.$allowed);
306
		header('Allow: '.$allowed);
308
	}
307
	}
309
 
308
 
310
	/**
309
	/**
311
	 * Send a HTTP 406 response header.
310
	 * Send a HTTP 406 response header.
312
	 */
311
	 */
313
	private function notAcceptable() {
312
	private function notAcceptable() {
314
		header('HTTP/1.0 406 Not Acceptable');
313
		header('HTTP/1.0 406 Not Acceptable');
315
		echo join(', ', array_keys(self::$config['renderers']));
314
		echo join(', ', array_keys(self::$config['renderers']));
316
	}
315
	}
317
 
316
 
318
	/**
317
	/**
319
	 * Send a HTTP 411 response header.
318
	 * Send a HTTP 411 response header.
320
	 */
319
	 */
321
	private function lengthRequired() {
320
	private function lengthRequired() {
322
		header('HTTP/1.0 411 Length Required');
321
		header('HTTP/1.0 411 Length Required');
323
	}
322
	}
324
 
323
 
325
	/**
324
	/**
326
	 * Send a HTTP 500 response header.
325
	 * Send a HTTP 500 response header.
327
	 */
326
	 */
328
	private function internalServerError() {
327
	private function internalServerError() {
329
		header('HTTP/1.0 500 Internal Server Error');
328
		header('HTTP/1.0 500 Internal Server Error');
330
	}
329
	}
331
}
330
}
332
?>
331
?>