source: sourcecode/system/core/Router.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 12.1 KB
Line 
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
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        /**
32         * Config class
33         *
34         * @var object
35         * @access public
36         */
37        var $config;
38        /**
39         * List of routes
40         *
41         * @var array
42         * @access public
43         */
44        var $routes                     = array();
45        /**
46         * List of error routes
47         *
48         * @var array
49         * @access public
50         */
51        var $error_routes       = array();
52        /**
53         * Current class name
54         *
55         * @var string
56         * @access public
57         */
58        var $class                      = '';
59        /**
60         * Current method name
61         *
62         * @var string
63         * @access public
64         */
65        var $method                     = 'index';
66        /**
67         * Sub-directory that contains the requested controller class
68         *
69         * @var string
70         * @access public
71         */
72        var $directory          = '';
73        /**
74         * Default controller (and method if specific)
75         *
76         * @var string
77         * @access public
78         */
79        var $default_controller;
80
81        /**
82         * Constructor
83         *
84         * Runs the route mapping function.
85         */
86        function __construct()
87        {
88                $this->config =& load_class('Config', 'core');
89                $this->uri =& load_class('URI', 'core');
90                log_message('debug', "Router Class Initialized");
91        }
92
93        // --------------------------------------------------------------------
94
95        /**
96         * Set the route mapping
97         *
98         * This function determines what should be served based on the URI request,
99         * as well as any "routes" that have been set in the routing config file.
100         *
101         * @access      private
102         * @return      void
103         */
104        function _set_routing()
105        {
106                // Are query strings enabled in the config file?  Normally CI doesn't utilize query strings
107                // since URI segments are more search-engine friendly, but they can optionally be used.
108                // If this feature is enabled, we will gather the directory/class/method a little differently
109                $segments = array();
110                if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
111                {
112                        if (isset($_GET[$this->config->item('directory_trigger')]))
113                        {
114                                $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')])));
115                                $segments[] = $this->fetch_directory();
116                        }
117
118                        if (isset($_GET[$this->config->item('controller_trigger')]))
119                        {
120                                $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
121                                $segments[] = $this->fetch_class();
122                        }
123
124                        if (isset($_GET[$this->config->item('function_trigger')]))
125                        {
126                                $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
127                                $segments[] = $this->fetch_method();
128                        }
129                }
130
131                // Load the routes.php file.
132                if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
133                {
134                        include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
135                }
136                elseif (is_file(APPPATH.'config/routes.php'))
137                {
138                        include(APPPATH.'config/routes.php');
139                }
140
141                $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
142                unset($route);
143
144                // Set the default controller so we can display it in the event
145                // the URI doesn't correlated to a valid controller.
146                $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);
147
148                // Were there any query string segments?  If so, we'll validate them and bail out since we're done.
149                if (count($segments) > 0)
150                {
151                        return $this->_validate_request($segments);
152                }
153
154                // Fetch the complete URI string
155                $this->uri->_fetch_uri_string();
156
157                // Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
158                if ($this->uri->uri_string == '')
159                {
160                        return $this->_set_default_controller();
161                }
162
163                // Do we need to remove the URL suffix?
164                $this->uri->_remove_url_suffix();
165
166                // Compile the segments into an array
167                $this->uri->_explode_segments();
168
169                // Parse any custom routing that may exist
170                $this->_parse_routes();
171
172                // Re-index the segment array so that it starts with 1 rather than 0
173                $this->uri->_reindex_segments();
174        }
175
176        // --------------------------------------------------------------------
177
178        /**
179         * Set the default controller
180         *
181         * @access      private
182         * @return      void
183         */
184        function _set_default_controller()
185        {
186                if ($this->default_controller === FALSE)
187                {
188                        show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
189                }
190                // Is the method being specified?
191                if (strpos($this->default_controller, '/') !== FALSE)
192                {
193                        $x = explode('/', $this->default_controller);
194
195                        $this->set_class($x[0]);
196                        $this->set_method($x[1]);
197                        $this->_set_request($x);
198                }
199                else
200                {
201                        $this->set_class($this->default_controller);
202                        $this->set_method('index');
203                        $this->_set_request(array($this->default_controller, 'index'));
204                }
205
206                // re-index the routed segments array so it starts with 1 rather than 0
207                $this->uri->_reindex_segments();
208
209                log_message('debug', "No URI present. Default controller set.");
210        }
211
212        // --------------------------------------------------------------------
213
214        /**
215         * Set the Route
216         *
217         * This function takes an array of URI segments as
218         * input, and sets the current class/method
219         *
220         * @access      private
221         * @param       array
222         * @param       bool
223         * @return      void
224         */
225        function _set_request($segments = array())
226        {
227                $segments = $this->_validate_request($segments);
228
229                if (count($segments) == 0)
230                {
231                        return $this->_set_default_controller();
232                }
233
234                $this->set_class($segments[0]);
235
236                if (isset($segments[1]))
237                {
238                        // A standard method request
239                        $this->set_method($segments[1]);
240                }
241                else
242                {
243                        // This lets the "routed" segment array identify that the default
244                        // index method is being used.
245                        $segments[1] = 'index';
246                }
247
248                // Update our "routed" segment array to contain the segments.
249                // Note: If there is no custom routing, this array will be
250                // identical to $this->uri->segments
251                $this->uri->rsegments = $segments;
252        }
253
254        // --------------------------------------------------------------------
255
256        /**
257         * Validates the supplied segments.  Attempts to determine the path to
258         * the controller.
259         *
260         * @access      private
261         * @param       array
262         * @return      array
263         */
264        function _validate_request($segments)
265        {
266                if (count($segments) == 0)
267                {
268                        return $segments;
269                }
270
271                // Does the requested controller exist in the root folder?
272                if (file_exists(APPPATH.'controllers/'.$segments[0].'.php'))
273                {
274                        return $segments;
275                }
276
277                // Is the controller in a sub-folder?
278                if (is_dir(APPPATH.'controllers/'.$segments[0]))
279                {
280                        // Set the directory and remove it from the segment array
281                        $this->set_directory($segments[0]);
282                        $segments = array_slice($segments, 1);
283
284                        if (count($segments) > 0)
285                        {
286                                // Does the requested controller exist in the sub-folder?
287                                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
288                                {
289                                        if ( ! empty($this->routes['404_override']))
290                                        {
291                                                $x = explode('/', $this->routes['404_override']);
292
293                                                $this->set_directory('');
294                                                $this->set_class($x[0]);
295                                                $this->set_method(isset($x[1]) ? $x[1] : 'index');
296
297                                                return $x;
298                                        }
299                                        else
300                                        {
301                                                show_404($this->fetch_directory().$segments[0]);
302                                        }
303                                }
304                        }
305                        else
306                        {
307                                // Is the method being specified in the route?
308                                if (strpos($this->default_controller, '/') !== FALSE)
309                                {
310                                        $x = explode('/', $this->default_controller);
311
312                                        $this->set_class($x[0]);
313                                        $this->set_method($x[1]);
314                                }
315                                else
316                                {
317                                        $this->set_class($this->default_controller);
318                                        $this->set_method('index');
319                                }
320
321                                // Does the default controller exist in the sub-folder?
322                                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
323                                {
324                                        $this->directory = '';
325                                        return array();
326                                }
327
328                        }
329
330                        return $segments;
331                }
332
333
334                // If we've gotten this far it means that the URI does not correlate to a valid
335                // controller class.  We will now see if there is an override
336                if ( ! empty($this->routes['404_override']))
337                {
338                        $x = explode('/', $this->routes['404_override']);
339
340                        $this->set_class($x[0]);
341                        $this->set_method(isset($x[1]) ? $x[1] : 'index');
342
343                        return $x;
344                }
345
346
347                // Nothing else to do at this point but show a 404
348                show_404($segments[0]);
349        }
350
351        // --------------------------------------------------------------------
352
353        /**
354         *  Parse Routes
355         *
356         * This function matches any routes that may exist in
357         * the config/routes.php file against the URI to
358         * determine if the class/method need to be remapped.
359         *
360         * @access      private
361         * @return      void
362         */
363        function _parse_routes()
364        {
365                // Turn the segment array into a URI string
366                $uri = implode('/', $this->uri->segments);
367
368                // Is there a literal match?  If so we're done
369                if (isset($this->routes[$uri]))
370                {
371                        return $this->_set_request(explode('/', $this->routes[$uri]));
372                }
373
374                // Loop through the route array looking for wild-cards
375                foreach ($this->routes as $key => $val)
376                {
377                        // Convert wild-cards to RegEx
378                        $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
379
380                        // Does the RegEx match?
381                        if (preg_match('#^'.$key.'$#', $uri))
382                        {
383                                // Do we have a back-reference?
384                                if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
385                                {
386                                        $val = preg_replace('#^'.$key.'$#', $val, $uri);
387                                }
388
389                                return $this->_set_request(explode('/', $val));
390                        }
391                }
392
393                // If we got this far it means we didn't encounter a
394                // matching route so we'll set the site default route
395                $this->_set_request($this->uri->segments);
396        }
397
398        // --------------------------------------------------------------------
399
400        /**
401         * Set the class name
402         *
403         * @access      public
404         * @param       string
405         * @return      void
406         */
407        function set_class($class)
408        {
409                $this->class = str_replace(array('/', '.'), '', $class);
410        }
411
412        // --------------------------------------------------------------------
413
414        /**
415         * Fetch the current class
416         *
417         * @access      public
418         * @return      string
419         */
420        function fetch_class()
421        {
422                return $this->class;
423        }
424
425        // --------------------------------------------------------------------
426
427        /**
428         *  Set the method name
429         *
430         * @access      public
431         * @param       string
432         * @return      void
433         */
434        function set_method($method)
435        {
436                $this->method = $method;
437        }
438
439        // --------------------------------------------------------------------
440
441        /**
442         *  Fetch the current method
443         *
444         * @access      public
445         * @return      string
446         */
447        function fetch_method()
448        {
449                if ($this->method == $this->fetch_class())
450                {
451                        return 'index';
452                }
453
454                return $this->method;
455        }
456
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 = str_replace(array('/', '.'), '', $dir).'/';
469        }
470
471        // --------------------------------------------------------------------
472
473        /**
474         *  Fetch the sub-directory (if any) that contains the requested controller class
475         *
476         * @access      public
477         * @return      string
478         */
479        function fetch_directory()
480        {
481                return $this->directory;
482        }
483
484        // --------------------------------------------------------------------
485
486        /**
487         *  Set the controller overrides
488         *
489         * @access      public
490         * @param       array
491         * @return      null
492         */
493        function _set_overrides($routing)
494        {
495                if ( ! is_array($routing))
496                {
497                        return;
498                }
499
500                if (isset($routing['directory']))
501                {
502                        $this->set_directory($routing['directory']);
503                }
504
505                if (isset($routing['controller']) AND $routing['controller'] != '')
506                {
507                        $this->set_class($routing['controller']);
508                }
509
510                if (isset($routing['function']))
511                {
512                        $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function'];
513                        $this->set_method($routing['function']);
514                }
515        }
516
517
518}
519// END Router Class
520
521/* End of file Router.php */
522/* Location: ./system/core/Router.php */
Note: See TracBrowser for help on using the repository browser.