upgrade to codeigniter 1.7.2 for f12
[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 - 2009, 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 = str_replace($_SERVER['SCRIPT_NAME'], '', (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 = $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.SELF;
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                         // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
190                         // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
191                         if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
192                         {
193                                 show_error('The URI you submitted has disallowed characters.', 400);
194                         }
195                 }
196
197                 // Convert programatic characters to entities
198                 $bad    = array('$',            '(',            ')',            '%28',          '%29');
199                 $good   = array('&#36;',        '&#40;',        '&#41;',        '&#40;',        '&#41;');
200
201                 return str_replace($bad, $good, $str);
202         }
203
204         // --------------------------------------------------------------------
205
206         /**
207          * Remove the suffix from the URL if needed
208          *
209          * @access      private
210          * @return      void
211          */
212         function _remove_url_suffix()
213         {
214                 if  ($this->config->item('url_suffix') != "")
215                 {
216                         $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
217                 }
218         }
219
220         // --------------------------------------------------------------------
221
222         /**
223          * Explode the URI Segments. The individual segments will
224          * be stored in the $this->segments array.
225          *
226          * @access      private
227          * @return      void
228          */
229         function _explode_segments()
230         {
231                 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
232                 {
233                         // Filter segments for security
234                         $val = trim($this->_filter_uri($val));
235
236                         if ($val != '')
237                         {
238                                 $this->segments[] = $val;
239                         }
240                 }
241         }
242
243         // --------------------------------------------------------------------
244         /**
245          * Re-index Segments
246          *
247          * This function re-indexes the $this->segment array so that it
248          * starts at 1 rather than 0.  Doing so makes it simpler to
249          * use functions like $this->uri->segment(n) since there is
250          * a 1:1 relationship between the segment array and the actual segments.
251          *
252          * @access      private
253          * @return      void
254          */
255         function _reindex_segments()
256         {
257                 array_unshift($this->segments, NULL);
258                 array_unshift($this->rsegments, NULL);
259                 unset($this->segments[0]);
260                 unset($this->rsegments[0]);
261         }
262
263         // --------------------------------------------------------------------
264
265         /**
266          * Fetch a URI Segment
267          *
268          * This function returns the URI segment based on the number provided.
269          *
270          * @access      public
271          * @param       integer
272          * @param       bool
273          * @return      string
274          */
275         function segment($n, $no_result = FALSE)
276         {
277                 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
278         }
279
280         // --------------------------------------------------------------------
281
282         /**
283          * Fetch a URI "routed" Segment
284          *
285          * This function returns the re-routed URI segment (assuming routing rules are used)
286          * based on the number provided.  If there is no routing this function returns the
287          * same result as $this->segment()
288          *
289          * @access      public
290          * @param       integer
291          * @param       bool
292          * @return      string
293          */
294         function rsegment($n, $no_result = FALSE)
295         {
296                 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
297         }
298
299         // --------------------------------------------------------------------
300
301         /**
302          * Generate a key value pair from the URI string
303          *
304          * This function generates and associative array of URI data starting
305          * at the supplied segment. For example, if this is your URI:
306          *
307          *      example.com/user/search/name/joe/location/UK/gender/male
308          *
309          * You can use this function to generate an array with this prototype:
310          *
311          * array (
312          *                      name => joe
313          *                      location => UK
314          *                      gender => male
315          *               )
316          *
317          * @access      public
318          * @param       integer the starting segment number
319          * @param       array   an array of default values
320          * @return      array
321          */
322         function uri_to_assoc($n = 3, $default = array())
323         {
324                 return $this->_uri_to_assoc($n, $default, 'segment');
325         }
326         /**
327          * Identical to above only it uses the re-routed segment array
328          *
329          */
330         function ruri_to_assoc($n = 3, $default = array())
331         {
332                 return $this->_uri_to_assoc($n, $default, 'rsegment');
333         }
334
335         // --------------------------------------------------------------------
336
337         /**
338          * Generate a key value pair from the URI string or Re-routed URI string
339          *
340          * @access      private
341          * @param       integer the starting segment number
342          * @param       array   an array of default values
343          * @param       string  which array we should use
344          * @return      array
345          */
346         function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
347         {
348                 if ($which == 'segment')
349                 {
350                         $total_segments = 'total_segments';
351                         $segment_array = 'segment_array';
352                 }
353                 else
354                 {
355                         $total_segments = 'total_rsegments';
356                         $segment_array = 'rsegment_array';
357                 }
358
359                 if ( ! is_numeric($n))
360                 {
361                         return $default;
362                 }
363
364                 if (isset($this->keyval[$n]))
365                 {
366                         return $this->keyval[$n];
367                 }
368
369                 if ($this->$total_segments() < $n)
370                 {
371                         if (count($default) == 0)
372                         {
373                                 return array();
374                         }
375
376                         $retval = array();
377                         foreach ($default as $val)
378                         {
379                                 $retval[$val] = FALSE;
380                         }
381                         return $retval;
382                 }
383
384                 $segments = array_slice($this->$segment_array(), ($n - 1));
385
386                 $i = 0;
387                 $lastval = '';
388                 $retval  = array();
389                 foreach ($segments as $seg)
390                 {
391                         if ($i % 2)
392                         {
393                                 $retval[$lastval] = $seg;
394                         }
395                         else
396                         {
397                                 $retval[$seg] = FALSE;
398                                 $lastval = $seg;
399                         }
400
401                         $i++;
402                 }
403
404                 if (count($default) > 0)
405                 {
406                         foreach ($default as $val)
407                         {
408                                 if ( ! array_key_exists($val, $retval))
409                                 {
410                                         $retval[$val] = FALSE;
411                                 }
412                         }
413                 }
414
415                 // Cache the array for reuse
416                 $this->keyval[$n] = $retval;
417                 return $retval;
418         }
419
420         // --------------------------------------------------------------------
421
422         /**
423          * Generate a URI string from an associative array
424          *
425          *
426          * @access      public
427          * @param       array   an associative array of key/values
428          * @return      array
429          */
430         function assoc_to_uri($array)
431         {
432                 $temp = array();
433                 foreach ((array)$array as $key => $val)
434                 {
435                         $temp[] = $key;
436                         $temp[] = $val;
437                 }
438
439                 return implode('/', $temp);
440         }
441
442         // --------------------------------------------------------------------
443
444         /**
445          * Fetch a URI Segment and add a trailing slash
446          *
447          * @access      public
448          * @param       integer
449          * @param       string
450          * @return      string
451          */
452         function slash_segment($n, $where = 'trailing')
453         {
454                 return $this->_slash_segment($n, $where, 'segment');
455         }
456
457         // --------------------------------------------------------------------
458
459         /**
460          * Fetch a URI Segment and add a trailing slash
461          *
462          * @access      public
463          * @param       integer
464          * @param       string
465          * @return      string
466          */
467         function slash_rsegment($n, $where = 'trailing')
468         {
469                 return $this->_slash_segment($n, $where, 'rsegment');
470         }
471
472         // --------------------------------------------------------------------
473
474         /**
475          * Fetch a URI Segment and add a trailing slash - helper function
476          *
477          * @access      private
478          * @param       integer
479          * @param       string
480          * @param       string
481          * @return      string
482          */
483         function _slash_segment($n, $where = 'trailing', $which = 'segment')
484         {
485                 if ($where == 'trailing')
486                 {
487                         $trailing       = '/';
488                         $leading        = '';
489                 }
490                 elseif ($where == 'leading')
491                 {
492                         $leading        = '/';
493                         $trailing       = '';
494                 }
495                 else
496                 {
497                         $leading        = '/';
498                         $trailing       = '/';
499                 }
500                 return $leading.$this->$which($n).$trailing;
501         }
502
503         // --------------------------------------------------------------------
504
505         /**
506          * Segment Array
507          *
508          * @access      public
509          * @return      array
510          */
511         function segment_array()
512         {
513                 return $this->segments;
514         }
515
516         // --------------------------------------------------------------------
517
518         /**
519          * Routed Segment Array
520          *
521          * @access      public
522          * @return      array
523          */
524         function rsegment_array()
525         {
526                 return $this->rsegments;
527         }
528
529         // --------------------------------------------------------------------
530
531         /**
532          * Total number of segments
533          *
534          * @access      public
535          * @return      integer
536          */
537         function total_segments()
538         {
539                 return count($this->segments);
540         }
541
542         // --------------------------------------------------------------------
543
544         /**
545          * Total number of routed segments
546          *
547          * @access      public
548          * @return      integer
549          */
550         function total_rsegments()
551         {
552                 return count($this->rsegments);
553         }
554
555         // --------------------------------------------------------------------
556
557         /**
558          * Fetch the entire URI string
559          *
560          * @access      public
561          * @return      string
562          */
563         function uri_string()
564         {
565                 return $this->uri_string;
566         }
567
568
569         // --------------------------------------------------------------------
570
571         /**
572          * Fetch the entire Re-routed URI string
573          *
574          * @access      public
575          * @return      string
576          */
577         function ruri_string()
578         {
579                 return '/'.implode('/', $this->rsegment_array()).'/';
580         }
581
582 }
583 // END URI Class
584
585 /* End of file URI.php */
586 /* Location: ./system/libraries/URI.php */