Subversion Repositories Applications.referentiel

Rev

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

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