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