Overview

Packages

  • Framework
  • None
  • PHP
  • Utilitaire

Classes

  • Bdd
  • Cache
  • CacheSimple
  • Chronometre
  • Cli
  • Config
  • Controleur
  • Debug
  • Framework
  • GestionnaireException
  • I18n
  • Log
  • Registre
  • RestClient
  • RestServeur
  • RestService
  • Script
  • SquelettePhp
  • Url
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: // declare(encoding='UTF-8');
  3: /**
  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
  6:  *
  7:  * @category    Php 5.2
  8:  * @package Framework
  9:  * @author      Christian SCHMIDT <schmidt@php.net> (Auteur classe originale)
 10:  * @author      Aurélien PERONNET <aurelien@tela-botanica.org>
 11:  * @author      Jean-Pascal MILCENT <jpm@tela-botanica.org>
 12:  * @copyright   Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
 13:  * @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
 14:  * @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
 15:  * @version SVN: $Id: Url.php 405 2012-02-22 15:45:39Z gduche $
 16:  * @link        /doc/framework/
 17: */
 18: class Url {
 19: 
 20:     /**
 21:      * Répresenter les tableaux dans les requêtes en utilisant la notation php []. Par défaut à true.
 22:      */
 23:     const OPTION_UTILISER_CROCHETS = 'utiliser_crochets';
 24: 
 25:     /**
 26:      * URL-encoder les clés des variables dans les requêtes. Par défaut à true.
 27:      */
 28:     const OPTION_ENCODER_CLES = 'encoder_cles';
 29: 
 30:     /**
 31:     * URL-encoder les valeurs des variables dans les requêtes. Par défaut à false.
 32:     */
 33:     const OPTION_ENCODER_VALEURS = 'encoder_valeurs';
 34:     
 35:     /**
 36:      * Séparateurs de variables lors du parsing de la requête. Chaque caractère
 37:      * est considéré comme un séparateur. Par défaut, spécifié par le paramêtre
 38:      * arg_separator.input dans php.ini (par défaut "&").
 39:      */
 40:     const OPTION_SEPARATEUR_ENTREE = 'separateur_entree';
 41: 
 42:     /**
 43:      * Séparateur de variables lors de la génération de la requête. Par défaut, spécifié
 44:      * par le paramètre arg_separator.output dans php.ini (par défaut "&").
 45:      */
 46:     const OPTION_SEPARATEUR_SORTIE = 'separateur_sortie';
 47: 
 48:     /**
 49:      * Options par défaut correspondant au comportement de php
 50:      * vis à vis de $_GET
 51:      */
 52:     private $options = array(
 53:         self::OPTION_UTILISER_CROCHETS => true,
 54:         self::OPTION_ENCODER_CLES => true,
 55:         self::OPTION_ENCODER_VALEURS => false,
 56:         self::OPTION_SEPARATEUR_ENTREE => '&',
 57:         self::OPTION_SEPARATEUR_SORTIE => '&');
 58: 
 59:     /**
 60:      * @var  string|bool
 61:      */
 62:     private $schema = false;
 63: 
 64:     /**
 65:      * @var  string|bool
 66:      */
 67:     private $infoUtilisateur = false;
 68: 
 69:     /**
 70:      * @var  string|bool
 71:      */
 72:     private $hote = false;
 73: 
 74:     /**
 75:      * @var  int|bool
 76:      */
 77:     private $port = false;
 78: 
 79:     /**
 80:      * @var  string
 81:      */
 82:     private $chemin = '';
 83: 
 84:     /**
 85:      * @var  string|bool
 86:      */
 87:     private $requete = false;
 88: 
 89:     /**
 90:      * @var  string|bool
 91:      */
 92:     private $fragment = false;
 93: 
 94:     /** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
 95:     private $parametres_obligatoires = array('url_arg_separateur_entree', 'url_arg_separateur_sortie');
 96:     
 97:     /**
 98:      * @param string $url    une URL relative ou absolue
 99:      * @param array  $options
100:      */
101:     public function __construct($url, $options = null) {
102:         Config::verifierPresenceParametres($this->parametres_obligatoires);
103:         
104:         $this->setOption(self::OPTION_SEPARATEUR_ENTREE, Config::get('url_arg_separateur_entree'));
105:         $this->setOption(self::OPTION_SEPARATEUR_SORTIE, Config::get('url_arg_separateur_sortie'));
106:         if (is_array($options)) {
107:             foreach ($options as $nomOption => $valeur) {
108:                 $this->setOption($nomOption);
109:             }
110:         }
111: 
112:         if (preg_match('@^([a-z][a-z0-9.+-]*):@i', $url, $reg)) {
113:             $this->schema = $reg[1];
114:             $url = substr($url, strlen($reg[0]));
115:         }
116: 
117:         if (preg_match('@^//([^/#?]+)@', $url, $reg)) {
118:             $this->setAutorite($reg[1]);
119:             $url = substr($url, strlen($reg[0]));
120:         }
121: 
122:         $i = strcspn($url, '?#');
123:         $this->chemin = substr($url, 0, $i);
124:         $url = substr($url, $i);
125: 
126:         if (preg_match('@^\?([^#]*)@', $url, $reg)) {
127:             $this->requete = $reg[1];
128:             $url = substr($url, strlen($reg[0]));
129:         }
130: 
131:         if ($url) {
132:             $this->fragment = substr($url, 1);
133:         }
134:     }
135:     
136:     /**
137:      * Renvoie la valeur de l'option specifiée.
138:      *
139:      * @param string $nomOption Nom de l'option demandée
140:      *
141:      * @return  mixed
142:      */
143:     public function getOption($nomOption) {
144:         return isset($this->options[$nomOption]) ? $this->options[$nomOption] : false;
145:     }
146: 
147:     /**
148:      * Met à jour la valeur de l'option spécifiée.
149:      *
150:      * @param string $nomOption une des constantes commençant par self::OPTION_
151:      * @param mixed  $valeur      valeur de l'option
152:      *
153:      * @return void
154:      * @see  self::OPTION_STRICTE
155:      * @see  self::OPTION_UTILISER_CROCHETS
156:      * @see  self::OPTION_ENCODER_CLES
157:      */
158:     public function setOption($nomOption, $valeur) {
159:         if (!array_key_exists($nomOption, $this->options)) {
160:             return false;
161:         }
162:         $this->options[$nomOption] = $valeur;
163:     }
164: 
165:     /**
166:      * Renvoie la partie autorité, i.e. [ infoUtilisateur "@" ] hote [ ":" port ], ou
167:      * false si celle-ci est absente.
168:      *
169:      * @return string|bool
170:      */
171:     private function getAutorite() {
172:         if (!$this->hote) {
173:             return false;
174:         }
175: 
176:         $autorite = '';
177: 
178:         if ($this->infoUtilisateur !== false) {
179:             $autorite .= $this->infoUtilisateur . '@';
180:         }
181: 
182:         $autorite .= $this->hote;
183: 
184:         if ($this->port !== false) {
185:             $autorite .= ':' . $this->port;
186:         }
187: 
188:         return $autorite;
189:     }
190: 
191:     /**
192:      * @param string|false $autorite
193:      *
194:      * @return void
195:      */
196:     private function setAutorite($autorite) {
197:         $this->user = false;
198:         $this->pass = false;
199:         $this->hote = false;
200:         $this->port = false;
201:         if (preg_match('@^(([^\@]+)\@)?([^:]+)(:(\d*))?$@', $autorite, $reg)) {
202:             if ($reg[1]) {
203:                 $this->infoUtilisateur = $reg[2];
204:             }
205: 
206:             $this->hote = $reg[3];
207:             if (isset($reg[5])) {
208:                 $this->port = intval($reg[5]);
209:             }
210:         }
211:     }
212: 
213:     /**
214:      * Renvoie vrai ou faux suivant que l'instance en cours représente une URL relative ou absolue.
215:      *
216:      * @return  bool
217:      */
218:     private function etreAbsolue() {
219:         return (bool) $this->schema;
220:     }
221:     
222:     /**
223:      * La suppression des segments à points est décrite dans la RFC 3986, section 5.2.4, e.g.
224:      * "/foo/../bar/baz" => "/bar/baz"
225:      *
226:      * @param string $chemin un chemin
227:      *
228:      * @return string un chemin
229:      */
230:     private static function supprimerSegmentsAPoints($chemin) {
231:         $sortie = '';
232: 
233:         // Assurons nous de ne pas nous retrouver piégés dans une boucle infinie due à un bug de cette méthode
234:         $j = 0;
235:         while ($chemin && $j++ < 100) {
236:             if (substr($chemin, 0, 2) == './') {// Étape A
237:                 $chemin = substr($chemin, 2);
238:             } else if (substr($chemin, 0, 3) == '../') {
239:                 $chemin = substr($chemin, 3);
240:             } else if (substr($chemin, 0, 3) == '/./' || $chemin == '/.') {// Étape B
241:                 $chemin = '/' . substr($chemin, 3);
242:             } else if (substr($chemin, 0, 4) == '/../' || $chemin == '/..') {// Étape C
243:                 $chemin = '/' . substr($chemin, 4);
244:                 $i = strrpos($sortie, '/');
245:                 $sortie = $i === false ? '' : substr($sortie, 0, $i);
246:             } else if ($chemin == '.' || $chemin == '..') {// Étape D
247:                 $chemin = '';
248:             } else {// Étape E
249:                 $i = strpos($chemin, '/');
250:                 if ($i === 0) {
251:                     $i = strpos($chemin, '/', 1);
252:                 }
253:                 if ($i === false) {
254:                     $i = strlen($chemin);
255:                 }
256:                 $sortie .= substr($chemin, 0, $i);
257:                 $chemin = substr($chemin, $i);
258:             }
259:         }
260: 
261:         return $sortie;
262:     }
263:     
264:     /**
265:      * (Re-)Création de la partie requête de l'URL à partir des données du tableau (passé en paramètre).
266:      * 
267:      * @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
268:      * @return void (Re-)Création de la partie requête.
269:      */
270:     public function setRequete(Array $parametres) {
271:         if (!$parametres) {
272:             $this->requete = false;
273:         } else {
274:             foreach ($parametres as $nom => $valeur) {
275:                 if ($this->getOption(self::OPTION_ENCODER_CLES)) {
276:                     $nom = rawurlencode($nom);
277:                 }
278: 
279:                 if ($this->getOption(self::OPTION_ENCODER_VALEURS)) {
280:                     $valeur = rawurlencode($valeur);
281:                 }
282:                 
283:                 if (is_array($valeur)) {
284:                     foreach ($valeur as $k => $v) {
285:                         if ($this->getOption(self::OPTION_UTILISER_CROCHETS)) {
286:                             $parties[] = sprintf('%s[%s]=%s', $nom, $k, $v);
287:                         } else {
288:                             $parties[] = $nom.'='.$v;
289:                         }
290:                     }
291:                 } else if (!is_null($valeur)) {
292:                     $parties[] = $nom . '=' . $valeur;
293:                 } else {
294:                     $parties[] = $nom;
295:                 }
296:             }
297:             $this->requete = implode($this->getOption(self::OPTION_SEPARATEUR_SORTIE), $parties);
298:         }
299:     }
300:     
301:     /**
302:      * (Re-)Création de la partie requête de l'URL à partir de la fusion du tableau (passé en paramètre) et 
303:      * les valeurs présentes dans $_GET.
304:      * 
305:      * @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
306:      * @return void (Re-)Création de la partie requête.
307:      */
308:     public function fusionnerRequete(Array $parametres) {
309:         if ($parametres) {
310:             $requete = $parametres + $_GET;
311:             $this->setRequete($requete);
312:         }
313:     }
314: 
315:     /**
316:      * Normalise les données de l'instance d'Url faisant appel à cette méthode.
317:      *
318:      * @return  void l'instance d'Url courrante est normalisée.
319:      */
320:     public function normaliser() {
321:         // Voir RFC 3886, section 6
322: 
323:         // les cchémas sont insesibles à la casse
324:         if ($this->schema) {
325:             $this->schema = strtolower($this->schema);
326:         }
327: 
328:         // les noms d'hotes sont insensibles à la casse
329:         if ($this->hote) {
330:             $this->hote = strtolower($this->hote);
331:         }
332: 
333:         // Supprimer le numéro de port par défaut pour les schemas connus (RFC 3986, section 6.2.3)
334:         if ($this->port && $this->schema && $this->port == getservbyname($this->schema, 'tcp')) {
335:             $this->port = false;
336:         }
337: 
338:         // normalisation dans le cas d'un encodage avec %XX pourcentage (RFC 3986, section 6.2.2.1)
339:         foreach (array('infoUtilisateur', 'hote', 'chemin') as $partie) {
340:             if ($this->$partie) {
341:                 $this->$partie  = preg_replace('/%[0-9a-f]{2}/ie', 'strtoupper("\0")', $this->$partie);
342:             }
343:         }
344: 
345:         // normalisation des segments du chemin (RFC 3986, section 6.2.2.3)
346:         $this->chemin = self::supprimerSegmentsAPoints($this->chemin);
347: 
348:         // normalisation basée sur le schéma (RFC 3986, section 6.2.3)
349:         if ($this->hote && !$this->chemin) {
350:             $this->chemin = '/';
351:         }
352:     }
353: 
354:     /**
355:      * Renvoie une instance d'objet Url representant l'URL canonique du script PHP en cours d'éxécution.
356:      *
357:      * @return Url retourne un objet Url ou null en cas d'erreur.
358:      */
359:     public static function getCanonique() {
360:         $url = null;
361:         if (!isset($_SERVER['REQUEST_METHOD'])) {
362:             trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
363:         } else {
364:             // À partir d'une URL relative
365:             $url = new self($_SERVER['PHP_SELF']);
366:             $url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
367:             $url->hote = $_SERVER['SERVER_NAME'];
368:             $port = intval($_SERVER['SERVER_PORT']);
369:             if ($url->schema == 'http' && $port != 80 || $url->schema == 'https' && $port != 443) {
370:                 $url->port = $port;
371:             }
372:         }
373:         return $url;
374:     }
375: 
376:     /**
377:      * Renvoie une instance d'objet Url representant l'URL utilisée pour récupérer la requête en cours.
378:      *
379:      * @return Url retourne un objet Url ou null en cas d'erreur.
380:      */
381:     public static function getDemande() {
382:         $url = null;
383:         if (!isset($_SERVER['REQUEST_METHOD'])) {
384:             trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
385:         } else {
386:             // On part d'une URL relative
387:             $url = new self($_SERVER['REQUEST_URI']);
388:             $url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
389:             // On met à jour les valeurs de l'hôte et si possible du port
390:             $url->setAutorite($_SERVER['HTTP_hote']);
391:         }
392:         return $url;
393:     }
394: 
395:     
396:     /**
397:      * Renvoie un représentation sous forme de chaine de l'URL.
398:      *
399:      * @return  string l'url
400:      */
401:     public function getURL() {
402:         // Voir RFC 3986, section 5.3
403:         $url = '';
404:         
405:         if ($this->schema !== false) {
406:             $url .= $this->schema . ':';
407:         }
408: 
409:         $autorite = $this->getAutorite();
410:         if ($autorite !== false) {
411:             $url .= '//' . $autorite;
412:         }
413:         $url .= $this->chemin;
414: 
415:         if ($this->requete !== false) {
416:             $url .= '?' . $this->requete;
417:         }
418: 
419:         if ($this->fragment !== false) {
420:             $url .= '#' . $this->fragment;
421:         }
422: 
423:         return $url;
424:     }
425: }
426: ?>
API documentation generated by ApiGen 2.8.0