PageRenderTime 90ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/environment/uri.php

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