blob: 0e4ff50c72ea3c78d65394c2378d6755bdda3cfd [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardd2df9bc2007-04-15 17:41:17 +00002/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Rick Ellisd02b5bf2008-09-12 23:35:31 +00009 * @copyright Copyright (c) 2008, EllisLab, Inc.
Derek Jones7a9193a2008-01-21 18:39:20 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
Derek Allardd2df9bc2007-04-15 17:41:17 +000012 * @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
Derek Allard3d879d52008-01-18 19:41:32 +000026 * @author ExpressionEngine Dev Team
Derek Jones7a9193a2008-01-21 18:39:20 +000027 * @link http://codeigniter.com/user_guide/libraries/uri.html
Derek Allardd2df9bc2007-04-15 17:41:17 +000028 */
29class CI_URI {
30
Derek Allardd2df9bc2007-04-15 17:41:17 +000031 var $keyval = array();
Rick Ellis30b40152007-07-20 00:01:13 +000032 var $uri_string;
33 var $segments = array();
34 var $rsegments = array();
Derek Allardd2df9bc2007-04-15 17:41:17 +000035
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 {
Rick Ellis30b40152007-07-20 00:01:13 +000047 $this->config =& load_class('Config');
Derek Allardd2df9bc2007-04-15 17:41:17 +000048 log_message('debug', "URI Class Initialized");
49 }
50
Rick Ellis30b40152007-07-20 00:01:13 +000051
52 // --------------------------------------------------------------------
53
54 /**
55 * Get the URI String
56 *
57 * @access private
58 * @return string
59 */
60 function _fetch_uri_string()
Rick Ellis8e3869a2008-10-01 02:01:53 +000061 {
Rick Ellis30b40152007-07-20 00:01:13 +000062 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
Rick Ellis8e3869a2008-10-01 02:01:53 +000068 if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
Rick Ellis30b40152007-07-20 00:01:13 +000069 {
Rick Ellis8e3869a2008-10-01 02:01:53 +000070 $this->uri_string = key($_GET);
Rick Ellisde2623c2007-07-21 18:28:24 +000071 return;
Rick Ellis30b40152007-07-20 00:01:13 +000072 }
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');
Rick Ellis8e3869a2008-10-01 02:01:53 +000077 if (trim($path, '/') != '' && $path != "/".SELF)
Rick Ellis30b40152007-07-20 00:01:13 +000078 {
79 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000080 return;
Rick Ellis30b40152007-07-20 00:01:13 +000081 }
82
83 // No PATH_INFO?... What about QUERY_STRING?
84 $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
Derek Jones27b50052008-04-14 14:03:04 +000085 if (trim($path, '/') != '')
Rick Ellis30b40152007-07-20 00:01:13 +000086 {
87 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000088 return;
Rick Ellis30b40152007-07-20 00:01:13 +000089 }
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');
Rick Ellis8e3869a2008-10-01 02:01:53 +000093 if (trim($path, '/') != '' && $path != "/".SELF)
Rick Ellis30b40152007-07-20 00:01:13 +000094 {
Derek Jones62a90202008-05-07 16:40:28 +000095 // remove path and script information so we have good URI data
96 $this->uri_string = str_replace($_SERVER['SCRIPT_NAME'], '', $path);
Rick Ellisde2623c2007-07-21 18:28:24 +000097 return;
Rick Ellis30b40152007-07-20 00:01:13 +000098 }
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();
Rick Ellisde2623c2007-07-21 18:28:24 +0000110 return;
Rick Ellis30b40152007-07-20 00:01:13 +0000111 }
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 }
Rick Ellis8e3869a2008-10-01 02:01:53 +0000122
Rick Ellis30b40152007-07-20 00:01:13 +0000123 // --------------------------------------------------------------------
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 {
Derek Jones0b59f272008-05-13 04:22:33 +0000137 if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
Rick Ellis30b40152007-07-20 00:01:13 +0000138 {
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 {
Rick Ellis8e3869a2008-10-01 02:01:53 +0000160 if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i])
Rick Ellis30b40152007-07-20 00:01:13 +0000161 {
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 {
Rick Ellis8e3869a2008-10-01 02:01:53 +0000187 if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
Rick Ellis30b40152007-07-20 00:01:13 +0000188 {
Derek Jones0b59f272008-05-13 04:22:33 +0000189 if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
Rick Ellis30b40152007-07-20 00:01:13 +0000190 {
191 exit('The URI you submitted has disallowed characters.');
192 }
Rick Ellis8e3869a2008-10-01 02:01:53 +0000193 }
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);
Rick Ellis30b40152007-07-20 00:01:13 +0000200 }
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 != '')
Rick Ellis8e3869a2008-10-01 02:01:53 +0000235 {
Rick Ellis30b40152007-07-20 00:01:13 +0000236 $this->segments[] = $val;
Rick Ellis8e3869a2008-10-01 02:01:53 +0000237 }
Rick Ellis30b40152007-07-20 00:01:13 +0000238 }
239 }
240
241 // --------------------------------------------------------------------
242 /**
243 * Re-index Segments
244 *
245 * This function re-indexes the $this->segment array so that it
Derek Allardcb36e342008-08-31 14:24:56 +0000246 * starts at 1 rather than 0. Doing so makes it simpler to
Rick Ellis30b40152007-07-20 00:01:13 +0000247 * 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 {
Derek Jones5453b8e2008-05-16 14:38:40 +0000255 array_unshift($this->segments, NULL);
256 array_unshift($this->rsegments, NULL);
Rick Ellis30b40152007-07-20 00:01:13 +0000257 unset($this->segments[0]);
Derek Jonesb0697892008-02-13 03:38:39 +0000258 unset($this->rsegments[0]);
Rick Ellis30b40152007-07-20 00:01:13 +0000259 }
260
Derek Allardd2df9bc2007-04-15 17:41:17 +0000261 // --------------------------------------------------------------------
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 {
Derek Jones0b59f272008-05-13 04:22:33 +0000275 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000276 }
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 {
Derek Jones0b59f272008-05-13 04:22:33 +0000294 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000295 }
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 *
Derek Jonesff845f92008-06-26 17:05:55 +0000305 * example.com/user/search/name/joe/location/UK/gender/male
Derek Allardd2df9bc2007-04-15 17:41:17 +0000306 *
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
Derek Jones0b59f272008-05-13 04:22:33 +0000357 if ( ! is_numeric($n))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000358 {
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 {
Derek Jones0b59f272008-05-13 04:22:33 +0000406 if ( ! array_key_exists($val, $retval))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000407 {
408 $retval[$val] = FALSE;
409 }
410 }
411 }
412
413 // Cache the array for reuse
414 $this->keyval[$n] = $retval;
415 return $retval;
416 }
417
Rick Ellis30b40152007-07-20 00:01:13 +0000418 // --------------------------------------------------------------------
419
Derek Allardd2df9bc2007-04-15 17:41:17 +0000420 /**
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
Rick Ellis30b40152007-07-20 00:01:13 +0000427 */
428 function assoc_to_uri($array)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000429 {
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 {
Rick Ellis30b40152007-07-20 00:01:13 +0000511 return $this->segments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000512 }
513
514 // --------------------------------------------------------------------
515
516 /**
517 * Routed Segment Array
518 *
519 * @access public
520 * @return array
521 */
522 function rsegment_array()
523 {
Rick Ellis30b40152007-07-20 00:01:13 +0000524 return $this->rsegments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000525 }
526
527 // --------------------------------------------------------------------
528
529 /**
530 * Total number of segments
531 *
532 * @access public
533 * @return integer
534 */
535 function total_segments()
536 {
Rick Ellis30b40152007-07-20 00:01:13 +0000537 return count($this->segments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000538 }
539
540 // --------------------------------------------------------------------
541
542 /**
543 * Total number of routed segments
544 *
545 * @access public
546 * @return integer
547 */
548 function total_rsegments()
549 {
Rick Ellis30b40152007-07-20 00:01:13 +0000550 return count($this->rsegments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000551 }
552
553 // --------------------------------------------------------------------
554
555 /**
556 * Fetch the entire URI string
557 *
558 * @access public
559 * @return string
560 */
561 function uri_string()
562 {
Rick Ellis30b40152007-07-20 00:01:13 +0000563 return $this->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000564 }
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
Derek Jones0b59f272008-05-13 04:22:33 +0000582
583/* End of file URI.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000584/* Location: ./system/libraries/URI.php */