PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/system/codeigniter/system/core/URI.php

https://bitbucket.org/mbaily/tremain
PHP | 597 lines | 258 code | 78 blank | 261 comment | 47 complexity | c0649c1cae8d39323e7ca247e5774f64 MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.2.4 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc.
  10. * @license http://codeigniter.com/user_guide/license.html
  11. * @link http://codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * URI Class
  18. *
  19. * Parses URIs and determines routing
  20. *
  21. * @package CodeIgniter
  22. * @subpackage Libraries
  23. * @category URI
  24. * @author EllisLab Dev Team
  25. * @link http://codeigniter.com/user_guide/libraries/uri.html
  26. */
  27. class CI_URI {
  28. var $uri_string;
  29. var $keyval = array();
  30. var $segments = array();
  31. var $rsegments = array();
  32. /**
  33. * Constructor
  34. *
  35. * Simply globalizes the $RTR object. The front
  36. * loads the Router class early on so it's not available
  37. * normally as other classes are.
  38. *
  39. * @access public
  40. */
  41. function __construct()
  42. {
  43. $this->config =& load_class('Config', 'core');
  44. log_message('debug', "URI Class Initialized");
  45. }
  46. // --------------------------------------------------------------------
  47. /**
  48. * Get the URI String
  49. *
  50. * @access private
  51. * @return string
  52. */
  53. function _fetch_uri_string()
  54. {
  55. if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
  56. {
  57. // Let's try the REQUEST_URI first, this will work in most situations
  58. if ($uri = $this->_detect_uri())
  59. {
  60. $this->_set_uri_string($uri);
  61. return;
  62. }
  63. // Is there a PATH_INFO variable?
  64. // Note: some servers seem to have trouble with getenv() so we'll test it two ways
  65. $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
  66. if (trim($path, '/') != '' && $path != "/".SELF)
  67. {
  68. $this->_set_uri_string($path);
  69. return;
  70. }
  71. // No PATH_INFO?... What about QUERY_STRING?
  72. $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
  73. if (trim($path, '/') != '')
  74. {
  75. $this->_set_uri_string($path);
  76. return;
  77. }
  78. // As a last ditch effort lets try using the $_GET array
  79. if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
  80. {
  81. $this->_set_uri_string(key($_GET));
  82. return;
  83. }
  84. // We've exhausted all our options...
  85. $this->uri_string = '';
  86. return;
  87. }
  88. $uri = strtoupper($this->config->item('uri_protocol'));
  89. if ($uri == 'REQUEST_URI')
  90. {
  91. $this->_set_uri_string($this->_detect_uri());
  92. return;
  93. }
  94. $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
  95. $this->_set_uri_string($path);
  96. }
  97. // --------------------------------------------------------------------
  98. /**
  99. * Set the URI String
  100. *
  101. * @access public
  102. * @return string
  103. */
  104. function _set_uri_string($str)
  105. {
  106. // Filter out control characters
  107. $str = remove_invisible_characters($str, FALSE);
  108. // If the URI contains only a slash we'll kill it
  109. $this->uri_string = ($str == '/') ? '' : $str;
  110. }
  111. // --------------------------------------------------------------------
  112. /**
  113. * Detects the URI
  114. *
  115. * This function will detect the URI automatically and fix the query string
  116. * if necessary.
  117. *
  118. * @access private
  119. * @return string
  120. */
  121. protected function _detect_uri()
  122. {
  123. if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
  124. {
  125. return '';
  126. }
  127. $uri = $_SERVER['REQUEST_URI'];
  128. if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
  129. {
  130. $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
  131. }
  132. elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
  133. {
  134. $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
  135. }
  136. // This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
  137. // URI is found, and also fixes the QUERY_STRING server var and $_GET array.
  138. if (strncmp($uri, '?/', 2) === 0)
  139. {
  140. $uri = substr($uri, 2);
  141. }
  142. $parts = preg_split('#\?#i', $uri, 2);
  143. $uri = $parts[0];
  144. if (isset($parts[1]))
  145. {
  146. $_SERVER['QUERY_STRING'] = $parts[1];
  147. parse_str($_SERVER['QUERY_STRING'], $_GET);
  148. }
  149. else
  150. {
  151. $_SERVER['QUERY_STRING'] = '';
  152. $_GET = array();
  153. }
  154. if ($uri == '/' || empty($uri))
  155. {
  156. return '/';
  157. }
  158. $uri = parse_url($uri, PHP_URL_PATH);
  159. // Do some final cleaning of the URI and return it
  160. return str_replace(array('//', '../'), '/', trim($uri, '/'));
  161. }
  162. // --------------------------------------------------------------------
  163. /**
  164. * Filter segments for malicious characters
  165. *
  166. * @access private
  167. * @param string
  168. * @return string
  169. */
  170. function _filter_uri($str)
  171. {
  172. if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
  173. {
  174. // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
  175. // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
  176. if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
  177. {
  178. show_error('The URI you submitted has disallowed characters.', 400);
  179. }
  180. }
  181. // Convert programatic characters to entities
  182. $bad = array('$', '(', ')', '%28', '%29');
  183. $good = array('&#36;', '&#40;', '&#41;', '&#40;', '&#41;');
  184. return str_replace($bad, $good, $str);
  185. }
  186. // --------------------------------------------------------------------
  187. /**
  188. * Remove the suffix from the URL if needed
  189. *
  190. * @access private
  191. * @return void
  192. */
  193. function _remove_url_suffix()
  194. {
  195. if ($this->config->item('url_suffix') != "")
  196. {
  197. $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
  198. }
  199. }
  200. // --------------------------------------------------------------------
  201. /**
  202. * Explode the URI Segments. The individual segments will
  203. * be stored in the $this->segments array.
  204. *
  205. * @access private
  206. * @return void
  207. */
  208. function _explode_segments()
  209. {
  210. foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
  211. {
  212. // Filter segments for security
  213. $val = trim($this->_filter_uri($val));
  214. if ($val != '')
  215. {
  216. $this->segments[] = $val;
  217. }
  218. }
  219. }
  220. // --------------------------------------------------------------------
  221. /**
  222. * Re-index Segments
  223. *
  224. * This function re-indexes the $this->segment array so that it
  225. * starts at 1 rather than 0. Doing so makes it simpler to
  226. * use functions like $this->uri->segment(n) since there is
  227. * a 1:1 relationship between the segment array and the actual segments.
  228. *
  229. * @access private
  230. * @return void
  231. */
  232. function _reindex_segments()
  233. {
  234. array_unshift($this->segments, NULL);
  235. array_unshift($this->rsegments, NULL);
  236. unset($this->segments[0]);
  237. unset($this->rsegments[0]);
  238. }
  239. // --------------------------------------------------------------------
  240. /**
  241. * Fetch a URI Segment
  242. *
  243. * This function returns the URI segment based on the number provided.
  244. *
  245. * @access public
  246. * @param integer
  247. * @param bool
  248. * @return string
  249. */
  250. function segment($n, $no_result = FALSE)
  251. {
  252. return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
  253. }
  254. // --------------------------------------------------------------------
  255. /**
  256. * Fetch a URI "routed" Segment
  257. *
  258. * This function returns the re-routed URI segment (assuming routing rules are used)
  259. * based on the number provided. If there is no routing this function returns the
  260. * same result as $this->segment()
  261. *
  262. * @access public
  263. * @param integer
  264. * @param bool
  265. * @return string
  266. */
  267. function rsegment($n, $no_result = FALSE)
  268. {
  269. return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
  270. }
  271. // --------------------------------------------------------------------
  272. /**
  273. * Generate a key value pair from the URI string
  274. *
  275. * This function generates and associative array of URI data starting
  276. * at the supplied segment. For example, if this is your URI:
  277. *
  278. * example.com/user/search/name/joe/location/UK/gender/male
  279. *
  280. * You can use this function to generate an array with this prototype:
  281. *
  282. * array (
  283. * name => joe
  284. * location => UK
  285. * gender => male
  286. * )
  287. *
  288. * @access public
  289. * @param integer the starting segment number
  290. * @param array an array of default values
  291. * @return array
  292. */
  293. function uri_to_assoc($n = 3, $default = array())
  294. {
  295. return $this->_uri_to_assoc($n, $default, 'segment');
  296. }
  297. /**
  298. * Identical to above only it uses the re-routed segment array
  299. *
  300. */
  301. function ruri_to_assoc($n = 3, $default = array())
  302. {
  303. return $this->_uri_to_assoc($n, $default, 'rsegment');
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * Generate a key value pair from the URI string or Re-routed URI string
  308. *
  309. * @access private
  310. * @param integer the starting segment number
  311. * @param array an array of default values
  312. * @param string which array we should use
  313. * @return array
  314. */
  315. function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
  316. {
  317. if ($which == 'segment')
  318. {
  319. $total_segments = 'total_segments';
  320. $segment_array = 'segment_array';
  321. }
  322. else
  323. {
  324. $total_segments = 'total_rsegments';
  325. $segment_array = 'rsegment_array';
  326. }
  327. if ( ! is_numeric($n))
  328. {
  329. return $default;
  330. }
  331. if (isset($this->keyval[$n]))
  332. {
  333. return $this->keyval[$n];
  334. }
  335. if ($this->$total_segments() < $n)
  336. {
  337. if (count($default) == 0)
  338. {
  339. return array();
  340. }
  341. $retval = array();
  342. foreach ($default as $val)
  343. {
  344. $retval[$val] = FALSE;
  345. }
  346. return $retval;
  347. }
  348. $segments = array_slice($this->$segment_array(), ($n - 1));
  349. $i = 0;
  350. $lastval = '';
  351. $retval = array();
  352. foreach ($segments as $seg)
  353. {
  354. if ($i % 2)
  355. {
  356. $retval[$lastval] = $seg;
  357. }
  358. else
  359. {
  360. $retval[$seg] = FALSE;
  361. $lastval = $seg;
  362. }
  363. $i++;
  364. }
  365. if (count($default) > 0)
  366. {
  367. foreach ($default as $val)
  368. {
  369. if ( ! array_key_exists($val, $retval))
  370. {
  371. $retval[$val] = FALSE;
  372. }
  373. }
  374. }
  375. // Cache the array for reuse
  376. $this->keyval[$n] = $retval;
  377. return $retval;
  378. }
  379. // --------------------------------------------------------------------
  380. /**
  381. * Generate a URI string from an associative array
  382. *
  383. *
  384. * @access public
  385. * @param array an associative array of key/values
  386. * @return array
  387. */
  388. function assoc_to_uri($array)
  389. {
  390. $temp = array();
  391. foreach ((array)$array as $key => $val)
  392. {
  393. $temp[] = $key;
  394. $temp[] = $val;
  395. }
  396. return implode('/', $temp);
  397. }
  398. // --------------------------------------------------------------------
  399. /**
  400. * Fetch a URI Segment and add a trailing slash
  401. *
  402. * @access public
  403. * @param integer
  404. * @param string
  405. * @return string
  406. */
  407. function slash_segment($n, $where = 'trailing')
  408. {
  409. return $this->_slash_segment($n, $where, 'segment');
  410. }
  411. // --------------------------------------------------------------------
  412. /**
  413. * Fetch a URI Segment and add a trailing slash
  414. *
  415. * @access public
  416. * @param integer
  417. * @param string
  418. * @return string
  419. */
  420. function slash_rsegment($n, $where = 'trailing')
  421. {
  422. return $this->_slash_segment($n, $where, 'rsegment');
  423. }
  424. // --------------------------------------------------------------------
  425. /**
  426. * Fetch a URI Segment and add a trailing slash - helper function
  427. *
  428. * @access private
  429. * @param integer
  430. * @param string
  431. * @param string
  432. * @return string
  433. */
  434. function _slash_segment($n, $where = 'trailing', $which = 'segment')
  435. {
  436. $leading = '/';
  437. $trailing = '/';
  438. if ($where == 'trailing')
  439. {
  440. $leading = '';
  441. }
  442. elseif ($where == 'leading')
  443. {
  444. $trailing = '';
  445. }
  446. return $leading.$this->$which($n).$trailing;
  447. }
  448. // --------------------------------------------------------------------
  449. /**
  450. * Segment Array
  451. *
  452. * @access public
  453. * @return array
  454. */
  455. function segment_array()
  456. {
  457. return $this->segments;
  458. }
  459. // --------------------------------------------------------------------
  460. /**
  461. * Routed Segment Array
  462. *
  463. * @access public
  464. * @return array
  465. */
  466. function rsegment_array()
  467. {
  468. return $this->rsegments;
  469. }
  470. // --------------------------------------------------------------------
  471. /**
  472. * Total number of segments
  473. *
  474. * @access public
  475. * @return integer
  476. */
  477. function total_segments()
  478. {
  479. return count($this->segments);
  480. }
  481. // --------------------------------------------------------------------
  482. /**
  483. * Total number of routed segments
  484. *
  485. * @access public
  486. * @return integer
  487. */
  488. function total_rsegments()
  489. {
  490. return count($this->rsegments);
  491. }
  492. // --------------------------------------------------------------------
  493. /**
  494. * Fetch the entire URI string
  495. *
  496. * @access public
  497. * @return string
  498. */
  499. function uri_string()
  500. {
  501. return $this->uri_string;
  502. }
  503. // --------------------------------------------------------------------
  504. /**
  505. * Fetch the entire Re-routed URI string
  506. *
  507. * @access public
  508. * @return string
  509. */
  510. function ruri_string()
  511. {
  512. return '/'.implode('/', $this->rsegment_array()).'/';
  513. }
  514. }
  515. // END URI Class
  516. /* End of file URI.php */
  517. /* Location: ./system/core/URI.php */