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

/Modifications Since 08/www/events/system/libraries/Router.php

https://github.com/holsinger/openfloor
PHP | 562 lines | 271 code | 74 blank | 217 comment | 59 complexity | 95f8adcb644ba517190aa4b165139ee4 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 4.3.2 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author Rick Ellis
  9. * @copyright Copyright (c) 2006, EllisLab, Inc.
  10. * @license http://www.codeignitor.com/user_guide/license.html
  11. * @link http://www.codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * Router Class
  18. *
  19. * Parses URIs and determines routing
  20. *
  21. * @package CodeIgniter
  22. * @subpackage Libraries
  23. * @author Rick Ellis
  24. * @category Libraries
  25. * @link http://www.codeigniter.com/user_guide/general/routing.html
  26. */
  27. class CI_Router {
  28. var $config;
  29. var $uri_string = '';
  30. var $segments = array();
  31. var $rsegments = array();
  32. var $routes = array();
  33. var $error_routes = array();
  34. var $class = '';
  35. var $method = 'index';
  36. var $directory = '';
  37. var $uri_protocol = 'auto';
  38. var $default_controller;
  39. var $scaffolding_request = FALSE; // Must be set to FALSE
  40. /**
  41. * Constructor
  42. *
  43. * Runs the route mapping function.
  44. */
  45. function CI_Router()
  46. {
  47. $this->config =& load_class('Config');
  48. $this->_set_route_mapping();
  49. log_message('debug', "Router Class Initialized");
  50. }
  51. // --------------------------------------------------------------------
  52. /**
  53. * Set the route mapping
  54. *
  55. * This function determines what should be served based on the URI request,
  56. * as well as any "routes" that have been set in the routing config file.
  57. *
  58. * @access private
  59. * @return void
  60. */
  61. function _set_route_mapping()
  62. {
  63. // Are query strings enabled in the config file?
  64. // If so, we're done since segment based URIs are not used with query strings.
  65. if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
  66. {
  67. $this->set_class(trim($this->_filter_uri($_GET[$this->config->item('controller_trigger')])));
  68. if (isset($_GET[$this->config->item('function_trigger')]))
  69. {
  70. $this->set_method(trim($this->_filter_uri($_GET[$this->config->item('function_trigger')])));
  71. }
  72. return;
  73. }
  74. // Load the routes.php file.
  75. @include(APPPATH.'config/routes'.EXT);
  76. $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
  77. unset($route);
  78. // Set the default controller so we can display it in the event
  79. // the URI doesn't correlated to a valid controller.
  80. $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);
  81. // Fetch the complete URI string
  82. $this->uri_string = $this->_get_uri_string();
  83. // If the URI contains only a slash we'll kill it
  84. if ($this->uri_string == '/')
  85. {
  86. $this->uri_string = '';
  87. }
  88. // Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
  89. if ($this->uri_string == '')
  90. {
  91. if ($this->default_controller === FALSE)
  92. {
  93. show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
  94. }
  95. $this->set_class($this->default_controller);
  96. $this->set_method('index');
  97. log_message('debug', "No URI present. Default controller set.");
  98. return;
  99. }
  100. unset($this->routes['default_controller']);
  101. // Do we need to remove the suffix specified in the config file?
  102. if ($this->config->item('url_suffix') != "")
  103. {
  104. $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
  105. }
  106. // Explode the URI Segments. The individual segments will
  107. // be stored in the $this->segments array.
  108. foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
  109. {
  110. // Filter segments for security
  111. $val = trim($this->_filter_uri($val));
  112. if ($val != '')
  113. $this->segments[] = $val;
  114. }
  115. // Parse any custom routing that may exist
  116. $this->_parse_routes();
  117. // Re-index the segment array so that it starts with 1 rather than 0
  118. $this->_reindex_segments();
  119. }
  120. // --------------------------------------------------------------------
  121. /**
  122. * Compile Segments
  123. *
  124. * This function takes an array of URI segments as
  125. * input, and puts it into the $this->segments array.
  126. * It also sets the current class/method
  127. *
  128. * @access private
  129. * @param array
  130. * @param bool
  131. * @return void
  132. */
  133. function _compile_segments($segments = array())
  134. {
  135. $segments = $this->_validate_segments($segments);
  136. if (count($segments) == 0)
  137. {
  138. return;
  139. }
  140. $this->set_class($segments[0]);
  141. if (isset($segments[1]))
  142. {
  143. // A scaffolding request. No funny business with the URL
  144. if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
  145. {
  146. $this->scaffolding_request = TRUE;
  147. unset($this->routes['scaffolding_trigger']);
  148. }
  149. else
  150. {
  151. // A standard method request
  152. $this->set_method($segments[1]);
  153. }
  154. }
  155. // Update our "routed" segment array to contain the segments.
  156. // Note: If there is no custom routing, this array will be
  157. // identical to $this->segments
  158. $this->rsegments = $segments;
  159. }
  160. // --------------------------------------------------------------------
  161. /**
  162. * Validates the supplied segments. Attempts to determine the path to
  163. * the controller.
  164. *
  165. * @access private
  166. * @param array
  167. * @return array
  168. */
  169. function _validate_segments($segments)
  170. {
  171. // Does the requested controller exist in the root folder?
  172. if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
  173. {
  174. return $segments;
  175. }
  176. // Is the controller in a sub-folder?
  177. if (is_dir(APPPATH.'controllers/'.$segments[0]))
  178. {
  179. // Set the directory and remove it from the segment array
  180. $this->set_directory($segments[0]);
  181. $segments = array_slice($segments, 1);
  182. if (count($segments) > 0)
  183. {
  184. // Does the requested controller exist in the sub-folder?
  185. if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
  186. {
  187. show_404();
  188. }
  189. }
  190. else
  191. {
  192. $this->set_class($this->default_controller);
  193. $this->set_method('index');
  194. // Does the default controller exist in the sub-folder?
  195. if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
  196. {
  197. $this->directory = '';
  198. return array();
  199. }
  200. }
  201. return $segments;
  202. }
  203. // Can't find the requested controller...
  204. show_404();
  205. }
  206. // --------------------------------------------------------------------
  207. /**
  208. * Re-index Segments
  209. *
  210. * This function re-indexes the $this->segment array so that it
  211. * starts at 1 rather then 0. Doing so makes it simpler to
  212. * use functions like $this->uri->segment(n) since there is
  213. * a 1:1 relationship between the segment array and the actual segments.
  214. *
  215. * @access private
  216. * @return void
  217. */
  218. function _reindex_segments()
  219. {
  220. // Is the routed segment array different then the main segment array?
  221. $diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;
  222. $i = 1;
  223. foreach ($this->segments as $val)
  224. {
  225. $this->segments[$i++] = $val;
  226. }
  227. unset($this->segments[0]);
  228. if ($diff == FALSE)
  229. {
  230. $this->rsegments = $this->segments;
  231. }
  232. else
  233. {
  234. $i = 1;
  235. foreach ($this->rsegments as $val)
  236. {
  237. $this->rsegments[$i++] = $val;
  238. }
  239. unset($this->rsegments[0]);
  240. }
  241. }
  242. // --------------------------------------------------------------------
  243. /**
  244. * Get the URI String
  245. *
  246. * @access private
  247. * @return string
  248. */
  249. function _get_uri_string()
  250. {
  251. if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
  252. {
  253. // If the URL has a question mark then it's simplest to just
  254. // build the URI string from the zero index of the $_GET array.
  255. // This avoids having to deal with $_SERVER variables, which
  256. // can be unreliable in some environments
  257. if (is_array($_GET) AND count($_GET) == 1)
  258. {
  259. // Note: Due to a bug in current() that affects some versions
  260. // of PHP we can not pass function call directly into it
  261. $keys = array_keys($_GET);
  262. return current($keys);
  263. }
  264. // Is there a PATH_INFO variable?
  265. // Note: some servers seem to have trouble with getenv() so we'll test it two ways
  266. $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
  267. if ($path != '' AND $path != "/".SELF)
  268. {
  269. return $path;
  270. }
  271. // No PATH_INFO?... What about QUERY_STRING?
  272. $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
  273. if ($path != '')
  274. {
  275. return $path;
  276. }
  277. // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
  278. $path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');
  279. if ($path != '' AND $path != "/".SELF)
  280. {
  281. return $path;
  282. }
  283. // We've exhausted all our options...
  284. return '';
  285. }
  286. else
  287. {
  288. $uri = strtoupper($this->config->item('uri_protocol'));
  289. if ($uri == 'REQUEST_URI')
  290. {
  291. return $this->_parse_request_uri();
  292. }
  293. return (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
  294. }
  295. }
  296. // --------------------------------------------------------------------
  297. /**
  298. * Parse the REQUEST_URI
  299. *
  300. * Due to the way REQUEST_URI works it usually contains path info
  301. * that makes it unusable as URI data. We'll trim off the unnecessary
  302. * data, hopefully arriving at a valid URI that we can use.
  303. *
  304. * @access private
  305. * @return string
  306. */
  307. function _parse_request_uri()
  308. {
  309. if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
  310. {
  311. return '';
  312. }
  313. $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
  314. if ($request_uri == '' OR $request_uri == SELF)
  315. {
  316. return '';
  317. }
  318. $fc_path = FCPATH;
  319. if (strpos($request_uri, '?') !== FALSE)
  320. {
  321. $fc_path .= '?';
  322. }
  323. $parsed_uri = explode("/", $request_uri);
  324. $i = 0;
  325. foreach(explode("/", $fc_path) as $segment)
  326. {
  327. if (isset($parsed_uri[$i]) AND $segment == $parsed_uri[$i])
  328. {
  329. $i++;
  330. }
  331. }
  332. $parsed_uri = implode("/", array_slice($parsed_uri, $i));
  333. if ($parsed_uri != '')
  334. {
  335. $parsed_uri = '/'.$parsed_uri;
  336. }
  337. return $parsed_uri;
  338. }
  339. // --------------------------------------------------------------------
  340. /**
  341. * Filter segments for malicious characters
  342. *
  343. * @access private
  344. * @param string
  345. * @return string
  346. */
  347. function _filter_uri($str)
  348. {
  349. if ($this->config->item('permitted_uri_chars') != '')
  350. {
  351. if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
  352. {
  353. exit('The URI you submitted has disallowed characters.');
  354. }
  355. }
  356. return $str;
  357. }
  358. // --------------------------------------------------------------------
  359. /**
  360. * Parse Routes
  361. *
  362. * This function matches any routes that may exist in
  363. * the config/routes.php file against the URI to
  364. * determine if the class/method need to be remapped.
  365. *
  366. * @access private
  367. * @return void
  368. */
  369. function _parse_routes()
  370. {
  371. // Do we even have any custom routing to deal with?
  372. // There is a default scaffolding trigger, so we'll look just for 1
  373. if (count($this->routes) == 1)
  374. {
  375. $this->_compile_segments($this->segments);
  376. return;
  377. }
  378. // Turn the segment array into a URI string
  379. $uri = implode('/', $this->segments);
  380. $num = count($this->segments);
  381. // Is there a literal match? If so we're done
  382. if (isset($this->routes[$uri]))
  383. {
  384. $this->_compile_segments(explode('/', $this->routes[$uri]));
  385. return;
  386. }
  387. // Loop through the route array looking for wild-cards
  388. foreach (array_slice($this->routes, 1) as $key => $val)
  389. {
  390. // Convert wild-cards to RegEx
  391. $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
  392. // Does the RegEx match?
  393. if (preg_match('#^'.$key.'$#', $uri))
  394. {
  395. // Do we have a back-reference?
  396. if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
  397. {
  398. $val = preg_replace('#^'.$key.'$#', $val, $uri);
  399. }
  400. $this->_compile_segments(explode('/', $val));
  401. return;
  402. }
  403. }
  404. // If we got this far it means we didn't encounter a
  405. // matching route so we'll set the site default route
  406. $this->_compile_segments($this->segments);
  407. }
  408. // --------------------------------------------------------------------
  409. /**
  410. * Set the class name
  411. *
  412. * @access public
  413. * @param string
  414. * @return void
  415. */
  416. function set_class($class)
  417. {
  418. $this->class = $class;
  419. }
  420. // --------------------------------------------------------------------
  421. /**
  422. * Fetch the current class
  423. *
  424. * @access public
  425. * @return string
  426. */
  427. function fetch_class()
  428. {
  429. return $this->class;
  430. }
  431. // --------------------------------------------------------------------
  432. /**
  433. * Set the method name
  434. *
  435. * @access public
  436. * @param string
  437. * @return void
  438. */
  439. function set_method($method)
  440. {
  441. $this->method = $method;
  442. }
  443. // --------------------------------------------------------------------
  444. /**
  445. * Fetch the current method
  446. *
  447. * @access public
  448. * @return string
  449. */
  450. function fetch_method()
  451. {
  452. if ($this->method == $this->fetch_class())
  453. {
  454. return 'index';
  455. }
  456. return $this->method;
  457. }
  458. // --------------------------------------------------------------------
  459. /**
  460. * Set the directory name
  461. *
  462. * @access public
  463. * @param string
  464. * @return void
  465. */
  466. function set_directory($dir)
  467. {
  468. $this->directory = $dir.'/';
  469. }
  470. // --------------------------------------------------------------------
  471. /**
  472. * Fetch the sub-directory (if any) that contains the requested controller class
  473. *
  474. * @access public
  475. * @return string
  476. */
  477. function fetch_directory()
  478. {
  479. return $this->directory;
  480. }
  481. }
  482. // END Router Class
  483. ?>