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

/Codeigniter/system/core/URI.php

https://github.com/bostonphp/Framework-Bakeoff-2011
PHP | 583 lines | 253 code | 75 blank | 255 comment | 55 complexity | 91972c541b96a7b187258e70644138c8 MD5 | raw file
Possible License(s): LGPL-2.1
  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.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author ExpressionEngine Dev Team
  9. * @copyright Copyright (c) 2008 - 2011, 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 ExpressionEngine Dev Team
  25. * @link http://codeigniter.com/user_guide/libraries/uri.html
  26. */
  27. class CI_URI {
  28. var $keyval = array();
  29. var $uri_string;
  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. // If the URL has a question mark then it's simplest to just
  58. // build the URI string from the zero index of the $_GET array.
  59. // This avoids having to deal with $_SERVER variables, which
  60. // can be unreliable in some environments
  61. if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
  62. {
  63. $this->uri_string = key($_GET);
  64. return;
  65. }
  66. // Is there a PATH_INFO variable?
  67. // Note: some servers seem to have trouble with getenv() so we'll test it two ways
  68. $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
  69. if (trim($path, '/') != '' && $path != "/".SELF)
  70. {
  71. $this->uri_string = $path;
  72. return;
  73. }
  74. // No PATH_INFO?... What about QUERY_STRING?
  75. $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
  76. if (trim($path, '/') != '')
  77. {
  78. $this->uri_string = $path;
  79. return;
  80. }
  81. // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
  82. $path = str_replace($_SERVER['SCRIPT_NAME'], '', (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO'));
  83. if (trim($path, '/') != '' && $path != "/".SELF)
  84. {
  85. // remove path and script information so we have good URI data
  86. $this->uri_string = $path;
  87. return;
  88. }
  89. // We've exhausted all our options...
  90. $this->uri_string = '';
  91. }
  92. else
  93. {
  94. $uri = strtoupper($this->config->item('uri_protocol'));
  95. if ($uri == 'REQUEST_URI')
  96. {
  97. $this->uri_string = $this->_parse_request_uri();
  98. return;
  99. }
  100. $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
  101. }
  102. // If the URI contains only a slash we'll kill it
  103. if ($this->uri_string == '/')
  104. {
  105. $this->uri_string = '';
  106. }
  107. }
  108. // --------------------------------------------------------------------
  109. /**
  110. * Parse the REQUEST_URI
  111. *
  112. * Due to the way REQUEST_URI works it usually contains path info
  113. * that makes it unusable as URI data. We'll trim off the unnecessary
  114. * data, hopefully arriving at a valid URI that we can use.
  115. *
  116. * @access private
  117. * @return string
  118. */
  119. function _parse_request_uri()
  120. {
  121. if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
  122. {
  123. return '';
  124. }
  125. $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
  126. if ($request_uri == '' OR $request_uri == SELF)
  127. {
  128. return '';
  129. }
  130. $fc_path = FCPATH.SELF;
  131. if (strpos($request_uri, '?') !== FALSE)
  132. {
  133. $fc_path .= '?';
  134. }
  135. $parsed_uri = explode("/", $request_uri);
  136. $i = 0;
  137. foreach(explode("/", $fc_path) as $segment)
  138. {
  139. if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i])
  140. {
  141. $i++;
  142. }
  143. }
  144. $parsed_uri = implode("/", array_slice($parsed_uri, $i));
  145. if ($parsed_uri != '')
  146. {
  147. $parsed_uri = '/'.$parsed_uri;
  148. }
  149. return $parsed_uri;
  150. }
  151. // --------------------------------------------------------------------
  152. /**
  153. * Filter segments for malicious characters
  154. *
  155. * @access private
  156. * @param string
  157. * @return string
  158. */
  159. function _filter_uri($str)
  160. {
  161. if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
  162. {
  163. // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
  164. // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
  165. if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
  166. {
  167. show_error('The URI you submitted has disallowed characters.', 400);
  168. }
  169. }
  170. // Convert programatic characters to entities
  171. $bad = array('$', '(', ')', '%28', '%29');
  172. $good = array('&#36;', '&#40;', '&#41;', '&#40;', '&#41;');
  173. return str_replace($bad, $good, $str);
  174. }
  175. // --------------------------------------------------------------------
  176. /**
  177. * Remove the suffix from the URL if needed
  178. *
  179. * @access private
  180. * @return void
  181. */
  182. function _remove_url_suffix()
  183. {
  184. if ($this->config->item('url_suffix') != "")
  185. {
  186. $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
  187. }
  188. }
  189. // --------------------------------------------------------------------
  190. /**
  191. * Explode the URI Segments. The individual segments will
  192. * be stored in the $this->segments array.
  193. *
  194. * @access private
  195. * @return void
  196. */
  197. function _explode_segments()
  198. {
  199. foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
  200. {
  201. // Filter segments for security
  202. $val = trim($this->_filter_uri($val));
  203. if ($val != '')
  204. {
  205. $this->segments[] = $val;
  206. }
  207. }
  208. }
  209. // --------------------------------------------------------------------
  210. /**
  211. * Re-index Segments
  212. *
  213. * This function re-indexes the $this->segment array so that it
  214. * starts at 1 rather than 0. Doing so makes it simpler to
  215. * use functions like $this->uri->segment(n) since there is
  216. * a 1:1 relationship between the segment array and the actual segments.
  217. *
  218. * @access private
  219. * @return void
  220. */
  221. function _reindex_segments()
  222. {
  223. array_unshift($this->segments, NULL);
  224. array_unshift($this->rsegments, NULL);
  225. unset($this->segments[0]);
  226. unset($this->rsegments[0]);
  227. }
  228. // --------------------------------------------------------------------
  229. /**
  230. * Fetch a URI Segment
  231. *
  232. * This function returns the URI segment based on the number provided.
  233. *
  234. * @access public
  235. * @param integer
  236. * @param bool
  237. * @return string
  238. */
  239. function segment($n, $no_result = FALSE)
  240. {
  241. return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
  242. }
  243. // --------------------------------------------------------------------
  244. /**
  245. * Fetch a URI "routed" Segment
  246. *
  247. * This function returns the re-routed URI segment (assuming routing rules are used)
  248. * based on the number provided. If there is no routing this function returns the
  249. * same result as $this->segment()
  250. *
  251. * @access public
  252. * @param integer
  253. * @param bool
  254. * @return string
  255. */
  256. function rsegment($n, $no_result = FALSE)
  257. {
  258. return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
  259. }
  260. // --------------------------------------------------------------------
  261. /**
  262. * Generate a key value pair from the URI string
  263. *
  264. * This function generates and associative array of URI data starting
  265. * at the supplied segment. For example, if this is your URI:
  266. *
  267. * example.com/user/search/name/joe/location/UK/gender/male
  268. *
  269. * You can use this function to generate an array with this prototype:
  270. *
  271. * array (
  272. * name => joe
  273. * location => UK
  274. * gender => male
  275. * )
  276. *
  277. * @access public
  278. * @param integer the starting segment number
  279. * @param array an array of default values
  280. * @return array
  281. */
  282. function uri_to_assoc($n = 3, $default = array())
  283. {
  284. return $this->_uri_to_assoc($n, $default, 'segment');
  285. }
  286. /**
  287. * Identical to above only it uses the re-routed segment array
  288. *
  289. */
  290. function ruri_to_assoc($n = 3, $default = array())
  291. {
  292. return $this->_uri_to_assoc($n, $default, 'rsegment');
  293. }
  294. // --------------------------------------------------------------------
  295. /**
  296. * Generate a key value pair from the URI string or Re-routed URI string
  297. *
  298. * @access private
  299. * @param integer the starting segment number
  300. * @param array an array of default values
  301. * @param string which array we should use
  302. * @return array
  303. */
  304. function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
  305. {
  306. if ($which == 'segment')
  307. {
  308. $total_segments = 'total_segments';
  309. $segment_array = 'segment_array';
  310. }
  311. else
  312. {
  313. $total_segments = 'total_rsegments';
  314. $segment_array = 'rsegment_array';
  315. }
  316. if ( ! is_numeric($n))
  317. {
  318. return $default;
  319. }
  320. if (isset($this->keyval[$n]))
  321. {
  322. return $this->keyval[$n];
  323. }
  324. if ($this->$total_segments() < $n)
  325. {
  326. if (count($default) == 0)
  327. {
  328. return array();
  329. }
  330. $retval = array();
  331. foreach ($default as $val)
  332. {
  333. $retval[$val] = FALSE;
  334. }
  335. return $retval;
  336. }
  337. $segments = array_slice($this->$segment_array(), ($n - 1));
  338. $i = 0;
  339. $lastval = '';
  340. $retval = array();
  341. foreach ($segments as $seg)
  342. {
  343. if ($i % 2)
  344. {
  345. $retval[$lastval] = $seg;
  346. }
  347. else
  348. {
  349. $retval[$seg] = FALSE;
  350. $lastval = $seg;
  351. }
  352. $i++;
  353. }
  354. if (count($default) > 0)
  355. {
  356. foreach ($default as $val)
  357. {
  358. if ( ! array_key_exists($val, $retval))
  359. {
  360. $retval[$val] = FALSE;
  361. }
  362. }
  363. }
  364. // Cache the array for reuse
  365. $this->keyval[$n] = $retval;
  366. return $retval;
  367. }
  368. // --------------------------------------------------------------------
  369. /**
  370. * Generate a URI string from an associative array
  371. *
  372. *
  373. * @access public
  374. * @param array an associative array of key/values
  375. * @return array
  376. */
  377. function assoc_to_uri($array)
  378. {
  379. $temp = array();
  380. foreach ((array)$array as $key => $val)
  381. {
  382. $temp[] = $key;
  383. $temp[] = $val;
  384. }
  385. return implode('/', $temp);
  386. }
  387. // --------------------------------------------------------------------
  388. /**
  389. * Fetch a URI Segment and add a trailing slash
  390. *
  391. * @access public
  392. * @param integer
  393. * @param string
  394. * @return string
  395. */
  396. function slash_segment($n, $where = 'trailing')
  397. {
  398. return $this->_slash_segment($n, $where, 'segment');
  399. }
  400. // --------------------------------------------------------------------
  401. /**
  402. * Fetch a URI Segment and add a trailing slash
  403. *
  404. * @access public
  405. * @param integer
  406. * @param string
  407. * @return string
  408. */
  409. function slash_rsegment($n, $where = 'trailing')
  410. {
  411. return $this->_slash_segment($n, $where, 'rsegment');
  412. }
  413. // --------------------------------------------------------------------
  414. /**
  415. * Fetch a URI Segment and add a trailing slash - helper function
  416. *
  417. * @access private
  418. * @param integer
  419. * @param string
  420. * @param string
  421. * @return string
  422. */
  423. function _slash_segment($n, $where = 'trailing', $which = 'segment')
  424. {
  425. $leading = '/';
  426. $trailing = '/';
  427. if ($where == 'trailing')
  428. {
  429. $leading = '';
  430. }
  431. elseif ($where == 'leading')
  432. {
  433. $trailing = '';
  434. }
  435. return $leading.$this->$which($n).$trailing;
  436. }
  437. // --------------------------------------------------------------------
  438. /**
  439. * Segment Array
  440. *
  441. * @access public
  442. * @return array
  443. */
  444. function segment_array()
  445. {
  446. return $this->segments;
  447. }
  448. // --------------------------------------------------------------------
  449. /**
  450. * Routed Segment Array
  451. *
  452. * @access public
  453. * @return array
  454. */
  455. function rsegment_array()
  456. {
  457. return $this->rsegments;
  458. }
  459. // --------------------------------------------------------------------
  460. /**
  461. * Total number of segments
  462. *
  463. * @access public
  464. * @return integer
  465. */
  466. function total_segments()
  467. {
  468. return count($this->segments);
  469. }
  470. // --------------------------------------------------------------------
  471. /**
  472. * Total number of routed segments
  473. *
  474. * @access public
  475. * @return integer
  476. */
  477. function total_rsegments()
  478. {
  479. return count($this->rsegments);
  480. }
  481. // --------------------------------------------------------------------
  482. /**
  483. * Fetch the entire URI string
  484. *
  485. * @access public
  486. * @return string
  487. */
  488. function uri_string()
  489. {
  490. return $this->uri_string;
  491. }
  492. // --------------------------------------------------------------------
  493. /**
  494. * Fetch the entire Re-routed URI string
  495. *
  496. * @access public
  497. * @return string
  498. */
  499. function ruri_string()
  500. {
  501. return '/'.implode('/', $this->rsegment_array()).'/';
  502. }
  503. }
  504. // END URI Class
  505. /* End of file URI.php */
  506. /* Location: ./system/core/URI.php */