Subversion Repositories Applications.framework

Rev

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

Rev 204 Rev 227
Line 1... Line 1...
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
* classe Url, gérant le découpage des paramètres, leurs modification etc...
4
 * Classe Url, gérant le découpage des paramètres, leurs modification etc...
5
* Traduction et conversion d'une classe (NET_Url2) issue de Pear
5
 * Traduction et conversion d'une classe (NET_Url2) issue de Pear
6
*
6
 *
7
* @category  Php5
7
 * @category	Php 5.2
8
* @package   Framework
8
 * @package	Framework
9
// Auteur principal
9
// Auteur principal
10
* @author	Christian Schmidt <schmidt@php.net>
10
 * @author		Christian Schmidt <schmidt@php.net>
11
// Autre auteurs
11
// Autre auteurs
12
* @author	Aurélien PERONNET <aurelien@tela-botanica.org>
12
 * @author		Aurélien PERONNET <aurelien@tela-botanica.org>
13
* @author	Jean-Pascal MILCENT <jpm@tela-botanica.org>
13
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
14
* @copyright 2009 Tela-Botanica
14
 * @copyright	2009 Tela-Botanica
15
* @license   http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
15
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
16
* @license   http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
16
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
17
* @version   SVN: $Id: Url.php 204 2010-07-19 13:23:56Z aurelien $
17
 * @version	SVN: $Id: Url.php 227 2010-11-10 15:04:58Z jpm $
18
* @link	  /doc/framework/
18
 * @link		/doc/framework/
19
*
-
 
20
*/
19
*/
21
class Url
20
class Url {
22
{
-
 
23
	/**
-
 
24
	 * Parsing strict dans resoudre() (voir RFC 3986, section 5.2.2). Par défaut
-
 
25
	 * à true.
-
 
26
	 */
-
 
27
	const OPTION_STRICTE = 'strict';
-
 
Line 28... Line 21...
28
 
21
 
29
	/**
22
	/**
30
	 * Répresenter les tableaux dans les requêtes en utilisant la notation php []. Par défaut à true.
23
	 * Répresenter les tableaux dans les requêtes en utilisant la notation php []. Par défaut à true.
31
	 */
24
	 */
Line 52... Line 45...
52
	/**
45
	/**
53
	 * Options par défaut correspondant au comportement de php
46
	 * Options par défaut correspondant au comportement de php
54
	 * vis à vis de $_GET
47
	 * vis à vis de $_GET
55
	 */
48
	 */
56
	private $options = array(
49
	private $options = array(
57
		self::OPTION_STRICTE => true,
-
 
58
		self::OPTION_UTILISER_CROCHETS => true,
50
		self::OPTION_UTILISER_CROCHETS => true,
59
		self::OPTION_ENCODER_CLES => true,
51
		self::OPTION_ENCODER_CLES => true,
60
		self::OPTION_SEPARATEUR_ENTREE => 'x&',
52
		self::OPTION_SEPARATEUR_ENTREE => 'x&',
61
		self::OPTION_SEPARATEUR_SORTIE => 'x&');
53
		self::OPTION_SEPARATEUR_SORTIE => 'x&');
Line 131... Line 123...
131
 
123
 
132
		if ($url) {
124
		if ($url) {
133
			$this->fragment = substr($url, 1);
125
			$this->fragment = substr($url, 1);
134
		}
126
		}
-
 
127
	}
Line 135... Line 128...
135
	}
128
	
136
 
-
 
137
	/**
-
 
138
	 * Retourne le schéma, c.a.d. "http" ou "urn", ou false si aucun schéma n'est
-
 
139
	 * spécifié, i.e. l'url est une url relative
-
 
140
	 *
-
 
141
	 * @return  string|bool
-
 
142
	 */
-
 
143
	public function getSchema() {
-
 
144
		return $this->schema;
-
 
145
	}
-
 
146
 
-
 
147
	/**
-
 
148
	 * @param string|bool $schema
-
 
149
	 *
-
 
150
	 * @return void
-
 
151
	 * @see	getSchema()
-
 
152
	 */
-
 
153
	public function setSchema($schema) {
-
 
154
		$this->schema = $schema;
-
 
155
	}
-
 
156
 
-
 
157
	/**
129
 
158
	 * renvoie la partie user de la partie infoUtilisateur (partie précédant le premier
-
 
159
	 *  ":"), ou false si aucune partie infoUtilisateur n'est définie.
-
 
160
	 *
-
 
161
	 * @return  string|bool
-
 
162
	 */
-
 
163
	public function getUtilisateur() {
-
 
164
		return $this->infoUtilisateur !== false ? preg_replace('@:.*$@', '', $this->infoUtilisateur) : false;
-
 
165
	}
-
 
166
 
-
 
167
	/**
-
 
168
	 * renvoie la partie mot de passe de la partie infoUtilisateur (partie après le premier
-
 
169
	 *  ":"), , ou false si aucune partie infoUtilisateur n'est définie (i.e. l'URL ne contient
-
 
170
	 * pas de "@" en face du nom d'hôte) ou si la partie infoUtilisateur ne contient pas de ":".
-
 
171
	 *
-
 
172
	 * @return  string|bool
-
 
173
	 */
-
 
174
	public function getMotDePasse() {
-
 
175
		return $this->infoUtilisateur !== false ? substr(strstr($this->infoUtilisateur, ':'), 1) : false;
-
 
176
	}
-
 
177
 
-
 
178
	/**
-
 
179
	 * Renvoie la partie userinfio, ou false si celle-ci n'existe pas, i.e. si la partie
-
 
180
	 * autorité ne contient pas de "@"
-
 
181
	 *
-
 
182
	 * @return  string|bool
-
 
183
	 */
-
 
184
	public function getInfoUtilisateur() {
-
 
185
		return $this->infoUtilisateur;
-
 
186
	}
-
 
187
 
-
 
188
	/**
-
 
189
	 * Setteur pour la partie infoUtilisateur. Si deux argument sont passé, ils sont combinés
130
	/**
190
	 * dans la partie infoUtilisateur de cette manière username ":" password.
131
	 * Met à jour la valeur de l'option spécifiée.
191
	 *
132
	 *
192
	 * @param string|bool $infoUtilisateur infoUtilisateur ou username
133
	 * @param string $nomOption une des constantes commençant par self::OPTION_
193
	 * @param string|bool $motDePasse
134
	 * @param mixed  $valeur	  valeur de l'option
-
 
135
	 *
-
 
136
	 * @return void
-
 
137
	 * @see  self::OPTION_STRICTE
194
	 *
138
	 * @see  self::OPTION_UTILISER_CROCHETS
195
	 * @return void
139
	 * @see  self::OPTION_ENCODER_CLES
196
	 */
140
	 */
197
	public function setInfoUtilisateur($infoUtilisateur, $motDePasse = false) {
141
	public function setOption($nomOption, $valeur) {
198
		$this->infoUtilisateur = $infoUtilisateur;
-
 
199
		if ($motDePasse !== false) {
142
		if (!array_key_exists($nomOption, $this->options)) {
200
			$this->infoUtilisateur .= ':' . $motDePasse;
-
 
201
		}
-
 
202
	}
-
 
203
 
-
 
204
	/**
-
 
205
	 * Renvoie la partie hôte, ou false s'il n'y a pas de partie autorité, c.a.d.
-
 
206
	 * l'URL est relative.
-
 
207
	 *
-
 
208
	 * @return  string|bool
-
 
209
	 */
-
 
210
	public function getHote() {
-
 
211
		return $this->hote;
-
 
212
	}
-
 
213
 
-
 
214
	/**
-
 
215
	 * @param string|bool $hote
-
 
216
	 *
-
 
217
	 * @return void
-
 
218
	 */
143
			return false;
219
	public function setHote($hote) {
-
 
220
		$this->hote = $hote;
-
 
221
	}
-
 
222
 
-
 
223
	/**
-
 
224
	 * Renvoie le numéro de port, ou false si aucun numéro de port n'est spécifié,
-
 
225
	 * i.e. le port par défaut doit utilisé.
-
 
226
	 *
-
 
227
	 * @return  int|bool
-
 
228
	 */
-
 
229
	public function getPort() {
-
 
230
		return $this->port;
-
 
231
	}
-
 
232
 
-
 
233
	/**
-
 
234
	 * @param int|bool $port
-
 
235
	 *
-
 
236
	 * @return void
-
 
237
	 */
-
 
238
	public function setPort($port) {
144
		}
Line 239... Line 145...
239
		$this->port = intval($port);
145
		$this->options[$nomOption] = $valeur;
240
	}
146
	}
241
 
147
 
242
	/**
148
	/**
243
	 * Renvoie la partie autorité, i.e. [ infoUtilisateur "@" ] hote [ ":" port ], ou
149
	 * Renvoie la partie autorité, i.e. [ infoUtilisateur "@" ] hote [ ":" port ], ou
244
	 * false si celle-ci est absente.
150
	 * false si celle-ci est absente.
245
	 *
151
	 *
246
	 * @return string|bool
152
	 * @return string|bool
247
	 */
153
	 */
248
	public function getAutorite() {
154
	private function getAutorite() {
Line 249... Line 155...
249
		if (!$this->hote) {
155
		if (!$this->hote) {
Line 268... Line 174...
268
	/**
174
	/**
269
	 * @param string|false $autorite
175
	 * @param string|false $autorite
270
	 *
176
	 *
271
	 * @return void
177
	 * @return void
272
	 */
178
	 */
273
	public function setAutorite($autorite) {
179
	private function setAutorite($autorite) {
274
		$this->user = false;
180
		$this->user = false;
275
		$this->pass = false;
181
		$this->pass = false;
276
		$this->hote = false;
182
		$this->hote = false;
277
		$this->port = false;
183
		$this->port = false;
278
		if (preg_match('@^(([^\@]+)\@)?([^:]+)(:(\d*))?$@', $autorite, $reg)) {
184
		if (preg_match('@^(([^\@]+)\@)?([^:]+)(:(\d*))?$@', $autorite, $reg)) {
Line 286... Line 192...
286
			}
192
			}
287
		}
193
		}
288
	}
194
	}
Line 289... Line 195...
289
 
195
 
290
	/**
-
 
291
	 * Renvoie la partie chemin (chemin) (éventuellement vide).
-
 
292
	 *
-
 
293
	 * @return string
-
 
294
	 */
-
 
295
	public function getChemin() {
-
 
296
		return $this->chemin;
-
 
297
	}
-
 
298
 
-
 
299
	/**
-
 
300
	 * @param string $chemin
-
 
301
	 *
-
 
302
	 * @return void
-
 
303
	 */
-
 
304
	public function setChemin($chemin) {
-
 
305
		$this->chemin = $chemin;
-
 
306
	}
-
 
307
 
-
 
308
	/**
-
 
309
	 * renvoie la chaine de requête (requete string) (sans le premier "?"), ou false si "?"
-
 
310
	 * n'est pas présent dans l'url.
-
 
311
	 *
-
 
312
	 * @return  string|bool
-
 
313
	 * @see	 self::getVariablesRequete()
-
 
314
	 */
-
 
315
	public function getRequete() {
-
 
316
		return $this->requete;
-
 
317
	}
-
 
318
 
-
 
319
	/**
-
 
320
	 * @param string|bool $requete
-
 
321
	 *
-
 
322
	 * @return void
-
 
323
	 * @see   self::setVariablesRequete()
-
 
324
	 */
-
 
325
	public function setRequete($requete) {
-
 
326
		$this->requete = $requete;
-
 
327
	}
-
 
328
 
-
 
329
	/**
196
	/**
330
	 * Renvoie le nom du fragment, ou false si "#" n'est pas present dans l'URL.
197
	 * Renvoie vrai ou faux suivant que l'instance en cours représente une URL relative ou absolue.
331
	 *
198
	 *
332
	 * @return  string|bool
199
	 * @return  bool
333
	 */
200
	 */
334
	public function getFragment() {
201
	private function etreAbsolue() {
335
		return $this->fragment;
202
		return (bool) $this->schema;
336
	}
203
	}
337
 
204
	
-
 
205
	/**
338
	/**
206
	 * La suppression des segments à points est décrite dans la RFC 3986, section 5.2.4, e.g.
339
	 * @param string|bool $fragment
207
	 * "/foo/../bar/baz" => "/bar/baz"
340
	 *
-
 
341
	 * @return void
-
 
342
	 */
-
 
343
	public function setFragment($fragment) {
-
 
344
		$this->fragment = $fragment;
-
 
345
	}
-
 
346
 
-
 
347
	/**
-
 
348
	 * Renvoie la requete string sous forme d'un tableau de variables telles qu'elles apparaitraient
208
	 *
349
	 * dans le $_GET d'un script PHP
209
	 * @param string $chemin un chemin
350
	 *
210
	 *
351
	 * @return  array
211
	 * @return string un chemin
352
	 */
212
	 */
353
	public function getVariablesRequete() {
213
	private static function supprimerSegmentsAPoints($chemin) {
354
		$pattern = '/' .
-
 
355
				   preg_quote($this->getOption(self::OPTION_SEPARATEUR_ENTREE), '/') .
-
 
356
				   '/';
-
 
357
		$parties   = preg_split($pattern, $this->requete, -1, PREG_SPLIT_NO_EMPTY);
-
 
358
		$retour  = array();
-
 
359
 
-
 
360
		foreach ($parties as $partie) {
-
 
361
			if (strpos($partie, '=') !== false) {
-
 
362
				list($cle, $valeur) = explode('=', $partie, 2);
-
 
363
			} else {
-
 
364
				$cle   = $partie;
-
 
365
				$valeur = null;
-
 
366
			}
-
 
367
 
-
 
368
			if ($this->getOption(self::OPTION_ENCODER_CLES)) {
-
 
369
				$cle = rawurldecode($cle);
-
 
370
			}
-
 
371
			$valeur = rawurldecode($valeur);
-
 
372
 
-
 
373
			if ($this->getOption(self::OPTION_UTILISER_CROCHETS) &&
-
 
374
				preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $cle, $matches)) {
-
 
375
 
-
 
376
				$cle = $matches[1];
-
 
Line -... Line 214...
-
 
214
		$sortie = '';
-
 
215
 
-
 
216
		// Assurons nous de ne pas nous retrouver piégés dans une boucle infinie due à un bug de cette méthode
-
 
217
		$j = 0;
-
 
218
		while ($chemin && $j++ < 100) {
377
				$idx = $matches[2];
219
			if (substr($chemin, 0, 2) == './') {// Étape A
-
 
220
				$chemin = substr($chemin, 2);
-
 
221
			} else if (substr($chemin, 0, 3) == '../') {
-
 
222
				$chemin = substr($chemin, 3);
-
 
223
			} else if (substr($chemin, 0, 3) == '/./' || $chemin == '/.') {// Étape B
-
 
224
				$chemin = '/' . substr($chemin, 3);
-
 
225
			} else if (substr($chemin, 0, 4) == '/../' || $chemin == '/..') {// Étape C
378
 
226
				$chemin = '/' . substr($chemin, 4);
-
 
227
				$i = strrpos($sortie, '/');
-
 
228
				$sortie = $i === false ? '' : substr($sortie, 0, $i);
-
 
229
			} else if ($chemin == '.' || $chemin == '..') {// Étape D
-
 
230
				$chemin = '';
-
 
231
			} else {// Étape E
379
				// On s'assure que c'est bien un tableau
232
				$i = strpos($chemin, '/');
380
				if (empty($retour[$cle]) || !is_array($retour[$cle])) {
233
				if ($i === 0) {
381
					$retour[$cle] = array();
-
 
382
				}
-
 
383
 
234
					$i = strpos($chemin, '/', 1);
384
				// Ajout des données
235
				}
385
				if ($idx === '') {
-
 
386
					$retour[$cle][] = $valeur;
-
 
387
				} else {
236
				if ($i === false) {
388
					$retour[$cle][$idx] = $valeur;
-
 
389
				}
-
 
390
			} elseif (!$this->getOption(self::OPTION_UTILISER_CROCHETS)
-
 
391
					  && !empty($retour[$cle])
-
 
392
			) {
237
					$i = strlen($chemin);
393
				$retour[$cle]   = (array) $retour[$cle];
-
 
394
				$retour[$cle][] = $valeur;
238
				}
395
			} else {
239
				$sortie .= substr($chemin, 0, $i);
396
				$retour[$cle] = $valeur;
240
				$chemin = substr($chemin, $i);
Line 397... Line 241...
397
			}
241
			}
398
		}
242
		}
399
 
243
 
400
		return $retour;
244
		return $sortie;
401
	}
245
	}
402
 
246
	
-
 
247
	/**
403
	/**
248
	 * (Re-)Création de la partie requête de l'URL à partir des données du tableau (passé en paramètre).
404
	 * @param array $tableau (nom => valeur) tableau
249
	 * 
405
	 *
250
	 * @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
406
	 * @return void
251
	 * @return void (Re-)Création de la partie requête.
407
	 */
252
	 */
408
	public function setVariablesRequete(array $tableau) {
253
	public function setRequete(Array $parametres) {
409
		if (!$tableau) {
254
		if (!$parametres) {
410
			$this->requete = false;
255
			$this->requete = false;
411
		} else {
256
		} else {
412
			foreach ($tableau as $nom => $valeur) {
257
			foreach ($parametres as $nom => $valeur) {
Line 413... Line 258...
413
				if ($this->getOption(self::OPTION_ENCODER_CLES)) {
258
				if ($this->getOption(self::OPTION_ENCODER_CLES)) {
414
					$nom = rawurlencode($nom);
259
					$nom = rawurlencode($nom);
415
				}
260
				}
416
 
261
 
-
 
262
				if (is_array($valeur)) {
417
				if (is_array($valeur)) {
263
					foreach ($valeur as $k => $v) {
-
 
264
						if ($this->getOption(self::OPTION_UTILISER_CROCHETS)) {
418
					foreach ($valeur as $k => $v) {
265
							$parties[] = sprintf('%s[%s]=%s', $nom, $k, $v);
419
						$parties[] = $this->getOption(self::OPTION_UTILISER_CROCHETS)
266
						} else {
420
							? sprintf('%s[%s]=%s', $nom, $k, $v)
267
							$parties[] = $nom.'='.$v;
421
							: ($nom . '=' . $v);
268
						}
422
					}
269
					}
423
				} elseif (!is_null($valeur)) {
270
				} else if (!is_null($valeur)) {
424
					$parties[] = $nom . '=' . $valeur;
271
					$parties[] = $nom . '=' . $valeur;
425
				} else {
272
				} else {
426
					$parties[] = $nom;
-
 
427
				}
273
					$parties[] = $nom;
428
			}
274
				}
429
			$this->requete = implode($this->getOption(self::OPTION_SEPARATEUR_SORTIE),
-
 
430
								   $parties);
-
 
431
		}
-
 
432
	}
-
 
433
 
-
 
434
	/**
-
 
435
	 * @param string $nom
-
 
436
	 * @param mixed  $valeur
-
 
437
	 *
-
 
438
	 * @return  array
-
 
439
	 */
-
 
440
	public function setVariableRequete($nom, $valeur) {
-
 
441
		$tableau = $this->getVariablesRequete();
-
 
442
		$tableau[$nom] = $valeur;
-
 
443
		$this->setVariablesRequete($tableau);
-
 
444
	}
-
 
445
 
-
 
446
	/**
-
 
447
	 * @param string $nom
-
 
448
	 *
-
 
449
	 * @return void
-
 
450
	 */
-
 
451
	public function unsetVariableRequete($nom) {
-
 
Line 452... Line 275...
452
		$tableau = $this->getVariablesRequete();
275
			}
453
		unset($tableau[$nom]);
276
			$this->requete = implode($this->getOption(self::OPTION_SEPARATEUR_SORTIE), $parties);
454
		$this->setVariablesRequete($tableau);
-
 
455
	}
277
		}
456
	
278
	}
457
	/**
279
	
458
	 * @param array $noms tableau des noms de variable à supprimer de l'url.
-
 
459
	 *
-
 
460
	 * @return void
-
 
461
	 */
-
 
462
	public function unsetVariablesRequete($noms) {
-
 
463
		$tableau = $this->getVariablesRequete();
-
 
464
		foreach ($noms as $nom) {
-
 
465
			unset($tableau[$nom]);
-
 
466
		}
280
	/**
467
		$this->setVariablesRequete($tableau);
-
 
468
	}
-
 
469
 
281
	 * (Re-)Création de la partie requête de l'URL à partir de la fusion du tableau (passé en paramètre) et 
470
	/**
282
	 * les valeurs présentes dans $_GET.
471
	 * Renvoie un représentation sous forme de chaine de l'URL
-
 
472
	 *
283
	 * 
473
	 * @return  string
-
 
474
	 */
284
	 * @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
475
	public function getURL() {
285
	 * @return void (Re-)Création de la partie requête.
476
		// Voir RFC 3986, section 5.3
286
	 */
477
		$url = "";
-
 
478
		
-
 
479
		if ($this->schema !== false) {
-
 
480
			$url .= $this->schema . ':';
-
 
481
		}
-
 
482
 
-
 
483
		$autorite = $this->getAutorite();
-
 
484
		if ($autorite !== false) {
-
 
485
			$url .= '//' . $autorite;
-
 
486
		}
-
 
487
		$url .= $this->chemin;
-
 
488
 
-
 
489
		if ($this->requete !== false) {
-
 
490
			$url .= '?' . $this->requete;
-
 
491
		}
-
 
492
 
-
 
493
		if ($this->fragment !== false) {
-
 
494
			$url .= '#' . $this->fragment;
-
 
495
		}
-
 
496
 
-
 
497
		return $url;
-
 
498
	}
-
 
499
 
-
 
500
	/**
-
 
501
	 * Renvoie une représentation de cette URL sous forme de chaine normalisée. Utile pour la
-
 
502
	 * comparaison d'URLs
-
 
503
	 *
-
 
504
	 * @return  string
-
 
505
	 */
287
	public function fusionnerRequete(Array $parametres) {
Line 506... Line 288...
506
	public function getURLNormalisee() {
288
		if ($parametres) {
507
		$url = clone $this;
289
			$requete = $parametres + $_GET;
508
		$url->normaliser();
290
			$this->setRequete($requete);
509
		return $url->getUrl();
291
		}
510
	}
292
	}
511
 
293
 
512
	/**
294
	/**
Line 513... Line 295...
513
	 * Renvoie une instance normalisée de Url
295
	 * Normalise les données de l'instance d'Url faisant appel à cette méthode.
514
	 *
296
	 *
515
	 * @return  Url
297
	 * @return  void l'instance d'Url courrante est normalisée.
516
	 */
298
	 */
Line 526... Line 308...
526
		if ($this->hote) {
308
		if ($this->hote) {
527
			$this->hote = strtolower($this->hote);
309
			$this->hote = strtolower($this->hote);
528
		}
310
		}
Line 529... Line 311...
529
 
311
 
530
		// Supprimer le numéro de port par défaut pour les schemas connus (RFC 3986, section 6.2.3)
-
 
531
		if ($this->port &&
-
 
532
			$this->schema &&
312
		// Supprimer le numéro de port par défaut pour les schemas connus (RFC 3986, section 6.2.3)
533
			$this->port == getservbyname($this->schema, 'tcp')) {
-
 
534
 
313
		if ($this->port && $this->schema && $this->port == getservbyname($this->schema, 'tcp')) {
535
			$this->port = false;
314
			$this->port = false;
Line 536... Line 315...
536
		}
315
		}
537
 
316
 
Line 550... Line 329...
550
			$this->chemin = '/';
329
			$this->chemin = '/';
551
		}
330
		}
552
	}
331
	}
Line 553... Line 332...
553
 
332
 
554
	/**
-
 
555
	 * Renvoie vrai ou faux suivant que l'instance en cours représente une URL relative ou absolue.
-
 
556
	 *
-
 
557
	 * @return  bool
-
 
558
	 */
-
 
559
	public function etreAbsolue() {
-
 
560
		return (bool) $this->schema;
-
 
561
	}
-
 
562
 
-
 
563
	/**
333
	/**
564
	 * Renvoie une instance de Url représentant une URL absolue relative à
-
 
565
	 * cette URL.
334
	 * Renvoie une instance d'objet Url representant l'URL canonique du script PHP en cours d'éxécution.
566
	 *
335
	 *
567
	 * @param Url|string $reference URL relative
-
 
568
	 *
-
 
569
	 * @return Url
336
	 * @return Url retourne un objet Url ou null en cas d'erreur.
570
	 */
337
	 */
571
	public function resoudre($reference) {
-
 
572
		if (is_string($reference)) {
-
 
573
			$reference = new self($reference);
-
 
574
		}
-
 
575
		if (!$this->etreAbsolue()) {
-
 
576
			throw new Exception('L\'URL de base doit être absolue !');
-
 
577
		}
-
 
578
 
-
 
579
		// Un parseur non strict peut choisir d'ignorer un schema dans la référence
-
 
580
		// si celui ci est identique au schéma de base de l'URI.
-
 
581
		if (!$this->getOption(self::OPTION_STRICTE) && $reference->schema == $this->schema) {
-
 
582
			$reference->schema = false;
-
 
583
		}
-
 
584
 
338
	public static function getCanonique() {
585
		$cible = new self('');
339
		$url = null;
586
		if ($reference->schema !== false) {
-
 
587
			$cible->schema = $reference->schema;
-
 
588
			$cible->setAutorite($reference->getAutorite());
340
		if (!isset($_SERVER['REQUEST_METHOD'])) {
589
			$cible->chemin  = self::supprimerSegmentsAPoints($reference->chemin);
-
 
590
			$cible->requete = $reference->requete;
341
			trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
591
		} else {
-
 
592
			$autorite = $reference->getAutorite();
342
		} else {
593
			if ($autorite !== false) {
343
			// À partir d'une URL relative
594
				$cible->setAutorite($autorite);
344
			$url = new self($_SERVER['PHP_SELF']);
595
				$cible->chemin  = self::supprimerSegmentsAPoints($reference->chemin);
345
			$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
596
				$cible->requete = $reference->requete;
-
 
597
			} else {
-
 
598
				if ($reference->chemin == '') {
-
 
599
					$cible->chemin = $this->chemin;
-
 
600
					if ($reference->requete !== false) {
-
 
601
						$cible->requete = $reference->requete;
-
 
602
					} else {
-
 
603
						$cible->requete = $this->requete;
-
 
604
					}
-
 
605
				} else {
-
 
606
					if (substr($reference->chemin, 0, 1) == '/') {
-
 
607
						$cible->chemin = self::supprimerSegmentsAPoints($reference->chemin);
-
 
608
					} else {
-
 
609
						// Concaténation chemins (RFC 3986, section 5.2.3)
-
 
610
						if ($this->hote !== false && $this->chemin == '') {
-
 
611
							$cible->chemin = '/' . $this->chemin;
-
 
612
						} else {
346
			$url->hote = $_SERVER['SERVER_NAME'];
613
							$i = strrpos($this->chemin, '/');
-
 
614
							if ($i !== false) {
347
			$port = intval($_SERVER['SERVER_PORT']);
615
								$cible->chemin = substr($this->chemin, 0, $i + 1);
-
 
616
							}
-
 
617
							$cible->chemin .= $reference->chemin;
-
 
618
						}
-
 
619
						$cible->chemin = self::supprimerSegmentsAPoints($cible->chemin);
-
 
620
					}
348
			if ($url->schema == 'http' && $port != 80 || $url->schema == 'https' && $port != 443) {
621
					$cible->requete = $reference->requete;
-
 
622
				}
-
 
623
				$cible->setAutorite($this->getAutorite());
349
				$url->port = $port;
624
			}
-
 
625
			$cible->schema = $this->schema;
350
			}
626
		}
-
 
627
 
-
 
628
		$cible->fragment = $reference->fragment;
-
 
629
 
351
		}
630
		return $cible;
-
 
631
	}
-
 
632
 
-
 
633
	/**
-
 
634
	 * La suppression des segments à points est décrite dans la RFC 3986, section 5.2.4, e.g.
-
 
635
	 * "/foo/../bar/baz" => "/bar/baz"
-
 
636
	 *
-
 
637
	 * @param string $chemin un chemin
-
 
638
	 *
-
 
639
	 * @return string un chemin
-
 
640
	 */
-
 
641
	private static function supprimerSegmentsAPoints($chemin) {
-
 
642
		$sortie = '';
-
 
643
 
-
 
644
		// Assurons de ne pas nous retrouver piégés dans une boucle infinie due à un bug de
-
 
645
		// cette méthode
-
 
646
		$j = 0;
-
 
647
		while ($chemin && $j++ < 100) {
-
 
648
			// Étape A
-
 
649
			if (substr($chemin, 0, 2) == './') {
-
 
650
				$chemin = substr($chemin, 2);
-
 
651
			} elseif (substr($chemin, 0, 3) == '../') {
-
 
652
				$chemin = substr($chemin, 3);
-
 
653
 
-
 
654
			// Étape B
-
 
655
			} elseif (substr($chemin, 0, 3) == '/./' || $chemin == '/.') {
-
 
656
				$chemin = '/' . substr($chemin, 3);
-
 
657
 
-
 
658
			// Étape C
-
 
659
			} elseif (substr($chemin, 0, 4) == '/../' || $chemin == '/..') {
-
 
660
				$chemin = '/' . substr($chemin, 4);
-
 
661
				$i = strrpos($sortie, '/');
-
 
662
				$sortie = $i === false ? '' : substr($sortie, 0, $i);
-
 
663
 
-
 
664
			// Étape D
-
 
665
			} elseif ($chemin == '.' || $chemin == '..') {
-
 
666
				$chemin = '';
-
 
667
 
-
 
668
			// Étape E
-
 
669
			} else {
-
 
670
				$i = strpos($chemin, '/');
-
 
671
				if ($i === 0) {
-
 
672
					$i = strpos($chemin, '/', 1);
-
 
673
				}
-
 
674
				if ($i === false) {
-
 
675
					$i = strlen($chemin);
-
 
676
				}
-
 
677
				$sortie .= substr($chemin, 0, $i);
-
 
678
				$chemin = substr($chemin, $i);
-
 
679
			}
-
 
680
		}
-
 
681
 
-
 
682
		return $sortie;
352
		return $url;
Line 683... Line 353...
683
	}
353
	}
684
 
354
 
685
	/**
-
 
686
	 * Renvoie une instance de Url representant l'URL canonique du script PHP
355
	/**
687
	 * en cours d'éxécution
356
	 * Renvoie une instance d'objet Url representant l'URL utilisée pour récupérer la requête en cours.
688
	 *
357
	 *
689
	 * @return  string
358
	 * @return Url retourne un objet Url ou null en cas d'erreur.
-
 
359
	 */
690
	 */
360
	public static function getDemande() {
691
	public static function getCanonique() {
-
 
692
		if (!isset($_SERVER['REQUEST_METHOD'])) {
361
		$url = null;
693
			// ALERT - pas d'URL en cours
362
		if (!isset($_SERVER['REQUEST_METHOD'])) {
694
			throw new Exception('Le script n\'a pas été appellé à travers un serveur web');
-
 
695
		}
363
			trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
696
 
364
		} else {
697
		// on part d'une URL relative
365
			// On part d'une URL relative
698
		$url = new self($_SERVER['PHP_SELF']);
-
 
699
		$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
-
 
700
		$url->hote = $_SERVER['SERVER_NAME'];
366
			$url = new self($_SERVER['REQUEST_URI']);
701
		$port = intval($_SERVER['SERVER_PORT']);
367
			$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
702
		if ($url->schema == 'http' && $port != 80 ||
-
 
703
			$url->schema == 'https' && $port != 443) {
-
 
704
 
368
			// On met à jour les valeurs de l'hôte et si possible du port
705
			$url->port = $port;
369
			$url->setAutorite($_SERVER['HTTP_hote']);
706
		}
370
		}
Line -... Line 371...
-
 
371
		return $url;
707
		return $url;
372
	}
708
	}
373
 
709
 
-
 
710
	/**
-
 
711
	 * Renvoie l'URL utilisée pour récupérer la requête en cours
-
 
712
	 *
-
 
713
	 * @return  string
-
 
714
	 */
-
 
715
	public static function getURLDemande() {
-
 
716
		return self::getDemande()->getUrl();
-
 
717
	}
-
 
718
 
-
 
719
	/**
374
	
720
	 * Renvoie une instance de Url representant l'URL utilisée pour
375
	/**
721
	 * récupérer la requête en cours
376
	 * Renvoie un représentation sous forme de chaine de l'URL.
722
	 *
377
	 *
723
	 * @return  Url
378
	 * @return  string l'url
-
 
379
	 */
-
 
380
	public function getURL() {
724
	 */
381
		// Voir RFC 3986, section 5.3
725
	public static function getDemande() {
382
		$url = "";
726
		if (!isset($_SERVER['REQUEST_METHOD'])) {
383
		
Line 727... Line -...
727
			// ALERTE - pas d'URL en cours
-
 
728
			throw new Exception('Le script n\'a pas été appellé à travers un serveur web');
384
		if ($this->schema !== false) {
729
		}
-
 
730
 
-
 
731
		// On part d'une URL relative
385
			$url .= $this->schema . ':';
732
		$url = new self($_SERVER['REQUEST_URI']);
386
		}
733
		$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
387
 
-
 
388
		$autorite = $this->getAutorite();
Line 734... Line -...
734
		// On met à jour les valeurs de l'hote et si possible du port
-
 
735
		$url->setAutorite($_SERVER['HTTP_hote']);
-
 
736
		return $url;
-
 
737
	}
-
 
738
 
-
 
739
	/**
-
 
740
	 * Met à jour la valeur de l'option spécifiée.
-
 
741
	 *
-
 
742
	 * @param string $nomOption une des constantes commençant par self::OPTION_
-
 
743
	 * @param mixed  $valeur	  valeur de l'option
-
 
744
	 *
-
 
745
	 * @return void
389
		if ($autorite !== false) {
746
	 * @see  self::OPTION_STRICTE
-
 
747
	 * @see  self::OPTION_UTILISER_CROCHETS
390
			$url .= '//' . $autorite;
748
	 * @see  self::OPTION_ENCODER_CLES
391
		}
749
	 */
-
 
750
	function setOption($nomOption, $valeur) {
-
 
Line 751... Line -...
751
		if (!array_key_exists($nomOption, $this->options)) {
-
 
752
			return false;
-
 
753
		}
-
 
754
		$this->options[$nomOption] = $valeur;
-
 
755
	}
-
 
756
 
-
 
757
	/**
-
 
758
	 * Renvoie la valeur de l'option specifiée.
392
		$url .= $this->chemin;
759
	 *
393
 
760
	 * @param string $nomOption Nom de l'option demandée
-
 
761
	 *
394
		if ($this->requete !== false) {
Line 762... Line -...
762
	 * @return  mixed
-
 
763
	 */
-
 
764
	function getOption($nomOption) {
395
			$url .= '?' . $this->requete;
765
		return isset($this->options[$nomOption])
396
		}
766
			? $this->options[$nomOption] : false;
397
 
-
 
398
		if ($this->fragment !== false) {
767
	}
399
			$url .= '#' . $this->fragment;