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