Router.php

Go to the documentation of this file.
00001 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
00002 /**
00003  * CodeIgniter
00004  *
00005  * An open source application development framework for PHP 4.3.2 or newer
00006  *
00007  * @package             CodeIgniter
00008  * @author              ExpressionEngine Dev Team
00009  * @copyright   Copyright (c) 2006, EllisLab, Inc.
00010  * @license             http://codeigniter.com/user_guide/license.html
00011  * @link                http://codeigniter.com
00012  * @since               Version 1.0
00013  * @filesource
00014  */
00015 
00016 // ------------------------------------------------------------------------
00017 
00018 /**
00019  * Router Class
00020  *
00021  * Parses URIs and determines routing
00022  *
00023  * @package             CodeIgniter
00024  * @subpackage  Libraries
00025  * @author              ExpressionEngine Dev Team
00026  * @category    Libraries
00027  * @link                http://codeigniter.com/user_guide/general/routing.html
00028  */
00029 class CI_Router {
00030 
00031         var $config;    
00032         var $routes             = array();
00033         var $error_routes       = array();
00034         var $class                      = '';
00035         var $method                     = 'index';
00036         var $directory          = '';
00037         var $uri_protocol       = 'auto';
00038         var $default_controller;
00039         var $scaffolding_request = FALSE; // Must be set to FALSE
00040         
00041         /**
00042          * Constructor
00043          *
00044          * Runs the route mapping function.
00045          */
00046         function CI_Router()
00047         {
00048                 $this->config =& load_class('Config');
00049                 $this->uri =& load_class('URI');
00050                 $this->_set_routing();
00051                 log_message('debug', "Router Class Initialized");
00052         }
00053         
00054         // --------------------------------------------------------------------
00055         
00056         /**
00057          * Set the route mapping
00058          *
00059          * This function determines what should be served based on the URI request,
00060          * as well as any "routes" that have been set in the routing config file.
00061          *
00062          * @access      private
00063          * @return      void
00064          */
00065         function _set_routing()
00066         {               
00067                 // Are query strings enabled in the config file?
00068                 // If so, we're done since segment based URIs are not used with query strings.
00069                 if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
00070                 {
00071                         $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
00072 
00073                         if (isset($_GET[$this->config->item('function_trigger')]))
00074                         {
00075                                 $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
00076                         }
00077                         
00078                         return;
00079                 }
00080                 
00081                 // Load the routes.php file.
00082                 @include(APPPATH.'config/routes'.EXT);
00083                 $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
00084                 unset($route);
00085 
00086                 // Set the default controller so we can display it in the event
00087                 // the URI doesn't correlated to a valid controller.
00088                 $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);     
00089                 
00090                 // Fetch the complete URI string
00091                 $this->uri->_fetch_uri_string();
00092         
00093                 // Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
00094                 if ($this->uri->uri_string == '')
00095                 {
00096                         if ($this->default_controller === FALSE)
00097                         {
00098                                 show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
00099                         }
00100                 
00101                         $this->set_class($this->default_controller);
00102                         $this->set_method('index');
00103                         $this->_set_request(array($this->default_controller, 'index'));
00104                         
00105                         // re-index the routed segments array so it starts with 1 rather than 0
00106                         $this->uri->_reindex_segments();
00107                         
00108                         log_message('debug', "No URI present. Default controller set.");
00109                         return;
00110                 }
00111                 unset($this->routes['default_controller']);
00112                 
00113                 // Do we need to remove the URL suffix?
00114                 $this->uri->_remove_url_suffix();
00115                 
00116                 // Compile the segments into an array
00117                 $this->uri->_explode_segments();
00118                 
00119                 // Parse any custom routing that may exist
00120                 $this->_parse_routes();         
00121                 
00122                 // Re-index the segment array so that it starts with 1 rather than 0
00123                 $this->uri->_reindex_segments();
00124         }
00125         
00126         // --------------------------------------------------------------------
00127         
00128         /**
00129          * Set the Route
00130          *
00131          * This function takes an array of URI segments as
00132          * input, and sets the current class/method
00133          *
00134          * @access      private
00135          * @param       array
00136          * @param       bool
00137          * @return      void
00138          */
00139         function _set_request($segments = array())
00140         {       
00141                 $segments = $this->_validate_request($segments);
00142                 
00143                 if (count($segments) == 0)
00144                 {
00145                         return;
00146                 }
00147                                                 
00148                 $this->set_class($segments[0]);
00149                 
00150                 if (isset($segments[1]))
00151                 {
00152                         // A scaffolding request. No funny business with the URL
00153                         if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
00154                         {
00155                                 $this->scaffolding_request = TRUE;
00156                                 unset($this->routes['scaffolding_trigger']);
00157                         }
00158                         else
00159                         {
00160                                 // A standard method request
00161                                 $this->set_method($segments[1]);
00162                         }
00163                 }
00164                 else
00165                 {
00166                         // This lets the "routed" segment array identify that the default
00167                         // index method is being used.
00168                         $segments[1] = 'index';
00169                 }
00170                 
00171                 // Update our "routed" segment array to contain the segments.
00172                 // Note: If there is no custom routing, this array will be
00173                 // identical to $this->uri->segments
00174                 $this->uri->rsegments = $segments;
00175         }
00176         
00177         // --------------------------------------------------------------------
00178         
00179         /**
00180          * Validates the supplied segments.  Attempts to determine the path to
00181          * the controller.
00182          *
00183          * @access      private
00184          * @param       array
00185          * @return      array
00186          */     
00187         function _validate_request($segments)
00188         {
00189                 // Does the requested controller exist in the root folder?
00190                 if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
00191                 {
00192                         return $segments;
00193                 }
00194 
00195                 // Is the controller in a sub-folder?
00196                 if (is_dir(APPPATH.'controllers/'.$segments[0]))
00197                 {               
00198                         // Set the directory and remove it from the segment array
00199                         $this->set_directory($segments[0]);
00200                         $segments = array_slice($segments, 1);
00201                         
00202                         if (count($segments) > 0)
00203                         {
00204                                 // Does the requested controller exist in the sub-folder?
00205                                 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
00206                                 {
00207                                         show_404($this->fetch_directory().$segments[0]);
00208                                 }
00209                         }
00210                         else
00211                         {
00212                                 $this->set_class($this->default_controller);
00213                                 $this->set_method('index');
00214                         
00215                                 // Does the default controller exist in the sub-folder?
00216                                 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
00217                                 {
00218                                         $this->directory = '';
00219                                         return array();
00220                                 }
00221                         
00222                         }
00223 
00224                         return $segments;
00225                 }
00226 
00227                 // Can't find the requested controller...
00228                 show_404($segments[0]);
00229         }
00230 
00231         // --------------------------------------------------------------------
00232 
00233         /**
00234          *  Parse Routes
00235          *
00236          * This function matches any routes that may exist in
00237          * the config/routes.php file against the URI to
00238          * determine if the class/method need to be remapped.
00239          *
00240          * @access      private
00241          * @return      void
00242          */
00243         function _parse_routes()
00244         {
00245                 // Do we even have any custom routing to deal with?
00246                 // There is a default scaffolding trigger, so we'll look just for 1
00247                 if (count($this->routes) == 1)
00248                 {
00249                         $this->_set_request($this->uri->segments);
00250                         return;
00251                 }
00252 
00253                 // Turn the segment array into a URI string
00254                 $uri = implode('/', $this->uri->segments);
00255 
00256                 // Is there a literal match?  If so we're done
00257                 if (isset($this->routes[$uri]))
00258                 {
00259                         $this->_set_request(explode('/', $this->routes[$uri]));         
00260                         return;
00261                 }
00262                                 
00263                 // Loop through the route array looking for wild-cards
00264                 foreach ($this->routes as $key => $val)
00265                 {                                               
00266                         // Convert wild-cards to RegEx
00267                         $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
00268                         
00269                         // Does the RegEx match?
00270                         if (preg_match('#^'.$key.'$#', $uri))
00271                         {                       
00272                                 // Do we have a back-reference?
00273                                 if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
00274                                 {
00275                                         $val = preg_replace('#^'.$key.'$#', $val, $uri);
00276                                 }
00277                         
00278                                 $this->_set_request(explode('/', $val));                
00279                                 return;
00280                         }
00281                 }
00282 
00283                 // If we got this far it means we didn't encounter a
00284                 // matching route so we'll set the site default route
00285                 $this->_set_request($this->uri->segments);
00286         }
00287 
00288         // --------------------------------------------------------------------
00289         
00290         /**
00291          * Set the class name
00292          *
00293          * @access      public
00294          * @param       string
00295          * @return      void
00296          */     
00297         function set_class($class)
00298         {
00299                 $this->class = $class;
00300         }
00301         
00302         // --------------------------------------------------------------------
00303         
00304         /**
00305          * Fetch the current class
00306          *
00307          * @access      public
00308          * @return      string
00309          */     
00310         function fetch_class()
00311         {
00312                 return $this->class;
00313         }
00314         
00315         // --------------------------------------------------------------------
00316         
00317         /**
00318          *  Set the method name
00319          *
00320          * @access      public
00321          * @param       string
00322          * @return      void
00323          */     
00324         function set_method($method)
00325         {
00326                 $this->method = $method;
00327         }
00328 
00329         // --------------------------------------------------------------------
00330         
00331         /**
00332          *  Fetch the current method
00333          *
00334          * @access      public
00335          * @return      string
00336          */     
00337         function fetch_method()
00338         {
00339                 if ($this->method == $this->fetch_class())
00340                 {
00341                         return 'index';
00342                 }
00343 
00344                 return $this->method;
00345         }
00346 
00347         // --------------------------------------------------------------------
00348         
00349         /**
00350          *  Set the directory name
00351          *
00352          * @access      public
00353          * @param       string
00354          * @return      void
00355          */     
00356         function set_directory($dir)
00357         {
00358                 $this->directory = $dir.'/';
00359         }
00360 
00361         // --------------------------------------------------------------------
00362         
00363         /**
00364          *  Fetch the sub-directory (if any) that contains the requested controller class
00365          *
00366          * @access      public
00367          * @return      string
00368          */     
00369         function fetch_directory()
00370         {
00371                 return $this->directory;
00372         }
00373 
00374 }
00375 // END Router Class
00376 
00377 /* End of file Router.php */
00378 /* Location: ./system/libraries/Router.php */