blob: 254a8a6e931d4ecfaab68aef3c02aed6561bd6db [file] [log] [blame]
Derek Allardd2df9bc2007-04-15 17:41:17 +00001<?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 Rick Ellis
9 * @copyright Copyright (c) 2006, EllisLab, Inc.
10 * @license http://www.codeignitor.com/user_guide/license.html
11 * @link http://www.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 Rick Ellis
27 * @link http://www.codeigniter.com/user_guide/libraries/uri.html
28 */
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 Ellisde2623c2007-07-21 18:28:24 +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
68 if (is_array($_GET) AND count($_GET) == 1)
69 {
70 // Note: Due to a bug in current() that affects some versions
71 // of PHP we can not pass function call directly into it
72 $keys = array_keys($_GET);
73 $this->uri_string = current($keys);
Rick Ellisde2623c2007-07-21 18:28:24 +000074 return;
Rick Ellis30b40152007-07-20 00:01:13 +000075 }
76
77 // Is there a PATH_INFO variable?
78 // Note: some servers seem to have trouble with getenv() so we'll test it two ways
79 $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
80 if ($path != '' AND $path != "/".SELF)
81 {
82 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000083 return;
Rick Ellis30b40152007-07-20 00:01:13 +000084 }
85
86 // No PATH_INFO?... What about QUERY_STRING?
87 $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
88 if ($path != '')
89 {
90 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000091 return;
Rick Ellis30b40152007-07-20 00:01:13 +000092 }
93
94 // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists?
95 $path = (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO');
96 if ($path != '' AND $path != "/".SELF)
97 {
98 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000099 return;
Rick Ellis30b40152007-07-20 00:01:13 +0000100 }
101
102 // We've exhausted all our options...
103 $this->uri_string = '';
104 }
105 else
106 {
107 $uri = strtoupper($this->config->item('uri_protocol'));
108
109 if ($uri == 'REQUEST_URI')
110 {
111 $this->uri_string = $this->_parse_request_uri();
Rick Ellisde2623c2007-07-21 18:28:24 +0000112 return;
Rick Ellis30b40152007-07-20 00:01:13 +0000113 }
114
115 $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
116 }
117
118 // If the URI contains only a slash we'll kill it
119 if ($this->uri_string == '/')
120 {
121 $this->uri_string = '';
122 }
123 }
Rick Ellisde2623c2007-07-21 18:28:24 +0000124
Rick Ellis30b40152007-07-20 00:01:13 +0000125 // --------------------------------------------------------------------
126
127 /**
128 * Parse the REQUEST_URI
129 *
130 * Due to the way REQUEST_URI works it usually contains path info
131 * that makes it unusable as URI data. We'll trim off the unnecessary
132 * data, hopefully arriving at a valid URI that we can use.
133 *
134 * @access private
135 * @return string
136 */
137 function _parse_request_uri()
138 {
139 if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
140 {
141 return '';
142 }
143
144 $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
145
146 if ($request_uri == '' OR $request_uri == SELF)
147 {
148 return '';
149 }
150
151 $fc_path = FCPATH;
152 if (strpos($request_uri, '?') !== FALSE)
153 {
154 $fc_path .= '?';
155 }
156
157 $parsed_uri = explode("/", $request_uri);
158
159 $i = 0;
160 foreach(explode("/", $fc_path) as $segment)
161 {
162 if (isset($parsed_uri[$i]) AND $segment == $parsed_uri[$i])
163 {
164 $i++;
165 }
166 }
167
168 $parsed_uri = implode("/", array_slice($parsed_uri, $i));
169
170 if ($parsed_uri != '')
171 {
172 $parsed_uri = '/'.$parsed_uri;
173 }
174
175 return $parsed_uri;
176 }
177
178 // --------------------------------------------------------------------
179
180 /**
181 * Filter segments for malicious characters
182 *
183 * @access private
184 * @param string
185 * @return string
186 */
187 function _filter_uri($str)
188 {
189 if ($this->config->item('permitted_uri_chars') != '')
190 {
191 if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
192 {
193 exit('The URI you submitted has disallowed characters.');
194 }
195 }
196 return $str;
197 }
198
199 // --------------------------------------------------------------------
200
201 /**
202 * Remove the suffix from the URL if needed
203 *
204 * @access private
205 * @return void
206 */
207 function _remove_url_suffix()
208 {
209 if ($this->config->item('url_suffix') != "")
210 {
211 $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
212 }
213 }
214
215 // --------------------------------------------------------------------
216
217 /**
218 * Explode the URI Segments. The individual segments will
219 * be stored in the $this->segments array.
220 *
221 * @access private
222 * @return void
223 */
224 function _explode_segments()
225 {
226 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
227 {
228 // Filter segments for security
229 $val = trim($this->_filter_uri($val));
230
231 if ($val != '')
232 $this->segments[] = $val;
233 }
234 }
235
236 // --------------------------------------------------------------------
237 /**
238 * Re-index Segments
239 *
240 * This function re-indexes the $this->segment array so that it
241 * starts at 1 rather then 0. Doing so makes it simpler to
242 * use functions like $this->uri->segment(n) since there is
243 * a 1:1 relationship between the segment array and the actual segments.
244 *
245 * @access private
246 * @return void
247 */
248 function _reindex_segments()
249 {
250 // Is the routed segment array different then the main segment array?
251 $diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;
252
253 $i = 1;
254 foreach ($this->segments as $val)
255 {
256 $this->segments[$i++] = $val;
257 }
258 unset($this->segments[0]);
259
260 if ($diff == FALSE)
261 {
262 $this->rsegments = $this->segments;
263 }
264 else
265 {
266 $i = 1;
267 foreach ($this->rsegments as $val)
268 {
269 $this->rsegments[$i++] = $val;
270 }
271 unset($this->rsegments[0]);
272 }
273 }
274
Derek Allardd2df9bc2007-04-15 17:41:17 +0000275 // --------------------------------------------------------------------
276
277 /**
278 * Fetch a URI Segment
279 *
280 * This function returns the URI segment based on the number provided.
281 *
282 * @access public
283 * @param integer
284 * @param bool
285 * @return string
286 */
287 function segment($n, $no_result = FALSE)
288 {
Rick Ellis30b40152007-07-20 00:01:13 +0000289 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000290 }
291
292 // --------------------------------------------------------------------
293
294 /**
295 * Fetch a URI "routed" Segment
296 *
297 * This function returns the re-routed URI segment (assuming routing rules are used)
298 * based on the number provided. If there is no routing this function returns the
299 * same result as $this->segment()
300 *
301 * @access public
302 * @param integer
303 * @param bool
304 * @return string
305 */
306 function rsegment($n, $no_result = FALSE)
307 {
Rick Ellis30b40152007-07-20 00:01:13 +0000308 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000309 }
310
311 // --------------------------------------------------------------------
312
313 /**
314 * Generate a key value pair from the URI string
315 *
316 * This function generates and associative array of URI data starting
317 * at the supplied segment. For example, if this is your URI:
318 *
319 * www.your-site.com/user/search/name/joe/location/UK/gender/male
320 *
321 * You can use this function to generate an array with this prototype:
322 *
323 * array (
324 * name => joe
325 * location => UK
326 * gender => male
327 * )
328 *
329 * @access public
330 * @param integer the starting segment number
331 * @param array an array of default values
332 * @return array
333 */
334 function uri_to_assoc($n = 3, $default = array())
335 {
336 return $this->_uri_to_assoc($n, $default, 'segment');
337 }
338 /**
339 * Identical to above only it uses the re-routed segment array
340 *
341 */
342 function ruri_to_assoc($n = 3, $default = array())
343 {
344 return $this->_uri_to_assoc($n, $default, 'rsegment');
345 }
346
347 // --------------------------------------------------------------------
348
349 /**
350 * Generate a key value pair from the URI string or Re-routed URI string
351 *
352 * @access private
353 * @param integer the starting segment number
354 * @param array an array of default values
355 * @param string which array we should use
356 * @return array
357 */
358 function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
359 {
360 if ($which == 'segment')
361 {
362 $total_segments = 'total_segments';
363 $segment_array = 'segment_array';
364 }
365 else
366 {
367 $total_segments = 'total_rsegments';
368 $segment_array = 'rsegment_array';
369 }
370
371 if ( ! is_numeric($n))
372 {
373 return $default;
374 }
375
376 if (isset($this->keyval[$n]))
377 {
378 return $this->keyval[$n];
379 }
380
381 if ($this->$total_segments() < $n)
382 {
383 if (count($default) == 0)
384 {
385 return array();
386 }
387
388 $retval = array();
389 foreach ($default as $val)
390 {
391 $retval[$val] = FALSE;
392 }
393 return $retval;
394 }
395
396 $segments = array_slice($this->$segment_array(), ($n - 1));
397
398 $i = 0;
399 $lastval = '';
400 $retval = array();
401 foreach ($segments as $seg)
402 {
403 if ($i % 2)
404 {
405 $retval[$lastval] = $seg;
406 }
407 else
408 {
409 $retval[$seg] = FALSE;
410 $lastval = $seg;
411 }
412
413 $i++;
414 }
415
416 if (count($default) > 0)
417 {
418 foreach ($default as $val)
419 {
420 if ( ! array_key_exists($val, $retval))
421 {
422 $retval[$val] = FALSE;
423 }
424 }
425 }
426
427 // Cache the array for reuse
428 $this->keyval[$n] = $retval;
429 return $retval;
430 }
431
Rick Ellis30b40152007-07-20 00:01:13 +0000432 // --------------------------------------------------------------------
433
Derek Allardd2df9bc2007-04-15 17:41:17 +0000434 /**
435 * Generate a URI string from an associative array
436 *
437 *
438 * @access public
439 * @param array an associative array of key/values
440 * @return array
Rick Ellis30b40152007-07-20 00:01:13 +0000441 */
442 function assoc_to_uri($array)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000443 {
444 $temp = array();
445 foreach ((array)$array as $key => $val)
446 {
447 $temp[] = $key;
448 $temp[] = $val;
449 }
450
451 return implode('/', $temp);
452 }
453
454 // --------------------------------------------------------------------
455
456 /**
457 * Fetch a URI Segment and add a trailing slash
458 *
459 * @access public
460 * @param integer
461 * @param string
462 * @return string
463 */
464 function slash_segment($n, $where = 'trailing')
465 {
466 return $this->_slash_segment($n, $where, 'segment');
467 }
468
469 // --------------------------------------------------------------------
470
471 /**
472 * Fetch a URI Segment and add a trailing slash
473 *
474 * @access public
475 * @param integer
476 * @param string
477 * @return string
478 */
479 function slash_rsegment($n, $where = 'trailing')
480 {
481 return $this->_slash_segment($n, $where, 'rsegment');
482 }
483
484 // --------------------------------------------------------------------
485
486 /**
487 * Fetch a URI Segment and add a trailing slash - helper function
488 *
489 * @access private
490 * @param integer
491 * @param string
492 * @param string
493 * @return string
494 */
495 function _slash_segment($n, $where = 'trailing', $which = 'segment')
496 {
497 if ($where == 'trailing')
498 {
499 $trailing = '/';
500 $leading = '';
501 }
502 elseif ($where == 'leading')
503 {
504 $leading = '/';
505 $trailing = '';
506 }
507 else
508 {
509 $leading = '/';
510 $trailing = '/';
511 }
512 return $leading.$this->$which($n).$trailing;
513 }
514
515 // --------------------------------------------------------------------
516
517 /**
518 * Segment Array
519 *
520 * @access public
521 * @return array
522 */
523 function segment_array()
524 {
Rick Ellis30b40152007-07-20 00:01:13 +0000525 return $this->segments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000526 }
527
528 // --------------------------------------------------------------------
529
530 /**
531 * Routed Segment Array
532 *
533 * @access public
534 * @return array
535 */
536 function rsegment_array()
537 {
Rick Ellis30b40152007-07-20 00:01:13 +0000538 return $this->rsegments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000539 }
540
541 // --------------------------------------------------------------------
542
543 /**
544 * Total number of segments
545 *
546 * @access public
547 * @return integer
548 */
549 function total_segments()
550 {
Rick Ellis30b40152007-07-20 00:01:13 +0000551 return count($this->segments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000552 }
553
554 // --------------------------------------------------------------------
555
556 /**
557 * Total number of routed segments
558 *
559 * @access public
560 * @return integer
561 */
562 function total_rsegments()
563 {
Rick Ellis30b40152007-07-20 00:01:13 +0000564 return count($this->rsegments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000565 }
566
567 // --------------------------------------------------------------------
568
569 /**
570 * Fetch the entire URI string
571 *
572 * @access public
573 * @return string
574 */
575 function uri_string()
576 {
Rick Ellis30b40152007-07-20 00:01:13 +0000577 return $this->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000578 }
579
580
581 // --------------------------------------------------------------------
582
583 /**
584 * Fetch the entire Re-routed URI string
585 *
586 * @access public
587 * @return string
588 */
589 function ruri_string()
590 {
591 return '/'.implode('/', $this->rsegment_array()).'/';
592 }
593
594}
595// END URI Class
adminb0dd10f2006-08-25 17:25:49 +0000596?>