source: sourcecode/system/core/URI.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 14.1 KB
Line 
1<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.1.6 or newer
6 *
7 * @package             CodeIgniter
8 * @author              ExpressionEngine Dev Team
9 * @copyright   Copyright (c) 2008 - 2011, 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 */
29class CI_URI {
30
31        /**
32         * List of cached uri segments
33         *
34         * @var array
35         * @access public
36         */
37        var     $keyval                 = array();
38        /**
39         * Current uri string
40         *
41         * @var string
42         * @access public
43         */
44        var $uri_string;
45        /**
46         * List of uri segments
47         *
48         * @var array
49         * @access public
50         */
51        var $segments           = array();
52        /**
53         * Re-indexed list of uri segments
54         * Starts at 1 instead of 0
55         *
56         * @var array
57         * @access public
58         */
59        var $rsegments          = array();
60
61        /**
62         * Constructor
63         *
64         * Simply globalizes the $RTR object.  The front
65         * loads the Router class early on so it's not available
66         * normally as other classes are.
67         *
68         * @access      public
69         */
70        function __construct()
71        {
72                $this->config =& load_class('Config', 'core');
73                log_message('debug', "URI Class Initialized");
74        }
75
76
77        // --------------------------------------------------------------------
78
79        /**
80         * Get the URI String
81         *
82         * @access      private
83         * @return      string
84         */
85        function _fetch_uri_string()
86        {
87                if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
88                {
89                        // Is the request coming from the command line?
90                        if (php_sapi_name() == 'cli' or defined('STDIN'))
91                        {
92                                $this->_set_uri_string($this->_parse_cli_args());
93                                return;
94                        }
95
96                        // Let's try the REQUEST_URI first, this will work in most situations
97                        if ($uri = $this->_detect_uri())
98                        {
99                                $this->_set_uri_string($uri);
100                                return;
101                        }
102
103                        // Is there a PATH_INFO variable?
104                        // Note: some servers seem to have trouble with getenv() so we'll test it two ways
105                        $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
106                        if (trim($path, '/') != '' && $path != "/".SELF)
107                        {
108                                $this->_set_uri_string($path);
109                                return;
110                        }
111
112                        // No PATH_INFO?... What about QUERY_STRING?
113                        $path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
114                        if (trim($path, '/') != '')
115                        {
116                                $this->_set_uri_string($path);
117                                return;
118                        }
119
120                        // As a last ditch effort lets try using the $_GET array
121                        if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
122                        {
123                                $this->_set_uri_string(key($_GET));
124                                return;
125                        }
126
127                        // We've exhausted all our options...
128                        $this->uri_string = '';
129                        return;
130                }
131
132                $uri = strtoupper($this->config->item('uri_protocol'));
133
134                if ($uri == 'REQUEST_URI')
135                {
136                        $this->_set_uri_string($this->_detect_uri());
137                        return;
138                }
139                elseif ($uri == 'CLI')
140                {
141                        $this->_set_uri_string($this->_parse_cli_args());
142                        return;
143                }
144
145                $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
146                $this->_set_uri_string($path);
147        }
148
149        // --------------------------------------------------------------------
150
151        /**
152         * Set the URI String
153         *
154         * @access      public
155         * @param       string
156         * @return      string
157         */
158        function _set_uri_string($str)
159        {
160                // Filter out control characters
161                $str = remove_invisible_characters($str, FALSE);
162
163                // If the URI contains only a slash we'll kill it
164                $this->uri_string = ($str == '/') ? '' : $str;
165        }
166
167        // --------------------------------------------------------------------
168
169        /**
170         * Detects the URI
171         *
172         * This function will detect the URI automatically and fix the query string
173         * if necessary.
174         *
175         * @access      private
176         * @return      string
177         */
178        private function _detect_uri()
179        {
180                if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
181                {
182                        return '';
183                }
184
185                $uri = $_SERVER['REQUEST_URI'];
186                if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
187                {
188                        $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
189                }
190                elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
191                {
192                        $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
193                }
194
195                // This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
196                // URI is found, and also fixes the QUERY_STRING server var and $_GET array.
197                if (strncmp($uri, '?/', 2) === 0)
198                {
199                        $uri = substr($uri, 2);
200                }
201                $parts = preg_split('#\?#i', $uri, 2);
202                $uri = $parts[0];
203                if (isset($parts[1]))
204                {
205                        $_SERVER['QUERY_STRING'] = $parts[1];
206                        parse_str($_SERVER['QUERY_STRING'], $_GET);
207                }
208                else
209                {
210                        $_SERVER['QUERY_STRING'] = '';
211                        $_GET = array();
212                }
213
214                if ($uri == '/' || empty($uri))
215                {
216                        return '/';
217                }
218
219                $uri = parse_url($uri, PHP_URL_PATH);
220
221                // Do some final cleaning of the URI and return it
222                return str_replace(array('//', '../'), '/', trim($uri, '/'));
223        }
224
225        // --------------------------------------------------------------------
226
227        /**
228         * Parse cli arguments
229         *
230         * Take each command line argument and assume it is a URI segment.
231         *
232         * @access      private
233         * @return      string
234         */
235        private function _parse_cli_args()
236        {
237                $args = array_slice($_SERVER['argv'], 1);
238
239                return $args ? '/' . implode('/', $args) : '';
240        }
241
242        // --------------------------------------------------------------------
243
244        /**
245         * Filter segments for malicious characters
246         *
247         * @access      private
248         * @param       string
249         * @return      string
250         */
251        function _filter_uri($str)
252        {
253                if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
254                {
255                        // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
256                        // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
257                        if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
258                        {
259                                show_error('The URI you submitted has disallowed characters.', 400);
260                        }
261                }
262
263                // Convert programatic characters to entities
264                $bad    = array('$',            '(',            ')',            '%28',          '%29');
265                $good   = array('&#36;',        '&#40;',        '&#41;',        '&#40;',        '&#41;');
266
267                return str_replace($bad, $good, $str);
268        }
269
270        // --------------------------------------------------------------------
271
272        /**
273         * Remove the suffix from the URL if needed
274         *
275         * @access      private
276         * @return      void
277         */
278        function _remove_url_suffix()
279        {
280                if  ($this->config->item('url_suffix') != "")
281                {
282                        $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
283                }
284        }
285
286        // --------------------------------------------------------------------
287
288        /**
289         * Explode the URI Segments. The individual segments will
290         * be stored in the $this->segments array.
291         *
292         * @access      private
293         * @return      void
294         */
295        function _explode_segments()
296        {
297                foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
298                {
299                        // Filter segments for security
300                        $val = trim($this->_filter_uri($val));
301
302                        if ($val != '')
303                        {
304                                $this->segments[] = $val;
305                        }
306                }
307        }
308
309        // --------------------------------------------------------------------
310        /**
311         * Re-index Segments
312         *
313         * This function re-indexes the $this->segment array so that it
314         * starts at 1 rather than 0.  Doing so makes it simpler to
315         * use functions like $this->uri->segment(n) since there is
316         * a 1:1 relationship between the segment array and the actual segments.
317         *
318         * @access      private
319         * @return      void
320         */
321        function _reindex_segments()
322        {
323                array_unshift($this->segments, NULL);
324                array_unshift($this->rsegments, NULL);
325                unset($this->segments[0]);
326                unset($this->rsegments[0]);
327        }
328
329        // --------------------------------------------------------------------
330
331        /**
332         * Fetch a URI Segment
333         *
334         * This function returns the URI segment based on the number provided.
335         *
336         * @access      public
337         * @param       integer
338         * @param       bool
339         * @return      string
340         */
341        function segment($n, $no_result = FALSE)
342        {
343                return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
344        }
345
346        // --------------------------------------------------------------------
347
348        /**
349         * Fetch a URI "routed" Segment
350         *
351         * This function returns the re-routed URI segment (assuming routing rules are used)
352         * based on the number provided.  If there is no routing this function returns the
353         * same result as $this->segment()
354         *
355         * @access      public
356         * @param       integer
357         * @param       bool
358         * @return      string
359         */
360        function rsegment($n, $no_result = FALSE)
361        {
362                return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
363        }
364
365        // --------------------------------------------------------------------
366
367        /**
368         * Generate a key value pair from the URI string
369         *
370         * This function generates and associative array of URI data starting
371         * at the supplied segment. For example, if this is your URI:
372         *
373         *      example.com/user/search/name/joe/location/UK/gender/male
374         *
375         * You can use this function to generate an array with this prototype:
376         *
377         * array (
378         *                      name => joe
379         *                      location => UK
380         *                      gender => male
381         *               )
382         *
383         * @access      public
384         * @param       integer the starting segment number
385         * @param       array   an array of default values
386         * @return      array
387         */
388        function uri_to_assoc($n = 3, $default = array())
389        {
390                return $this->_uri_to_assoc($n, $default, 'segment');
391        }
392        /**
393         * Identical to above only it uses the re-routed segment array
394         *
395         * @access      public
396         * @param       integer the starting segment number
397         * @param       array   an array of default values
398         * @return      array
399         *
400         */
401        function ruri_to_assoc($n = 3, $default = array())
402        {
403                return $this->_uri_to_assoc($n, $default, 'rsegment');
404        }
405
406        // --------------------------------------------------------------------
407
408        /**
409         * Generate a key value pair from the URI string or Re-routed URI string
410         *
411         * @access      private
412         * @param       integer the starting segment number
413         * @param       array   an array of default values
414         * @param       string  which array we should use
415         * @return      array
416         */
417        function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
418        {
419                if ($which == 'segment')
420                {
421                        $total_segments = 'total_segments';
422                        $segment_array = 'segment_array';
423                }
424                else
425                {
426                        $total_segments = 'total_rsegments';
427                        $segment_array = 'rsegment_array';
428                }
429
430                if ( ! is_numeric($n))
431                {
432                        return $default;
433                }
434
435                if (isset($this->keyval[$n]))
436                {
437                        return $this->keyval[$n];
438                }
439
440                if ($this->$total_segments() < $n)
441                {
442                        if (count($default) == 0)
443                        {
444                                return array();
445                        }
446
447                        $retval = array();
448                        foreach ($default as $val)
449                        {
450                                $retval[$val] = FALSE;
451                        }
452                        return $retval;
453                }
454
455                $segments = array_slice($this->$segment_array(), ($n - 1));
456
457                $i = 0;
458                $lastval = '';
459                $retval  = array();
460                foreach ($segments as $seg)
461                {
462                        if ($i % 2)
463                        {
464                                $retval[$lastval] = $seg;
465                        }
466                        else
467                        {
468                                $retval[$seg] = FALSE;
469                                $lastval = $seg;
470                        }
471
472                        $i++;
473                }
474
475                if (count($default) > 0)
476                {
477                        foreach ($default as $val)
478                        {
479                                if ( ! array_key_exists($val, $retval))
480                                {
481                                        $retval[$val] = FALSE;
482                                }
483                        }
484                }
485
486                // Cache the array for reuse
487                $this->keyval[$n] = $retval;
488                return $retval;
489        }
490
491        // --------------------------------------------------------------------
492
493        /**
494         * Generate a URI string from an associative array
495         *
496         *
497         * @access      public
498         * @param       array   an associative array of key/values
499         * @return      array
500         */
501        function assoc_to_uri($array)
502        {
503                $temp = array();
504                foreach ((array)$array as $key => $val)
505                {
506                        $temp[] = $key;
507                        $temp[] = $val;
508                }
509
510                return implode('/', $temp);
511        }
512
513        // --------------------------------------------------------------------
514
515        /**
516         * Fetch a URI Segment and add a trailing slash
517         *
518         * @access      public
519         * @param       integer
520         * @param       string
521         * @return      string
522         */
523        function slash_segment($n, $where = 'trailing')
524        {
525                return $this->_slash_segment($n, $where, 'segment');
526        }
527
528        // --------------------------------------------------------------------
529
530        /**
531         * Fetch a URI Segment and add a trailing slash
532         *
533         * @access      public
534         * @param       integer
535         * @param       string
536         * @return      string
537         */
538        function slash_rsegment($n, $where = 'trailing')
539        {
540                return $this->_slash_segment($n, $where, 'rsegment');
541        }
542
543        // --------------------------------------------------------------------
544
545        /**
546         * Fetch a URI Segment and add a trailing slash - helper function
547         *
548         * @access      private
549         * @param       integer
550         * @param       string
551         * @param       string
552         * @return      string
553         */
554        function _slash_segment($n, $where = 'trailing', $which = 'segment')
555        {
556                $leading        = '/';
557                $trailing       = '/';
558
559                if ($where == 'trailing')
560                {
561                        $leading        = '';
562                }
563                elseif ($where == 'leading')
564                {
565                        $trailing       = '';
566                }
567
568                return $leading.$this->$which($n).$trailing;
569        }
570
571        // --------------------------------------------------------------------
572
573        /**
574         * Segment Array
575         *
576         * @access      public
577         * @return      array
578         */
579        function segment_array()
580        {
581                return $this->segments;
582        }
583
584        // --------------------------------------------------------------------
585
586        /**
587         * Routed Segment Array
588         *
589         * @access      public
590         * @return      array
591         */
592        function rsegment_array()
593        {
594                return $this->rsegments;
595        }
596
597        // --------------------------------------------------------------------
598
599        /**
600         * Total number of segments
601         *
602         * @access      public
603         * @return      integer
604         */
605        function total_segments()
606        {
607                return count($this->segments);
608        }
609
610        // --------------------------------------------------------------------
611
612        /**
613         * Total number of routed segments
614         *
615         * @access      public
616         * @return      integer
617         */
618        function total_rsegments()
619        {
620                return count($this->rsegments);
621        }
622
623        // --------------------------------------------------------------------
624
625        /**
626         * Fetch the entire URI string
627         *
628         * @access      public
629         * @return      string
630         */
631        function uri_string()
632        {
633                return $this->uri_string;
634        }
635
636
637        // --------------------------------------------------------------------
638
639        /**
640         * Fetch the entire Re-routed URI string
641         *
642         * @access      public
643         * @return      string
644         */
645        function ruri_string()
646        {
647                return '/'.implode('/', $this->rsegment_array());
648        }
649
650}
651// END URI Class
652
653/* End of file URI.php */
654/* Location: ./system/core/URI.php */
Note: See TracBrowser for help on using the repository browser.