/libraries/joomla/uri/uri.php

https://github.com/J2MTecnologia/joomla-3.x · PHP · 821 lines · 344 code · 81 blank · 396 comment · 55 complexity · 68591dd6d4bddfad0a047c116af66eba MD5 · raw file

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