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

/system/codeigniter/system/core/Router.php

https://bitbucket.org/mbaily/tremain
PHP | 460 lines | 217 code | 70 blank | 173 comment | 36 complexity | 7a952021d9b863ff08755d5fe145cf88 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. * Router Class
  18. *
  19. * Parses URIs and determines routing
  20. *
  21. * @package CodeIgniter
  22. * @subpackage Libraries
  23. * @author EllisLab Dev Team
  24. * @category Libraries
  25. * @link http://codeigniter.com/user_guide/general/routing.html
  26. */
  27. class CI_Router {
  28. var $config;
  29. var $routes = array();
  30. var $class = '';
  31. var $method = 'index';
  32. var $directory = '';
  33. var $default_controller;
  34. /**
  35. * Constructor
  36. *
  37. * Runs the route mapping function.
  38. */
  39. function __construct()
  40. {
  41. $this->config =& load_class('Config', 'core');
  42. $this->uri =& load_class('URI', 'core');
  43. log_message('debug', "Router Class Initialized");
  44. }
  45. // --------------------------------------------------------------------
  46. /**
  47. * Set the route mapping
  48. *
  49. * This function determines what should be served based on the URI request,
  50. * as well as any "routes" that have been set in the routing config file.
  51. *
  52. * @access private
  53. * @return void
  54. */
  55. function _set_routing()
  56. {
  57. // Are query strings enabled in the config file? Normally CI doesn't utilize query strings
  58. // since URI segments are more search-engine friendly, but they can optionally be used.
  59. // If this feature is enabled, we will gather the directory/class/method a little differently
  60. $segments = array();
  61. if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
  62. {
  63. if (isset($_GET[$this->config->item('directory_trigger')]))
  64. {
  65. $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')])));
  66. $segments[] = $this->fetch_directory();
  67. }
  68. if (isset($_GET[$this->config->item('controller_trigger')]))
  69. {
  70. $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
  71. $segments[] = $this->fetch_class();
  72. }
  73. if (isset($_GET[$this->config->item('function_trigger')]))
  74. {
  75. $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
  76. $segments[] = $this->fetch_method();
  77. }
  78. }
  79. // Load the routes.php file.
  80. @include(APPPATH.'config/routes.php');
  81. $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
  82. unset($route);
  83. // Set the default controller so we can display it in the event
  84. // the URI doesn't correlated to a valid controller.
  85. $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);
  86. // Were there any query string segments? If so, we'll validate them and bail out since we're done.
  87. if (count($segments) > 0)
  88. {
  89. return $this->_validate_request($segments);
  90. }
  91. // Fetch the complete URI string
  92. $this->uri->_fetch_uri_string();
  93. // Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
  94. if ($this->uri->uri_string == '')
  95. {
  96. return $this->_set_default_controller();
  97. }
  98. // Do we need to remove the URL suffix?
  99. $this->uri->_remove_url_suffix();
  100. // Compile the segments into an array
  101. $this->uri->_explode_segments();
  102. // Parse any custom routing that may exist
  103. $this->_parse_routes();
  104. // Re-index the segment array so that it starts with 1 rather than 0
  105. $this->uri->_reindex_segments();
  106. }
  107. // --------------------------------------------------------------------
  108. /**
  109. * Set the default controller
  110. *
  111. * @access private
  112. * @return void
  113. */
  114. function _set_default_controller()
  115. {
  116. if ($this->default_controller === FALSE)
  117. {
  118. show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
  119. }
  120. // Is the method being specified?
  121. if (strpos($this->default_controller, '/') !== FALSE)
  122. {
  123. $x = explode('/', $this->default_controller);
  124. $this->set_class($x[0]);
  125. $this->set_method($x[1]);
  126. $this->_set_request($x);
  127. }
  128. else
  129. {
  130. $this->set_class($this->default_controller);
  131. $this->set_method('index');
  132. $this->_set_request(array($this->default_controller, 'index'));
  133. }
  134. // re-index the routed segments array so it starts with 1 rather than 0
  135. $this->uri->_reindex_segments();
  136. log_message('debug', "No URI present. Default controller set.");
  137. }
  138. // --------------------------------------------------------------------
  139. /**
  140. * Set the Route
  141. *
  142. * This function takes an array of URI segments as
  143. * input, and sets the current class/method
  144. *
  145. * @access private
  146. * @param array
  147. * @param bool
  148. * @return void
  149. */
  150. function _set_request($segments = array())
  151. {
  152. $segments = $this->_validate_request($segments);
  153. if (count($segments) == 0)
  154. {
  155. return $this->_set_default_controller();
  156. }
  157. $this->set_class($segments[0]);
  158. if (isset($segments[1]))
  159. {
  160. // A standard method request
  161. $this->set_method($segments[1]);
  162. }
  163. else
  164. {
  165. // This lets the "routed" segment array identify that the default
  166. // index method is being used.
  167. $segments[1] = 'index';
  168. }
  169. // Update our "routed" segment array to contain the segments.
  170. // Note: If there is no custom routing, this array will be
  171. // identical to $this->uri->segments
  172. $this->uri->rsegments = $segments;
  173. }
  174. // --------------------------------------------------------------------
  175. /**
  176. * Validates the supplied segments. Attempts to determine the path to
  177. * the controller.
  178. *
  179. * @access private
  180. * @param array
  181. * @return array
  182. */
  183. function _validate_request($segments)
  184. {
  185. if (count($segments) == 0)
  186. {
  187. return $segments;
  188. }
  189. // Does the requested controller exist in the root folder?
  190. if (file_exists(APPPATH.'controllers/'.$segments[0].'.php'))
  191. {
  192. return $segments;
  193. }
  194. // Is the controller in a sub-folder?
  195. if (is_dir(APPPATH.'controllers/'.$segments[0]))
  196. {
  197. // Set the directory and remove it from the segment array
  198. $this->set_directory($segments[0]);
  199. $segments = array_slice($segments, 1);
  200. if (count($segments) > 0)
  201. {
  202. // Does the requested controller exist in the sub-folder?
  203. if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
  204. {
  205. show_404($this->fetch_directory().$segments[0]);
  206. }
  207. }
  208. else
  209. {
  210. // Is the method being specified in the route?
  211. if (strpos($this->default_controller, '/') !== FALSE)
  212. {
  213. $x = explode('/', $this->default_controller);
  214. $this->set_class($x[0]);
  215. $this->set_method($x[1]);
  216. }
  217. else
  218. {
  219. $this->set_class($this->default_controller);
  220. $this->set_method('index');
  221. }
  222. // Does the default controller exist in the sub-folder?
  223. if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
  224. {
  225. $this->directory = '';
  226. return array();
  227. }
  228. }
  229. return $segments;
  230. }
  231. // If we've gotten this far it means that the URI does not correlate to a valid
  232. // controller class. We will now see if there is an override
  233. if (isset($this->routes['404_override']) AND $this->routes['404_override'] != '')
  234. {
  235. if (strpos($this->routes['404_override'], '/') !== FALSE)
  236. {
  237. $x = explode('/', $this->routes['404_override']);
  238. $this->set_class($x[0]);
  239. $this->set_method($x[1]);
  240. return $x;
  241. }
  242. }
  243. // Nothing else to do at this point but show a 404
  244. show_404($segments[0]);
  245. }
  246. // --------------------------------------------------------------------
  247. /**
  248. * Parse Routes
  249. *
  250. * This function matches any routes that may exist in
  251. * the config/routes.php file against the URI to
  252. * determine if the class/method need to be remapped.
  253. *
  254. * @access private
  255. * @return void
  256. */
  257. function _parse_routes()
  258. {
  259. // Turn the segment array into a URI string
  260. $uri = implode('/', $this->uri->segments);
  261. // Is there a literal match? If so we're done
  262. if (isset($this->routes[$uri]))
  263. {
  264. return $this->_set_request(explode('/', $this->routes[$uri]));
  265. }
  266. // Loop through the route array looking for wild-cards
  267. foreach ($this->routes as $key => $val)
  268. {
  269. // Convert wild-cards to RegEx
  270. $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
  271. // Does the RegEx match?
  272. if (preg_match('#^'.$key.'$#', $uri))
  273. {
  274. // Do we have a back-reference?
  275. if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
  276. {
  277. $val = preg_replace('#^'.$key.'$#', $val, $uri);
  278. }
  279. return $this->_set_request(explode('/', $val));
  280. }
  281. }
  282. // If we got this far it means we didn't encounter a
  283. // matching route so we'll set the site default route
  284. $this->_set_request($this->uri->segments);
  285. }
  286. // --------------------------------------------------------------------
  287. /**
  288. * Set the class name
  289. *
  290. * @access public
  291. * @param string
  292. * @return void
  293. */
  294. function set_class($class)
  295. {
  296. $this->class = str_replace(array('/', '.'), '', $class);
  297. }
  298. // --------------------------------------------------------------------
  299. /**
  300. * Fetch the current class
  301. *
  302. * @access public
  303. * @return string
  304. */
  305. function fetch_class()
  306. {
  307. return $this->class;
  308. }
  309. // --------------------------------------------------------------------
  310. /**
  311. * Set the method name
  312. *
  313. * @access public
  314. * @param string
  315. * @return void
  316. */
  317. function set_method($method)
  318. {
  319. $this->method = $method;
  320. }
  321. // --------------------------------------------------------------------
  322. /**
  323. * Fetch the current method
  324. *
  325. * @access public
  326. * @return string
  327. */
  328. function fetch_method()
  329. {
  330. if ($this->method == $this->fetch_class())
  331. {
  332. return 'index';
  333. }
  334. return $this->method;
  335. }
  336. // --------------------------------------------------------------------
  337. /**
  338. * Set the directory name
  339. *
  340. * @access public
  341. * @param string
  342. * @return void
  343. */
  344. function set_directory($dir)
  345. {
  346. $this->directory = str_replace(array('/', '.'), '', $dir).'/';
  347. }
  348. // --------------------------------------------------------------------
  349. /**
  350. * Fetch the sub-directory (if any) that contains the requested controller class
  351. *
  352. * @access public
  353. * @return string
  354. */
  355. function fetch_directory()
  356. {
  357. return $this->directory;
  358. }
  359. // --------------------------------------------------------------------
  360. /**
  361. * Set the controller overrides
  362. *
  363. * @access public
  364. * @param array
  365. * @return null
  366. */
  367. function _set_overrides($routing)
  368. {
  369. if ( ! is_array($routing))
  370. {
  371. return;
  372. }
  373. if (isset($routing['directory']))
  374. {
  375. $this->set_directory($routing['directory']);
  376. }
  377. if (isset($routing['controller']) AND $routing['controller'] != '')
  378. {
  379. $this->set_class($routing['controller']);
  380. }
  381. if (isset($routing['function']))
  382. {
  383. $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function'];
  384. $this->set_method($routing['function']);
  385. }
  386. }
  387. }
  388. // END Router Class
  389. /* End of file Router.php */
  390. /* Location: ./system/core/Router.php */