Subversion Repositories Applications.referentiel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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