converted to unix-style eol
[www-register-wizard.git] / libraries / Router.php
1 <?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  */
29 class 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                         }
100
101                         // Turn the default route into an array.  We explode it in the event that
102                         // the controller is located in a subfolder
103                         $segments = $this->_validate_request(explode('/', $this->default_controller));
104
105                         // Set the class and method
106                         $this->set_class($segments[0]);
107                         $this->set_method('index');
108                         
109                         // Assign the segments to the URI class
110                         $this->uri->rsegments = $segments;
111                         
112                         // re-index the routed segments array so it starts with 1 rather than 0
113                         $this->uri->_reindex_segments();
114                         
115                         log_message('debug', "No URI present. Default controller set.");
116                         return;
117                 }
118                 unset($this->routes['default_controller']);
119                 
120                 // Do we need to remove the URL suffix?
121                 $this->uri->_remove_url_suffix();
122                 
123                 // Compile the segments into an array
124                 $this->uri->_explode_segments();
125                 
126                 // Parse any custom routing that may exist
127                 $this->_parse_routes();         
128                 
129                 // Re-index the segment array so that it starts with 1 rather than 0
130                 $this->uri->_reindex_segments();
131         }
132         
133         // --------------------------------------------------------------------
134         
135         /**
136          * Set the Route
137          *
138          * This function takes an array of URI segments as
139          * input, and sets the current class/method
140          *
141          * @access      private
142          * @param       array
143          * @param       bool
144          * @return      void
145          */
146         function _set_request($segments = array())
147         {       
148                 $segments = $this->_validate_request($segments);
149                 
150                 if (count($segments) == 0)
151                 {
152                         return;
153                 }
154                                                 
155                 $this->set_class($segments[0]);
156                 
157                 if (isset($segments[1]))
158                 {
159                         // A scaffolding request. No funny business with the URL
160                         if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
161                         {
162                                 $this->scaffolding_request = TRUE;
163                                 unset($this->routes['scaffolding_trigger']);
164                         }
165                         else
166                         {
167                                 // A standard method request
168                                 $this->set_method($segments[1]);
169                         }
170                 }
171                 else
172                 {
173                         // This lets the "routed" segment array identify that the default
174                         // index method is being used.
175                         $segments[1] = 'index';
176                 }
177                 
178                 // Update our "routed" segment array to contain the segments.
179                 // Note: If there is no custom routing, this array will be
180                 // identical to $this->uri->segments
181                 $this->uri->rsegments = $segments;
182         }
183         
184         // --------------------------------------------------------------------
185         
186         /**
187          * Validates the supplied segments.  Attempts to determine the path to
188          * the controller.
189          *
190          * @access      private
191          * @param       array
192          * @return      array
193          */     
194         function _validate_request($segments)
195         {
196                 // Does the requested controller exist in the root folder?
197                 if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
198                 {
199                         return $segments;
200                 }
201
202                 // Is the controller in a sub-folder?
203                 if (is_dir(APPPATH.'controllers/'.$segments[0]))
204                 {               
205                         // Set the directory and remove it from the segment array
206                         $this->set_directory($segments[0]);
207                         $segments = array_slice($segments, 1);
208                         
209                         if (count($segments) > 0)
210                         {
211                                 // Does the requested controller exist in the sub-folder?
212                                 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
213                                 {
214                                         show_404($this->fetch_directory().$segments[0]);
215                                 }
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.EXT))
224                                 {
225                                         $this->directory = '';
226                                         return array();
227                                 }
228                         
229                         }
230
231                         return $segments;
232                 }
233
234                 // Can't find the requested controller...
235                 show_404($segments[0]);
236         }
237
238         // --------------------------------------------------------------------
239
240         /**
241          *  Parse Routes
242          *
243          * This function matches any routes that may exist in
244          * the config/routes.php file against the URI to
245          * determine if the class/method need to be remapped.
246          *
247          * @access      private
248          * @return      void
249          */
250         function _parse_routes()
251         {
252                 // Do we even have any custom routing to deal with?
253                 // There is a default scaffolding trigger, so we'll look just for 1
254                 if (count($this->routes) == 1)
255                 {
256                         $this->_set_request($this->uri->segments);
257                         return;
258                 }
259
260                 // Turn the segment array into a URI string
261                 $uri = implode('/', $this->uri->segments);
262
263                 // Is there a literal match?  If so we're done
264                 if (isset($this->routes[$uri]))
265                 {
266                         $this->_set_request(explode('/', $this->routes[$uri]));         
267                         return;
268                 }
269                                 
270                 // Loop through the route array looking for wild-cards
271                 foreach ($this->routes as $key => $val)
272                 {                                               
273                         // Convert wild-cards to RegEx
274                         $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
275                         
276                         // Does the RegEx match?
277                         if (preg_match('#^'.$key.'$#', $uri))
278                         {                       
279                                 // Do we have a back-reference?
280                                 if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
281                                 {
282                                         $val = preg_replace('#^'.$key.'$#', $val, $uri);
283                                 }
284                         
285                                 $this->_set_request(explode('/', $val));                
286                                 return;
287                         }
288                 }
289
290                 // If we got this far it means we didn't encounter a
291                 // matching route so we'll set the site default route
292                 $this->_set_request($this->uri->segments);
293         }
294
295         // --------------------------------------------------------------------
296         
297         /**
298          * Set the class name
299          *
300          * @access      public
301          * @param       string
302          * @return      void
303          */     
304         function set_class($class)
305         {
306                 $this->class = $class;
307         }
308         
309         // --------------------------------------------------------------------
310         
311         /**
312          * Fetch the current class
313          *
314          * @access      public
315          * @return      string
316          */     
317         function fetch_class()
318         {
319                 return $this->class;
320         }
321         
322         // --------------------------------------------------------------------
323         
324         /**
325          *  Set the method name
326          *
327          * @access      public
328          * @param       string
329          * @return      void
330          */     
331         function set_method($method)
332         {
333                 $this->method = $method;
334         }
335
336         // --------------------------------------------------------------------
337         
338         /**
339          *  Fetch the current method
340          *
341          * @access      public
342          * @return      string
343          */     
344         function fetch_method()
345         {
346                 if ($this->method == $this->fetch_class())
347                 {
348                         return 'index';
349                 }
350
351                 return $this->method;
352         }
353
354         // --------------------------------------------------------------------
355         
356         /**
357          *  Set the directory name
358          *
359          * @access      public
360          * @param       string
361          * @return      void
362          */     
363         function set_directory($dir)
364         {
365                 $this->directory = $dir.'/';
366         }
367
368         // --------------------------------------------------------------------
369         
370         /**
371          *  Fetch the sub-directory (if any) that contains the requested controller class
372          *
373          * @access      public
374          * @return      string
375          */     
376         function fetch_directory()
377         {
378                 return $this->directory;
379         }
380
381 }
382 // END Router Class
383
384 /* End of file Router.php */
385 /* Location: ./system/libraries/Router.php */