blob: c6063a2805eacc8eb727bdea16ae7b98cc8773cc [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
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 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000028
Derek Allard2067d1a2008-11-13 22:59:24 +000029/**
30 * Input Class
31 *
32 * Pre-processes global input data for security
33 *
34 * @package CodeIgniter
35 * @subpackage Libraries
36 * @category Input
Derek Jonesf4a4bd82011-10-20 12:18:42 -050037 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000038 * @link http://codeigniter.com/user_guide/libraries/input.html
39 */
40class CI_Input {
Derek Allard2067d1a2008-11-13 22:59:24 +000041
David Behler9b5df592011-08-14 21:04:17 +020042 /**
43 * IP address of the current user
44 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030045 * @var string
David Behler9b5df592011-08-14 21:04:17 +020046 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030047 public $ip_address = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030048
David Behler9b5df592011-08-14 21:04:17 +020049 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030050 * User agent strin
David Behler9b5df592011-08-14 21:04:17 +020051 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030052 * @var string
David Behler9b5df592011-08-14 21:04:17 +020053 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030054 public $user_agent = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030055
David Behler9b5df592011-08-14 21:04:17 +020056 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030057 * Allow GET array flag
David Behler9b5df592011-08-14 21:04:17 +020058 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030059 * If set to FALSE, then $_GET will be set to an empty array.
David Behler9b5df592011-08-14 21:04:17 +020060 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030061 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020062 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030063 protected $_allow_get_array = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030064
David Behler9b5df592011-08-14 21:04:17 +020065 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030066 * Standartize new lines flag
David Behler9b5df592011-08-14 21:04:17 +020067 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030068 * If set to TRUE, then newlines are standardized.
69 *
70 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020071 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030072 protected $_standardize_newlines = TRUE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030073
David Behler9b5df592011-08-14 21:04:17 +020074 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +030075 * Enable XSS flag
76 *
77 * Determines whether the XSS filter is always active when
78 * GET, POST or COOKIE data is encountered.
79 * Set automatically based on config setting.
80 *
81 * @var bool
82 */
83 protected $_enable_xss = FALSE;
84
85 /**
86 * Enable CSRF flag
87 *
David Behler9b5df592011-08-14 21:04:17 +020088 * Enables a CSRF cookie token to be set.
Andrey Andreev1887ec62012-10-27 16:22:07 +030089 * Set automatically based on config setting.
David Behler9b5df592011-08-14 21:04:17 +020090 *
Andrey Andreev1887ec62012-10-27 16:22:07 +030091 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020092 */
Andrey Andreev1887ec62012-10-27 16:22:07 +030093 protected $_enable_csrf = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030094
David Behler9b5df592011-08-14 21:04:17 +020095 /**
96 * List of all HTTP request headers
97 *
98 * @var array
99 */
Andrey Andreev1887ec62012-10-27 16:22:07 +0300100 protected $headers = array();
David Behler9b5df592011-08-14 21:04:17 +0200101
Derek Allard2067d1a2008-11-13 22:59:24 +0000102 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300103 * Class constructor
Greg Akera9263282010-11-10 15:26:43 -0600104 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300105 * Determines whether to globally enable the XSS processing
106 * and whether to allow the $_GET array.
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300107 *
108 * @return void
Greg Akera9263282010-11-10 15:26:43 -0600109 */
110 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +0000111 {
Andrey Andreev13774972012-01-08 04:30:33 +0200112 log_message('debug', 'Input Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000113
Phil Sturgeonc8089152010-12-27 19:06:28 +0000114 $this->_allow_get_array = (config_item('allow_get_array') === TRUE);
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200115 $this->_enable_xss = (config_item('global_xss_filtering') === TRUE);
116 $this->_enable_csrf = (config_item('csrf_protection') === TRUE);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600117
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400118 global $SEC;
119 $this->security =& $SEC;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600120
Pascal Krieteaaec1e42011-01-20 00:01:21 -0500121 // Do we need the UTF-8 class?
Derek Jones69fc4fc2010-03-02 13:36:31 -0600122 if (UTF8_ENABLED === TRUE)
123 {
124 global $UNI;
125 $this->uni =& $UNI;
126 }
127
128 // Sanitize global arrays
Derek Allard2067d1a2008-11-13 22:59:24 +0000129 $this->_sanitize_globals();
130 }
131
132 // --------------------------------------------------------------------
133
134 /**
Greg Akera9263282010-11-10 15:26:43 -0600135 * Fetch from array
136 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300137 * Internal method used to retrieve values from global arrays.
Greg Akera9263282010-11-10 15:26:43 -0600138 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300139 * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc.
140 * @param string $index Index for item to be fetched from $array
141 * @param bool $xss_clean Whether to apply XSS filtering
142 * @return mixed
Greg Akera9263282010-11-10 15:26:43 -0600143 */
Bo-Yi Wu47213792011-09-13 22:44:07 +0800144 protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000145 {
146 if ( ! isset($array[$index]))
147 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100148 return NULL;
Derek Allard2067d1a2008-11-13 22:59:24 +0000149 }
150
151 if ($xss_clean === TRUE)
152 {
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400153 return $this->security->xss_clean($array[$index]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000154 }
155
156 return $array[$index];
157 }
158
159 // --------------------------------------------------------------------
160
161 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400162 * Fetch an item from the GET array
163 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300164 * @param string $index Index for item to be fetched from $_GET
165 * @param bool $xss_clean Whether to apply XSS filtering
166 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400167 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800168 public function get($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000169 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000170 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200171 if ($index === NULL && ! empty($_GET))
vascopjff1cfa12011-02-13 21:30:19 +0000172 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000173 $get = array();
vascopjff1cfa12011-02-13 21:30:19 +0000174
175 // loop through the full _GET array
Phil Sturgeon44f21052011-02-15 21:39:25 +0000176 foreach (array_keys($_GET) as $key)
vascopjff1cfa12011-02-13 21:30:19 +0000177 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000178 $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean);
vascopjff1cfa12011-02-13 21:30:19 +0000179 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000180 return $get;
vascopjff1cfa12011-02-13 21:30:19 +0000181 }
182
Derek Allard2067d1a2008-11-13 22:59:24 +0000183 return $this->_fetch_from_array($_GET, $index, $xss_clean);
184 }
185
186 // --------------------------------------------------------------------
187
188 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400189 * Fetch an item from the POST array
190 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300191 * @param string $index Index for item to be fetched from $_POST
192 * @param bool $xss_clean Whether to apply XSS filtering
193 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400194 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800195 public function post($index = NULL, $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000196 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000197 // Check if a field has been provided
Andrey Andreev9448afb2012-02-08 19:49:19 +0200198 if ($index === NULL && ! empty($_POST))
vascopj0ba58b82011-02-06 14:20:21 +0000199 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000200 $post = array();
vascopj0ba58b82011-02-06 14:20:21 +0000201
Phil Sturgeon44f21052011-02-15 21:39:25 +0000202 // Loop through the full _POST array and return it
203 foreach (array_keys($_POST) as $key)
vascopj0ba58b82011-02-06 14:20:21 +0000204 {
Phil Sturgeon44f21052011-02-15 21:39:25 +0000205 $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean);
vascopj0ba58b82011-02-06 14:20:21 +0000206 }
Phil Sturgeon44f21052011-02-15 21:39:25 +0000207 return $post;
vascopj0ba58b82011-02-06 14:20:21 +0000208 }
David Behler9b5df592011-08-14 21:04:17 +0200209
Derek Allard2067d1a2008-11-13 22:59:24 +0000210 return $this->_fetch_from_array($_POST, $index, $xss_clean);
211 }
212
213 // --------------------------------------------------------------------
214
215 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300216 * Fetch an item from POST data with fallback to GET
Timothy Warren40403d22012-04-19 16:38:50 -0400217 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300218 * @param string $index Index for item to be fetched from $_POST or $_GET
219 * @param bool $xss_clean Whether to apply XSS filtering
220 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400221 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800222 public function get_post($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000223 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200224 return isset($_POST[$index])
225 ? $this->post($index, $xss_clean)
226 : $this->get($index, $xss_clean);
Derek Allard2067d1a2008-11-13 22:59:24 +0000227 }
228
229 // --------------------------------------------------------------------
230
231 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400232 * Fetch an item from the COOKIE array
233 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300234 * @param string $index Index for item to be fetched from $_COOKIE
235 * @param bool $xss_clean Whether to apply XSS filtering
236 * @return mixed
Timothy Warren40403d22012-04-19 16:38:50 -0400237 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800238 public function cookie($index = '', $xss_clean = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000239 {
240 return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
241 }
242
Andrey Andreev1887ec62012-10-27 16:22:07 +0300243 // --------------------------------------------------------------------
244
245 /**
246 * Fetch an item from the SERVER array
247 *
248 * @param string $index Index for item to be fetched from $_SERVER
249 * @param bool $xss_clean Whether to apply XSS filtering
250 * @return mixed
251 */
252 public function server($index = '', $xss_clean = FALSE)
253 {
254 return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
255 }
256
Derek Jones69fc4fc2010-03-02 13:36:31 -0600257 // ------------------------------------------------------------------------
258
259 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400260 * Set cookie
261 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300262 * Accepts an arbitrary number of parameters (up to 7) or an associative
Timothy Warren40403d22012-04-19 16:38:50 -0400263 * array in the first parameter containing all the values.
264 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300265 * @param string|mixed[] $name Cookie name or an array containing parameters
266 * @param string $value Cookie value
267 * @param int $expire Cookie expiration time in seconds
268 * @param string $domain Cookie domain (e.g.: '.yourdomain.com')
269 * @param string $path Cookie path (default: '/')
270 * @param string $prefix Cookie name prefix
271 * @param bool $secure Whether to only transfer cookies via SSL
272 * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
Timothy Warren40403d22012-04-19 16:38:50 -0400273 * @return void
274 */
freewil4ad0fd82012-03-13 22:37:42 -0400275 public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600276 {
277 if (is_array($name))
278 {
tobiasbg9aa7dc92011-02-18 21:57:13 +0100279 // always leave 'name' in last place, as the loop will break otherwise, due to $$item
freewil4ad0fd82012-03-13 22:37:42 -0400280 foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600281 {
282 if (isset($name[$item]))
283 {
284 $$item = $name[$item];
285 }
286 }
287 }
288
Alex Bilbieed944a32012-06-02 11:07:47 +0100289 if ($prefix === '' && config_item('cookie_prefix') !== '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600290 {
291 $prefix = config_item('cookie_prefix');
292 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300293
294 if ($domain == '' && config_item('cookie_domain') != '')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600295 {
296 $domain = config_item('cookie_domain');
297 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300298
Alex Bilbieed944a32012-06-02 11:07:47 +0100299 if ($path === '/' && config_item('cookie_path') !== '/')
Derek Jones69fc4fc2010-03-02 13:36:31 -0600300 {
301 $path = config_item('cookie_path');
302 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300303
Alex Bilbieed944a32012-06-02 11:07:47 +0100304 if ($secure === FALSE && config_item('cookie_secure') !== FALSE)
tobiasbg9aa7dc92011-02-18 21:57:13 +0100305 {
306 $secure = config_item('cookie_secure');
307 }
Andrey Andreev9ba661b2012-06-04 14:44:34 +0300308
Alex Bilbieed944a32012-06-02 11:07:47 +0100309 if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
freewil4ad0fd82012-03-13 22:37:42 -0400310 {
311 $httponly = config_item('cookie_httponly');
312 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600313
314 if ( ! is_numeric($expire))
315 {
316 $expire = time() - 86500;
317 }
318 else
319 {
Phil Sturgeonc8089152010-12-27 19:06:28 +0000320 $expire = ($expire > 0) ? time() + $expire : 0;
Derek Jones69fc4fc2010-03-02 13:36:31 -0600321 }
322
freewil4ad0fd82012-03-13 22:37:42 -0400323 setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600324 }
325
Derek Allard2067d1a2008-11-13 22:59:24 +0000326 // --------------------------------------------------------------------
327
328 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400329 * Fetch the IP Address
330 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300331 * Determines and validates the visitor's IP address.
332 *
333 * @return string IP address
Timothy Warren40403d22012-04-19 16:38:50 -0400334 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800335 public function ip_address()
Derek Allard2067d1a2008-11-13 22:59:24 +0000336 {
337 if ($this->ip_address !== FALSE)
338 {
339 return $this->ip_address;
340 }
Barry Mienydd671972010-10-04 16:33:58 +0200341
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300342 $proxy_ips = config_item('proxy_ips');
Andrey Andreevea7a8662012-10-09 13:36:31 +0300343 if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300344 {
345 $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
346 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300347
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300348 $this->ip_address = $this->server('REMOTE_ADDR');
349
350 if ($proxy_ips)
351 {
352 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 -0300353 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300354 if (($spoof = $this->server($header)) !== NULL)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300355 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300356 // Some proxies typically list the whole chain of IP
357 // addresses through which the client has reached us.
358 // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
359 if (strpos($spoof, ',') !== FALSE)
Jordan Pittman8960acf2012-07-23 09:05:49 -0300360 {
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300361 $spoof = explode(',', $spoof, 2);
362 $spoof = $spoof[0];
363 }
364
365 if ( ! $this->valid_ip($spoof))
366 {
367 $spoof = NULL;
368 }
369 else
370 {
Jordan Pittmana5a71352012-07-20 19:36:43 -0300371 break;
372 }
373 }
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300374 }
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300375
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300376 if ($spoof)
Andrey Andreev5b92ae12012-10-04 13:05:03 +0300377 {
Andrey Andreev9df35b42012-10-09 13:37:58 +0300378 for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300379 {
380 // Check if we have an IP address or a subnet
381 if (strpos($proxy_ips[$i], '/') === FALSE)
382 {
383 // An IP address (and not a subnet) is specified.
384 // We can compare right away.
385 if ($proxy_ips[$i] === $this->ip_address)
386 {
387 $this->ip_address = $spoof;
388 break;
389 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000390
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300391 continue;
392 }
393
394 // We have a subnet ... now the heavy lifting begins
395 isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
396
397 // If the proxy entry doesn't match the IP protocol - skip it
398 if (strpos($proxy_ips[$i], $separator) === FALSE)
399 {
400 continue;
401 }
402
403 // Convert the REMOTE_ADDR IP address to binary, if needed
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300404 if ( ! isset($ip, $sprintf))
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300405 {
406 if ($separator === ':')
407 {
408 // Make sure we're have the "full" IPv6 format
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300409 $ip = explode(':',
410 str_replace('::',
411 str_repeat(':', 9 - substr_count($this->ip_address, ':')),
412 $this->ip_address
413 )
414 );
415
416 for ($i = 0; $i < 8; $i++)
417 {
418 $ip[$i] = intval($ip[$i], 16);
419 }
420
421 $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300422 }
423 else
424 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300425 $ip = explode('.', $this->ip_address);
426 $sprintf = '%08b%08b%08b%08b';
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300427 }
428
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300429 $ip = vsprintf($sprintf, $ip);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300430 }
431
432 // Split the netmask length off the network address
433 list($netaddr, $masklen) = explode('/', $proxy_ips[$i], 2);
434
435 // Again, an IPv6 address is most likely in a compressed form
436 if ($separator === ':')
437 {
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300438 $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
439 for ($i = 0; $i < 8; $i++)
440 {
441 $netaddr[$i] = intval($netaddr[$i], 16);
442 }
443 }
444 else
445 {
446 $netaddr = explode('.', $netaddr);
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300447 }
448
Andrey Andreev82d2cf12012-10-13 12:38:42 +0300449 // Convert to binary and finally compare
450 if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
Andrey Andreev9ac557f2012-10-06 20:27:57 +0300451 {
452 $this->ip_address = $spoof;
453 break;
454 }
455 }
456 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000457 }
458
Derek Allard2067d1a2008-11-13 22:59:24 +0000459 if ( ! $this->valid_ip($this->ip_address))
460 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200461 return $this->ip_address = '0.0.0.0';
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 }
463
464 return $this->ip_address;
465 }
466
467 // --------------------------------------------------------------------
468
469 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400470 * Validate IP Address
471 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300472 * @param string $ip IP address
473 * @param string $which IP protocol: 'ipv4' or 'ipv6'
Timothy Warren40403d22012-04-19 16:38:50 -0400474 * @return bool
475 */
Andrey Andreev5a257182012-06-10 06:18:14 +0300476 public function valid_ip($ip, $which = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000477 {
Andrey Andreev5a257182012-06-10 06:18:14 +0300478 switch (strtolower($which))
479 {
480 case 'ipv4':
481 $which = FILTER_FLAG_IPV4;
482 break;
483 case 'ipv6':
484 $which = FILTER_FLAG_IPV6;
485 break;
486 default:
487 $which = NULL;
488 break;
489 }
490
491 return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
Derek Allard2067d1a2008-11-13 22:59:24 +0000492 }
493
494 // --------------------------------------------------------------------
495
496 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300497 * Fetch User Agent string
Timothy Warren40403d22012-04-19 16:38:50 -0400498 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300499 * @return string|null User Agent string or NULL if it doesn't exist
Timothy Warren40403d22012-04-19 16:38:50 -0400500 */
Bo-Yi Wu4db872f2011-09-12 10:52:37 +0800501 public function user_agent()
Derek Allard2067d1a2008-11-13 22:59:24 +0000502 {
503 if ($this->user_agent !== FALSE)
504 {
505 return $this->user_agent;
506 }
507
Andrey Andreev1887ec62012-10-27 16:22:07 +0300508 return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
Derek Allard2067d1a2008-11-13 22:59:24 +0000509 }
510
511 // --------------------------------------------------------------------
512
513 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400514 * Sanitize Globals
515 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300516 * Internal method serving for the following purposes:
Timothy Warren40403d22012-04-19 16:38:50 -0400517 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300518 * - Unsets $_GET data (if query strings are not enabled)
519 * - Unsets all globals if register_globals is enabled
520 * - Cleans POST, COOKIE and SERVER data
521 * - Standardizes newline characters to PHP_EOL
Timothy Warren40403d22012-04-19 16:38:50 -0400522 *
523 * @return void
524 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200525 protected function _sanitize_globals()
Derek Allard2067d1a2008-11-13 22:59:24 +0000526 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600527 // It would be "wrong" to unset any of these GLOBALS.
Timothy Warren40403d22012-04-19 16:38:50 -0400528 $protected = array(
529 '_SERVER',
530 '_GET',
531 '_POST',
532 '_FILES',
533 '_REQUEST',
534 '_SESSION',
535 '_ENV',
536 'GLOBALS',
537 'HTTP_RAW_POST_DATA',
538 'system_folder',
539 'application_folder',
540 'BM',
541 'EXT',
542 'CFG',
543 'URI',
544 'RTR',
Timothy Warren67cb3ee2012-04-19 16:41:52 -0400545 'OUT',
Timothy Warren40403d22012-04-19 16:38:50 -0400546 'IN'
547 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000548
Andrey Andreev1887ec62012-10-27 16:22:07 +0300549 // Unset globals for security.
Derek Jones69fc4fc2010-03-02 13:36:31 -0600550 // This is effectively the same as register_globals = off
Andrey Andreev1887ec62012-10-27 16:22:07 +0300551 // PHP 5.4 no longer has the register_globals functionality.
552 if ( ! is_php('5.4'))
Derek Allard2067d1a2008-11-13 22:59:24 +0000553 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300554 foreach (array($_GET, $_POST, $_COOKIE) as $global)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600555 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300556 if (is_array($global))
Derek Jones69fc4fc2010-03-02 13:36:31 -0600557 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300558 foreach ($global as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600559 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300560 if ( ! in_array($key, $protected))
561 {
562 global $$key;
563 $$key = NULL;
564 }
Derek Jones69fc4fc2010-03-02 13:36:31 -0600565 }
566 }
Andrey Andreev1887ec62012-10-27 16:22:07 +0300567 elseif ( ! in_array($global, $protected))
568 {
569 global $$global;
570 $$global = NULL;
571 }
Andrey Andreev92ebfb62012-05-17 12:49:24 +0300572 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000573 }
574
Derek Jones69fc4fc2010-03-02 13:36:31 -0600575 // Is $_GET data allowed? If not we'll set the $_GET to an empty array
Alex Bilbieed944a32012-06-02 11:07:47 +0100576 if ($this->_allow_get_array === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000577 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600578 $_GET = array();
Derek Allard2067d1a2008-11-13 22:59:24 +0000579 }
Andrey Andreev9448afb2012-02-08 19:49:19 +0200580 elseif (is_array($_GET) && count($_GET) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000581 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200582 foreach ($_GET as $key => $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000583 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200584 $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000585 }
586 }
587
Derek Jones69fc4fc2010-03-02 13:36:31 -0600588 // Clean $_POST Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200589 if (is_array($_POST) && count($_POST) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000590 {
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500591 foreach ($_POST as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600592 {
593 $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
594 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000595 }
596
Derek Jones69fc4fc2010-03-02 13:36:31 -0600597 // Clean $_COOKIE Data
Andrey Andreev9448afb2012-02-08 19:49:19 +0200598 if (is_array($_COOKIE) && count($_COOKIE) > 0)
Derek Allard2067d1a2008-11-13 22:59:24 +0000599 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600600 // Also get rid of specially treated cookies that might be set by a server
601 // or silly application, that are of no use to a CI application anyway
602 // but that when present will trip our 'Disallowed Key Characters' alarm
603 // http://www.ietf.org/rfc/rfc2109.txt
604 // note that the key names below are single quoted strings, and are not PHP variables
605 unset($_COOKIE['$Version']);
606 unset($_COOKIE['$Path']);
607 unset($_COOKIE['$Domain']);
608
Pascal Kriete5d5895f2011-02-14 13:27:07 -0500609 foreach ($_COOKIE as $key => $val)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600610 {
611 $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
612 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000613 }
614
Derek Jones69fc4fc2010-03-02 13:36:31 -0600615 // Sanitize PHP_SELF
616 $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
617
Derek Jones69fc4fc2010-03-02 13:36:31 -0600618 // CSRF Protection check
Andrey Andreeve45ad2b2012-10-09 13:11:15 +0300619 if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
Derek Allard2067d1a2008-11-13 22:59:24 +0000620 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600621 $this->security->csrf_verify();
Derek Allard2067d1a2008-11-13 22:59:24 +0000622 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000623
Andrey Andreev90cfe142012-01-08 04:46:42 +0200624 log_message('debug', 'Global POST and COOKIE data sanitized');
Derek Allard2067d1a2008-11-13 22:59:24 +0000625 }
626
627 // --------------------------------------------------------------------
628
629 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400630 * Clean Input Data
631 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300632 * Internal method that aids in escaping data and
633 * standardizing newline characters to PHP_EOL.
Timothy Warren40403d22012-04-19 16:38:50 -0400634 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300635 * @param string|string[] $str Input string(s)
Timothy Warren40403d22012-04-19 16:38:50 -0400636 * @return string
637 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200638 protected function _clean_input_data($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000639 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600640 if (is_array($str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000641 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600642 $new_array = array();
Andrey Andreev1887ec62012-10-27 16:22:07 +0300643 foreach (array_keys($str) as $key)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600644 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300645 $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600646 }
647 return $new_array;
Derek Allard2067d1a2008-11-13 22:59:24 +0000648 }
649
Andrey Andreevaf728622011-10-20 10:11:59 +0300650 /* We strip slashes if magic quotes is on to keep things consistent
651
652 NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
653 it will probably not exist in future versions at all.
654 */
655 if ( ! is_php('5.4') && get_magic_quotes_gpc())
Derek Allard2067d1a2008-11-13 22:59:24 +0000656 {
Derek Jones69fc4fc2010-03-02 13:36:31 -0600657 $str = stripslashes($str);
658 }
659
660 // Clean UTF-8 if supported
661 if (UTF8_ENABLED === TRUE)
662 {
663 $str = $this->uni->clean_string($str);
664 }
David Behler9b5df592011-08-14 21:04:17 +0200665
Pascal Kriete14a0ac62011-04-05 14:55:56 -0400666 // Remove control characters
667 $str = remove_invisible_characters($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600668
669 // Should we filter the input data?
670 if ($this->_enable_xss === TRUE)
671 {
672 $str = $this->security->xss_clean($str);
673 }
674
675 // Standardize newlines if needed
Alex Bilbieed944a32012-06-02 11:07:47 +0100676 if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
Derek Jones69fc4fc2010-03-02 13:36:31 -0600677 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200678 return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000679 }
680
681 return $str;
682 }
683
684 // --------------------------------------------------------------------
685
686 /**
Timothy Warren40403d22012-04-19 16:38:50 -0400687 * Clean Keys
688 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300689 * Internal method that helps to prevent malicious users
Timothy Warren40403d22012-04-19 16:38:50 -0400690 * from trying to exploit keys we make sure that keys are
691 * only named with alpha-numeric text and a few other items.
692 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300693 * @param string $str Input string
Timothy Warren40403d22012-04-19 16:38:50 -0400694 * @return string
695 */
Andrey Andreev90cfe142012-01-08 04:46:42 +0200696 protected function _clean_input_keys($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000697 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200698 if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str))
Derek Allard2067d1a2008-11-13 22:59:24 +0000699 {
Kevin Cuppd63e4012012-02-05 14:14:32 -0500700 set_status_header(503);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600701 exit('Disallowed Key Characters.');
Derek Allard2067d1a2008-11-13 22:59:24 +0000702 }
703
Derek Jones69fc4fc2010-03-02 13:36:31 -0600704 // Clean UTF-8 if supported
705 if (UTF8_ENABLED === TRUE)
706 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200707 return $this->uni->clean_string($str);
Derek Jones69fc4fc2010-03-02 13:36:31 -0600708 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000709
Derek Jones69fc4fc2010-03-02 13:36:31 -0600710 return $str;
711 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000712
Greg Akerec2f5712010-11-15 16:22:12 -0600713 // --------------------------------------------------------------------
714
715 /**
716 * Request Headers
717 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300718 * @param bool $xss_clean Whether to apply XSS filtering
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200719 * @return array
Greg Akerec2f5712010-11-15 16:22:12 -0600720 */
721 public function request_headers($xss_clean = FALSE)
722 {
Andrey Andreev1887ec62012-10-27 16:22:07 +0300723 // In Apache, you can simply call apache_request_headers()
Greg Akerec2f5712010-11-15 16:22:12 -0600724 if (function_exists('apache_request_headers'))
725 {
726 $headers = apache_request_headers();
727 }
728 else
729 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200730 $headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
Greg Akerec2f5712010-11-15 16:22:12 -0600731
732 foreach ($_SERVER as $key => $val)
733 {
Andrey Andreev64e98aa2012-01-07 20:29:10 +0200734 if (strpos($key, 'HTTP_') === 0)
Greg Akerec2f5712010-11-15 16:22:12 -0600735 {
736 $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
737 }
738 }
739 }
740
741 // take SOME_HEADER and turn it into Some-Header
742 foreach ($headers as $key => $val)
743 {
744 $key = str_replace('_', ' ', strtolower($key));
745 $key = str_replace(' ', '-', ucwords($key));
David Behler9b5df592011-08-14 21:04:17 +0200746
Greg Akerec2f5712010-11-15 16:22:12 -0600747 $this->headers[$key] = $val;
748 }
David Behler9b5df592011-08-14 21:04:17 +0200749
Greg Akerec2f5712010-11-15 16:22:12 -0600750 return $this->headers;
751 }
752
753 // --------------------------------------------------------------------
754
755 /**
756 * Get Request Header
757 *
758 * Returns the value of a single member of the headers class member
759 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300760 * @param string $index Header name
761 * @param bool $xss_clean Whether to apply XSS filtering
762 * @return string|bool The requested header on success or FALSE on failure
Greg Akerec2f5712010-11-15 16:22:12 -0600763 */
764 public function get_request_header($index, $xss_clean = FALSE)
765 {
766 if (empty($this->headers))
767 {
768 $this->request_headers();
769 }
David Behler9b5df592011-08-14 21:04:17 +0200770
Greg Akerec2f5712010-11-15 16:22:12 -0600771 if ( ! isset($this->headers[$index]))
772 {
Phil Sturgeon55a6ddb2012-05-23 18:37:24 +0100773 return NULL;
Greg Akerec2f5712010-11-15 16:22:12 -0600774 }
775
Andrey Andreev9448afb2012-02-08 19:49:19 +0200776 return ($xss_clean === TRUE)
777 ? $this->security->xss_clean($this->headers[$index])
778 : $this->headers[$index];
Greg Akerec2f5712010-11-15 16:22:12 -0600779 }
780
Greg Aker081ac9d2010-11-22 14:42:53 -0600781 // --------------------------------------------------------------------
Phil Sturgeonc3828712011-01-19 12:31:47 +0000782
Greg Aker081ac9d2010-11-22 14:42:53 -0600783 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300784 * Is AJAX request?
Greg Aker081ac9d2010-11-22 14:42:53 -0600785 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300786 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
Greg Aker081ac9d2010-11-22 14:42:53 -0600787 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200788 * @return bool
Greg Aker081ac9d2010-11-22 14:42:53 -0600789 */
790 public function is_ajax_request()
791 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200792 return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
Greg Aker081ac9d2010-11-22 14:42:53 -0600793 }
794
Phil Sturgeonc3828712011-01-19 12:31:47 +0000795 // --------------------------------------------------------------------
796
797 /**
Andrey Andreev1887ec62012-10-27 16:22:07 +0300798 * Is CLI request?
Phil Sturgeonc3828712011-01-19 12:31:47 +0000799 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300800 * Test to see if a request was made from the command line.
Phil Sturgeonc3828712011-01-19 12:31:47 +0000801 *
Andrey Andreev9448afb2012-02-08 19:49:19 +0200802 * @return bool
Phil Sturgeonc3828712011-01-19 12:31:47 +0000803 */
804 public function is_cli_request()
805 {
Andrey Andreev9448afb2012-02-08 19:49:19 +0200806 return (php_sapi_name() === 'cli' OR defined('STDIN'));
Phil Sturgeonc3828712011-01-19 12:31:47 +0000807 }
808
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100809 // --------------------------------------------------------------------
810
811 /**
812 * Get Request Method
813 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300814 * Return the request method
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100815 *
Andrey Andreev1887ec62012-10-27 16:22:07 +0300816 * @param bool $upper Whether to return in upper or lower case
817 * (default: FALSE)
818 * @return string
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100819 */
Michiel Vugteveen704fb162012-03-07 20:42:33 +0100820 public function method($upper = FALSE)
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100821 {
Michiel Vugteveendc900df2012-03-07 20:41:37 +0100822 return ($upper)
823 ? strtoupper($this->server('REQUEST_METHOD'))
824 : strtolower($this->server('REQUEST_METHOD'));
Michiel Vugteveenbe0ca262012-03-07 19:09:51 +0100825 }
826
Derek Allard2067d1a2008-11-13 22:59:24 +0000827}
Derek Allard2067d1a2008-11-13 22:59:24 +0000828
829/* End of file Input.php */
Timothy Warren40403d22012-04-19 16:38:50 -0400830/* Location: ./system/core/Input.php */