blob: ec935d5310a95ce2b490b6c72ac9fafe8cd6d3de [file] [log] [blame]
Andrey Andreev64e98aa2012-01-07 20:29:10 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Phil Sturgeon07c1ac82012-03-09 17:03:37 +00005 * An open source application development framework for PHP 5.2.4 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
Andrey Andreev64e98aa2012-01-07 20:29:10 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev64e98aa2012-01-07 20:29:10 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
Greg Aker0defe5d2012-01-01 18:46:41 -060021 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
Derek Jonesf4a4bd82011-10-20 12:18:42 -050022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * Input Class
30 *
31 * Pre-processes global input data for security
32 *
33 * @package CodeIgniter
34 * @subpackage Libraries
35 * @category Input
Derek Jonesf4a4bd82011-10-20 12:18:42 -050036 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000037 * @link http://codeigniter.com/user_guide/libraries/input.html
38 */
39class CI_Input {
Derek Allard2067d1a2008-11-13 22:59:24 +000040
David Behler9b5df592011-08-14 21:04:17 +020041 /**
42 * IP address of the current user
43 *
44 * @var string
45 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040046 public $ip_address = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030047
David Behler9b5df592011-08-14 21:04:17 +020048 /**
49 * user agent (web browser) being used by the current user
50 *
51 * @var string
52 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040053 public $user_agent = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030054
David Behler9b5df592011-08-14 21:04:17 +020055 /**
56 * If FALSE, then $_GET will be set to an empty array
57 *
58 * @var bool
59 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040060 protected $_allow_get_array = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030061
David Behler9b5df592011-08-14 21:04:17 +020062 /**
63 * If TRUE, then newlines are standardized
64 *
65 * @var bool
66 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040067 protected $_standardize_newlines = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030068
David Behler9b5df592011-08-14 21:04:17 +020069 /**
70 * Determines whether the XSS filter is always active when GET, POST or COOKIE data is encountered
71 * Set automatically based on config setting
72 *
73 * @var bool
74 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040075 protected $_enable_xss = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030076
David Behler9b5df592011-08-14 21:04:17 +020077 /**
78 * Enables a CSRF cookie token to be set.
79 * Set automatically based on config setting
80 *
81 * @var bool
82 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040083 protected $_enable_csrf = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030084
David Behler9b5df592011-08-14 21:04:17 +020085 /**
86 * List of all HTTP request headers
87 *
88 * @var array
89 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040090 protected $headers = array();
David Behler9b5df592011-08-14 21:04:17 +020091
Derek Allard2067d1a2008-11-13 22:59:24 +000092 /**
Greg Akera9263282010-11-10 15:26:43 -060093 * Constructor
94 *
95 * Sets whether to globally enable the XSS processing
96 * and whether to allow the $_GET array
Andrey Andreev92ebfb62012-05-17 12:49:24 +030097 *
98 * @return void
Greg Akera9263282010-11-10 15:26:43 -060099 */
100 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +0000101 {
Andrey Andreev13774972012-01-08 04:30:33 +0200102 log_message('debug', 'Input Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000103
Phil Sturgeonc8089152010-12-27 19:06:28 +0000104 $this->_allow_get_array = (config_item('allow_get_array') === TRUE);
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200105 $this->_enable_xss = (config_item('global_xss_filtering') === TRUE);
106 $this->_enable_csrf = (config_item('csrf_protection') === TRUE);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600107
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400108 global $SEC;
109 $this->security =& $SEC;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600110
Pascal Krieteaaec1e42011-01-20 00:01:21 -0500111 // Do we need the UTF-8 class?
Derek Jones69fc4fc2010-03-02 13:36:31 -0600112 if (UTF8_ENABLED === TRUE)
113 {
114 global $UNI;
115 $this->uni =& $UNI;
116 }
117
118 // Sanitize global arrays
Derek Allard2067d1a2008-11-13 22:59:24 +0000119 $this->_sanitize_globals();
120 }
121
122 // --------------------------------------------------------------------
123
124 /**
Greg Akera9263282010-11-10 15:26:43 -0600125 * Fetch from array
126 *
127 * This is a helper function to retrieve values from global arrays
128 *
Greg Akera9263282010-11-10 15:26:43 -0600129 * @param array
130 * @param string
131 * @param bool
132 * @return string
133 */
Bo-Yi Wu47213792011-09-13 22:44:07 +0800134 protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000135 {
136 if ( ! isset($array[$index]))
137 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100138 return NULL;
Derek Allard2067d1a2008-11-13 22:59:24 +0000139 }
140
141 if ($xss_clean === TRUE)
142 {
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400143 return $this->security->xss_clean($array[$index]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000144 }
145
146 return $array[$index];
147 }
148
149 // --------------------------------------------------------------------
150
151 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400152 * Fetch an item from the GET array
153 *
154 * @param string
155 * @param bool
156 * @return string
157 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800158 public function get($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000159 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000160 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200161 if ($index === NULL && ! empty($_GET))
vascopjff1cfa12011-02-13 21:30:19 +0000162 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000163 $get = array();
vascopjff1cfa12011-02-13 21:30:19 +0000164
165 // loop through the full _GET array
Phil Sturgeon44f21052011-02-15 21:39:25 +0000166 foreach (array_keys($_GET) as $key)
vascopjff1cfa12011-02-13 21:30:19 +0000167 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000168 $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean);
vascopjff1cfa12011-02-13 21:30:19 +0000169 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000170 return $get;
vascopjff1cfa12011-02-13 21:30:19 +0000171 }
172
Derek Allard2067d1a2008-11-13 22:59:24 +0000173 return $this->_fetch_from_array($_GET, $index, $xss_clean);
174 }
175
176 // --------------------------------------------------------------------
177
178 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400179 * Fetch an item from the POST array
180 *
181 * @param string
182 * @param bool
183 * @return string
184 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800185 public function post($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000186 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000187 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200188 if ($index === NULL && ! empty($_POST))
vascopj0ba58b82011-02-06 14:20:21 +0000189 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000190 $post = array();
vascopj0ba58b82011-02-06 14:20:21 +0000191
Phil Sturgeon44f21052011-02-15 21:39:25 +0000192 // Loop through the full _POST array and return it
193 foreach (array_keys($_POST) as $key)
vascopj0ba58b82011-02-06 14:20:21 +0000194 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000195 $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean);
vascopj0ba58b82011-02-06 14:20:21 +0000196 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000197 return $post;
vascopj0ba58b82011-02-06 14:20:21 +0000198 }
David Behler9b5df592011-08-14 21:04:17 +0200199
Derek Allard2067d1a2008-11-13 22:59:24 +0000200 return $this->_fetch_from_array($_POST, $index, $xss_clean);
201 }
202
Derek Jones69fc4fc2010-03-02 13:36:31 -0600203
Derek Allard2067d1a2008-11-13 22:59:24 +0000204 // --------------------------------------------------------------------
205
206 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400207 * Fetch an item from either the GET array or the POST
208 *
209 * @param string The index key
210 * @param bool XSS cleaning
211 * @return string
212 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800213 public function get_post($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000214 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200215 return isset($_POST[$index])
216 ? $this->post($index, $xss_clean)
217 : $this->get($index, $xss_clean);
Derek Allard2067d1a2008-11-13 22:59:24 +0000218 }
219
220 // --------------------------------------------------------------------
221
222 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400223 * Fetch an item from the COOKIE array
224 *
225 * @param string
226 * @param bool
227 * @return string
228 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800229 public function cookie($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000230 {
231 return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
232 }
233
Derek Jones69fc4fc2010-03-02 13:36:31 -0600234 // ------------------------------------------------------------------------
235
236 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400237 * Set cookie
238 *
239 * Accepts seven parameters, or you can submit an associative
240 * array in the first parameter containing all the values.
241 *
242 * @param mixed
243 * @param string the value of the cookie
244 * @param string the number of seconds until expiration
245 * @param string the cookie domain. Usually: .yourdomain.com
246 * @param string the cookie path
247 * @param string the cookie prefix
248 * @param bool true makes the cookie secure
249 * @param bool true makes the cookie accessible via http(s) only (no javascript)
250 * @return void
251 */
freewil4ad0fd82012-03-13 22:37:42 -0400252 public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600253 {
254 if (is_array($name))
255 {
tobiasbg9aa7dc92011-02-18 21:57:13 +0100256 // always leave 'name' in last place, as the loop will break otherwise, due to $$item
freewil4ad0fd82012-03-13 22:37:42 -0400257 foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600258 {
259 if (isset($name[$item]))
260 {
261 $$item = $name[$item];
262 }
263 }
264 }
265
Alex Bilbieed944a32012-06-02 11:07:47 +0100266 if ($prefix === '' && config_item('cookie_prefix') !== '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600267 {
268 $prefix = config_item('cookie_prefix');
269 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300270
271 if ($domain == '' && config_item('cookie_domain') != '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600272 {
273 $domain = config_item('cookie_domain');
274 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300275
Alex Bilbieed944a32012-06-02 11:07:47 +0100276 if ($path === '/' && config_item('cookie_path') !== '/')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600277 {
278 $path = config_item('cookie_path');
279 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300280
Alex Bilbieed944a32012-06-02 11:07:47 +0100281 if ($secure === FALSE && config_item('cookie_secure') !== FALSE)
tobiasbg9aa7dc92011-02-18 21:57:13 +0100282 {
283 $secure = config_item('cookie_secure');
284 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300285
Alex Bilbieed944a32012-06-02 11:07:47 +0100286 if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
freewil4ad0fd82012-03-13 22:37:42 -0400287 {
288 $httponly = config_item('cookie_httponly');
289 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600290
291 if ( ! is_numeric($expire))
292 {
293 $expire = time() - 86500;
294 }
295 else
296 {
Phil Sturgeonc8089152010-12-27 19:06:28 +0000297 $expire = ($expire > 0) ? time() + $expire : 0;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600298 }
299
freewil4ad0fd82012-03-13 22:37:42 -0400300 setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600301 }
302
Derek Allard2067d1a2008-11-13 22:59:24 +0000303 // --------------------------------------------------------------------
304
305 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400306 * Fetch an item from the SERVER array
307 *
308 * @param string
309 * @param bool
310 * @return string
311 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800312 public function server($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000313 {
314 return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
315 }
316
317 // --------------------------------------------------------------------
318
319 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400320 * Fetch the IP Address
321 *
322 * @return string
323 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800324 public function ip_address()
Derek Allard2067d1a2008-11-13 22:59:24 +0000325 {
326 if ($this->ip_address !== FALSE)
327 {
328 return $this->ip_address;
329 }
Barry Mienydd671972010-10-04 16:33:58 +0200330
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300331 $proxy_ips = config_item('proxy_ips');
Andrey Andreevea7a8662012-10-09 13:36:31 +0300332 if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300333 {
334 $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
335 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300336
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300337 $this->ip_address = $this->server('REMOTE_ADDR');
338
339 if ($proxy_ips)
340 {
341 foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300342 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300343 if (($spoof = $this->server($header)) !== NULL)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300344 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300345 // Some proxies typically list the whole chain of IP
346 // addresses through which the client has reached us.
347 // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
348 if (strpos($spoof, ',') !== FALSE)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300349 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300350 $spoof = explode(',', $spoof, 2);
351 $spoof = $spoof[0];
352 }
353
354 if ( ! $this->valid_ip($spoof))
355 {
356 $spoof = NULL;
357 }
358 else
359 {
Jordan Pittmana5a71352012-07-20 19:36:43 -0300360 break;
361 }
362 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300363 }
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300364
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300365 if ($spoof)
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300366 {
Andrey Andreev9df35b42012-10-09 13:37:58 +0300367 for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300368 {
369 // Check if we have an IP address or a subnet
370 if (strpos($proxy_ips[$i], '/') === FALSE)
371 {
372 // An IP address (and not a subnet) is specified.
373 // We can compare right away.
374 if ($proxy_ips[$i] === $this->ip_address)
375 {
376 $this->ip_address = $spoof;
377 break;
378 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000379
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300380 continue;
381 }
382
383 // We have a subnet ... now the heavy lifting begins
384 isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
385
386 // If the proxy entry doesn't match the IP protocol - skip it
387 if (strpos($proxy_ips[$i], $separator) === FALSE)
388 {
389 continue;
390 }
391
392 // Convert the REMOTE_ADDR IP address to binary, if needed
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300393 if ( ! isset($ip, $sprintf))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300394 {
395 if ($separator === ':')
396 {
397 // Make sure we're have the "full" IPv6 format
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300398 $ip = explode(':',
399 str_replace('::',
400 str_repeat(':', 9 - substr_count($this->ip_address, ':')),
401 $this->ip_address
402 )
403 );
404
405 for ($i = 0; $i < 8; $i++)
406 {
407 $ip[$i] = intval($ip[$i], 16);
408 }
409
410 $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300411 }
412 else
413 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300414 $ip = explode('.', $this->ip_address);
415 $sprintf = '%08b%08b%08b%08b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300416 }
417
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300418 $ip = vsprintf($sprintf, $ip);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300419 }
420
421 // Split the netmask length off the network address
422 list($netaddr, $masklen) = explode('/', $proxy_ips[$i], 2);
423
424 // Again, an IPv6 address is most likely in a compressed form
425 if ($separator === ':')
426 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300427 $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
428 for ($i = 0; $i < 8; $i++)
429 {
430 $netaddr[$i] = intval($netaddr[$i], 16);
431 }
432 }
433 else
434 {
435 $netaddr = explode('.', $netaddr);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300436 }
437
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300438 // Convert to binary and finally compare
439 if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300440 {
441 $this->ip_address = $spoof;
442 break;
443 }
444 }
445 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000446 }
447
Derek Allard2067d1a2008-11-13 22:59:24 +0000448 if ( ! $this->valid_ip($this->ip_address))
449 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200450 return $this->ip_address = '0.0.0.0';
Derek Allard2067d1a2008-11-13 22:59:24 +0000451 }
452
453 return $this->ip_address;
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400459 * Validate IP Address
460 *
Timothy Warren40403d22012-04-19 16:38:50 -0400461 * @param string
Andrey Andreev5a257182012-06-10 06:18:14 +0300462 * @param string 'ipv4' or 'ipv6'
Timothy Warren40403d22012-04-19 16:38:50 -0400463 * @return bool
464 */
Andrey Andreev5a257182012-06-10 06:18:14 +0300465 public function valid_ip($ip, $which = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 {
Andrey Andreev5a257182012-06-10 06:18:14 +0300467 switch (strtolower($which))
468 {
469 case 'ipv4':
470 $which = FILTER_FLAG_IPV4;
471 break;
472 case 'ipv6':
473 $which = FILTER_FLAG_IPV6;
474 break;
475 default:
476 $which = NULL;
477 break;
478 }
479
480 return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
Derek Allard2067d1a2008-11-13 22:59:24 +0000481 }
482
483 // --------------------------------------------------------------------
484
485 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400486 * User Agent
487 *
488 * @return string
489 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800490 public function user_agent()
Derek Allard2067d1a2008-11-13 22:59:24 +0000491 {
492 if ($this->user_agent !== FALSE)
493 {
494 return $this->user_agent;
495 }
496
Andrey Andreev9448afb2012-02-08 19:49:19 +0200497 return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000498 }
499
500 // --------------------------------------------------------------------
501
502 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400503 * Sanitize Globals
504 *
505 * This function does the following:
506 *
507 * - Unsets $_GET data (if query strings are not enabled)
508 * - Unsets all globals if register_globals is enabled
509 * - Standardizes newline characters to \n
510 *
511 * @return void
512 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200513 protected function _sanitize_globals()
Derek Allard2067d1a2008-11-13 22:59:24 +0000514 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600515 // It would be "wrong" to unset any of these GLOBALS.
Timothy Warren40403d22012-04-19 16:38:50 -0400516 $protected = array(
517 '_SERVER',
518 '_GET',
519 '_POST',
520 '_FILES',
521 '_REQUEST',
522 '_SESSION',
523 '_ENV',
524 'GLOBALS',
525 'HTTP_RAW_POST_DATA',
526 'system_folder',
527 'application_folder',
528 'BM',
529 'EXT',
530 'CFG',
531 'URI',
532 'RTR',
Timothy Warren67cb3ee2012-04-19 16:41:52 -0400533 'OUT',
Timothy Warren40403d22012-04-19 16:38:50 -0400534 'IN'
535 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000536
Barry Mienydd671972010-10-04 16:33:58 +0200537 // Unset globals for securiy.
Derek Jones69fc4fc2010-03-02 13:36:31 -0600538 // This is effectively the same as register_globals = off
539 foreach (array($_GET, $_POST, $_COOKIE) as $global)
Derek Allard2067d1a2008-11-13 22:59:24 +0000540 {
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300541 if (is_array($global))
Derek Jones69fc4fc2010-03-02 13:36:31 -0600542 {
543 foreach ($global as $key => $val)
544 {
545 if ( ! in_array($key, $protected))
546 {
547 global $$key;
548 $$key = NULL;
549 }
550 }
551 }
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300552 elseif ( ! in_array($global, $protected))
553 {
554 global $$global;
555 $$global = NULL;
556 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000557 }
558
Derek Jones69fc4fc2010-03-02 13:36:31 -0600559 // Is $_GET data allowed? If not we'll set the $_GET to an empty array
Alex Bilbieed944a32012-06-02 11:07:47 +0100560 if ($this->_allow_get_array === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000561 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600562 $_GET = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000563 }
Andrey Andreev9448afb2012-02-08 19:49:19 +0200564 elseif (is_array($_GET) && count($_GET) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000565 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200566 foreach ($_GET as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000567 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200568 $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000569 }
570 }
571
Derek Jones69fc4fc2010-03-02 13:36:31 -0600572 // Clean $_POST Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200573 if (is_array($_POST) && count($_POST) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000574 {
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500575 foreach ($_POST as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600576 {
577 $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
578 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000579 }
580
Derek Jones69fc4fc2010-03-02 13:36:31 -0600581 // Clean $_COOKIE Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200582 if (is_array($_COOKIE) && count($_COOKIE) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000583 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600584 // Also get rid of specially treated cookies that might be set by a server
585 // or silly application, that are of no use to a CI application anyway
586 // but that when present will trip our 'Disallowed Key Characters' alarm
587 // http://www.ietf.org/rfc/rfc2109.txt
588 // note that the key names below are single quoted strings, and are not PHP variables
589 unset($_COOKIE['$Version']);
590 unset($_COOKIE['$Path']);
591 unset($_COOKIE['$Domain']);
592
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500593 foreach ($_COOKIE as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600594 {
595 $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
596 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000597 }
598
Derek Jones69fc4fc2010-03-02 13:36:31 -0600599 // Sanitize PHP_SELF
600 $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
601
Derek Jones69fc4fc2010-03-02 13:36:31 -0600602 // CSRF Protection check
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300603 if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
Derek Allard2067d1a2008-11-13 22:59:24 +0000604 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600605 $this->security->csrf_verify();
Derek Allard2067d1a2008-11-13 22:59:24 +0000606 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000607
Andrey Andreev90cfe142012-01-08 04:46:42 +0200608 log_message('debug', 'Global POST and COOKIE data sanitized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000609 }
610
611 // --------------------------------------------------------------------
612
613 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400614 * Clean Input Data
615 *
616 * This is a helper function. It escapes data and
617 * standardizes newline characters to \n
618 *
619 * @param string
620 * @return string
621 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200622 protected function _clean_input_data($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000623 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600624 if (is_array($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000625 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600626 $new_array = array();
627 foreach ($str as $key => $val)
628 {
629 $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
630 }
631 return $new_array;
Derek Allard2067d1a2008-11-13 22:59:24 +0000632 }
633
Andrey Andreevaf728622011-10-20 10:11:59 +0300634 /* We strip slashes if magic quotes is on to keep things consistent
635
636 NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
637 it will probably not exist in future versions at all.
638 */
639 if ( ! is_php('5.4') && get_magic_quotes_gpc())
Derek Allard2067d1a2008-11-13 22:59:24 +0000640 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600641 $str = stripslashes($str);
642 }
643
644 // Clean UTF-8 if supported
645 if (UTF8_ENABLED === TRUE)
646 {
647 $str = $this->uni->clean_string($str);
648 }
David Behler9b5df592011-08-14 21:04:17 +0200649
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400650 // Remove control characters
651 $str = remove_invisible_characters($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600652
653 // Should we filter the input data?
654 if ($this->_enable_xss === TRUE)
655 {
656 $str = $this->security->xss_clean($str);
657 }
658
659 // Standardize newlines if needed
Alex Bilbieed944a32012-06-02 11:07:47 +0100660 if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600661 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200662 return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000663 }
664
665 return $str;
666 }
667
668 // --------------------------------------------------------------------
669
670 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400671 * Clean Keys
672 *
673 * This is a helper function. To prevent malicious users
674 * from trying to exploit keys we make sure that keys are
675 * only named with alpha-numeric text and a few other items.
676 *
677 * @param string
678 * @return string
679 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200680 protected function _clean_input_keys($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000681 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200682 if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000683 {
Kevin Cuppd63e4012012-02-05 14:14:32 -0500684 set_status_header(503);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600685 exit('Disallowed Key Characters.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000686 }
687
Derek Jones69fc4fc2010-03-02 13:36:31 -0600688 // Clean UTF-8 if supported
689 if (UTF8_ENABLED === TRUE)
690 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200691 return $this->uni->clean_string($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600692 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000693
Derek Jones69fc4fc2010-03-02 13:36:31 -0600694 return $str;
695 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000696
Greg Akerec2f5712010-11-15 16:22:12 -0600697 // --------------------------------------------------------------------
698
699 /**
700 * Request Headers
701 *
David Behler9b5df592011-08-14 21:04:17 +0200702 * In Apache, you can simply call apache_request_headers(), however for
Greg Akerec2f5712010-11-15 16:22:12 -0600703 * people running other webservers the function is undefined.
704 *
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300705 * @param bool XSS cleaning
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200706 * @return array
Greg Akerec2f5712010-11-15 16:22:12 -0600707 */
708 public function request_headers($xss_clean = FALSE)
709 {
710 // Look at Apache go!
711 if (function_exists('apache_request_headers'))
712 {
713 $headers = apache_request_headers();
714 }
715 else
716 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200717 $headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
Greg Akerec2f5712010-11-15 16:22:12 -0600718
719 foreach ($_SERVER as $key => $val)
720 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200721 if (strpos($key, 'HTTP_') === 0)
Greg Akerec2f5712010-11-15 16:22:12 -0600722 {
723 $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
724 }
725 }
726 }
727
728 // take SOME_HEADER and turn it into Some-Header
729 foreach ($headers as $key => $val)
730 {
731 $key = str_replace('_', ' ', strtolower($key));
732 $key = str_replace(' ', '-', ucwords($key));
David Behler9b5df592011-08-14 21:04:17 +0200733
Greg Akerec2f5712010-11-15 16:22:12 -0600734 $this->headers[$key] = $val;
735 }
David Behler9b5df592011-08-14 21:04:17 +0200736
Greg Akerec2f5712010-11-15 16:22:12 -0600737 return $this->headers;
738 }
739
740 // --------------------------------------------------------------------
741
742 /**
743 * Get Request Header
744 *
745 * Returns the value of a single member of the headers class member
746 *
Andrey Andreev773e1172012-02-08 23:02:19 +0200747 * @param string array key for $this->headers
Andrey Andreev9448afb2012-02-08 19:49:19 +0200748 * @param bool XSS Clean or not
Andrey Andreev773e1172012-02-08 23:02:19 +0200749 * @return mixed FALSE on failure, string on success
Greg Akerec2f5712010-11-15 16:22:12 -0600750 */
751 public function get_request_header($index, $xss_clean = FALSE)
752 {
753 if (empty($this->headers))
754 {
755 $this->request_headers();
756 }
David Behler9b5df592011-08-14 21:04:17 +0200757
Greg Akerec2f5712010-11-15 16:22:12 -0600758 if ( ! isset($this->headers[$index]))
759 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100760 return NULL;
Greg Akerec2f5712010-11-15 16:22:12 -0600761 }
762
Andrey Andreev9448afb2012-02-08 19:49:19 +0200763 return ($xss_clean === TRUE)
764 ? $this->security->xss_clean($this->headers[$index])
765 : $this->headers[$index];
Greg Akerec2f5712010-11-15 16:22:12 -0600766 }
767
Greg Aker081ac9d2010-11-22 14:42:53 -0600768 // --------------------------------------------------------------------
Phil Sturgeonc3828712011-01-19 12:31:47 +0000769
Greg Aker081ac9d2010-11-22 14:42:53 -0600770 /**
771 * Is ajax Request?
772 *
773 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header
774 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200775 * @return bool
Greg Aker081ac9d2010-11-22 14:42:53 -0600776 */
777 public function is_ajax_request()
778 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200779 return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
Greg Aker081ac9d2010-11-22 14:42:53 -0600780 }
781
Phil Sturgeonc3828712011-01-19 12:31:47 +0000782 // --------------------------------------------------------------------
783
784 /**
785 * Is cli Request?
786 *
787 * Test to see if a request was made from the command line
788 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200789 * @return bool
Phil Sturgeonc3828712011-01-19 12:31:47 +0000790 */
791 public function is_cli_request()
792 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200793 return (php_sapi_name() === 'cli' OR defined('STDIN'));
Phil Sturgeonc3828712011-01-19 12:31:47 +0000794 }
795
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100796 // --------------------------------------------------------------------
797
798 /**
799 * Get Request Method
800 *
Michiel Vugteveendc900df2012-03-07 20:41:37 +0100801 * Return the Request Method
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100802 *
Michiel Vugteveendc900df2012-03-07 20:41:37 +0100803 * @param bool uppercase or lowercase
Michiel Vugteveen7c8841f2012-03-07 20:49:06 +0100804 * @return bool
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100805 */
Michiel Vugteveen704fb162012-03-07 20:42:33 +0100806 public function method($upper = FALSE)
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100807 {
Michiel Vugteveendc900df2012-03-07 20:41:37 +0100808 return ($upper)
809 ? strtoupper($this->server('REQUEST_METHOD'))
810 : strtolower($this->server('REQUEST_METHOD'));
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100811 }
812
Derek Allard2067d1a2008-11-13 22:59:24 +0000813}
Derek Allard2067d1a2008-11-13 22:59:24 +0000814
815/* End of file Input.php */
Timothy Warren40403d22012-04-19 16:38:50 -0400816/* Location: ./system/core/Input.php */