Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
uri.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Uri
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * JUri Class
14  *
15  * This class serves two purposes. First it parses a URI and provides a common interface
16  * for the Joomla Platform to access and manipulate a URI. Second it obtains the URI of
17  * the current executing script from the server regardless of server.
18  *
19  * @package Joomla.Platform
20  * @subpackage Uri
21  * @since 11.1
22  */
23 class JUri
24 {
25  /**
26  * @var string Original URI
27  * @since 12.1
28  */
29  protected $uri = null;
30 
31  /**
32  * @var string Protocol
33  * @since 12.1
34  */
35  protected $scheme = null;
36 
37  /**
38  * @var string Host
39  * @since 12.1
40  */
41  protected $host = null;
42 
43  /**
44  * @var integer Port
45  * @since 12.1
46  */
47  protected $port = null;
48 
49  /**
50  * @var string Username
51  * @since 12.1
52  */
53  protected $user = null;
54 
55  /**
56  * @var string Password
57  * @since 12.1
58  */
59  protected $pass = null;
60 
61  /**
62  * @var string Path
63  * @since 12.1
64  */
65  protected $path = null;
66 
67  /**
68  * @var string Query
69  * @since 12.1
70  */
71  protected $query = null;
72 
73  /**
74  * @var string Anchor
75  * @since 12.1
76  */
77  protected $fragment = null;
78 
79  /**
80  * @var array Query variable hash
81  * @since 12.1
82  */
83  protected $vars = array();
84 
85  /**
86  * @var array An array of JUri instances.
87  * @since 11.1
88  */
89  protected static $instances = array();
90 
91  /**
92  * @var array The current calculated base url segments.
93  * @since 11.1
94  */
95  protected static $base = array();
96 
97  /**
98  * @var array The current calculated root url segments.
99  * @since 11.1
100  */
101  protected static $root = array();
102 
103  /**
104  * @var string The current url.
105  * @since 11.1
106  */
107  protected static $current;
108 
109  /**
110  * Constructor.
111  * You can pass a URI string to the constructor to initialise a specific URI.
112  *
113  * @param string $uri The optional URI string
114  *
115  * @since 11.1
116  */
117  public function __construct($uri = null)
118  {
119  if (!is_null($uri))
120  {
121  $this->parse($uri);
122  }
123  }
124 
125  /**
126  * Magic method to get the string representation of the URI object.
127  *
128  * @return string
129  *
130  * @since 11.1
131  */
132  public function __toString()
133  {
134  return $this->toString();
135  }
136 
137  /**
138  * Returns the global JUri object, only creating it
139  * if it doesn't already exist.
140  *
141  * @param string $uri The URI to parse. [optional: if null uses script URI]
142  *
143  * @return JUri The URI object.
144  *
145  * @since 11.1
146  */
147  public static function getInstance($uri = 'SERVER')
148  {
149  if (empty(self::$instances[$uri]))
150  {
151  // Are we obtaining the URI from the server?
152  if ($uri == 'SERVER')
153  {
154  // Determine if the request was over SSL (HTTPS).
155  if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off'))
156  {
157  $https = 's://';
158  }
159  else
160  {
161  $https = '://';
162  }
163 
164  /*
165  * Since we are assigning the URI from the server variables, we first need
166  * to determine if we are running on apache or IIS. If PHP_SELF and REQUEST_URI
167  * are present, we will assume we are running on apache.
168  */
169 
170  if (!empty($_SERVER['PHP_SELF']) && !empty($_SERVER['REQUEST_URI']))
171  {
172  // To build the entire URI we need to prepend the protocol, and the http host
173  // to the URI string.
174  $theURI = 'http' . $https . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
175  }
176  else
177  {
178  /*
179  * Since we do not have REQUEST_URI to work with, we will assume we are
180  * running on IIS and will therefore need to work some magic with the SCRIPT_NAME and
181  * QUERY_STRING environment variables.
182  *
183  * IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable... thanks, MS
184  */
185  $theURI = 'http' . $https . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
186 
187  // If the query string exists append it to the URI string
188  if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING']))
189  {
190  $theURI .= '?' . $_SERVER['QUERY_STRING'];
191  }
192  }
193 
194  // Extra cleanup to remove invalid chars in the URL to prevent injections through the Host header
195  $theURI = str_replace(array("'", '"', '<', '>'), array("%27", "%22", "%3C", "%3E"), $theURI);
196  }
197  else
198  {
199  // We were given a URI
200  $theURI = $uri;
201  }
202 
203  self::$instances[$uri] = new JUri($theURI);
204  }
205 
206  return self::$instances[$uri];
207  }
208 
209  /**
210  * Returns the base URI for the request.
211  *
212  * @param boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
213  *
214  * @return string The base URI string
215  *
216  * @since 11.1
217  */
218  public static function base($pathonly = false)
219  {
220  // Get the base request path.
221  if (empty(self::$base))
222  {
223  $config = JFactory::getConfig();
224  $live_site = $config->get('live_site');
225 
226  if (trim($live_site) != '')
227  {
228  $uri = self::getInstance($live_site);
229  self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
230  self::$base['path'] = rtrim($uri->toString(array('path')), '/\\');
231 
232  if (defined('JPATH_BASE') && defined('JPATH_ADMINISTRATOR'))
233  {
234  if (JPATH_BASE == JPATH_ADMINISTRATOR)
235  {
236  self::$base['path'] .= '/administrator';
237  }
238  }
239  }
240  else
241  {
242  $uri = self::getInstance();
243  self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
244 
245  if (strpos(php_sapi_name(), 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI']))
246  {
247  // PHP-CGI on Apache with "cgi.fix_pathinfo = 0"
248 
249  // We shouldn't have user-supplied PATH_INFO in PHP_SELF in this case
250  // because PHP will not work with PATH_INFO at all.
251  $script_name = $_SERVER['PHP_SELF'];
252  }
253  else
254  {
255  // Others
256  $script_name = $_SERVER['SCRIPT_NAME'];
257  }
258 
259  self::$base['path'] = rtrim(dirname($script_name), '/\\');
260  }
261  }
262 
263  return $pathonly === false ? self::$base['prefix'] . self::$base['path'] . '/' : self::$base['path'];
264  }
265 
266  /**
267  * Returns the root URI for the request.
268  *
269  * @param boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
270  * @param string $path The path
271  *
272  * @return string The root URI string.
273  *
274  * @since 11.1
275  */
276  public static function root($pathonly = false, $path = null)
277  {
278  // Get the scheme
279  if (empty(self::$root))
280  {
281  $uri = self::getInstance(self::base());
282  self::$root['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
283  self::$root['path'] = rtrim($uri->toString(array('path')), '/\\');
284  }
285 
286  // Get the scheme
287  if (isset($path))
288  {
289  self::$root['path'] = $path;
290  }
291 
292  return $pathonly === false ? self::$root['prefix'] . self::$root['path'] . '/' : self::$root['path'];
293  }
294 
295  /**
296  * Returns the URL for the request, minus the query.
297  *
298  * @return string
299  *
300  * @since 11.1
301  */
302  public static function current()
303  {
304  // Get the current URL.
305  if (empty(self::$current))
306  {
307  $uri = self::getInstance();
308  self::$current = $uri->toString(array('scheme', 'host', 'port', 'path'));
309  }
310 
311  return self::$current;
312  }
313 
314  /**
315  * Method to reset class static members for testing and other various issues.
316  *
317  * @return void
318  *
319  * @since 11.1
320  */
321  public static function reset()
322  {
323  self::$instances = array();
324  self::$base = array();
325  self::$root = array();
326  self::$current = '';
327  }
328 
329  /**
330  * Parse a given URI and populate the class fields.
331  *
332  * @param string $uri The URI string to parse.
333  *
334  * @return boolean True on success.
335  *
336  * @since 11.1
337  */
338  public function parse($uri)
339  {
340  // Set the original URI to fall back on
341  $this->uri = $uri;
342 
343  /*
344  * Parse the URI and populate the object fields. If URI is parsed properly,
345  * set method return value to true.
346  */
347  $parts = JString::parse_url($uri);
348 
349  $retval = ($parts) ? true : false;
350 
351  // We need to replace &amp; with & for parse_str to work right...
352  if (isset($parts['query']) && strpos($parts['query'], '&amp;'))
353  {
354  $parts['query'] = str_replace('&amp;', '&', $parts['query']);
355  }
356 
357  $this->scheme = isset($parts['scheme']) ? $parts['scheme'] : null;
358  $this->user = isset($parts['user']) ? $parts['user'] : null;
359  $this->pass = isset($parts['pass']) ? $parts['pass'] : null;
360  $this->host = isset($parts['host']) ? $parts['host'] : null;
361  $this->port = isset($parts['port']) ? $parts['port'] : null;
362  $this->path = isset($parts['path']) ? $parts['path'] : null;
363  $this->query = isset($parts['query']) ? $parts['query'] : null;
364  $this->fragment = isset($parts['fragment']) ? $parts['fragment'] : null;
365 
366  // Parse the query
367  if (isset($parts['query']))
368  {
369  parse_str($parts['query'], $this->vars);
370  }
371 
372  return $retval;
373  }
374 
375  /**
376  * Returns full uri string.
377  *
378  * @param array $parts An array specifying the parts to render.
379  *
380  * @return string The rendered URI string.
381  *
382  * @since 11.1
383  */
384  public function toString(array $parts = array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'))
385  {
386  // Make sure the query is created
387  $query = $this->getQuery();
388 
389  $uri = '';
390  $uri .= in_array('scheme', $parts) ? (!empty($this->scheme) ? $this->scheme . '://' : '') : '';
391  $uri .= in_array('user', $parts) ? $this->user : '';
392  $uri .= in_array('pass', $parts) ? (!empty($this->pass) ? ':' : '') . $this->pass . (!empty($this->user) ? '@' : '') : '';
393  $uri .= in_array('host', $parts) ? $this->host : '';
394  $uri .= in_array('port', $parts) ? (!empty($this->port) ? ':' : '') . $this->port : '';
395  $uri .= in_array('path', $parts) ? $this->path : '';
396  $uri .= in_array('query', $parts) ? (!empty($query) ? '?' . $query : '') : '';
397  $uri .= in_array('fragment', $parts) ? (!empty($this->fragment) ? '#' . $this->fragment : '') : '';
398 
399  return $uri;
400  }
401 
402  /**
403  * Adds a query variable and value, replacing the value if it
404  * already exists and returning the old value.
405  *
406  * @param string $name Name of the query variable to set.
407  * @param string $value Value of the query variable.
408  *
409  * @return string Previous value for the query variable.
410  *
411  * @since 11.1
412  */
413  public function setVar($name, $value)
414  {
415  $tmp = isset($this->vars[$name]) ? $this->vars[$name] : null;
416 
417  $this->vars[$name] = $value;
418 
419  // Empty the query
420  $this->query = null;
421 
422  return $tmp;
423  }
424 
425  /**
426  * Checks if variable exists.
427  *
428  * @param string $name Name of the query variable to check.
429  *
430  * @return boolean True if the variable exists.
431  *
432  * @since 11.1
433  */
434  public function hasVar($name)
435  {
436  return array_key_exists($name, $this->vars);
437  }
438 
439  /**
440  * Returns a query variable by name.
441  *
442  * @param string $name Name of the query variable to get.
443  * @param string $default Default value to return if the variable is not set.
444  *
445  * @return array Query variables.
446  *
447  * @since 11.1
448  */
449  public function getVar($name, $default = null)
450  {
451  if (array_key_exists($name, $this->vars))
452  {
453  return $this->vars[$name];
454  }
455 
456  return $default;
457  }
458 
459  /**
460  * Removes an item from the query string variables if it exists.
461  *
462  * @param string $name Name of variable to remove.
463  *
464  * @return void
465  *
466  * @since 11.1
467  */
468  public function delVar($name)
469  {
470  if (array_key_exists($name, $this->vars))
471  {
472  unset($this->vars[$name]);
473 
474  // Empty the query
475  $this->query = null;
476  }
477  }
478 
479  /**
480  * Sets the query to a supplied string in format:
481  * foo=bar&x=y
482  *
483  * @param mixed $query The query string or array.
484  *
485  * @return void
486  *
487  * @since 11.1
488  */
489  public function setQuery($query)
490  {
491  if (is_array($query))
492  {
493  $this->vars = $query;
494  }
495  else
496  {
497  if (strpos($query, '&amp;') !== false)
498  {
499  $query = str_replace('&amp;', '&', $query);
500  }
501 
502  parse_str($query, $this->vars);
503  }
504 
505  // Empty the query
506  $this->query = null;
507  }
508 
509  /**
510  * Returns flat query string.
511  *
512  * @param boolean $toArray True to return the query as a key => value pair array.
513  *
514  * @return string Query string.
515  *
516  * @since 11.1
517  */
518  public function getQuery($toArray = false)
519  {
520  if ($toArray)
521  {
522  return $this->vars;
523  }
524 
525  // If the query is empty build it first
526  if (is_null($this->query))
527  {
528  $this->query = self::buildQuery($this->vars);
529  }
530 
531  return $this->query;
532  }
533 
534  /**
535  * Build a query from a array (reverse of the PHP parse_str()).
536  *
537  * @param array $params The array of key => value pairs to return as a query string.
538  *
539  * @return string The resulting query string.
540  *
541  * @see parse_str()
542  * @since 11.1
543  */
544  public static function buildQuery(array $params)
545  {
546  if (count($params) == 0)
547  {
548  return false;
549  }
550 
551  return urldecode(http_build_query($params, '', '&'));
552  }
553 
554  /**
555  * Get URI scheme (protocol)
556  * ie. http, https, ftp, etc...
557  *
558  * @return string The URI scheme.
559  *
560  * @since 11.1
561  */
562  public function getScheme()
563  {
564  return $this->scheme;
565  }
566 
567  /**
568  * Set URI scheme (protocol)
569  * ie. http, https, ftp, etc...
570  *
571  * @param string $scheme The URI scheme.
572  *
573  * @return void
574  *
575  * @since 11.1
576  */
577  public function setScheme($scheme)
578  {
579  $this->scheme = $scheme;
580  }
581 
582  /**
583  * Get URI username
584  * Returns the username, or null if no username was specified.
585  *
586  * @return string The URI username.
587  *
588  * @since 11.1
589  */
590  public function getUser()
591  {
592  return $this->user;
593  }
594 
595  /**
596  * Set URI username.
597  *
598  * @param string $user The URI username.
599  *
600  * @return void
601  *
602  * @since 11.1
603  */
604  public function setUser($user)
605  {
606  $this->user = $user;
607  }
608 
609  /**
610  * Get URI password
611  * Returns the password, or null if no password was specified.
612  *
613  * @return string The URI password.
614  *
615  * @since 11.1
616  */
617  public function getPass()
618  {
619  return $this->pass;
620  }
621 
622  /**
623  * Set URI password.
624  *
625  * @param string $pass The URI password.
626  *
627  * @return void
628  *
629  * @since 11.1
630  */
631  public function setPass($pass)
632  {
633  $this->pass = $pass;
634  }
635 
636  /**
637  * Get URI host
638  * Returns the hostname/ip or null if no hostname/ip was specified.
639  *
640  * @return string The URI host.
641  *
642  * @since 11.1
643  */
644  public function getHost()
645  {
646  return $this->host;
647  }
648 
649  /**
650  * Set URI host.
651  *
652  * @param string $host The URI host.
653  *
654  * @return void
655  *
656  * @since 11.1
657  */
658  public function setHost($host)
659  {
660  $this->host = $host;
661  }
662 
663  /**
664  * Get URI port
665  * Returns the port number, or null if no port was specified.
666  *
667  * @return integer The URI port number.
668  *
669  * @since 11.1
670  */
671  public function getPort()
672  {
673  return (isset($this->port)) ? $this->port : null;
674  }
675 
676  /**
677  * Set URI port.
678  *
679  * @param integer $port The URI port number.
680  *
681  * @return void
682  *
683  * @since 11.1
684  */
685  public function setPort($port)
686  {
687  $this->port = $port;
688  }
689 
690  /**
691  * Gets the URI path string.
692  *
693  * @return string The URI path string.
694  *
695  * @since 11.1
696  */
697  public function getPath()
698  {
699  return $this->path;
700  }
701 
702  /**
703  * Set the URI path string.
704  *
705  * @param string $path The URI path string.
706  *
707  * @return void
708  *
709  * @since 11.1
710  */
711  public function setPath($path)
712  {
713  $this->path = $this->_cleanPath($path);
714  }
715 
716  /**
717  * Get the URI archor string
718  * Everything after the "#".
719  *
720  * @return string The URI anchor string.
721  *
722  * @since 11.1
723  */
724  public function getFragment()
725  {
726  return $this->fragment;
727  }
728 
729  /**
730  * Set the URI anchor string
731  * everything after the "#".
732  *
733  * @param string $anchor The URI anchor string.
734  *
735  * @return void
736  *
737  * @since 11.1
738  */
739  public function setFragment($anchor)
740  {
741  $this->fragment = $anchor;
742  }
743 
744  /**
745  * Checks whether the current URI is using HTTPS.
746  *
747  * @return boolean True if using SSL via HTTPS.
748  *
749  * @since 11.1
750  */
751  public function isSSL()
752  {
753  return $this->getScheme() == 'https' ? true : false;
754  }
755 
756  /**
757  * Checks if the supplied URL is internal
758  *
759  * @param string $url The URL to check.
760  *
761  * @return boolean True if Internal.
762  *
763  * @since 11.1
764  */
765  public static function isInternal($url)
766  {
767  $uri = self::getInstance($url);
768  $base = $uri->toString(array('scheme', 'host', 'port', 'path'));
769  $host = $uri->toString(array('scheme', 'host', 'port'));
770 
771  if (stripos($base, self::base()) !== 0 && !empty($host))
772  {
773  return false;
774  }
775 
776  return true;
777  }
778 
779  /**
780  * Resolves //, ../ and ./ from a path and returns
781  * the result. Eg:
782  *
783  * /foo/bar/../boo.php => /foo/boo.php
784  * /foo/bar/../../boo.php => /boo.php
785  * /foo/bar/.././/boo.php => /foo/boo.php
786  *
787  * @param string $path The URI path to clean.
788  *
789  * @return string Cleaned and resolved URI path.
790  *
791  * @since 11.1
792  */
793  protected function _cleanPath($path)
794  {
795  $path = explode('/', preg_replace('#(/+)#', '/', $path));
796 
797  for ($i = 0, $n = count($path); $i < $n; $i++)
798  {
799  if ($path[$i] == '.' || $path[$i] == '..')
800  {
801  if (($path[$i] == '.') || ($path[$i] == '..' && $i == 1 && $path[0] == ''))
802  {
803  unset($path[$i]);
804  $path = array_values($path);
805  $i--;
806  $n--;
807  }
808  elseif ($path[$i] == '..' && ($i > 1 || ($i == 1 && $path[0] != '')))
809  {
810  unset($path[$i]);
811  unset($path[$i - 1]);
812  $path = array_values($path);
813  $i -= 2;
814  $n -= 2;
815  }
816  }
817  }
818 
819  return implode('/', $path);
820  }
821 }