blob: 5aafbb4cd57925ec59f6e94f06dc544fb38c2d42 [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 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
Derek Allard3d879d52008-01-18 19:41:32 +000026 * @author ExpressionEngine Dev Team
Derek Allardd2df9bc2007-04-15 17:41:17 +000027 * @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');
Derek Jones500b9d32008-01-19 17:12:31 +000081 if ($path != '' AND $path != '/' AND $path != "/".SELF)
Rick Ellis30b40152007-07-20 00:01:13 +000082 {
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');
Derek Jones500b9d32008-01-19 17:12:31 +000089 if ($path != '' AND $path != '/')
Rick Ellis30b40152007-07-20 00:01:13 +000090 {
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');
Derek Jones500b9d32008-01-19 17:12:31 +000097 if ($path != '' AND $path != '/' AND $path != "/".SELF)
Rick Ellis30b40152007-07-20 00:01:13 +000098 {
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 {
Derek Jones500b9d32008-01-19 17:12:31 +0000190 if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
Rick Ellis30b40152007-07-20 00:01:13 +0000191 {
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 }
Derek Jones500b9d32008-01-19 17:12:31 +0000196 }
197
198 return $str;
Rick Ellis30b40152007-07-20 00:01:13 +0000199 }
200
201 // --------------------------------------------------------------------
202
203 /**
204 * Remove the suffix from the URL if needed
205 *
206 * @access private
207 * @return void
208 */
209 function _remove_url_suffix()
210 {
211 if ($this->config->item('url_suffix') != "")
212 {
213 $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
214 }
215 }
216
217 // --------------------------------------------------------------------
218
219 /**
220 * Explode the URI Segments. The individual segments will
221 * be stored in the $this->segments array.
222 *
223 * @access private
224 * @return void
225 */
226 function _explode_segments()
227 {
228 foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
229 {
230 // Filter segments for security
231 $val = trim($this->_filter_uri($val));
232
233 if ($val != '')
234 $this->segments[] = $val;
235 }
236 }
237
238 // --------------------------------------------------------------------
239 /**
240 * Re-index Segments
241 *
242 * This function re-indexes the $this->segment array so that it
243 * starts at 1 rather then 0. Doing so makes it simpler to
244 * use functions like $this->uri->segment(n) since there is
245 * a 1:1 relationship between the segment array and the actual segments.
246 *
247 * @access private
248 * @return void
249 */
250 function _reindex_segments()
251 {
252 // Is the routed segment array different then the main segment array?
253 $diff = (count(array_diff($this->rsegments, $this->segments)) == 0) ? FALSE : TRUE;
254
255 $i = 1;
256 foreach ($this->segments as $val)
257 {
258 $this->segments[$i++] = $val;
259 }
260 unset($this->segments[0]);
261
262 if ($diff == FALSE)
263 {
264 $this->rsegments = $this->segments;
265 }
266 else
267 {
268 $i = 1;
269 foreach ($this->rsegments as $val)
270 {
271 $this->rsegments[$i++] = $val;
272 }
273 unset($this->rsegments[0]);
274 }
275 }
276
Derek Allardd2df9bc2007-04-15 17:41:17 +0000277 // --------------------------------------------------------------------
278
279 /**
280 * Fetch a URI Segment
281 *
282 * This function returns the URI segment based on the number provided.
283 *
284 * @access public
285 * @param integer
286 * @param bool
287 * @return string
288 */
289 function segment($n, $no_result = FALSE)
290 {
Rick Ellis30b40152007-07-20 00:01:13 +0000291 return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000292 }
293
294 // --------------------------------------------------------------------
295
296 /**
297 * Fetch a URI "routed" Segment
298 *
299 * This function returns the re-routed URI segment (assuming routing rules are used)
300 * based on the number provided. If there is no routing this function returns the
301 * same result as $this->segment()
302 *
303 * @access public
304 * @param integer
305 * @param bool
306 * @return string
307 */
308 function rsegment($n, $no_result = FALSE)
309 {
Rick Ellis30b40152007-07-20 00:01:13 +0000310 return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
Derek Allardd2df9bc2007-04-15 17:41:17 +0000311 }
312
313 // --------------------------------------------------------------------
314
315 /**
316 * Generate a key value pair from the URI string
317 *
318 * This function generates and associative array of URI data starting
319 * at the supplied segment. For example, if this is your URI:
320 *
321 * www.your-site.com/user/search/name/joe/location/UK/gender/male
322 *
323 * You can use this function to generate an array with this prototype:
324 *
325 * array (
326 * name => joe
327 * location => UK
328 * gender => male
329 * )
330 *
331 * @access public
332 * @param integer the starting segment number
333 * @param array an array of default values
334 * @return array
335 */
336 function uri_to_assoc($n = 3, $default = array())
337 {
338 return $this->_uri_to_assoc($n, $default, 'segment');
339 }
340 /**
341 * Identical to above only it uses the re-routed segment array
342 *
343 */
344 function ruri_to_assoc($n = 3, $default = array())
345 {
346 return $this->_uri_to_assoc($n, $default, 'rsegment');
347 }
348
349 // --------------------------------------------------------------------
350
351 /**
352 * Generate a key value pair from the URI string or Re-routed URI string
353 *
354 * @access private
355 * @param integer the starting segment number
356 * @param array an array of default values
357 * @param string which array we should use
358 * @return array
359 */
360 function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
361 {
362 if ($which == 'segment')
363 {
364 $total_segments = 'total_segments';
365 $segment_array = 'segment_array';
366 }
367 else
368 {
369 $total_segments = 'total_rsegments';
370 $segment_array = 'rsegment_array';
371 }
372
373 if ( ! is_numeric($n))
374 {
375 return $default;
376 }
377
378 if (isset($this->keyval[$n]))
379 {
380 return $this->keyval[$n];
381 }
382
383 if ($this->$total_segments() < $n)
384 {
385 if (count($default) == 0)
386 {
387 return array();
388 }
389
390 $retval = array();
391 foreach ($default as $val)
392 {
393 $retval[$val] = FALSE;
394 }
395 return $retval;
396 }
397
398 $segments = array_slice($this->$segment_array(), ($n - 1));
399
400 $i = 0;
401 $lastval = '';
402 $retval = array();
403 foreach ($segments as $seg)
404 {
405 if ($i % 2)
406 {
407 $retval[$lastval] = $seg;
408 }
409 else
410 {
411 $retval[$seg] = FALSE;
412 $lastval = $seg;
413 }
414
415 $i++;
416 }
417
418 if (count($default) > 0)
419 {
420 foreach ($default as $val)
421 {
422 if ( ! array_key_exists($val, $retval))
423 {
424 $retval[$val] = FALSE;
425 }
426 }
427 }
428
429 // Cache the array for reuse
430 $this->keyval[$n] = $retval;
431 return $retval;
432 }
433
Rick Ellis30b40152007-07-20 00:01:13 +0000434 // --------------------------------------------------------------------
435
Derek Allardd2df9bc2007-04-15 17:41:17 +0000436 /**
437 * Generate a URI string from an associative array
438 *
439 *
440 * @access public
441 * @param array an associative array of key/values
442 * @return array
Rick Ellis30b40152007-07-20 00:01:13 +0000443 */
444 function assoc_to_uri($array)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000445 {
446 $temp = array();
447 foreach ((array)$array as $key => $val)
448 {
449 $temp[] = $key;
450 $temp[] = $val;
451 }
452
453 return implode('/', $temp);
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
459 * Fetch a URI Segment and add a trailing slash
460 *
461 * @access public
462 * @param integer
463 * @param string
464 * @return string
465 */
466 function slash_segment($n, $where = 'trailing')
467 {
468 return $this->_slash_segment($n, $where, 'segment');
469 }
470
471 // --------------------------------------------------------------------
472
473 /**
474 * Fetch a URI Segment and add a trailing slash
475 *
476 * @access public
477 * @param integer
478 * @param string
479 * @return string
480 */
481 function slash_rsegment($n, $where = 'trailing')
482 {
483 return $this->_slash_segment($n, $where, 'rsegment');
484 }
485
486 // --------------------------------------------------------------------
487
488 /**
489 * Fetch a URI Segment and add a trailing slash - helper function
490 *
491 * @access private
492 * @param integer
493 * @param string
494 * @param string
495 * @return string
496 */
497 function _slash_segment($n, $where = 'trailing', $which = 'segment')
498 {
499 if ($where == 'trailing')
500 {
501 $trailing = '/';
502 $leading = '';
503 }
504 elseif ($where == 'leading')
505 {
506 $leading = '/';
507 $trailing = '';
508 }
509 else
510 {
511 $leading = '/';
512 $trailing = '/';
513 }
514 return $leading.$this->$which($n).$trailing;
515 }
516
517 // --------------------------------------------------------------------
518
519 /**
520 * Segment Array
521 *
522 * @access public
523 * @return array
524 */
525 function segment_array()
526 {
Rick Ellis30b40152007-07-20 00:01:13 +0000527 return $this->segments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000528 }
529
530 // --------------------------------------------------------------------
531
532 /**
533 * Routed Segment Array
534 *
535 * @access public
536 * @return array
537 */
538 function rsegment_array()
539 {
Rick Ellis30b40152007-07-20 00:01:13 +0000540 return $this->rsegments;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000541 }
542
543 // --------------------------------------------------------------------
544
545 /**
546 * Total number of segments
547 *
548 * @access public
549 * @return integer
550 */
551 function total_segments()
552 {
Rick Ellis30b40152007-07-20 00:01:13 +0000553 return count($this->segments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000554 }
555
556 // --------------------------------------------------------------------
557
558 /**
559 * Total number of routed segments
560 *
561 * @access public
562 * @return integer
563 */
564 function total_rsegments()
565 {
Rick Ellis30b40152007-07-20 00:01:13 +0000566 return count($this->rsegments);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000567 }
568
569 // --------------------------------------------------------------------
570
571 /**
572 * Fetch the entire URI string
573 *
574 * @access public
575 * @return string
576 */
577 function uri_string()
578 {
Rick Ellis30b40152007-07-20 00:01:13 +0000579 return $this->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000580 }
581
582
583 // --------------------------------------------------------------------
584
585 /**
586 * Fetch the entire Re-routed URI string
587 *
588 * @access public
589 * @return string
590 */
591 function ruri_string()
592 {
593 return '/'.implode('/', $this->rsegment_array()).'/';
594 }
595
596}
597// END URI Class
adminb0dd10f2006-08-25 17:25:49 +0000598?>