blob: f6213c34e2abf9a2a1a12e922853556e6ff64be7 [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 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030044 * @var string
David Behler9b5df592011-08-14 21:04:17 +020045 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030046 public $ip_address = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030047
David Behler9b5df592011-08-14 21:04:17 +020048 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030049 * User agent strin
David Behler9b5df592011-08-14 21:04:17 +020050 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030051 * @var string
David Behler9b5df592011-08-14 21:04:17 +020052 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030053 public $user_agent = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030054
David Behler9b5df592011-08-14 21:04:17 +020055 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030056 * Allow GET array flag
David Behler9b5df592011-08-14 21:04:17 +020057 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030058 * If set to FALSE, then $_GET will be set to an empty array.
David Behler9b5df592011-08-14 21:04:17 +020059 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030060 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020061 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030062 protected $_allow_get_array = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030063
David Behler9b5df592011-08-14 21:04:17 +020064 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030065 * Standartize new lines flag
David Behler9b5df592011-08-14 21:04:17 +020066 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030067 * If set to TRUE, then newlines are standardized.
68 *
69 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020070 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030071 protected $_standardize_newlines = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030072
David Behler9b5df592011-08-14 21:04:17 +020073 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030074 * Enable XSS flag
75 *
76 * Determines whether the XSS filter is always active when
77 * GET, POST or COOKIE data is encountered.
78 * Set automatically based on config setting.
79 *
80 * @var bool
81 */
82 protected $_enable_xss = FALSE;
83
84 /**
85 * Enable CSRF flag
86 *
David Behler9b5df592011-08-14 21:04:17 +020087 * Enables a CSRF cookie token to be set.
Andrey Andreev1887ec62012-10-27 16:22:07 +030088 * Set automatically based on config setting.
David Behler9b5df592011-08-14 21:04:17 +020089 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030090 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020091 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030092 protected $_enable_csrf = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030093
David Behler9b5df592011-08-14 21:04:17 +020094 /**
95 * List of all HTTP request headers
96 *
97 * @var array
98 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030099 protected $headers = array();
David Behler9b5df592011-08-14 21:04:17 +0200100
Derek Allard2067d1a2008-11-13 22:59:24 +0000101 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300102 * Class constructor
Greg Akera9263282010-11-10 15:26:43 -0600103 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300104 * Determines whether to globally enable the XSS processing
105 * and whether to allow the $_GET array.
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300106 *
107 * @return void
Greg Akera9263282010-11-10 15:26:43 -0600108 */
109 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +0000110 {
Andrey Andreev13774972012-01-08 04:30:33 +0200111 log_message('debug', 'Input Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000112
Phil Sturgeonc8089152010-12-27 19:06:28 +0000113 $this->_allow_get_array = (config_item('allow_get_array') === TRUE);
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200114 $this->_enable_xss = (config_item('global_xss_filtering') === TRUE);
115 $this->_enable_csrf = (config_item('csrf_protection') === TRUE);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600116
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400117 global $SEC;
118 $this->security =& $SEC;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600119
Pascal Krieteaaec1e42011-01-20 00:01:21 -0500120 // Do we need the UTF-8 class?
Derek Jones69fc4fc2010-03-02 13:36:31 -0600121 if (UTF8_ENABLED === TRUE)
122 {
123 global $UNI;
124 $this->uni =& $UNI;
125 }
126
127 // Sanitize global arrays
Derek Allard2067d1a2008-11-13 22:59:24 +0000128 $this->_sanitize_globals();
129 }
130
131 // --------------------------------------------------------------------
132
133 /**
Greg Akera9263282010-11-10 15:26:43 -0600134 * Fetch from array
135 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300136 * Internal method used to retrieve values from global arrays.
Greg Akera9263282010-11-10 15:26:43 -0600137 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300138 * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc.
139 * @param string $index Index for item to be fetched from $array
140 * @param bool $xss_clean Whether to apply XSS filtering
141 * @return mixed
Greg Akera9263282010-11-10 15:26:43 -0600142 */
Bo-Yi Wu47213792011-09-13 22:44:07 +0800143 protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000144 {
145 if ( ! isset($array[$index]))
146 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100147 return NULL;
Derek Allard2067d1a2008-11-13 22:59:24 +0000148 }
149
150 if ($xss_clean === TRUE)
151 {
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400152 return $this->security->xss_clean($array[$index]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000153 }
154
155 return $array[$index];
156 }
157
158 // --------------------------------------------------------------------
159
160 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400161 * Fetch an item from the GET array
162 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300163 * @param string $index Index for item to be fetched from $_GET
164 * @param bool $xss_clean Whether to apply XSS filtering
165 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400166 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800167 public function get($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000168 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000169 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200170 if ($index === NULL && ! empty($_GET))
vascopjff1cfa12011-02-13 21:30:19 +0000171 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000172 $get = array();
vascopjff1cfa12011-02-13 21:30:19 +0000173
174 // loop through the full _GET array
Phil Sturgeon44f21052011-02-15 21:39:25 +0000175 foreach (array_keys($_GET) as $key)
vascopjff1cfa12011-02-13 21:30:19 +0000176 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000177 $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean);
vascopjff1cfa12011-02-13 21:30:19 +0000178 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000179 return $get;
vascopjff1cfa12011-02-13 21:30:19 +0000180 }
181
Derek Allard2067d1a2008-11-13 22:59:24 +0000182 return $this->_fetch_from_array($_GET, $index, $xss_clean);
183 }
184
185 // --------------------------------------------------------------------
186
187 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400188 * Fetch an item from the POST array
189 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300190 * @param string $index Index for item to be fetched from $_POST
191 * @param bool $xss_clean Whether to apply XSS filtering
192 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400193 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800194 public function post($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000195 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000196 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200197 if ($index === NULL && ! empty($_POST))
vascopj0ba58b82011-02-06 14:20:21 +0000198 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000199 $post = array();
vascopj0ba58b82011-02-06 14:20:21 +0000200
Phil Sturgeon44f21052011-02-15 21:39:25 +0000201 // Loop through the full _POST array and return it
202 foreach (array_keys($_POST) as $key)
vascopj0ba58b82011-02-06 14:20:21 +0000203 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000204 $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean);
vascopj0ba58b82011-02-06 14:20:21 +0000205 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000206 return $post;
vascopj0ba58b82011-02-06 14:20:21 +0000207 }
David Behler9b5df592011-08-14 21:04:17 +0200208
Derek Allard2067d1a2008-11-13 22:59:24 +0000209 return $this->_fetch_from_array($_POST, $index, $xss_clean);
210 }
211
212 // --------------------------------------------------------------------
213
214 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300215 * Fetch an item from POST data with fallback to GET
Timothy Warren40403d22012-04-19 16:38:50 -0400216 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300217 * @param string $index Index for item to be fetched from $_POST or $_GET
218 * @param bool $xss_clean Whether to apply XSS filtering
219 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400220 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800221 public function get_post($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000222 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200223 return isset($_POST[$index])
224 ? $this->post($index, $xss_clean)
225 : $this->get($index, $xss_clean);
Derek Allard2067d1a2008-11-13 22:59:24 +0000226 }
227
228 // --------------------------------------------------------------------
229
230 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400231 * Fetch an item from the COOKIE array
232 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300233 * @param string $index Index for item to be fetched from $_COOKIE
234 * @param bool $xss_clean Whether to apply XSS filtering
235 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400236 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800237 public function cookie($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000238 {
239 return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
240 }
241
Andrey Andreev1887ec62012-10-27 16:22:07 +0300242 // --------------------------------------------------------------------
243
244 /**
245 * Fetch an item from the SERVER array
246 *
247 * @param string $index Index for item to be fetched from $_SERVER
248 * @param bool $xss_clean Whether to apply XSS filtering
249 * @return mixed
250 */
251 public function server($index = '', $xss_clean = FALSE)
252 {
253 return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
254 }
255
Derek Jones69fc4fc2010-03-02 13:36:31 -0600256 // ------------------------------------------------------------------------
257
258 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400259 * Set cookie
260 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300261 * Accepts an arbitrary number of parameters (up to 7) or an associative
Timothy Warren40403d22012-04-19 16:38:50 -0400262 * array in the first parameter containing all the values.
263 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300264 * @param string|mixed[] $name Cookie name or an array containing parameters
265 * @param string $value Cookie value
266 * @param int $expire Cookie expiration time in seconds
267 * @param string $domain Cookie domain (e.g.: '.yourdomain.com')
268 * @param string $path Cookie path (default: '/')
269 * @param string $prefix Cookie name prefix
270 * @param bool $secure Whether to only transfer cookies via SSL
271 * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
Timothy Warren40403d22012-04-19 16:38:50 -0400272 * @return void
273 */
freewil4ad0fd82012-03-13 22:37:42 -0400274 public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600275 {
276 if (is_array($name))
277 {
tobiasbg9aa7dc92011-02-18 21:57:13 +0100278 // always leave 'name' in last place, as the loop will break otherwise, due to $$item
freewil4ad0fd82012-03-13 22:37:42 -0400279 foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600280 {
281 if (isset($name[$item]))
282 {
283 $$item = $name[$item];
284 }
285 }
286 }
287
Alex Bilbieed944a32012-06-02 11:07:47 +0100288 if ($prefix === '' && config_item('cookie_prefix') !== '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600289 {
290 $prefix = config_item('cookie_prefix');
291 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300292
293 if ($domain == '' && config_item('cookie_domain') != '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600294 {
295 $domain = config_item('cookie_domain');
296 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300297
Alex Bilbieed944a32012-06-02 11:07:47 +0100298 if ($path === '/' && config_item('cookie_path') !== '/')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600299 {
300 $path = config_item('cookie_path');
301 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300302
Alex Bilbieed944a32012-06-02 11:07:47 +0100303 if ($secure === FALSE && config_item('cookie_secure') !== FALSE)
tobiasbg9aa7dc92011-02-18 21:57:13 +0100304 {
305 $secure = config_item('cookie_secure');
306 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300307
Alex Bilbieed944a32012-06-02 11:07:47 +0100308 if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
freewil4ad0fd82012-03-13 22:37:42 -0400309 {
310 $httponly = config_item('cookie_httponly');
311 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600312
313 if ( ! is_numeric($expire))
314 {
315 $expire = time() - 86500;
316 }
317 else
318 {
Phil Sturgeonc8089152010-12-27 19:06:28 +0000319 $expire = ($expire > 0) ? time() + $expire : 0;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600320 }
321
freewil4ad0fd82012-03-13 22:37:42 -0400322 setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600323 }
324
Derek Allard2067d1a2008-11-13 22:59:24 +0000325 // --------------------------------------------------------------------
326
327 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400328 * Fetch the IP Address
329 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300330 * Determines and validates the visitor's IP address.
331 *
332 * @return string IP address
Timothy Warren40403d22012-04-19 16:38:50 -0400333 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800334 public function ip_address()
Derek Allard2067d1a2008-11-13 22:59:24 +0000335 {
336 if ($this->ip_address !== FALSE)
337 {
338 return $this->ip_address;
339 }
Barry Mienydd671972010-10-04 16:33:58 +0200340
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300341 $proxy_ips = config_item('proxy_ips');
Andrey Andreevea7a8662012-10-09 13:36:31 +0300342 if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300343 {
344 $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
345 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300346
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300347 $this->ip_address = $this->server('REMOTE_ADDR');
348
349 if ($proxy_ips)
350 {
351 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 -0300352 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300353 if (($spoof = $this->server($header)) !== NULL)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300354 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300355 // Some proxies typically list the whole chain of IP
356 // addresses through which the client has reached us.
357 // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
358 if (strpos($spoof, ',') !== FALSE)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300359 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300360 $spoof = explode(',', $spoof, 2);
361 $spoof = $spoof[0];
362 }
363
364 if ( ! $this->valid_ip($spoof))
365 {
366 $spoof = NULL;
367 }
368 else
369 {
Jordan Pittmana5a71352012-07-20 19:36:43 -0300370 break;
371 }
372 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300373 }
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300374
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300375 if ($spoof)
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300376 {
Andrey Andreev9df35b42012-10-09 13:37:58 +0300377 for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300378 {
379 // Check if we have an IP address or a subnet
380 if (strpos($proxy_ips[$i], '/') === FALSE)
381 {
382 // An IP address (and not a subnet) is specified.
383 // We can compare right away.
384 if ($proxy_ips[$i] === $this->ip_address)
385 {
386 $this->ip_address = $spoof;
387 break;
388 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000389
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300390 continue;
391 }
392
393 // We have a subnet ... now the heavy lifting begins
394 isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
395
396 // If the proxy entry doesn't match the IP protocol - skip it
397 if (strpos($proxy_ips[$i], $separator) === FALSE)
398 {
399 continue;
400 }
401
402 // Convert the REMOTE_ADDR IP address to binary, if needed
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300403 if ( ! isset($ip, $sprintf))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300404 {
405 if ($separator === ':')
406 {
407 // Make sure we're have the "full" IPv6 format
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300408 $ip = explode(':',
409 str_replace('::',
410 str_repeat(':', 9 - substr_count($this->ip_address, ':')),
411 $this->ip_address
412 )
413 );
414
415 for ($i = 0; $i < 8; $i++)
416 {
417 $ip[$i] = intval($ip[$i], 16);
418 }
419
420 $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300421 }
422 else
423 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300424 $ip = explode('.', $this->ip_address);
425 $sprintf = '%08b%08b%08b%08b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300426 }
427
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300428 $ip = vsprintf($sprintf, $ip);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300429 }
430
431 // Split the netmask length off the network address
432 list($netaddr, $masklen) = explode('/', $proxy_ips[$i], 2);
433
434 // Again, an IPv6 address is most likely in a compressed form
435 if ($separator === ':')
436 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300437 $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
438 for ($i = 0; $i < 8; $i++)
439 {
440 $netaddr[$i] = intval($netaddr[$i], 16);
441 }
442 }
443 else
444 {
445 $netaddr = explode('.', $netaddr);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300446 }
447
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300448 // Convert to binary and finally compare
449 if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300450 {
451 $this->ip_address = $spoof;
452 break;
453 }
454 }
455 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000456 }
457
Derek Allard2067d1a2008-11-13 22:59:24 +0000458 if ( ! $this->valid_ip($this->ip_address))
459 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200460 return $this->ip_address = '0.0.0.0';
Derek Allard2067d1a2008-11-13 22:59:24 +0000461 }
462
463 return $this->ip_address;
464 }
465
466 // --------------------------------------------------------------------
467
468 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400469 * Validate IP Address
470 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300471 * @param string $ip IP address
472 * @param string $which IP protocol: 'ipv4' or 'ipv6'
Timothy Warren40403d22012-04-19 16:38:50 -0400473 * @return bool
474 */
Andrey Andreev5a257182012-06-10 06:18:14 +0300475 public function valid_ip($ip, $which = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000476 {
Andrey Andreev5a257182012-06-10 06:18:14 +0300477 switch (strtolower($which))
478 {
479 case 'ipv4':
480 $which = FILTER_FLAG_IPV4;
481 break;
482 case 'ipv6':
483 $which = FILTER_FLAG_IPV6;
484 break;
485 default:
486 $which = NULL;
487 break;
488 }
489
490 return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
Derek Allard2067d1a2008-11-13 22:59:24 +0000491 }
492
493 // --------------------------------------------------------------------
494
495 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300496 * Fetch User Agent string
Timothy Warren40403d22012-04-19 16:38:50 -0400497 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300498 * @return string|null User Agent string or NULL if it doesn't exist
Timothy Warren40403d22012-04-19 16:38:50 -0400499 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800500 public function user_agent()
Derek Allard2067d1a2008-11-13 22:59:24 +0000501 {
502 if ($this->user_agent !== FALSE)
503 {
504 return $this->user_agent;
505 }
506
Andrey Andreev1887ec62012-10-27 16:22:07 +0300507 return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
Derek Allard2067d1a2008-11-13 22:59:24 +0000508 }
509
510 // --------------------------------------------------------------------
511
512 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400513 * Sanitize Globals
514 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300515 * Internal method serving for the following purposes:
Timothy Warren40403d22012-04-19 16:38:50 -0400516 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300517 * - Unsets $_GET data (if query strings are not enabled)
518 * - Unsets all globals if register_globals is enabled
519 * - Cleans POST, COOKIE and SERVER data
520 * - Standardizes newline characters to PHP_EOL
Timothy Warren40403d22012-04-19 16:38:50 -0400521 *
522 * @return void
523 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200524 protected function _sanitize_globals()
Derek Allard2067d1a2008-11-13 22:59:24 +0000525 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600526 // It would be "wrong" to unset any of these GLOBALS.
Timothy Warren40403d22012-04-19 16:38:50 -0400527 $protected = array(
528 '_SERVER',
529 '_GET',
530 '_POST',
531 '_FILES',
532 '_REQUEST',
533 '_SESSION',
534 '_ENV',
535 'GLOBALS',
536 'HTTP_RAW_POST_DATA',
537 'system_folder',
538 'application_folder',
539 'BM',
540 'EXT',
541 'CFG',
542 'URI',
543 'RTR',
Timothy Warren67cb3ee2012-04-19 16:41:52 -0400544 'OUT',
Timothy Warren40403d22012-04-19 16:38:50 -0400545 'IN'
546 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000547
Andrey Andreev1887ec62012-10-27 16:22:07 +0300548 // Unset globals for security.
Derek Jones69fc4fc2010-03-02 13:36:31 -0600549 // This is effectively the same as register_globals = off
Andrey Andreev1887ec62012-10-27 16:22:07 +0300550 // PHP 5.4 no longer has the register_globals functionality.
551 if ( ! is_php('5.4'))
Derek Allard2067d1a2008-11-13 22:59:24 +0000552 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300553 foreach (array($_GET, $_POST, $_COOKIE) as $global)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600554 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300555 if (is_array($global))
Derek Jones69fc4fc2010-03-02 13:36:31 -0600556 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300557 foreach ($global as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600558 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300559 if ( ! in_array($key, $protected))
560 {
561 global $$key;
562 $$key = NULL;
563 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600564 }
565 }
Andrey Andreev1887ec62012-10-27 16:22:07 +0300566 elseif ( ! in_array($global, $protected))
567 {
568 global $$global;
569 $$global = NULL;
570 }
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300571 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000572 }
573
Derek Jones69fc4fc2010-03-02 13:36:31 -0600574 // Is $_GET data allowed? If not we'll set the $_GET to an empty array
Alex Bilbieed944a32012-06-02 11:07:47 +0100575 if ($this->_allow_get_array === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000576 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600577 $_GET = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000578 }
Andrey Andreev9448afb2012-02-08 19:49:19 +0200579 elseif (is_array($_GET) && count($_GET) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000580 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200581 foreach ($_GET as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000582 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200583 $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000584 }
585 }
586
Derek Jones69fc4fc2010-03-02 13:36:31 -0600587 // Clean $_POST Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200588 if (is_array($_POST) && count($_POST) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000589 {
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500590 foreach ($_POST as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600591 {
592 $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
593 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000594 }
595
Derek Jones69fc4fc2010-03-02 13:36:31 -0600596 // Clean $_COOKIE Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200597 if (is_array($_COOKIE) && count($_COOKIE) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000598 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600599 // Also get rid of specially treated cookies that might be set by a server
600 // or silly application, that are of no use to a CI application anyway
601 // but that when present will trip our 'Disallowed Key Characters' alarm
602 // http://www.ietf.org/rfc/rfc2109.txt
603 // note that the key names below are single quoted strings, and are not PHP variables
604 unset($_COOKIE['$Version']);
605 unset($_COOKIE['$Path']);
606 unset($_COOKIE['$Domain']);
607
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500608 foreach ($_COOKIE as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600609 {
610 $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
611 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000612 }
613
Derek Jones69fc4fc2010-03-02 13:36:31 -0600614 // Sanitize PHP_SELF
615 $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
616
Derek Jones69fc4fc2010-03-02 13:36:31 -0600617 // CSRF Protection check
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300618 if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
Derek Allard2067d1a2008-11-13 22:59:24 +0000619 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600620 $this->security->csrf_verify();
Derek Allard2067d1a2008-11-13 22:59:24 +0000621 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000622
Andrey Andreev90cfe142012-01-08 04:46:42 +0200623 log_message('debug', 'Global POST and COOKIE data sanitized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000624 }
625
626 // --------------------------------------------------------------------
627
628 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400629 * Clean Input Data
630 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300631 * Internal method that aids in escaping data and
632 * standardizing newline characters to PHP_EOL.
Timothy Warren40403d22012-04-19 16:38:50 -0400633 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300634 * @param string|string[] $str Input string(s)
Timothy Warren40403d22012-04-19 16:38:50 -0400635 * @return string
636 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200637 protected function _clean_input_data($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000638 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600639 if (is_array($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000640 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600641 $new_array = array();
Andrey Andreev1887ec62012-10-27 16:22:07 +0300642 foreach (array_keys($str) as $key)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600643 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300644 $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600645 }
646 return $new_array;
Derek Allard2067d1a2008-11-13 22:59:24 +0000647 }
648
Andrey Andreevaf728622011-10-20 10:11:59 +0300649 /* We strip slashes if magic quotes is on to keep things consistent
650
651 NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
652 it will probably not exist in future versions at all.
653 */
654 if ( ! is_php('5.4') && get_magic_quotes_gpc())
Derek Allard2067d1a2008-11-13 22:59:24 +0000655 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600656 $str = stripslashes($str);
657 }
658
659 // Clean UTF-8 if supported
660 if (UTF8_ENABLED === TRUE)
661 {
662 $str = $this->uni->clean_string($str);
663 }
David Behler9b5df592011-08-14 21:04:17 +0200664
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400665 // Remove control characters
666 $str = remove_invisible_characters($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600667
668 // Should we filter the input data?
669 if ($this->_enable_xss === TRUE)
670 {
671 $str = $this->security->xss_clean($str);
672 }
673
674 // Standardize newlines if needed
Alex Bilbieed944a32012-06-02 11:07:47 +0100675 if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600676 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200677 return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000678 }
679
680 return $str;
681 }
682
683 // --------------------------------------------------------------------
684
685 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400686 * Clean Keys
687 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300688 * Internal method that helps to prevent malicious users
Timothy Warren40403d22012-04-19 16:38:50 -0400689 * from trying to exploit keys we make sure that keys are
690 * only named with alpha-numeric text and a few other items.
691 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300692 * @param string $str Input string
Timothy Warren40403d22012-04-19 16:38:50 -0400693 * @return string
694 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200695 protected function _clean_input_keys($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000696 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200697 if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000698 {
Kevin Cuppd63e4012012-02-05 14:14:32 -0500699 set_status_header(503);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600700 exit('Disallowed Key Characters.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000701 }
702
Derek Jones69fc4fc2010-03-02 13:36:31 -0600703 // Clean UTF-8 if supported
704 if (UTF8_ENABLED === TRUE)
705 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200706 return $this->uni->clean_string($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600707 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000708
Derek Jones69fc4fc2010-03-02 13:36:31 -0600709 return $str;
710 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000711
Greg Akerec2f5712010-11-15 16:22:12 -0600712 // --------------------------------------------------------------------
713
714 /**
715 * Request Headers
716 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300717 * @param bool $xss_clean Whether to apply XSS filtering
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200718 * @return array
Greg Akerec2f5712010-11-15 16:22:12 -0600719 */
720 public function request_headers($xss_clean = FALSE)
721 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300722 // In Apache, you can simply call apache_request_headers()
Greg Akerec2f5712010-11-15 16:22:12 -0600723 if (function_exists('apache_request_headers'))
724 {
725 $headers = apache_request_headers();
726 }
727 else
728 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200729 $headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
Greg Akerec2f5712010-11-15 16:22:12 -0600730
731 foreach ($_SERVER as $key => $val)
732 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200733 if (strpos($key, 'HTTP_') === 0)
Greg Akerec2f5712010-11-15 16:22:12 -0600734 {
735 $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
736 }
737 }
738 }
739
740 // take SOME_HEADER and turn it into Some-Header
741 foreach ($headers as $key => $val)
742 {
743 $key = str_replace('_', ' ', strtolower($key));
744 $key = str_replace(' ', '-', ucwords($key));
David Behler9b5df592011-08-14 21:04:17 +0200745
Greg Akerec2f5712010-11-15 16:22:12 -0600746 $this->headers[$key] = $val;
747 }
David Behler9b5df592011-08-14 21:04:17 +0200748
Greg Akerec2f5712010-11-15 16:22:12 -0600749 return $this->headers;
750 }
751
752 // --------------------------------------------------------------------
753
754 /**
755 * Get Request Header
756 *
757 * Returns the value of a single member of the headers class member
758 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300759 * @param string $index Header name
760 * @param bool $xss_clean Whether to apply XSS filtering
761 * @return string|bool The requested header on success or FALSE on failure
Greg Akerec2f5712010-11-15 16:22:12 -0600762 */
763 public function get_request_header($index, $xss_clean = FALSE)
764 {
765 if (empty($this->headers))
766 {
767 $this->request_headers();
768 }
David Behler9b5df592011-08-14 21:04:17 +0200769
Greg Akerec2f5712010-11-15 16:22:12 -0600770 if ( ! isset($this->headers[$index]))
771 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100772 return NULL;
Greg Akerec2f5712010-11-15 16:22:12 -0600773 }
774
Andrey Andreev9448afb2012-02-08 19:49:19 +0200775 return ($xss_clean === TRUE)
776 ? $this->security->xss_clean($this->headers[$index])
777 : $this->headers[$index];
Greg Akerec2f5712010-11-15 16:22:12 -0600778 }
779
Greg Aker081ac9d2010-11-22 14:42:53 -0600780 // --------------------------------------------------------------------
Phil Sturgeonc3828712011-01-19 12:31:47 +0000781
Greg Aker081ac9d2010-11-22 14:42:53 -0600782 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300783 * Is AJAX request?
Greg Aker081ac9d2010-11-22 14:42:53 -0600784 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300785 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
Greg Aker081ac9d2010-11-22 14:42:53 -0600786 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200787 * @return bool
Greg Aker081ac9d2010-11-22 14:42:53 -0600788 */
789 public function is_ajax_request()
790 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200791 return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
Greg Aker081ac9d2010-11-22 14:42:53 -0600792 }
793
Phil Sturgeonc3828712011-01-19 12:31:47 +0000794 // --------------------------------------------------------------------
795
796 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300797 * Is CLI request?
Phil Sturgeonc3828712011-01-19 12:31:47 +0000798 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300799 * Test to see if a request was made from the command line.
Phil Sturgeonc3828712011-01-19 12:31:47 +0000800 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200801 * @return bool
Phil Sturgeonc3828712011-01-19 12:31:47 +0000802 */
803 public function is_cli_request()
804 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200805 return (php_sapi_name() === 'cli' OR defined('STDIN'));
Phil Sturgeonc3828712011-01-19 12:31:47 +0000806 }
807
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100808 // --------------------------------------------------------------------
809
810 /**
811 * Get Request Method
812 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300813 * Return the request method
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100814 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300815 * @param bool $upper Whether to return in upper or lower case
816 * (default: FALSE)
817 * @return string
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100818 */
Michiel Vugteveen704fb162012-03-07 20:42:33 +0100819 public function method($upper = FALSE)
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100820 {
Michiel Vugteveendc900df2012-03-07 20:41:37 +0100821 return ($upper)
822 ? strtoupper($this->server('REQUEST_METHOD'))
823 : strtolower($this->server('REQUEST_METHOD'));
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100824 }
825
Derek Allard2067d1a2008-11-13 22:59:24 +0000826}
Derek Allard2067d1a2008-11-13 22:59:24 +0000827
828/* End of file Input.php */
Timothy Warren40403d22012-04-19 16:38:50 -0400829/* Location: ./system/core/Input.php */