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