Provide better error reporting and error checking when updating a network
[www-register-wizard.git] / libraries / URI.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  * URI Class\r
20  *\r
21  * Parses URIs and determines routing\r
22  *\r
23  * @package             CodeIgniter\r
24  * @subpackage  Libraries\r
25  * @category    URI\r
26  * @author              ExpressionEngine Dev Team\r
27  * @link                http://codeigniter.com/user_guide/libraries/uri.html\r
28  */\r
29 class CI_URI {\r
30 \r
31         var     $keyval = array();\r
32         var $uri_string;\r
33         var $segments           = array();\r
34         var $rsegments          = array();\r
35 \r
36         /**\r
37          * Constructor\r
38          *\r
39          * Simply globalizes the $RTR object.  The front\r
40          * loads the Router class early on so it's not available\r
41          * normally as other classes are.\r
42          *\r
43          * @access      public\r
44          */             \r
45         function CI_URI()\r
46         {\r
47                 $this->config =& load_class('Config');\r
48                 log_message('debug', "URI Class Initialized");\r
49         }\r
50         \r
51         \r
52         // --------------------------------------------------------------------\r
53         \r
54         /**\r
55          * Get the URI String\r
56          *\r
57          * @access      private\r
58          * @return      string\r
59          */     \r
60         function _fetch_uri_string()\r
61         {\r
62                 if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')\r
63                 {\r
64                         // If the URL has a question mark then it's simplest to just\r
65                         // build the URI string from the zero index of the $_GET array.\r
66                         // This avoids having to deal with $_SERVER variables, which\r
67                         // can be unreliable in some environments\r
68                         if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')\r
69                         {\r
70                                 $this->uri_string = key($_GET);\r
71                                 return;\r
72                         }\r
73                 \r
74                         // Is there a PATH_INFO variable?\r
75                         // Note: some servers seem to have trouble with getenv() so we'll test it two ways              \r
76                         $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');                  \r
77                         if (trim($path, '/') != '' && $path != "/".SELF)\r
78                         {\r
79                                 $this->uri_string = $path;\r
80                                 return;\r
81                         }\r
82                                         \r
83                         // No PATH_INFO?... What about QUERY_STRING?\r
84                         $path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');        \r
85                         if (trim($path, '/') != '')\r
86                         {\r
87                                 $this->uri_string = $path;\r
88                                 return;\r
89                         }\r
90                         \r
91                         // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?\r
92                         $path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');   \r
93                         if (trim($path, '/') != '' && $path != "/".SELF)\r
94                         {\r
95                                 // remove path and script information so we have good URI data\r
96                                 $this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);\r
97                                 return;\r
98                         }\r
99 \r
100                         // We've exhausted all our options...\r
101                         $this->uri_string = '';\r
102                 }\r
103                 else\r
104                 {\r
105                         $uri = strtoupper($this->config->item('uri_protocol'));\r
106                         \r
107                         if ($uri == 'REQUEST_URI')\r
108                         {\r
109                                 $this->uri_string = $this->_parse_request_uri();\r
110                                 return;\r
111                         }\r
112                         \r
113                         $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);\r
114                 }\r
115                 \r
116                 // If the URI contains only a slash we'll kill it\r
117                 if ($this->uri_string == '/')\r
118                 {\r
119                         $this->uri_string = '';\r
120                 }               \r
121         }\r
122 \r
123         // --------------------------------------------------------------------\r
124         \r
125         /**\r
126          * Parse the REQUEST_URI\r
127          *\r
128          * Due to the way REQUEST_URI works it usually contains path info\r
129          * that makes it unusable as URI data.  We'll trim off the unnecessary\r
130          * data, hopefully arriving at a valid URI that we can use.\r
131          *\r
132          * @access      private\r
133          * @return      string\r
134          */     \r
135         function _parse_request_uri()\r
136         {\r
137                 if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')\r
138                 {\r
139                         return '';\r
140                 }\r
141                 \r
142                 $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));\r
143 \r
144                 if ($request_uri == '' OR $request_uri == SELF)\r
145                 {\r
146                         return '';\r
147                 }\r
148                 \r
149                 $fc_path = FCPATH;              \r
150                 if (strpos($request_uri, '?') !== FALSE)\r
151                 {\r
152                         $fc_path .= '?';\r
153                 }\r
154                 \r
155                 $parsed_uri = explode("/", $request_uri);\r
156                                 \r
157                 $i = 0;\r
158                 foreach(explode("/", $fc_path) as $segment)\r
159                 {\r
160                         if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i])\r
161                         {\r
162                                 $i++;\r
163                         }\r
164                 }\r
165                 \r
166                 $parsed_uri = implode("/", array_slice($parsed_uri, $i));\r
167                 \r
168                 if ($parsed_uri != '')\r
169                 {\r
170                         $parsed_uri = '/'.$parsed_uri;\r
171                 }\r
172 \r
173                 return $parsed_uri;\r
174         }\r
175 \r
176         // --------------------------------------------------------------------\r
177         \r
178         /**\r
179          * Filter segments for malicious characters\r
180          *\r
181          * @access      private\r
182          * @param       string\r
183          * @return      string\r
184          */     \r
185         function _filter_uri($str)\r
186         {\r
187                 if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)\r
188                 {\r
189                         if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))\r
190                         {\r
191                                 exit('The URI you submitted has disallowed characters.');\r
192                         }\r
193                 }       \r
194                 \r
195                 // Convert programatic characters to entities\r
196                 $bad    = array('$',            '(',            ')',            '%28',          '%29');\r
197                 $good   = array('&#36;',        '&#40;',        '&#41;',        '&#40;',        '&#41;');\r
198                 \r
199                 return str_replace($bad, $good, $str);\r
200         }\r
201 \r
202         // --------------------------------------------------------------------\r
203         \r
204         /**\r
205          * Remove the suffix from the URL if needed\r
206          *\r
207          * @access      private\r
208          * @return      void\r
209          */     \r
210         function _remove_url_suffix()\r
211         {\r
212                 if  ($this->config->item('url_suffix') != "")\r
213                 {\r
214                         $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);\r
215                 }\r
216         }\r
217         \r
218         // --------------------------------------------------------------------\r
219         \r
220         /**\r
221          * Explode the URI Segments. The individual segments will\r
222          * be stored in the $this->segments array.      \r
223          *\r
224          * @access      private\r
225          * @return      void\r
226          */             \r
227         function _explode_segments()\r
228         {\r
229                 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)\r
230                 {\r
231                         // Filter segments for security\r
232                         $val = trim($this->_filter_uri($val));\r
233                         \r
234                         if ($val != '')\r
235                         {\r
236                                 $this->segments[] = $val;\r
237                         }\r
238                 }\r
239         }\r
240         \r
241         // -------------------------------------------------------------------- \r
242         /**\r
243          * Re-index Segments\r
244          *\r
245          * This function re-indexes the $this->segment array so that it\r
246          * starts at 1 rather than 0.  Doing so makes it simpler to\r
247          * use functions like $this->uri->segment(n) since there is\r
248          * a 1:1 relationship between the segment array and the actual segments.\r
249          *\r
250          * @access      private\r
251          * @return      void\r
252          */     \r
253         function _reindex_segments()\r
254         {\r
255                 array_unshift($this->segments, NULL);\r
256                 array_unshift($this->rsegments, NULL);\r
257                 unset($this->segments[0]);\r
258                 unset($this->rsegments[0]);\r
259         }       \r
260         \r
261         // --------------------------------------------------------------------\r
262         \r
263         /**\r
264          * Fetch a URI Segment\r
265          *\r
266          * This function returns the URI segment based on the number provided.\r
267          *\r
268          * @access      public\r
269          * @param       integer\r
270          * @param       bool\r
271          * @return      string\r
272          */\r
273         function segment($n, $no_result = FALSE)\r
274         {\r
275                 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];\r
276         }\r
277 \r
278         // --------------------------------------------------------------------\r
279         \r
280         /**\r
281          * Fetch a URI "routed" Segment\r
282          *\r
283          * This function returns the re-routed URI segment (assuming routing rules are used)\r
284          * based on the number provided.  If there is no routing this function returns the\r
285          * same result as $this->segment()\r
286          *\r
287          * @access      public\r
288          * @param       integer\r
289          * @param       bool\r
290          * @return      string\r
291          */\r
292         function rsegment($n, $no_result = FALSE)\r
293         {\r
294                 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];\r
295         }\r
296 \r
297         // --------------------------------------------------------------------\r
298         \r
299         /**\r
300          * Generate a key value pair from the URI string\r
301          *\r
302          * This function generates and associative array of URI data starting\r
303          * at the supplied segment. For example, if this is your URI:\r
304          *\r
305          *      example.com/user/search/name/joe/location/UK/gender/male\r
306          *\r
307          * You can use this function to generate an array with this prototype:\r
308          *\r
309          * array (\r
310          *                      name => joe\r
311          *                      location => UK\r
312          *                      gender => male\r
313          *               )\r
314          *\r
315          * @access      public\r
316          * @param       integer the starting segment number\r
317          * @param       array   an array of default values\r
318          * @return      array\r
319          */\r
320         function uri_to_assoc($n = 3, $default = array())\r
321         {\r
322                 return $this->_uri_to_assoc($n, $default, 'segment');\r
323         }\r
324         /**\r
325          * Identical to above only it uses the re-routed segment array\r
326          *\r
327          */\r
328         function ruri_to_assoc($n = 3, $default = array())\r
329         {\r
330                 return $this->_uri_to_assoc($n, $default, 'rsegment');\r
331         }\r
332 \r
333         // --------------------------------------------------------------------\r
334         \r
335         /**\r
336          * Generate a key value pair from the URI string or Re-routed URI string\r
337          *\r
338          * @access      private\r
339          * @param       integer the starting segment number\r
340          * @param       array   an array of default values\r
341          * @param       string  which array we should use\r
342          * @return      array\r
343          */\r
344         function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')\r
345         {\r
346                 if ($which == 'segment')\r
347                 {\r
348                         $total_segments = 'total_segments';\r
349                         $segment_array = 'segment_array';\r
350                 }\r
351                 else\r
352                 {\r
353                         $total_segments = 'total_rsegments';\r
354                         $segment_array = 'rsegment_array';\r
355                 }\r
356                 \r
357                 if ( ! is_numeric($n))\r
358                 {\r
359                         return $default;\r
360                 }\r
361         \r
362                 if (isset($this->keyval[$n]))\r
363                 {\r
364                         return $this->keyval[$n];\r
365                 }\r
366         \r
367                 if ($this->$total_segments() < $n)\r
368                 {\r
369                         if (count($default) == 0)\r
370                         {\r
371                                 return array();\r
372                         }\r
373                         \r
374                         $retval = array();\r
375                         foreach ($default as $val)\r
376                         {\r
377                                 $retval[$val] = FALSE;\r
378                         }               \r
379                         return $retval;\r
380                 }\r
381 \r
382                 $segments = array_slice($this->$segment_array(), ($n - 1));\r
383 \r
384                 $i = 0;\r
385                 $lastval = '';\r
386                 $retval  = array();\r
387                 foreach ($segments as $seg)\r
388                 {\r
389                         if ($i % 2)\r
390                         {\r
391                                 $retval[$lastval] = $seg;\r
392                         }\r
393                         else\r
394                         {\r
395                                 $retval[$seg] = FALSE;\r
396                                 $lastval = $seg;\r
397                         }\r
398                 \r
399                         $i++;\r
400                 }\r
401 \r
402                 if (count($default) > 0)\r
403                 {\r
404                         foreach ($default as $val)\r
405                         {\r
406                                 if ( ! array_key_exists($val, $retval))\r
407                                 {\r
408                                         $retval[$val] = FALSE;\r
409                                 }\r
410                         }\r
411                 }\r
412 \r
413                 // Cache the array for reuse\r
414                 $this->keyval[$n] = $retval;\r
415                 return $retval;\r
416         }\r
417 \r
418         // --------------------------------------------------------------------\r
419 \r
420         /**\r
421          * Generate a URI string from an associative array\r
422          *\r
423          *\r
424          * @access      public\r
425          * @param       array   an associative array of key/values\r
426          * @return      array\r
427          */     \r
428         function assoc_to_uri($array)\r
429         {       \r
430                 $temp = array();\r
431                 foreach ((array)$array as $key => $val)\r
432                 {\r
433                         $temp[] = $key;\r
434                         $temp[] = $val;\r
435                 }\r
436                 \r
437                 return implode('/', $temp);\r
438         }\r
439 \r
440         // --------------------------------------------------------------------\r
441         \r
442         /**\r
443          * Fetch a URI Segment and add a trailing slash\r
444          *\r
445          * @access      public\r
446          * @param       integer\r
447          * @param       string\r
448          * @return      string\r
449          */\r
450         function slash_segment($n, $where = 'trailing')\r
451         {\r
452                 return $this->_slash_segment($n, $where, 'segment');\r
453         }\r
454 \r
455         // --------------------------------------------------------------------\r
456         \r
457         /**\r
458          * Fetch a URI Segment and add a trailing slash\r
459          *\r
460          * @access      public\r
461          * @param       integer\r
462          * @param       string\r
463          * @return      string\r
464          */\r
465         function slash_rsegment($n, $where = 'trailing')\r
466         {\r
467                 return $this->_slash_segment($n, $where, 'rsegment');\r
468         }\r
469         \r
470         // --------------------------------------------------------------------\r
471         \r
472         /**\r
473          * Fetch a URI Segment and add a trailing slash - helper function\r
474          *\r
475          * @access      private\r
476          * @param       integer\r
477          * @param       string\r
478          * @param       string\r
479          * @return      string\r
480          */\r
481         function _slash_segment($n, $where = 'trailing', $which = 'segment')\r
482         {       \r
483                 if ($where == 'trailing')\r
484                 {\r
485                         $trailing       = '/';\r
486                         $leading        = '';\r
487                 }\r
488                 elseif ($where == 'leading')\r
489                 {\r
490                         $leading        = '/';\r
491                         $trailing       = '';\r
492                 }\r
493                 else\r
494                 {\r
495                         $leading        = '/';\r
496                         $trailing       = '/';\r
497                 }\r
498                 return $leading.$this->$which($n).$trailing;\r
499         }\r
500         \r
501         // --------------------------------------------------------------------\r
502         \r
503         /**\r
504          * Segment Array\r
505          *\r
506          * @access      public\r
507          * @return      array\r
508          */\r
509         function segment_array()\r
510         {\r
511                 return $this->segments;\r
512         }\r
513 \r
514         // --------------------------------------------------------------------\r
515         \r
516         /**\r
517          * Routed Segment Array\r
518          *\r
519          * @access      public\r
520          * @return      array\r
521          */\r
522         function rsegment_array()\r
523         {\r
524                 return $this->rsegments;\r
525         }\r
526         \r
527         // --------------------------------------------------------------------\r
528         \r
529         /**\r
530          * Total number of segments\r
531          *\r
532          * @access      public\r
533          * @return      integer\r
534          */\r
535         function total_segments()\r
536         {\r
537                 return count($this->segments);\r
538         }\r
539 \r
540         // --------------------------------------------------------------------\r
541         \r
542         /**\r
543          * Total number of routed segments\r
544          *\r
545          * @access      public\r
546          * @return      integer\r
547          */\r
548         function total_rsegments()\r
549         {\r
550                 return count($this->rsegments);\r
551         }\r
552         \r
553         // --------------------------------------------------------------------\r
554         \r
555         /**\r
556          * Fetch the entire URI string\r
557          *\r
558          * @access      public\r
559          * @return      string\r
560          */\r
561         function uri_string()\r
562         {\r
563                 return $this->uri_string;\r
564         }\r
565 \r
566         \r
567         // --------------------------------------------------------------------\r
568         \r
569         /**\r
570          * Fetch the entire Re-routed URI string\r
571          *\r
572          * @access      public\r
573          * @return      string\r
574          */\r
575         function ruri_string()\r
576         {\r
577                 return '/'.implode('/', $this->rsegment_array()).'/';\r
578         }\r
579 \r
580 }\r
581 // END URI Class\r
582 \r
583 /* End of file URI.php */\r
584 /* Location: ./system/libraries/URI.php */