PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/joomla/environment/uri.php

http://github.com/joomla/joomla-platform
PHP | 813 lines | 346 code | 74 blank | 393 comment | 44 complexity | d0d12c3801a6b97a59793599d0b12927 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Environment
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 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 Environment
  19. * @since 11.1
  20. */
  21. class JURI
  22. {
  23. /**
  24. * @var string Original URI
  25. * @since 11.1
  26. */
  27. protected $_uri = null;
  28. /**
  29. * @var string Protocol
  30. * @since 11.1
  31. */
  32. protected $_scheme = null;
  33. /**
  34. * @var string Host
  35. * @since 11.1
  36. */
  37. protected $_host = null;
  38. /**
  39. * @var integer Port
  40. * @since 11.1
  41. */
  42. protected $_port = null;
  43. /**
  44. * @var string Username
  45. * @since 11.1
  46. */
  47. protected $_user = null;
  48. /**
  49. * @var string Password
  50. * @since 11.1
  51. */
  52. protected $_pass = null;
  53. /**
  54. * @var string Path
  55. * @since 11.1
  56. */
  57. protected $_path = null;
  58. /**
  59. * @var string Query
  60. * @since 11.1
  61. */
  62. protected $_query = null;
  63. /**
  64. * @var string Anchor
  65. * @since 11.1
  66. */
  67. protected $_fragment = null;
  68. /**
  69. * @var array Query variable hash
  70. * @since 11.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. }
  173. else
  174. {
  175. // We were given a URI
  176. $theURI = $uri;
  177. }
  178. // Create the new JURI instance
  179. self::$instances[$uri] = new JURI($theURI);
  180. }
  181. return self::$instances[$uri];
  182. }
  183. /**
  184. * Returns the base URI for the request.
  185. *
  186. * @param boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
  187. *
  188. * @return string The base URI string
  189. *
  190. * @since 11.1
  191. */
  192. public static function base($pathonly = false)
  193. {
  194. // Get the base request path.
  195. if (empty(self::$base))
  196. {
  197. $config = JFactory::getConfig();
  198. $live_site = $config->get('live_site');
  199. if (trim($live_site) != '')
  200. {
  201. $uri = self::getInstance($live_site);
  202. self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
  203. self::$base['path'] = rtrim($uri->toString(array('path')), '/\\');
  204. if (JPATH_BASE == JPATH_ADMINISTRATOR)
  205. {
  206. self::$base['path'] .= '/administrator';
  207. }
  208. }
  209. else
  210. {
  211. $uri = self::getInstance();
  212. self::$base['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
  213. if (strpos(php_sapi_name(), 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI']))
  214. {
  215. // PHP-CGI on Apache with "cgi.fix_pathinfo = 0"
  216. // We shouldn't have user-supplied PATH_INFO in PHP_SELF in this case
  217. // because PHP will not work with PATH_INFO at all.
  218. $script_name = $_SERVER['PHP_SELF'];
  219. }
  220. else
  221. {
  222. // Others
  223. $script_name = $_SERVER['SCRIPT_NAME'];
  224. }
  225. self::$base['path'] = rtrim(dirname($script_name), '/\\');
  226. }
  227. }
  228. return $pathonly === false ? self::$base['prefix'] . self::$base['path'] . '/' : self::$base['path'];
  229. }
  230. /**
  231. * Returns the root URI for the request.
  232. *
  233. * @param boolean $pathonly If false, prepend the scheme, host and port information. Default is false.
  234. * @param string $path The path
  235. *
  236. * @return string The root URI string.
  237. *
  238. * @since 11.1
  239. */
  240. public static function root($pathonly = false, $path = null)
  241. {
  242. // Get the scheme
  243. if (empty(self::$root))
  244. {
  245. $uri = self::getInstance(self::base());
  246. self::$root['prefix'] = $uri->toString(array('scheme', 'host', 'port'));
  247. self::$root['path'] = rtrim($uri->toString(array('path')), '/\\');
  248. }
  249. // Get the scheme
  250. if (isset($path))
  251. {
  252. self::$root['path'] = $path;
  253. }
  254. return $pathonly === false ? self::$root['prefix'] . self::$root['path'] . '/' : self::$root['path'];
  255. }
  256. /**
  257. * Returns the URL for the request, minus the query.
  258. *
  259. * @return string
  260. *
  261. * @since 11.1
  262. */
  263. public static function current()
  264. {
  265. // Get the current URL.
  266. if (empty(self::$current))
  267. {
  268. $uri = self::getInstance();
  269. self::$current = $uri->toString(array('scheme', 'host', 'port', 'path'));
  270. }
  271. return self::$current;
  272. }
  273. /**
  274. * Method to reset class static members for testing and other various issues.
  275. *
  276. * @return void
  277. *
  278. * @since 11.1
  279. */
  280. public static function reset()
  281. {
  282. self::$instances = array();
  283. self::$base = array();
  284. self::$root = array();
  285. self::$current = '';
  286. }
  287. /**
  288. * Parse a given URI and populate the class fields.
  289. *
  290. * @param string $uri The URI string to parse.
  291. *
  292. * @return boolean True on success.
  293. *
  294. * @since 11.1
  295. */
  296. public function parse($uri)
  297. {
  298. // Initialise variables
  299. $retval = false;
  300. // Set the original URI to fall back on
  301. $this->_uri = $uri;
  302. // Parse the URI and populate the object fields. If URI is parsed properly,
  303. // set method return value to true.
  304. if ($_parts = JString::parse_url($uri))
  305. {
  306. $retval = true;
  307. }
  308. // We need to replace &amp; with & for parse_str to work right...
  309. if (isset($_parts['query']) && strpos($_parts['query'], '&amp;'))
  310. {
  311. $_parts['query'] = str_replace('&amp;', '&', $_parts['query']);
  312. }
  313. $this->_scheme = isset($_parts['scheme']) ? $_parts['scheme'] : null;
  314. $this->_user = isset($_parts['user']) ? $_parts['user'] : null;
  315. $this->_pass = isset($_parts['pass']) ? $_parts['pass'] : null;
  316. $this->_host = isset($_parts['host']) ? $_parts['host'] : null;
  317. $this->_port = isset($_parts['port']) ? $_parts['port'] : null;
  318. $this->_path = isset($_parts['path']) ? $_parts['path'] : null;
  319. $this->_query = isset($_parts['query']) ? $_parts['query'] : null;
  320. $this->_fragment = isset($_parts['fragment']) ? $_parts['fragment'] : null;
  321. // Parse the query
  322. if (isset($_parts['query']))
  323. {
  324. parse_str($_parts['query'], $this->_vars);
  325. }
  326. return $retval;
  327. }
  328. /**
  329. * Returns full uri string.
  330. *
  331. * @param array $parts An array specifying the parts to render.
  332. *
  333. * @return string The rendered URI string.
  334. *
  335. * @since 11.1
  336. */
  337. public function toString(array $parts = array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'))
  338. {
  339. // Make sure the query is created
  340. $query = $this->getQuery();
  341. $uri = '';
  342. $uri .= in_array('scheme', $parts) ? (!empty($this->_scheme) ? $this->_scheme . '://' : '') : '';
  343. $uri .= in_array('user', $parts) ? $this->_user : '';
  344. $uri .= in_array('pass', $parts) ? (!empty($this->_pass) ? ':' : '') . $this->_pass . (!empty($this->_user) ? '@' : '') : '';
  345. $uri .= in_array('host', $parts) ? $this->_host : '';
  346. $uri .= in_array('port', $parts) ? (!empty($this->_port) ? ':' : '') . $this->_port : '';
  347. $uri .= in_array('path', $parts) ? $this->_path : '';
  348. $uri .= in_array('query', $parts) ? (!empty($query) ? '?' . $query : '') : '';
  349. $uri .= in_array('fragment', $parts) ? (!empty($this->_fragment) ? '#' . $this->_fragment : '') : '';
  350. return $uri;
  351. }
  352. /**
  353. * Adds a query variable and value, replacing the value if it
  354. * already exists and returning the old value.
  355. *
  356. * @param string $name Name of the query variable to set.
  357. * @param string $value Value of the query variable.
  358. *
  359. * @return string Previous value for the query variable.
  360. *
  361. * @since 11.1
  362. */
  363. public function setVar($name, $value)
  364. {
  365. $tmp = @$this->_vars[$name];
  366. $this->_vars[$name] = $value;
  367. // Empty the query
  368. $this->_query = null;
  369. return $tmp;
  370. }
  371. /**
  372. * Checks if variable exists.
  373. *
  374. * @param string $name Name of the query variable to check.
  375. *
  376. * @return boolean True if the variable exists.
  377. *
  378. * @since 11.1
  379. */
  380. public function hasVar($name)
  381. {
  382. return array_key_exists($name, $this->_vars);
  383. }
  384. /**
  385. * Returns a query variable by name.
  386. *
  387. * @param string $name Name of the query variable to get.
  388. * @param string $default Default value to return if the variable is not set.
  389. *
  390. * @return array Query variables.
  391. *
  392. * @since 11.1
  393. */
  394. public function getVar($name, $default = null)
  395. {
  396. if (array_key_exists($name, $this->_vars))
  397. {
  398. return $this->_vars[$name];
  399. }
  400. return $default;
  401. }
  402. /**
  403. * Removes an item from the query string variables if it exists.
  404. *
  405. * @param string $name Name of variable to remove.
  406. *
  407. * @return void
  408. *
  409. * @since 11.1
  410. */
  411. public function delVar($name)
  412. {
  413. if (array_key_exists($name, $this->_vars))
  414. {
  415. unset($this->_vars[$name]);
  416. // Empty the query
  417. $this->_query = null;
  418. }
  419. }
  420. /**
  421. * Sets the query to a supplied string in format:
  422. * foo=bar&x=y
  423. *
  424. * @param mixed $query The query string or array.
  425. *
  426. * @return void
  427. *
  428. * @since 11.1
  429. */
  430. public function setQuery($query)
  431. {
  432. if (is_array($query))
  433. {
  434. $this->_vars = $query;
  435. }
  436. else
  437. {
  438. if (strpos($query, '&amp;') !== false)
  439. {
  440. $query = str_replace('&amp;', '&', $query);
  441. }
  442. parse_str($query, $this->_vars);
  443. }
  444. // Empty the query
  445. $this->_query = null;
  446. }
  447. /**
  448. * Returns flat query string.
  449. *
  450. * @param boolean $toArray True to return the query as a key => value pair array.
  451. *
  452. * @return string Query string.
  453. *
  454. * @since 11.1
  455. */
  456. public function getQuery($toArray = false)
  457. {
  458. if ($toArray)
  459. {
  460. return $this->_vars;
  461. }
  462. // If the query is empty build it first
  463. if (is_null($this->_query))
  464. {
  465. $this->_query = self::buildQuery($this->_vars);
  466. }
  467. return $this->_query;
  468. }
  469. /**
  470. * Build a query from a array (reverse of the PHP parse_str()).
  471. *
  472. * @param array $params The array of key => value pairs to return as a query string.
  473. *
  474. * @return string The resulting query string.
  475. *
  476. * @see parse_str()
  477. * @since 11.1
  478. */
  479. public static function buildQuery(array $params)
  480. {
  481. if (count($params) == 0)
  482. {
  483. return false;
  484. }
  485. return urldecode(http_build_query($params, '', '&'));
  486. }
  487. /**
  488. * Get URI scheme (protocol)
  489. * ie. http, https, ftp, etc...
  490. *
  491. * @return string The URI scheme.
  492. *
  493. * @since 11.1
  494. */
  495. public function getScheme()
  496. {
  497. return $this->_scheme;
  498. }
  499. /**
  500. * Set URI scheme (protocol)
  501. * ie. http, https, ftp, etc...
  502. *
  503. * @param string $scheme The URI scheme.
  504. *
  505. * @return void
  506. *
  507. * @since 11.1
  508. */
  509. public function setScheme($scheme)
  510. {
  511. $this->_scheme = $scheme;
  512. }
  513. /**
  514. * Get URI username
  515. * Returns the username, or null if no username was specified.
  516. *
  517. * @return string The URI username.
  518. *
  519. * @since 11.1
  520. */
  521. public function getUser()
  522. {
  523. return $this->_user;
  524. }
  525. /**
  526. * Set URI username.
  527. *
  528. * @param string $user The URI username.
  529. *
  530. * @return void
  531. *
  532. * @since 11.1
  533. */
  534. public function setUser($user)
  535. {
  536. $this->_user = $user;
  537. }
  538. /**
  539. * Get URI password
  540. * Returns the password, or null if no password was specified.
  541. *
  542. * @return string The URI password.
  543. *
  544. * @since 11.1
  545. */
  546. public function getPass()
  547. {
  548. return $this->_pass;
  549. }
  550. /**
  551. * Set URI password.
  552. *
  553. * @param string $pass The URI password.
  554. *
  555. * @return void
  556. *
  557. * @since 11.1
  558. */
  559. public function setPass($pass)
  560. {
  561. $this->_pass = $pass;
  562. }
  563. /**
  564. * Get URI host
  565. * Returns the hostname/ip or null if no hostname/ip was specified.
  566. *
  567. * @return string The URI host.
  568. *
  569. * @since 11.1
  570. */
  571. public function getHost()
  572. {
  573. return $this->_host;
  574. }
  575. /**
  576. * Set URI host.
  577. *
  578. * @param string $host The URI host.
  579. *
  580. * @return void
  581. *
  582. * @since 11.1
  583. */
  584. public function setHost($host)
  585. {
  586. $this->_host = $host;
  587. }
  588. /**
  589. * Get URI port
  590. * Returns the port number, or null if no port was specified.
  591. *
  592. * @return integer The URI port number.
  593. *
  594. * @since 11.1
  595. */
  596. public function getPort()
  597. {
  598. return (isset($this->_port)) ? $this->_port : null;
  599. }
  600. /**
  601. * Set URI port.
  602. *
  603. * @param integer $port The URI port number.
  604. *
  605. * @return void
  606. *
  607. * @since 11.1
  608. */
  609. public function setPort($port)
  610. {
  611. $this->_port = $port;
  612. }
  613. /**
  614. * Gets the URI path string.
  615. *
  616. * @return string The URI path string.
  617. *
  618. * @since 11.1
  619. */
  620. public function getPath()
  621. {
  622. return $this->_path;
  623. }
  624. /**
  625. * Set the URI path string.
  626. *
  627. * @param string $path The URI path string.
  628. *
  629. * @return void
  630. *
  631. * @since 11.1
  632. */
  633. public function setPath($path)
  634. {
  635. $this->_path = $this->_cleanPath($path);
  636. }
  637. /**
  638. * Get the URI archor string
  639. * Everything after the "#".
  640. *
  641. * @return string The URI anchor string.
  642. *
  643. * @since 11.1
  644. */
  645. public function getFragment()
  646. {
  647. return $this->_fragment;
  648. }
  649. /**
  650. * Set the URI anchor string
  651. * everything after the "#".
  652. *
  653. * @param string $anchor The URI anchor string.
  654. *
  655. * @return void
  656. *
  657. * @since 11.1
  658. */
  659. public function setFragment($anchor)
  660. {
  661. $this->_fragment = $anchor;
  662. }
  663. /**
  664. * Checks whether the current URI is using HTTPS.
  665. *
  666. * @return boolean True if using SSL via HTTPS.
  667. *
  668. * @since 11.1
  669. */
  670. public function isSSL()
  671. {
  672. return $this->getScheme() == 'https' ? true : false;
  673. }
  674. /**
  675. * Checks if the supplied URL is internal
  676. *
  677. * @param string $url The URL to check.
  678. *
  679. * @return boolean True if Internal.
  680. *
  681. * @since 11.1
  682. */
  683. public static function isInternal($url)
  684. {
  685. $uri = self::getInstance($url);
  686. $base = $uri->toString(array('scheme', 'host', 'port', 'path'));
  687. $host = $uri->toString(array('scheme', 'host', 'port'));
  688. if (stripos($base, self::base()) !== 0 && !empty($host))
  689. {
  690. return false;
  691. }
  692. return true;
  693. }
  694. /**
  695. * Resolves //, ../ and ./ from a path and returns
  696. * the result. Eg:
  697. *
  698. * /foo/bar/../boo.php => /foo/boo.php
  699. * /foo/bar/../../boo.php => /boo.php
  700. * /foo/bar/.././/boo.php => /foo/boo.php
  701. *
  702. * @param string $path The URI path to clean.
  703. *
  704. * @return string Cleaned and resolved URI path.
  705. *
  706. * @since 11.1
  707. */
  708. protected function _cleanPath($path)
  709. {
  710. $path = explode('/', preg_replace('#(/+)#', '/', $path));
  711. for ($i = 0, $n = count($path); $i < $n; $i++)
  712. {
  713. if ($path[$i] == '.' or $path[$i] == '..')
  714. {
  715. if (($path[$i] == '.') or ($path[$i] == '..' and $i == 1 and $path[0] == ''))
  716. {
  717. unset($path[$i]);
  718. $path = array_values($path);
  719. $i--;
  720. $n--;
  721. }
  722. elseif ($path[$i] == '..' and ($i > 1 or ($i == 1 and $path[0] != '')))
  723. {
  724. unset($path[$i]);
  725. unset($path[$i - 1]);
  726. $path = array_values($path);
  727. $i -= 2;
  728. $n -= 2;
  729. }
  730. }
  731. }
  732. return implode('/', $path);
  733. }
  734. }