]>
Commit | Line | Data |
---|---|---|
59c06b17 CS |
1 | <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
2 | /** | |
3 | * CodeIgniter | |
4 | * | |
5 | * An open source application development framework for PHP 5.1.6 or newer | |
6 | * | |
7 | * @package CodeIgniter | |
8 | * @author ExpressionEngine Dev Team | |
9 | * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. | |
10 | * @license http://codeigniter.com/user_guide/license.html | |
11 | * @link http://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 ExpressionEngine Dev Team | |
27 | * @link http://codeigniter.com/user_guide/libraries/uri.html | |
28 | */ | |
29 | class CI_URI { | |
30 | ||
31 | /** | |
32 | * List of cached uri segments | |
33 | * | |
34 | * @var array | |
35 | * @access public | |
36 | */ | |
37 | var $keyval = array(); | |
38 | /** | |
39 | * Current uri string | |
40 | * | |
41 | * @var string | |
42 | * @access public | |
43 | */ | |
44 | var $uri_string; | |
45 | /** | |
46 | * List of uri segments | |
47 | * | |
48 | * @var array | |
49 | * @access public | |
50 | */ | |
51 | var $segments = array(); | |
52 | /** | |
53 | * Re-indexed list of uri segments | |
54 | * Starts at 1 instead of 0 | |
55 | * | |
56 | * @var array | |
57 | * @access public | |
58 | */ | |
59 | var $rsegments = array(); | |
60 | ||
61 | /** | |
62 | * Constructor | |
63 | * | |
64 | * Simply globalizes the $RTR object. The front | |
65 | * loads the Router class early on so it's not available | |
66 | * normally as other classes are. | |
67 | * | |
68 | * @access public | |
69 | */ | |
70 | function __construct() | |
71 | { | |
72 | $this->config =& load_class('Config', 'core'); | |
73 | log_message('debug', "URI Class Initialized"); | |
74 | } | |
75 | ||
76 | ||
77 | // -------------------------------------------------------------------- | |
78 | ||
79 | /** | |
80 | * Get the URI String | |
81 | * | |
82 | * @access private | |
83 | * @return string | |
84 | */ | |
85 | function _fetch_uri_string() | |
86 | { | |
87 | if (strtoupper($this->config->item('uri_protocol')) == 'AUTO') | |
88 | { | |
89 | // Is the request coming from the command line? | |
90 | if (php_sapi_name() == 'cli' or defined('STDIN')) | |
91 | { | |
92 | $this->_set_uri_string($this->_parse_cli_args()); | |
93 | return; | |
94 | } | |
95 | ||
96 | // Let's try the REQUEST_URI first, this will work in most situations | |
97 | if ($uri = $this->_detect_uri()) | |
98 | { | |
99 | $this->_set_uri_string($uri); | |
100 | return; | |
101 | } | |
102 | ||
103 | // Is there a PATH_INFO variable? | |
104 | // Note: some servers seem to have trouble with getenv() so we'll test it two ways | |
105 | $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO'); | |
106 | if (trim($path, '/') != '' && $path != "/".SELF) | |
107 | { | |
108 | $this->_set_uri_string($path); | |
109 | return; | |
110 | } | |
111 | ||
112 | // No PATH_INFO?... What about QUERY_STRING? | |
113 | $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); | |
114 | if (trim($path, '/') != '') | |
115 | { | |
116 | $this->_set_uri_string($path); | |
117 | return; | |
118 | } | |
119 | ||
120 | // As a last ditch effort lets try using the $_GET array | |
121 | if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') | |
122 | { | |
123 | $this->_set_uri_string(key($_GET)); | |
124 | return; | |
125 | } | |
126 | ||
127 | // We've exhausted all our options... | |
128 | $this->uri_string = ''; | |
129 | return; | |
130 | } | |
131 | ||
132 | $uri = strtoupper($this->config->item('uri_protocol')); | |
133 | ||
134 | if ($uri == 'REQUEST_URI') | |
135 | { | |
136 | $this->_set_uri_string($this->_detect_uri()); | |
137 | return; | |
138 | } | |
139 | elseif ($uri == 'CLI') | |
140 | { | |
141 | $this->_set_uri_string($this->_parse_cli_args()); | |
142 | return; | |
143 | } | |
144 | ||
145 | $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); | |
146 | $this->_set_uri_string($path); | |
147 | } | |
148 | ||
149 | // -------------------------------------------------------------------- | |
150 | ||
151 | /** | |
152 | * Set the URI String | |
153 | * | |
154 | * @access public | |
155 | * @param string | |
156 | * @return string | |
157 | */ | |
158 | function _set_uri_string($str) | |
159 | { | |
160 | // Filter out control characters | |
161 | $str = remove_invisible_characters($str, FALSE); | |
162 | ||
163 | // If the URI contains only a slash we'll kill it | |
164 | $this->uri_string = ($str == '/') ? '' : $str; | |
165 | } | |
166 | ||
167 | // -------------------------------------------------------------------- | |
168 | ||
169 | /** | |
170 | * Detects the URI | |
171 | * | |
172 | * This function will detect the URI automatically and fix the query string | |
173 | * if necessary. | |
174 | * | |
175 | * @access private | |
176 | * @return string | |
177 | */ | |
178 | private function _detect_uri() | |
179 | { | |
180 | if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) | |
181 | { | |
182 | return ''; | |
183 | } | |
184 | ||
185 | $uri = $_SERVER['REQUEST_URI']; | |
186 | if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) | |
187 | { | |
188 | $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); | |
189 | } | |
190 | elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) | |
191 | { | |
192 | $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); | |
193 | } | |
194 | ||
195 | // This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct | |
196 | // URI is found, and also fixes the QUERY_STRING server var and $_GET array. | |
197 | if (strncmp($uri, '?/', 2) === 0) | |
198 | { | |
199 | $uri = substr($uri, 2); | |
200 | } | |
201 | $parts = preg_split('#\?#i', $uri, 2); | |
202 | $uri = $parts[0]; | |
203 | if (isset($parts[1])) | |
204 | { | |
205 | $_SERVER['QUERY_STRING'] = $parts[1]; | |
206 | parse_str($_SERVER['QUERY_STRING'], $_GET); | |
207 | } | |
208 | else | |
209 | { | |
210 | $_SERVER['QUERY_STRING'] = ''; | |
211 | $_GET = array(); | |
212 | } | |
213 | ||
214 | if ($uri == '/' || empty($uri)) | |
215 | { | |
216 | return '/'; | |
217 | } | |
218 | ||
219 | $uri = parse_url($uri, PHP_URL_PATH); | |
220 | ||
221 | // Do some final cleaning of the URI and return it | |
222 | return str_replace(array('//', '../'), '/', trim($uri, '/')); | |
223 | } | |
224 | ||
225 | // -------------------------------------------------------------------- | |
226 | ||
227 | /** | |
228 | * Parse cli arguments | |
229 | * | |
230 | * Take each command line argument and assume it is a URI segment. | |
231 | * | |
232 | * @access private | |
233 | * @return string | |
234 | */ | |
235 | private function _parse_cli_args() | |
236 | { | |
237 | $args = array_slice($_SERVER['argv'], 1); | |
238 | ||
239 | return $args ? '/' . implode('/', $args) : ''; | |
240 | } | |
241 | ||
242 | // -------------------------------------------------------------------- | |
243 | ||
244 | /** | |
245 | * Filter segments for malicious characters | |
246 | * | |
247 | * @access private | |
248 | * @param string | |
249 | * @return string | |
250 | */ | |
251 | function _filter_uri($str) | |
252 | { | |
253 | if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE) | |
254 | { | |
255 | // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards | |
256 | // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern | |
257 | if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str)) | |
258 | { | |
259 | show_error('The URI you submitted has disallowed characters.', 400); | |
260 | } | |
261 | } | |
262 | ||
263 | // Convert programatic characters to entities | |
264 | $bad = array('$', '(', ')', '%28', '%29'); | |
265 | $good = array('$', '(', ')', '(', ')'); | |
266 | ||
267 | return str_replace($bad, $good, $str); | |
268 | } | |
269 | ||
270 | // -------------------------------------------------------------------- | |
271 | ||
272 | /** | |
273 | * Remove the suffix from the URL if needed | |
274 | * | |
275 | * @access private | |
276 | * @return void | |
277 | */ | |
278 | function _remove_url_suffix() | |
279 | { | |
280 | if ($this->config->item('url_suffix') != "") | |
281 | { | |
282 | $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string); | |
283 | } | |
284 | } | |
285 | ||
286 | // -------------------------------------------------------------------- | |
287 | ||
288 | /** | |
289 | * Explode the URI Segments. The individual segments will | |
290 | * be stored in the $this->segments array. | |
291 | * | |
292 | * @access private | |
293 | * @return void | |
294 | */ | |
295 | function _explode_segments() | |
296 | { | |
297 | foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) | |
298 | { | |
299 | // Filter segments for security | |
300 | $val = trim($this->_filter_uri($val)); | |
301 | ||
302 | if ($val != '') | |
303 | { | |
304 | $this->segments[] = $val; | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | // -------------------------------------------------------------------- | |
310 | /** | |
311 | * Re-index Segments | |
312 | * | |
313 | * This function re-indexes the $this->segment array so that it | |
314 | * starts at 1 rather than 0. Doing so makes it simpler to | |
315 | * use functions like $this->uri->segment(n) since there is | |
316 | * a 1:1 relationship between the segment array and the actual segments. | |
317 | * | |
318 | * @access private | |
319 | * @return void | |
320 | */ | |
321 | function _reindex_segments() | |
322 | { | |
323 | array_unshift($this->segments, NULL); | |
324 | array_unshift($this->rsegments, NULL); | |
325 | unset($this->segments[0]); | |
326 | unset($this->rsegments[0]); | |
327 | } | |
328 | ||
329 | // -------------------------------------------------------------------- | |
330 | ||
331 | /** | |
332 | * Fetch a URI Segment | |
333 | * | |
334 | * This function returns the URI segment based on the number provided. | |
335 | * | |
336 | * @access public | |
337 | * @param integer | |
338 | * @param bool | |
339 | * @return string | |
340 | */ | |
341 | function segment($n, $no_result = FALSE) | |
342 | { | |
343 | return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n]; | |
344 | } | |
345 | ||
346 | // -------------------------------------------------------------------- | |
347 | ||
348 | /** | |
349 | * Fetch a URI "routed" Segment | |
350 | * | |
351 | * This function returns the re-routed URI segment (assuming routing rules are used) | |
352 | * based on the number provided. If there is no routing this function returns the | |
353 | * same result as $this->segment() | |
354 | * | |
355 | * @access public | |
356 | * @param integer | |
357 | * @param bool | |
358 | * @return string | |
359 | */ | |
360 | function rsegment($n, $no_result = FALSE) | |
361 | { | |
362 | return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n]; | |
363 | } | |
364 | ||
365 | // -------------------------------------------------------------------- | |
366 | ||
367 | /** | |
368 | * Generate a key value pair from the URI string | |
369 | * | |
370 | * This function generates and associative array of URI data starting | |
371 | * at the supplied segment. For example, if this is your URI: | |
372 | * | |
373 | * example.com/user/search/name/joe/location/UK/gender/male | |
374 | * | |
375 | * You can use this function to generate an array with this prototype: | |
376 | * | |
377 | * array ( | |
378 | * name => joe | |
379 | * location => UK | |
380 | * gender => male | |
381 | * ) | |
382 | * | |
383 | * @access public | |
384 | * @param integer the starting segment number | |
385 | * @param array an array of default values | |
386 | * @return array | |
387 | */ | |
388 | function uri_to_assoc($n = 3, $default = array()) | |
389 | { | |
390 | return $this->_uri_to_assoc($n, $default, 'segment'); | |
391 | } | |
392 | /** | |
393 | * Identical to above only it uses the re-routed segment array | |
394 | * | |
395 | * @access public | |
396 | * @param integer the starting segment number | |
397 | * @param array an array of default values | |
398 | * @return array | |
399 | * | |
400 | */ | |
401 | function ruri_to_assoc($n = 3, $default = array()) | |
402 | { | |
403 | return $this->_uri_to_assoc($n, $default, 'rsegment'); | |
404 | } | |
405 | ||
406 | // -------------------------------------------------------------------- | |
407 | ||
408 | /** | |
409 | * Generate a key value pair from the URI string or Re-routed URI string | |
410 | * | |
411 | * @access private | |
412 | * @param integer the starting segment number | |
413 | * @param array an array of default values | |
414 | * @param string which array we should use | |
415 | * @return array | |
416 | */ | |
417 | function _uri_to_assoc($n = 3, $default = array(), $which = 'segment') | |
418 | { | |
419 | if ($which == 'segment') | |
420 | { | |
421 | $total_segments = 'total_segments'; | |
422 | $segment_array = 'segment_array'; | |
423 | } | |
424 | else | |
425 | { | |
426 | $total_segments = 'total_rsegments'; | |
427 | $segment_array = 'rsegment_array'; | |
428 | } | |
429 | ||
430 | if ( ! is_numeric($n)) | |
431 | { | |
432 | return $default; | |
433 | } | |
434 | ||
435 | if (isset($this->keyval[$n])) | |
436 | { | |
437 | return $this->keyval[$n]; | |
438 | } | |
439 | ||
440 | if ($this->$total_segments() < $n) | |
441 | { | |
442 | if (count($default) == 0) | |
443 | { | |
444 | return array(); | |
445 | } | |
446 | ||
447 | $retval = array(); | |
448 | foreach ($default as $val) | |
449 | { | |
450 | $retval[$val] = FALSE; | |
451 | } | |
452 | return $retval; | |
453 | } | |
454 | ||
455 | $segments = array_slice($this->$segment_array(), ($n - 1)); | |
456 | ||
457 | $i = 0; | |
458 | $lastval = ''; | |
459 | $retval = array(); | |
460 | foreach ($segments as $seg) | |
461 | { | |
462 | if ($i % 2) | |
463 | { | |
464 | $retval[$lastval] = $seg; | |
465 | } | |
466 | else | |
467 | { | |
468 | $retval[$seg] = FALSE; | |
469 | $lastval = $seg; | |
470 | } | |
471 | ||
472 | $i++; | |
473 | } | |
474 | ||
475 | if (count($default) > 0) | |
476 | { | |
477 | foreach ($default as $val) | |
478 | { | |
479 | if ( ! array_key_exists($val, $retval)) | |
480 | { | |
481 | $retval[$val] = FALSE; | |
482 | } | |
483 | } | |
484 | } | |
485 | ||
486 | // Cache the array for reuse | |
487 | $this->keyval[$n] = $retval; | |
488 | return $retval; | |
489 | } | |
490 | ||
491 | // -------------------------------------------------------------------- | |
492 | ||
493 | /** | |
494 | * Generate a URI string from an associative array | |
495 | * | |
496 | * | |
497 | * @access public | |
498 | * @param array an associative array of key/values | |
499 | * @return array | |
500 | */ | |
501 | function assoc_to_uri($array) | |
502 | { | |
503 | $temp = array(); | |
504 | foreach ((array)$array as $key => $val) | |
505 | { | |
506 | $temp[] = $key; | |
507 | $temp[] = $val; | |
508 | } | |
509 | ||
510 | return implode('/', $temp); | |
511 | } | |
512 | ||
513 | // -------------------------------------------------------------------- | |
514 | ||
515 | /** | |
516 | * Fetch a URI Segment and add a trailing slash | |
517 | * | |
518 | * @access public | |
519 | * @param integer | |
520 | * @param string | |
521 | * @return string | |
522 | */ | |
523 | function slash_segment($n, $where = 'trailing') | |
524 | { | |
525 | return $this->_slash_segment($n, $where, 'segment'); | |
526 | } | |
527 | ||
528 | // -------------------------------------------------------------------- | |
529 | ||
530 | /** | |
531 | * Fetch a URI Segment and add a trailing slash | |
532 | * | |
533 | * @access public | |
534 | * @param integer | |
535 | * @param string | |
536 | * @return string | |
537 | */ | |
538 | function slash_rsegment($n, $where = 'trailing') | |
539 | { | |
540 | return $this->_slash_segment($n, $where, 'rsegment'); | |
541 | } | |
542 | ||
543 | // -------------------------------------------------------------------- | |
544 | ||
545 | /** | |
546 | * Fetch a URI Segment and add a trailing slash - helper function | |
547 | * | |
548 | * @access private | |
549 | * @param integer | |
550 | * @param string | |
551 | * @param string | |
552 | * @return string | |
553 | */ | |
554 | function _slash_segment($n, $where = 'trailing', $which = 'segment') | |
555 | { | |
556 | $leading = '/'; | |
557 | $trailing = '/'; | |
558 | ||
559 | if ($where == 'trailing') | |
560 | { | |
561 | $leading = ''; | |
562 | } | |
563 | elseif ($where == 'leading') | |
564 | { | |
565 | $trailing = ''; | |
566 | } | |
567 | ||
568 | return $leading.$this->$which($n).$trailing; | |
569 | } | |
570 | ||
571 | // -------------------------------------------------------------------- | |
572 | ||
573 | /** | |
574 | * Segment Array | |
575 | * | |
576 | * @access public | |
577 | * @return array | |
578 | */ | |
579 | function segment_array() | |
580 | { | |
581 | return $this->segments; | |
582 | } | |
583 | ||
584 | // -------------------------------------------------------------------- | |
585 | ||
586 | /** | |
587 | * Routed Segment Array | |
588 | * | |
589 | * @access public | |
590 | * @return array | |
591 | */ | |
592 | function rsegment_array() | |
593 | { | |
594 | return $this->rsegments; | |
595 | } | |
596 | ||
597 | // -------------------------------------------------------------------- | |
598 | ||
599 | /** | |
600 | * Total number of segments | |
601 | * | |
602 | * @access public | |
603 | * @return integer | |
604 | */ | |
605 | function total_segments() | |
606 | { | |
607 | return count($this->segments); | |
608 | } | |
609 | ||
610 | // -------------------------------------------------------------------- | |
611 | ||
612 | /** | |
613 | * Total number of routed segments | |
614 | * | |
615 | * @access public | |
616 | * @return integer | |
617 | */ | |
618 | function total_rsegments() | |
619 | { | |
620 | return count($this->rsegments); | |
621 | } | |
622 | ||
623 | // -------------------------------------------------------------------- | |
624 | ||
625 | /** | |
626 | * Fetch the entire URI string | |
627 | * | |
628 | * @access public | |
629 | * @return string | |
630 | */ | |
631 | function uri_string() | |
632 | { | |
633 | return $this->uri_string; | |
634 | } | |
635 | ||
636 | ||
637 | // -------------------------------------------------------------------- | |
638 | ||
639 | /** | |
640 | * Fetch the entire Re-routed URI string | |
641 | * | |
642 | * @access public | |
643 | * @return string | |
644 | */ | |
645 | function ruri_string() | |
646 | { | |
647 | return '/'.implode('/', $this->rsegment_array()); | |
648 | } | |
649 | ||
650 | } | |
651 | // END URI Class | |
652 | ||
653 | /* End of file URI.php */ | |
654 | /* Location: ./system/core/URI.php */ |