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) 2008, 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                         // Turn the default route into an array.  We explode it in the event that
00102                         // the controller is located in a subfolder
00103                         $segments = $this->_validate_request(explode('/', $this->default_controller));
00104 
00105                         // Set the class and method
00106                         $this->set_class($segments[0]);
00107                         $this->set_method('index');
00108                         
00109                         // Assign the segments to the URI class
00110                         $this->uri->rsegments = $segments;
00111                         
00112                         // re-index the routed segments array so it starts with 1 rather than 0
00113                         $this->uri->_reindex_segments();
00114                         
00115                         log_message('debug', "No URI present. Default controller set.");
00116                         return;
00117                 }
00118                 unset($this->routes['default_controller']);
00119                 
00120                 // Do we need to remove the URL suffix?
00121                 $this->uri->_remove_url_suffix();
00122                 
00123                 // Compile the segments into an array
00124                 $this->uri->_explode_segments();
00125                 
00126                 // Parse any custom routing that may exist
00127                 $this->_parse_routes();         
00128                 
00129                 // Re-index the segment array so that it starts with 1 rather than 0
00130                 $this->uri->_reindex_segments();
00131         }
00132         
00133         // --------------------------------------------------------------------
00134         
00135         /**
00136          * Set the Route
00137          *
00138          * This function takes an array of URI segments as
00139          * input, and sets the current class/method
00140          *
00141          * @access      private
00142          * @param       array
00143          * @param       bool
00144          * @return      void
00145          */
00146         function _set_request($segments = array())
00147         {       
00148                 $segments = $this->_validate_request($segments);
00149                 
00150                 if (count($segments) == 0)
00151                 {
00152                         return;
00153                 }
00154                                                 
00155                 $this->set_class($segments[0]);
00156                 
00157                 if (isset($segments[1]))
00158                 {
00159                         // A scaffolding request. No funny business with the URL
00160                         if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
00161                         {
00162                                 $this->scaffolding_request = TRUE;
00163                                 unset($this->routes['scaffolding_trigger']);
00164                         }
00165                         else
00166                         {
00167                                 // A standard method request
00168                                 $this->set_method($segments[1]);
00169                         }
00170                 }
00171                 else
00172                 {
00173                         // This lets the "routed" segment array identify that the default
00174                         // index method is being used.
00175                         $segments[1] = 'index';
00176                 }
00177                 
00178                 // Update our "routed" segment array to contain the segments.
00179                 // Note: If there is no custom routing, this array will be
00180                 // identical to $this->uri->segments
00181                 $this->uri->rsegments = $segments;
00182         }
00183         
00184         // --------------------------------------------------------------------
00185         
00186         /**
00187          * Validates the supplied segments.  Attempts to determine the path to
00188          * the controller.
00189          *
00190          * @access      private
00191          * @param       array
00192          * @return      array
00193          */     
00194         function _validate_request($segments)
00195         {
00196                 // Does the requested controller exist in the root folder?
00197                 if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
00198                 {
00199                         return $segments;
00200                 }
00201 
00202                 // Is the controller in a sub-folder?
00203                 if (is_dir(APPPATH.'controllers/'.$segments[0]))
00204                 {               
00205                         // Set the directory and remove it from the segment array
00206                         $this->set_directory($segments[0]);
00207                         $segments = array_slice($segments, 1);
00208                         
00209                         if (count($segments) > 0)
00210                         {
00211                                 // Does the requested controller exist in the sub-folder?
00212                                 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
00213                                 {
00214                                         show_404($this->fetch_directory().$segments[0]);
00215                                 }
00216                         }
00217                         else
00218                         {
00219                                 $this->set_class($this->default_controller);
00220                                 $this->set_method('index');
00221                         
00222                                 // Does the default controller exist in the sub-folder?
00223                                 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
00224                                 {
00225                                         $this->directory = '';
00226                                         return array();
00227                                 }
00228                         
00229                         }
00230 
00231                         return $segments;
00232                 }
00233 
00234                 // Can't find the requested controller...
00235                 show_404($segments[0]);
00236         }
00237 
00238         // --------------------------------------------------------------------
00239 
00240         /**
00241          *  Parse Routes
00242          *
00243          * This function matches any routes that may exist in
00244          * the config/routes.php file against the URI to
00245          * determine if the class/method need to be remapped.
00246          *
00247          * @access      private
00248          * @return      void
00249          */
00250         function _parse_routes()
00251         {
00252                 // Do we even have any custom routing to deal with?
00253                 // There is a default scaffolding trigger, so we'll look just for 1
00254                 if (count($this->routes) == 1)
00255                 {
00256                         $this->_set_request($this->uri->segments);
00257                         return;
00258                 }
00259 
00260                 // Turn the segment array into a URI string
00261                 $uri = implode('/', $this->uri->segments);
00262 
00263                 // Is there a literal match?  If so we're done
00264                 if (isset($this->routes[$uri]))
00265                 {
00266                         $this->_set_request(explode('/', $this->routes[$uri]));         
00267                         return;
00268                 }
00269                                 
00270                 // Loop through the route array looking for wild-cards
00271                 foreach ($this->routes as $key => $val)
00272                 {                                               
00273                         // Convert wild-cards to RegEx
00274                         $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
00275                         
00276                         // Does the RegEx match?
00277                         if (preg_match('#^'.$key.'$#', $uri))
00278                         {                       
00279                                 // Do we have a back-reference?
00280                                 if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
00281                                 {
00282                                         $val = preg_replace('#^'.$key.'$#', $val, $uri);
00283                                 }
00284                         
00285                                 $this->_set_request(explode('/', $val));                
00286                                 return;
00287                         }
00288                 }
00289 
00290                 // If we got this far it means we didn't encounter a
00291                 // matching route so we'll set the site default route
00292                 $this->_set_request($this->uri->segments);
00293         }
00294 
00295         // --------------------------------------------------------------------
00296         
00297         /**
00298          * Set the class name
00299          *
00300          * @access      public
00301          * @param       string
00302          * @return      void
00303          */     
00304         function set_class($class)
00305         {
00306                 $this->class = $class;
00307         }
00308         
00309         // --------------------------------------------------------------------
00310         
00311         /**
00312          * Fetch the current class
00313          *
00314          * @access      public
00315          * @return      string
00316          */     
00317         function fetch_class()
00318         {
00319                 return $this->class;
00320         }
00321         
00322         // --------------------------------------------------------------------
00323         
00324         /**
00325          *  Set the method name
00326          *
00327          * @access      public
00328          * @param       string
00329          * @return      void
00330          */     
00331         function set_method($method)
00332         {
00333                 $this->method = $method;
00334         }
00335 
00336         // --------------------------------------------------------------------
00337         
00338         /**
00339          *  Fetch the current method
00340          *
00341          * @access      public
00342          * @return      string
00343          */     
00344         function fetch_method()
00345         {
00346                 if ($this->method == $this->fetch_class())
00347                 {
00348                         return 'index';
00349                 }
00350 
00351                 return $this->method;
00352         }
00353 
00354         // --------------------------------------------------------------------
00355         
00356         /**
00357          *  Set the directory name
00358          *
00359          * @access      public
00360          * @param       string
00361          * @return      void
00362          */     
00363         function set_directory($dir)
00364         {
00365                 $this->directory = $dir.'/';
00366         }
00367 
00368         // --------------------------------------------------------------------
00369         
00370         /**
00371          *  Fetch the sub-directory (if any) that contains the requested controller class
00372          *
00373          * @access      public
00374          * @return      string
00375          */     
00376         function fetch_directory()
00377         {
00378                 return $this->directory;
00379         }
00380 
00381 }
00382 // END Router Class
00383 
00384 /* End of file Router.php */
00385 /* Location: ./system/libraries/Router.php */