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