blob: 8de26f933ee9eb6b3f5741c6ea2ec879d42f2560 [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
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Derek Allardd2df9bc2007-04-15 17:41:17 +00009 * @copyright Copyright (c) 2006, 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 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 {
Derek Jones27126102008-01-29 23:43:09 +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');
Derek Jones500b9d32008-01-19 17:12:31 +000077 if ($path != '' AND $path != '/' AND $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 Jones500b9d32008-01-19 17:12:31 +000085 if ($path != '' AND $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');
Derek Jones500b9d32008-01-19 17:12:31 +000093 if ($path != '' AND $path != '/' AND $path != "/".SELF)
Rick Ellis30b40152007-07-20 00:01:13 +000094 {
95 $this->uri_string = $path;
Rick Ellisde2623c2007-07-21 18:28:24 +000096 return;
Rick Ellis30b40152007-07-20 00:01:13 +000097 }
98
99 // We've exhausted all our options...
100 $this->uri_string = '';
101 }
102 else
103 {
104 $uri = strtoupper($this->config->item('uri_protocol'));
105
106 if ($uri == 'REQUEST_URI')
107 {
108 $this->uri_string = $this->_parse_request_uri();
Rick Ellisde2623c2007-07-21 18:28:24 +0000109 return;
Rick Ellis30b40152007-07-20 00:01:13 +0000110 }
111
112 $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
113 }
114
115 // If the URI contains only a slash we'll kill it
116 if ($this->uri_string == '/')
117 {
118 $this->uri_string = '';
119 }
120 }
Rick Ellisde2623c2007-07-21 18:28:24 +0000121
Rick Ellis30b40152007-07-20 00:01:13 +0000122 // --------------------------------------------------------------------
123
124 /**
125 * Parse the REQUEST_URI
126 *
127 * Due to the way REQUEST_URI works it usually contains path info
128 * that makes it unusable as URI data. We'll trim off the unnecessary
129 * data, hopefully arriving at a valid URI that we can use.
130 *
131 * @access private
132 * @return string
133 */
134 function _parse_request_uri()
135 {
136 if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '')
137 {
138 return '';
139 }
140
141 $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI']));
142
143 if ($request_uri == '' OR $request_uri == SELF)
144 {
145 return '';
146 }
147
148 $fc_path = FCPATH;
149 if (strpos($request_uri, '?') !== FALSE)
150 {
151 $fc_path .= '?';
152 }
153
154 $parsed_uri = explode("/", $request_uri);
155
156 $i = 0;
157 foreach(explode("/", $fc_path) as $segment)
158 {
159 if (isset($parsed_uri[$i]) AND $segment == $parsed_uri[$i])
160 {
161 $i++;
162 }
163 }
164
165 $parsed_uri = implode("/", array_slice($parsed_uri, $i));
166
167 if ($parsed_uri != '')
168 {
169 $parsed_uri = '/'.$parsed_uri;
170 }
171
172 return $parsed_uri;
173 }
174
175 // --------------------------------------------------------------------
176
177 /**
178 * Filter segments for malicious characters
179 *
180 * @access private
181 * @param string
182 * @return string
183 */
184 function _filter_uri($str)
185 {
Derek Jones500b9d32008-01-19 17:12:31 +0000186 if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
Rick Ellis30b40152007-07-20 00:01:13 +0000187 {
188 if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", $str))
189 {
190 exit('The URI you submitted has disallowed characters.');
191 }
Derek Jones500b9d32008-01-19 17:12:31 +0000192 }
193
194 return $str;
Rick Ellis30b40152007-07-20 00:01:13 +0000195 }
196
197 // --------------------------------------------------------------------
198
199 /**
200 * Remove the suffix from the URL if needed
201 *
202 * @access private
203 * @return void
204 */
205 function _remove_url_suffix()
206 {
207 if ($this->config->item('url_suffix') != "")
208 {
209 $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
210 }
211 }
212
213 // --------------------------------------------------------------------
214
215 /**
216 * Explode the URI Segments. The individual segments will
217 * be stored in the $this->segments array.
218 *
219 * @access private
220 * @return void
221 */
222 function _explode_segments()
223 {
224 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
225 {
226 // Filter segments for security
227 $val = trim($this->_filter_uri($val));
228
229 if ($val != '')
230 $this->segments[] = $val;
231 }
232 }
233
234 // --------------------------------------------------------------------
235 /**
236 * Re-index Segments
237 *
238 * This function re-indexes the $this->segment array so that it
239 * starts at 1 rather then 0. Doing so makes it simpler to
240 * use functions like $this->uri->segment(n) since there is
241 * a 1:1 relationship between the segment array and the actual segments.
242 *
243 * @access private
244 * @return void
245 */
246 function _reindex_segments()
247 {
248 // Is the routed segment array different then the main segment array?
Derek Jones240292e2008-01-30 00:18:05 +0000249 // have to compute the diff both ways since PHP returns only values in $arr1 that are not in $arr2.
250 $diff = (array_diff($this->rsegments, $this->segments) != array_diff($this->segments, $this->rsegments)) ? TRUE : FALSE;
251
Rick Ellis30b40152007-07-20 00:01:13 +0000252 $i = 1;
253 foreach ($this->segments as $val)
254 {
255 $this->segments[$i++] = $val;
256 }
257 unset($this->segments[0]);
258
259 if ($diff == FALSE)
260 {
261 $this->rsegments = $this->segments;
262 }
263 else
264 {
265 $i = 1;
266 foreach ($this->rsegments as $val)
267 {
268 $this->rsegments[$i++] = $val;
269 }
270 unset($this->rsegments[0]);
271 }
272 }
273
Derek Allardd2df9bc2007-04-15 17:41:17 +0000274 // --------------------------------------------------------------------
275
276 /**
277 * Fetch a URI Segment
278 *
279 * This function returns the URI segment based on the number provided.
280 *
281 * @access public
282 * @param integer
283 * @param bool
284 * @return string
285 */
286 function segment($n, $no_result = FALSE)
287 {
Rick Ellis30b40152007-07-20 00:01:13 +0000288 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000289 }
290
291 // --------------------------------------------------------------------
292
293 /**
294 * Fetch a URI "routed" Segment
295 *
296 * This function returns the re-routed URI segment (assuming routing rules are used)
297 * based on the number provided. If there is no routing this function returns the
298 * same result as $this->segment()
299 *
300 * @access public
301 * @param integer
302 * @param bool
303 * @return string
304 */
305 function rsegment($n, $no_result = FALSE)
306 {
Rick Ellis30b40152007-07-20 00:01:13 +0000307 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000308 }
309
310 // --------------------------------------------------------------------
311
312 /**
313 * Generate a key value pair from the URI string
314 *
315 * This function generates and associative array of URI data starting
316 * at the supplied segment. For example, if this is your URI:
317 *
318 * www.your-site.com/user/search/name/joe/location/UK/gender/male
319 *
320 * You can use this function to generate an array with this prototype:
321 *
322 * array (
323 * name => joe
324 * location => UK
325 * gender => male
326 * )
327 *
328 * @access public
329 * @param integer the starting segment number
330 * @param array an array of default values
331 * @return array
332 */
333 function uri_to_assoc($n = 3, $default = array())
334 {
335 return $this->_uri_to_assoc($n, $default, 'segment');
336 }
337 /**
338 * Identical to above only it uses the re-routed segment array
339 *
340 */
341 function ruri_to_assoc($n = 3, $default = array())
342 {
343 return $this->_uri_to_assoc($n, $default, 'rsegment');
344 }
345
346 // --------------------------------------------------------------------
347
348 /**
349 * Generate a key value pair from the URI string or Re-routed URI string
350 *
351 * @access private
352 * @param integer the starting segment number
353 * @param array an array of default values
354 * @param string which array we should use
355 * @return array
356 */
357 function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
358 {
359 if ($which == 'segment')
360 {
361 $total_segments = 'total_segments';
362 $segment_array = 'segment_array';
363 }
364 else
365 {
366 $total_segments = 'total_rsegments';
367 $segment_array = 'rsegment_array';
368 }
369
370 if ( ! is_numeric($n))
371 {
372 return $default;
373 }
374
375 if (isset($this->keyval[$n]))
376 {
377 return $this->keyval[$n];
378 }
379
380 if ($this->$total_segments() < $n)
381 {
382 if (count($default) == 0)
383 {
384 return array();
385 }
386
387 $retval = array();
388 foreach ($default as $val)
389 {
390 $retval[$val] = FALSE;
391 }
392 return $retval;
393 }
394
395 $segments = array_slice($this->$segment_array(), ($n - 1));
396
397 $i = 0;
398 $lastval = '';
399 $retval = array();
400 foreach ($segments as $seg)
401 {
402 if ($i % 2)
403 {
404 $retval[$lastval] = $seg;
405 }
406 else
407 {
408 $retval[$seg] = FALSE;
409 $lastval = $seg;
410 }
411
412 $i++;
413 }
414
415 if (count($default) > 0)
416 {
417 foreach ($default as $val)
418 {
419 if ( ! array_key_exists($val, $retval))
420 {
421 $retval[$val] = FALSE;
422 }
423 }
424 }
425
426 // Cache the array for reuse
427 $this->keyval[$n] = $retval;
428 return $retval;
429 }
430
Rick Ellis30b40152007-07-20 00:01:13 +0000431 // --------------------------------------------------------------------
432
Derek Allardd2df9bc2007-04-15 17:41:17 +0000433 /**
434 * Generate a URI string from an associative array
435 *
436 *
437 * @access public
438 * @param array an associative array of key/values
439 * @return array
Rick Ellis30b40152007-07-20 00:01:13 +0000440 */
441 function assoc_to_uri($array)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000442 {
443 $temp = array();
444 foreach ((array)$array as $key => $val)
445 {
446 $temp[] = $key;
447 $temp[] = $val;
448 }
449
450 return implode('/', $temp);
451 }
452
453 // --------------------------------------------------------------------
454
455 /**
456 * Fetch a URI Segment and add a trailing slash
457 *
458 * @access public
459 * @param integer
460 * @param string
461 * @return string
462 */
463 function slash_segment($n, $where = 'trailing')
464 {
465 return $this->_slash_segment($n, $where, 'segment');
466 }
467
468 // --------------------------------------------------------------------
469
470 /**
471 * Fetch a URI Segment and add a trailing slash
472 *
473 * @access public
474 * @param integer
475 * @param string
476 * @return string
477 */
478 function slash_rsegment($n, $where = 'trailing')
479 {
480 return $this->_slash_segment($n, $where, 'rsegment');
481 }
482
483 // --------------------------------------------------------------------
484
485 /**
486 * Fetch a URI Segment and add a trailing slash - helper function
487 *
488 * @access private
489 * @param integer
490 * @param string
491 * @param string
492 * @return string
493 */
494 function _slash_segment($n, $where = 'trailing', $which = 'segment')
495 {
496 if ($where == 'trailing')
497 {
498 $trailing = '/';
499 $leading = '';
500 }
501 elseif ($where == 'leading')
502 {
503 $leading = '/';
504 $trailing = '';
505 }
506 else
507 {
508 $leading = '/';
509 $trailing = '/';
510 }
511 return $leading.$this->$which($n).$trailing;
512 }
513
514 // --------------------------------------------------------------------
515
516 /**
517 * Segment Array
518 *
519 * @access public
520 * @return array
521 */
522 function segment_array()
523 {
Rick Ellis30b40152007-07-20 00:01:13 +0000524 return $this->segments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000525 }
526
527 // --------------------------------------------------------------------
528
529 /**
530 * Routed Segment Array
531 *
532 * @access public
533 * @return array
534 */
535 function rsegment_array()
536 {
Rick Ellis30b40152007-07-20 00:01:13 +0000537 return $this->rsegments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000538 }
539
540 // --------------------------------------------------------------------
541
542 /**
543 * Total number of segments
544 *
545 * @access public
546 * @return integer
547 */
548 function total_segments()
549 {
Rick Ellis30b40152007-07-20 00:01:13 +0000550 return count($this->segments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000551 }
552
553 // --------------------------------------------------------------------
554
555 /**
556 * Total number of routed segments
557 *
558 * @access public
559 * @return integer
560 */
561 function total_rsegments()
562 {
Rick Ellis30b40152007-07-20 00:01:13 +0000563 return count($this->rsegments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000564 }
565
566 // --------------------------------------------------------------------
567
568 /**
569 * Fetch the entire URI string
570 *
571 * @access public
572 * @return string
573 */
574 function uri_string()
575 {
Rick Ellis30b40152007-07-20 00:01:13 +0000576 return $this->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000577 }
578
579
580 // --------------------------------------------------------------------
581
582 /**
583 * Fetch the entire Re-routed URI string
584 *
585 * @access public
586 * @return string
587 */
588 function ruri_string()
589 {
590 return '/'.implode('/', $this->rsegment_array()).'/';
591 }
592
593}
594// END URI Class
adminb0dd10f2006-08-25 17:25:49 +0000595?>