blob: 0760dc830d3083ed3fd73e0384aed051721087bc [file] [log] [blame]
Derek Allard2067d1a2008-11-13 22:59:24 +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 ExpressionEngine Dev Team
Derek Jones7f3719f2010-01-05 13:35:37 +00009 * @copyright Copyright (c) 2008 - 2010, EllisLab, Inc.
Derek Allard2067d1a2008-11-13 22:59:24 +000010 * @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 * Input Class
20 *
21 * Pre-processes global input data for security
22 *
23 * @package CodeIgniter
24 * @subpackage Libraries
25 * @category Input
26 * @author ExpressionEngine Dev Team
27 * @link http://codeigniter.com/user_guide/libraries/input.html
28 */
29class CI_Input {
Derek Allard2067d1a2008-11-13 22:59:24 +000030
Derek Jones69fc4fc2010-03-02 13:36:31 -060031 var $ip_address = FALSE;
32 var $user_agent = FALSE;
33 var $_allow_get_array = FALSE;
34 var $_standardize_newlines = TRUE;
35 var $_enable_xss = FALSE; // Set automatically based on config setting
36 var $_enable_csrf = FALSE; // Set automatically based on config setting
37
Derek Allard2067d1a2008-11-13 22:59:24 +000038
39 /**
40 * Constructor
41 *
42 * Sets whether to globally enable the XSS processing
43 * and whether to allow the $_GET array
44 *
45 * @access public
46 */
47 function CI_Input()
48 {
49 log_message('debug', "Input Class Initialized");
50
Derek Jones69fc4fc2010-03-02 13:36:31 -060051 $this->_allow_get_array = (config_item('enable_query_strings') === TRUE) ? TRUE : FALSE;
52 $this->_enable_xss = (config_item('global_xss_filtering') === TRUE) ? TRUE : FALSE;
53 $this->_enable_csrf = (config_item('csrf_protection') === TRUE) ? TRUE : FALSE;
54
55 // Do we need to load the security class?
56 if ($this->_enable_xss == TRUE OR $this->_enable_csrf == TRUE)
57 {
58 $this->security =& load_class('Security');
59 }
60
61 // Do we need the Unicode class?
62 if (UTF8_ENABLED === TRUE)
63 {
64 global $UNI;
65 $this->uni =& $UNI;
66 }
67
68 // Sanitize global arrays
Derek Allard2067d1a2008-11-13 22:59:24 +000069 $this->_sanitize_globals();
70 }
71
72 // --------------------------------------------------------------------
73
74 /**
Derek Allard2067d1a2008-11-13 22:59:24 +000075 * Fetch from array
76 *
77 * This is a helper function to retrieve values from global arrays
78 *
79 * @access private
80 * @param array
81 * @param string
82 * @param bool
83 * @return string
84 */
85 function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
86 {
87 if ( ! isset($array[$index]))
88 {
89 return FALSE;
90 }
91
92 if ($xss_clean === TRUE)
93 {
Derek Jones69fc4fc2010-03-02 13:36:31 -060094 $_security =& load_class('Security');
95 return $_security->xss_clean($array[$index]);
Derek Allard2067d1a2008-11-13 22:59:24 +000096 }
97
98 return $array[$index];
99 }
100
101 // --------------------------------------------------------------------
102
103 /**
104 * Fetch an item from the GET array
105 *
106 * @access public
107 * @param string
108 * @param bool
109 * @return string
110 */
111 function get($index = '', $xss_clean = FALSE)
112 {
113 return $this->_fetch_from_array($_GET, $index, $xss_clean);
114 }
115
116 // --------------------------------------------------------------------
117
118 /**
119 * Fetch an item from the POST array
120 *
121 * @access public
122 * @param string
123 * @param bool
124 * @return string
125 */
126 function post($index = '', $xss_clean = FALSE)
127 {
128 return $this->_fetch_from_array($_POST, $index, $xss_clean);
129 }
130
Derek Jones69fc4fc2010-03-02 13:36:31 -0600131
Derek Allard2067d1a2008-11-13 22:59:24 +0000132 // --------------------------------------------------------------------
133
134 /**
135 * Fetch an item from either the GET array or the POST
136 *
137 * @access public
138 * @param string The index key
139 * @param bool XSS cleaning
140 * @return string
141 */
142 function get_post($index = '', $xss_clean = FALSE)
143 {
144 if ( ! isset($_POST[$index]) )
145 {
146 return $this->get($index, $xss_clean);
147 }
148 else
149 {
150 return $this->post($index, $xss_clean);
151 }
152 }
153
154 // --------------------------------------------------------------------
155
156 /**
157 * Fetch an item from the COOKIE array
158 *
159 * @access public
160 * @param string
161 * @param bool
162 * @return string
163 */
164 function cookie($index = '', $xss_clean = FALSE)
165 {
166 return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
167 }
168
Derek Jones69fc4fc2010-03-02 13:36:31 -0600169 // ------------------------------------------------------------------------
170
171 /**
172 * Set cookie
173 *
174 * Accepts six parameter, or you can submit an associative
175 * array in the first parameter containing all the values.
176 *
177 * @access public
178 * @param mixed
179 * @param string the value of the cookie
180 * @param string the number of seconds until expiration
181 * @param string the cookie domain. Usually: .yourdomain.com
182 * @param string the cookie path
183 * @param string the cookie prefix
184 * @return void
185 */
186 function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '')
187 {
188 if (is_array($name))
189 {
190 foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'name') as $item)
191 {
192 if (isset($name[$item]))
193 {
194 $$item = $name[$item];
195 }
196 }
197 }
198
199 if ($prefix == '' AND config_item('cookie_prefix') != '')
200 {
201 $prefix = config_item('cookie_prefix');
202 }
203 if ($domain == '' AND config_item('cookie_domain') != '')
204 {
205 $domain = config_item('cookie_domain');
206 }
207 if ($path == '/' AND config_item('cookie_path') != '/')
208 {
209 $path = config_item('cookie_path');
210 }
211
212 if ( ! is_numeric($expire))
213 {
214 $expire = time() - 86500;
215 }
216 else
217 {
218 if ($expire > 0)
219 {
220 $expire = time() + $expire;
221 }
222 else
223 {
224 $expire = 0;
225 }
226 }
227
228 setcookie($prefix.$name, $value, $expire, $path, $domain, 0);
229 }
230
Derek Allard2067d1a2008-11-13 22:59:24 +0000231 // --------------------------------------------------------------------
232
233 /**
234 * Fetch an item from the SERVER array
235 *
236 * @access public
237 * @param string
238 * @param bool
239 * @return string
240 */
241 function server($index = '', $xss_clean = FALSE)
242 {
243 return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
244 }
245
246 // --------------------------------------------------------------------
247
248 /**
249 * Fetch the IP Address
250 *
251 * @access public
252 * @return string
253 */
254 function ip_address()
255 {
256 if ($this->ip_address !== FALSE)
257 {
258 return $this->ip_address;
259 }
Derek Jonesc5972282009-02-04 21:40:20 +0000260
Derek Jones42b2e172009-02-05 16:59:45 +0000261 if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
Derek Jonesc5972282009-02-04 21:40:20 +0000262 {
Derek Jones42b2e172009-02-05 16:59:45 +0000263 $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
Derek Jonesc5972282009-02-04 21:40:20 +0000264 $proxies = is_array($proxies) ? $proxies : array($proxies);
Derek Allard2067d1a2008-11-13 22:59:24 +0000265
Derek Jonesc5972282009-02-04 21:40:20 +0000266 $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
267 }
268 elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP'))
Derek Allard2067d1a2008-11-13 22:59:24 +0000269 {
270 $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
271 }
272 elseif ($this->server('REMOTE_ADDR'))
273 {
274 $this->ip_address = $_SERVER['REMOTE_ADDR'];
275 }
276 elseif ($this->server('HTTP_CLIENT_IP'))
277 {
278 $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
279 }
280 elseif ($this->server('HTTP_X_FORWARDED_FOR'))
281 {
282 $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
283 }
284
285 if ($this->ip_address === FALSE)
286 {
287 $this->ip_address = '0.0.0.0';
288 return $this->ip_address;
289 }
290
291 if (strstr($this->ip_address, ','))
292 {
293 $x = explode(',', $this->ip_address);
Derek Jonesc5972282009-02-04 21:40:20 +0000294 $this->ip_address = trim(end($x));
Derek Allard2067d1a2008-11-13 22:59:24 +0000295 }
296
297 if ( ! $this->valid_ip($this->ip_address))
298 {
299 $this->ip_address = '0.0.0.0';
300 }
301
302 return $this->ip_address;
303 }
304
305 // --------------------------------------------------------------------
306
307 /**
308 * Validate IP Address
309 *
310 * Updated version suggested by Geert De Deckere
311 *
312 * @access public
313 * @param string
314 * @return string
315 */
316 function valid_ip($ip)
317 {
318 $ip_segments = explode('.', $ip);
319
320 // Always 4 segments needed
321 if (count($ip_segments) != 4)
322 {
323 return FALSE;
324 }
325 // IP can not start with 0
326 if ($ip_segments[0][0] == '0')
327 {
328 return FALSE;
329 }
330 // Check each segment
331 foreach ($ip_segments as $segment)
332 {
333 // IP segments must be digits and can not be
334 // longer than 3 digits or greater then 255
335 if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
336 {
337 return FALSE;
338 }
339 }
340
341 return TRUE;
342 }
343
344 // --------------------------------------------------------------------
345
346 /**
347 * User Agent
348 *
349 * @access public
350 * @return string
351 */
352 function user_agent()
353 {
354 if ($this->user_agent !== FALSE)
355 {
356 return $this->user_agent;
357 }
358
359 $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
360
361 return $this->user_agent;
362 }
363
364 // --------------------------------------------------------------------
365
366 /**
Derek Jones69fc4fc2010-03-02 13:36:31 -0600367 * Sanitize Globals
Derek Allard2067d1a2008-11-13 22:59:24 +0000368 *
Derek Jones69fc4fc2010-03-02 13:36:31 -0600369 * This function does the following:
370 *
371 * Unsets $_GET data (if query strings are not enabled)
372 *
373 * Unsets all globals if register_globals is enabled
374 *
375 * Standardizes newline characters to \n
376 *
377 * @access private
378 * @return void
Derek Allard2067d1a2008-11-13 22:59:24 +0000379 */
Derek Jones69fc4fc2010-03-02 13:36:31 -0600380 function _sanitize_globals()
Derek Allard2067d1a2008-11-13 22:59:24 +0000381 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600382 // It would be "wrong" to unset any of these GLOBALS.
383 $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',
384 'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN');
Derek Allard2067d1a2008-11-13 22:59:24 +0000385
Derek Jones69fc4fc2010-03-02 13:36:31 -0600386 // Unset globals for securiy.
387 // This is effectively the same as register_globals = off
388 foreach (array($_GET, $_POST, $_COOKIE) as $global)
Derek Allard2067d1a2008-11-13 22:59:24 +0000389 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600390 if ( ! is_array($global))
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600392 if ( ! in_array($global, $protected))
393 {
394 global $$global;
395 $$global = NULL;
396 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000397 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600398 else
399 {
400 foreach ($global as $key => $val)
401 {
402 if ( ! in_array($key, $protected))
403 {
404 global $$key;
405 $$key = NULL;
406 }
407 }
408 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000409 }
410
Derek Jones69fc4fc2010-03-02 13:36:31 -0600411 // Is $_GET data allowed? If not we'll set the $_GET to an empty array
412 if ($this->_allow_get_array == FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000413 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600414 $_GET = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000415 }
416 else
417 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600418 if (is_array($_GET) AND count($_GET) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000419 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600420 foreach($_GET as $key => $val)
421 {
422 $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
423 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000424 }
425 }
426
Derek Jones69fc4fc2010-03-02 13:36:31 -0600427 // Clean $_POST Data
428 if (is_array($_POST) AND count($_POST) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000429 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600430 foreach($_POST as $key => $val)
431 {
432 $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
433 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000434 }
435
Derek Jones69fc4fc2010-03-02 13:36:31 -0600436 // Clean $_COOKIE Data
437 if (is_array($_COOKIE) AND count($_COOKIE) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000438 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600439 // Also get rid of specially treated cookies that might be set by a server
440 // or silly application, that are of no use to a CI application anyway
441 // but that when present will trip our 'Disallowed Key Characters' alarm
442 // http://www.ietf.org/rfc/rfc2109.txt
443 // note that the key names below are single quoted strings, and are not PHP variables
444 unset($_COOKIE['$Version']);
445 unset($_COOKIE['$Path']);
446 unset($_COOKIE['$Domain']);
447
448 foreach($_COOKIE as $key => $val)
449 {
450 $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
451 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000452 }
453
Derek Jones69fc4fc2010-03-02 13:36:31 -0600454 // Sanitize PHP_SELF
455 $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
456
457
458 // CSRF Protection check
459 if ($this->_enable_csrf == TRUE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000460 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600461 $this->security->csrf_verify();
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000463
Derek Jones69fc4fc2010-03-02 13:36:31 -0600464 log_message('debug', "Global POST and COOKIE data sanitized");
Derek Allard2067d1a2008-11-13 22:59:24 +0000465 }
466
467 // --------------------------------------------------------------------
468
469 /**
Derek Jones69fc4fc2010-03-02 13:36:31 -0600470 * Clean Input Data
Derek Allard2067d1a2008-11-13 22:59:24 +0000471 *
Derek Jones69fc4fc2010-03-02 13:36:31 -0600472 * This is a helper function. It escapes data and
473 * standardizes newline characters to \n
Derek Allard2067d1a2008-11-13 22:59:24 +0000474 *
475 * @access private
476 * @param string
Derek Allard2067d1a2008-11-13 22:59:24 +0000477 * @return string
478 */
Derek Jones69fc4fc2010-03-02 13:36:31 -0600479 function _clean_input_data($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000480 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600481 if (is_array($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000482 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600483 $new_array = array();
484 foreach ($str as $key => $val)
485 {
486 $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
487 }
488 return $new_array;
Derek Allard2067d1a2008-11-13 22:59:24 +0000489 }
490
Derek Jones69fc4fc2010-03-02 13:36:31 -0600491 // We strip slashes if magic quotes is on to keep things consistent
492 if (get_magic_quotes_gpc())
Derek Allard2067d1a2008-11-13 22:59:24 +0000493 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600494 $str = stripslashes($str);
495 }
496
497 // Clean UTF-8 if supported
498 if (UTF8_ENABLED === TRUE)
499 {
500 $str = $this->uni->clean_string($str);
501 }
502
503 // Should we filter the input data?
504 if ($this->_enable_xss === TRUE)
505 {
506 $str = $this->security->xss_clean($str);
507 }
508
509 // Standardize newlines if needed
510 if ($this->_standardize_newlines == TRUE)
511 {
512 if (strpos($str, "\r") !== FALSE)
513 {
514 $str = str_replace(array("\r\n", "\r"), "\n", $str);
515 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000516 }
517
518 return $str;
519 }
520
521 // --------------------------------------------------------------------
522
523 /**
Derek Jones69fc4fc2010-03-02 13:36:31 -0600524 * Clean Keys
Derek Allard2067d1a2008-11-13 22:59:24 +0000525 *
Derek Jones69fc4fc2010-03-02 13:36:31 -0600526 * This is a helper function. To prevent malicious users
527 * from trying to exploit keys we make sure that keys are
528 * only named with alpha-numeric text and a few other items.
Derek Allard2067d1a2008-11-13 22:59:24 +0000529 *
Derek Jones69fc4fc2010-03-02 13:36:31 -0600530 * @access private
Derek Allard2067d1a2008-11-13 22:59:24 +0000531 * @param string
532 * @return string
533 */
Derek Jones69fc4fc2010-03-02 13:36:31 -0600534 function _clean_input_keys($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000535 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600536 if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000537 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600538 exit('Disallowed Key Characters.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000539 }
540
Derek Jones69fc4fc2010-03-02 13:36:31 -0600541 // Clean UTF-8 if supported
542 if (UTF8_ENABLED === TRUE)
543 {
544 $str = $this->uni->clean_string($str);
545 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000546
Derek Jones69fc4fc2010-03-02 13:36:31 -0600547 return $str;
548 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000549
550}
551// END Input class
552
553/* End of file Input.php */
Derek Jonesc68dfbf2010-03-02 12:59:23 -0600554/* Location: ./system/core/Input.php */