当前位置: 代码迷 >> PHP >> CI框架源码翻阅-Input.php
  详细解决方案

CI框架源码翻阅-Input.php

热度:48   发布时间:2016-04-28 21:54:38.0
CI框架源码阅读---------Input.php
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');/** * CodeIgniter * * An open source application development framework for PHP 5.1.6 or newer * * @package		CodeIgniter * @author		ExpressionEngine Dev Team * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc. * @license		http://codeigniter.com/user_guide/license.html * @link		http://codeigniter.com * @since		Version 1.0 * @filesource */// ------------------------------------/** * Input Class *  * Pre-processes global input data for security * * @package		CodeIgniter * @subpackage	Libraries * @category	Input * @author		ExpressionEngine Dev Team * @link		http://codeigniter.com/user_guide/libraries/input.html */class CI_Input {	/**	 * IP address of the current user	 * 当前用户的ip地址	 * @var string	 */	var $ip_address				= FALSE;	/**	 * user agent (web browser) being used by the current user	 * 当前用户(web浏览器)代理	 * @var string	 */	var $user_agent				= FALSE;	/**	 * If FALSE, then $_GET will be set to an empty array	 * 如果是FALSE , $_GET将被设置为空数组	 * @var bool	 */	var $_allow_get_array		= TRUE;	/**	 * If TRUE, then newlines are standardized	 * 如果为TRUR,新行将被标准化	 *	 * @var bool	 */	var $_standardize_newlines	= TRUE;	/**	 * Determines whether the XSS filter is always active when GET, POST or COOKIE data is encountered	 * Set automatically based on config setting	 * 决定是否总是在GET ,POST , COOKIE数据中进行XSS过滤     * 在配置选项里面配置是否自动开启	 * 	 * @var bool	 */	var $_enable_xss			= FALSE;	/**	 * Enables a CSRF cookie token to be set.	 * Set automatically based on config setting	 * 允许CSRF cookie令牌	 *	 * @var bool	 */	var $_enable_csrf			= FALSE;	/**	 * List of all HTTP request headers	 * HTTP请求头部的列表	 * @var array	 */	protected $headers			= array();	/**	 * Constructor	 * 设置是否全局允许XSS处理和是否允许使用$_GET数组	 * Sets whether to globally enable the XSS processing	 * and whether to allow the $_GET array	 *	 * @return	void	 */	public function __construct()	{		log_message('debug', "Input Class Initialized");		// 从配置文件中获取是否进行全局允许使用$_GET XSS过滤和csrf保护		$this->_allow_get_array	= (config_item('allow_get_array') === TRUE);		$this->_enable_xss		= (config_item('global_xss_filtering') === TRUE);		$this->_enable_csrf		= (config_item('csrf_protection') === TRUE);				// 清除globals变量,在开启了globals_register的情况下,相当于关闭了此配置。		// 开启一道 安全防护				global $SEC;		$this->security =& $SEC;		// Do we need the UTF-8 class?		if (UTF8_ENABLED === TRUE)		{			global $UNI;			$this->uni =& $UNI;		}		// Sanitize global arrays		$this->_sanitize_globals();	}	// --------------------------------	/**	 * Fetch from array	 * 从$array获取值,如果设置了xss_clean 那么进行过滤 	 * This is a helper function to retrieve 检索 values from global arrays	 * 这是一个帮助函数用来从全局数组中检索	 *	 * @access	private	 * @param	array	 * @param	string	 * @param	bool	 * @return	string	 */	function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)	{		if ( ! isset($array[$index]))		{			return FALSE;		}		if ($xss_clean === TRUE)		{			return $this->security->xss_clean($array[$index]);		}		return $array[$index];	}	// --------------------------------	/**	* Fetch an item from the GET array	* 获取过滤后的GET数组	* @access	public	* @param	string	* @param	bool	* @return	string	*/	function get($index = NULL, $xss_clean = FALSE)	{		// Check if a field has been provided		// 检查是否一个字段已经被提供		if ($index === NULL AND ! empty($_GET))		{			$get = array();			// loop through the full _GET array			// 遍历_GET数组			foreach (array_keys($_GET) as $key)			{				$get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean);			}			return $get;		}		return $this->_fetch_from_array($_GET, $index, $xss_clean);	}	// --------------------------------	/**	* Fetch an item from the POST array	* 获取过滤后的$_POST值	* @access	public	* @param	string	* @param	bool	* @return	string	*/	function post($index = NULL, $xss_clean = FALSE)	{		// Check if a field has been provided		if ($index === NULL AND ! empty($_POST))		{			$post = array();			// Loop through the full _POST array and return it			foreach (array_keys($_POST) as $key)			{				$post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean);			}			return $post;		}		return $this->_fetch_from_array($_POST, $index, $xss_clean);	}	// --------------------------------	/**	* Fetch an item from either the GET array or the POST	* 从get和post中获取值, post优先	* @access	public	* @param	string	The index key	* @param	bool	XSS cleaning	* @return	string	*/	function get_post($index = '', $xss_clean = FALSE)	{		if ( ! isset($_POST[$index]) )		{			return $this->get($index, $xss_clean);		}		else		{			return $this->post($index, $xss_clean);		}	}	// --------------------------------	/**	* Fetch an item from the COOKIE array	* 返回过滤后的COOKIE值	* @access	public	* @param	string	* @param	bool	* @return	string	*/	function cookie($index = '', $xss_clean = FALSE)	{		return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);	}	// ------------------------------------	/**	* Set cookie	*	* Accepts six parameter, or you can submit an associative	* array in the first parameter containing all the values.	* 接收6个参数或者接收一个关联数组里面包含所有的值	* @access	public	* @param	mixed	* @param	string	the value of the cookie	* @param	string	the number of seconds until expiration	* @param	string	the cookie domain.  Usually:  .yourdomain.com	* @param	string	the cookie path	* @param	string	the cookie prefix	* @param	bool	true makes the cookie secure	* @return	void	*/	function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)	{		// 如果第一个值是数组 将数组中的值分别赋值给留个参数		if (is_array($name))		{			// always leave 'name' in last place, as the loop will break otherwise, due to $$item			foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item)			{				if (isset($name[$item]))				{					$$item = $name[$item];				}			}		}		// 如果某个参数为默认值但是config.php中的配置不是默认值		// 则使用config.php中的配置值		if ($prefix == '' AND config_item('cookie_prefix') != '')		{			$prefix = config_item('cookie_prefix');		}		if ($domain == '' AND config_item('cookie_domain') != '')		{			$domain = config_item('cookie_domain');		}		if ($path == '/' AND config_item('cookie_path') != '/')		{			$path = config_item('cookie_path');		}		if ($secure == FALSE AND config_item('cookie_secure') != FALSE)		{			$secure = config_item('cookie_secure');		}		if ( ! is_numeric($expire))		{			$expire = time() - 86500;		}		else		{			$expire = ($expire > 0) ? time() + $expire : 0;		}		setcookie($prefix.$name, $value, $expire, $path, $domain, $secure);	}	// --------------------------------	/**	* Fetch an item from the SERVER array	* 返回过滤后的$_SERVER值	* @access	public	* @param	string	* @param	bool	* @return	string	*/	function server($index = '', $xss_clean = FALSE)	{		return $this->_fetch_from_array($_SERVER, $index, $xss_clean);	}	// --------------------------------	/**	* Fetch the IP Address	* 返回当前用户的IP。如果IP地址无效,返回0.0.0.0的IP:	* @return	string	*/	public function ip_address()	{		// 如果已经有了ip_address 则返回		if ($this->ip_address !== FALSE)		{			return $this->ip_address;		}		$proxy_ips = config_item('proxy_ips');		if ( ! empty($proxy_ips))		{			$proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));			foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)			{				if (($spoof = $this->server($header)) !== FALSE)				{					// Some proxies typically list the whole chain of IP					// addresses through which the client has reached us.					// e.g. client_ip, proxy_ip1, proxy_ip2, etc.					if (strpos($spoof, ',') !== FALSE)					{						$spoof = explode(',', $spoof, 2);						$spoof = $spoof[0];					}					if ( ! $this->valid_ip($spoof))					{						$spoof = FALSE;					}					else					{						break;					}				}			}			$this->ip_address = ($spoof !== FALSE && in_array($_SERVER['REMOTE_ADDR'], $proxy_ips, TRUE))				? $spoof : $_SERVER['REMOTE_ADDR'];		}		else		{			$this->ip_address = $_SERVER['REMOTE_ADDR'];		}		if ( ! $this->valid_ip($this->ip_address))		{			$this->ip_address = '0.0.0.0';		}		return $this->ip_address;	}	// --------------------------------	/**	* Validate IP Address	* 测试输入的IP地址是不是有效,返回布尔值TRUE或者FALSE。 	* 注意:$this->input->ip_address()自动测试输入的IP地址本身格式是不是有效。	* @access	public	* @param	string	* @param	string	ipv4 or ipv6	* @return	bool	*/	public function valid_ip($ip, $which = '')	{		$which = strtolower($which);		// First check if filter_var is available		if (is_callable('filter_var'))		{			switch ($which) {				case 'ipv4':					$flag = FILTER_FLAG_IPV4;					break;				case 'ipv6':					$flag = FILTER_FLAG_IPV6;					break;				default:					$flag = '';					break;			}			return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag);		}		if ($which !== 'ipv6' && $which !== 'ipv4')		{			if (strpos($ip, ':') !== FALSE)			{				$which = 'ipv6';			}			elseif (strpos($ip, '.') !== FALSE)			{				$which = 'ipv4';			}			else			{				return FALSE;			}		}		$func = '_valid_'.$which;		return $this->$func($ip);	}	// --------------------------------	/**	* Validate IPv4 Address	* 验证ipv4地址	* Updated version suggested by Geert De Deckere	*	* @access	protected	* @param	string	* @return	bool	*/	protected function _valid_ipv4($ip)	{		$ip_segments = explode('.', $ip);		// Always 4 segments needed		if (count($ip_segments) !== 4)		{			return FALSE;		}		// IP can not start with 0		if ($ip_segments[0][0] == '0')		{			return FALSE;		}		// Check each segment		foreach ($ip_segments as $segment)		{			// IP segments must be digits and can not be			// longer than 3 digits or greater then 255			if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)			{				return FALSE;			}		}		return TRUE;	}	// --------------------------------	/**	* Validate IPv6 Address	* 验证ipv6地址	* @access	protected	* @param	string	* @return	bool	*/	protected function _valid_ipv6($str)	{		// 8 groups, separated by :		// 0-ffff per group		// one set of consecutive 0 groups can be collapsed to ::		$groups = 8;		$collapsed = FALSE;		$chunks = array_filter(			preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE)		);		// Rule out easy nonsense		if (current($chunks) == ':' OR end($chunks) == ':')		{			return FALSE;		}		// PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well		if (strpos(end($chunks), '.') !== FALSE)		{			$ipv4 = array_pop($chunks);			if ( ! $this->_valid_ipv4($ipv4))			{				return FALSE;			}			$groups--;		}		while ($seg = array_pop($chunks))		{			if ($seg[0] == ':')			{				if (--$groups == 0)				{					return FALSE;	// too many groups				}				if (strlen($seg) > 2)				{					return FALSE;	// long separator				}				if ($seg == '::')				{					if ($collapsed)					{						return FALSE;	// multiple collapsed					}					$collapsed = TRUE;				}			}			elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4)			{				return FALSE; // invalid segment			}		}		return $collapsed OR $groups == 1;	}	// --------------------------------	/**	* User Agent	* 返回当前用户正在使用的浏览器的user agent信息。 如果不能得到数据,返回FALSE。	* 一般user_agent为空的时候被认定为手机访问,或者curl的抓取,或则会蜘蛛抓取	* @access	public	* @return	string	*/	function user_agent()	{		if ($this->user_agent !== FALSE)		{			return $this->user_agent;		}		$this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];		return $this->user_agent;	}	// --------------------------------	/**	* Sanitize Globals	* 清理全局数组	* This function does the following:	* 这个函数做了下面的操作:	* Unsets $_GET data (if query strings are not enabled)	* 销毁$_GET (如果query strings 没有开启)	* Unsets all globals if register_globals is enabled	* 销毁所有全局数组如果register_globals开启	*	* Standardizes newline characters to \n	* 标准化换行符\n	* @access	private	* @return	void	*/	function _sanitize_globals()	{		// It would be "wrong" to unset any of these GLOBALS.		// 销毁下面的全局数组将是错误的。		$protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST',							'_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',							'system_folder', 'application_folder', 'BM', 'EXT',							'CFG', 'URI', 'RTR', 'OUT', 'IN');		// Unset globals for securiy.为了安全销毁除了上面之外的全局数组		// This is effectively the same as register_globals = off		// 这样的效果和register_globals是相同的        // 经过下面处理后,所有的非保护的全局变量将被删除掉				foreach (array($_GET, $_POST, $_COOKIE) as $global)		{			if ( ! is_array($global))			{				if ( ! in_array($global, $protected))				{					global $$global;					$$global = NULL;				}			}			else			{				foreach ($global as $key => $val)				{					if ( ! in_array($key, $protected))					{						global $$key;						$$key = NULL;					}				}			}		}		// Is $_GET data allowed? If not we'll set the $_GET to an empty array		// 是否允许$_GET数据? 如果不允许的话,设置$_GET为空数组		if ($this->_allow_get_array == FALSE)		{			$_GET = array();		}		else		{			if (is_array($_GET) AND count($_GET) > 0)			{				foreach ($_GET as $key => $val)				{					$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);				}			}		}		// Clean $_POST Data		// 过滤$_POST 数组		if (is_array($_POST) AND count($_POST) > 0)		{			foreach ($_POST as $key => $val)			{				$_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);			}		}		// Clean $_COOKIE Data		// 过滤$_COOKIE数组		if (is_array($_COOKIE) AND count($_COOKIE) > 0)		{			// Also get rid of specially treated cookies that might be set by a server			// or silly application, that are of no use to a CI application anyway			// but that when present will trip our 'Disallowed Key Characters' alarm			// http://www.ietf.org/rfc/rfc2109.txt			// note that the key names below are single quoted strings, and are not PHP variables			unset($_COOKIE['$Version']);			unset($_COOKIE['$Path']);			unset($_COOKIE['$Domain']);			foreach ($_COOKIE as $key => $val)			{				$_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);			}		}		// Sanitize PHP_SELF		$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);		// CSRF Protection check on HTTP requests		// CSRF保护检测http请求		if ($this->_enable_csrf == TRUE && ! $this->is_cli_request())		{			$this->security->csrf_verify();		}		log_message('debug', "Global POST and COOKIE data sanitized");	}	// --------------------------------	/**	* Clean Input Data	* 过滤input数据	* This is a helper function. It escapes data and	* standardizes newline characters to \n	*	* @access	private	* @param	string	* @return	string	*/	function _clean_input_data($str)	{		if (is_array($str))		{			$new_array = array();			foreach ($str as $key => $val)			{				$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);			}			return $new_array;		}		/* We strip slashes if magic quotes is on to keep things consistent			如果小于PHP5.4版本,并且get_magic_quotes_gpc开启了,则去掉斜线。			   NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and		   it will probably not exist in future versions at all。		   注意:在PHP5.4及之后版本,get_magic_quotes_gpc()将总是返回0,		   在后续版本中可能会移除该特性		*/		if ( ! is_php('5.4') && get_magic_quotes_gpc())		{			$str = stripslashes($str);		}		// Clean UTF-8 if supported 如果支持清理utf8		if (UTF8_ENABLED === TRUE)		{			$str = $this->uni->clean_string($str);		}		// Remove control characters 		$str = remove_invisible_characters($str);		// Should we filter the input data?		if ($this->_enable_xss === TRUE)		{			$str = $this->security->xss_clean($str);		}		// Standardize newlines if needed		if ($this->_standardize_newlines == TRUE)		{			if (strpos($str, "\r") !== FALSE)			{				$str = str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);			}		}		return $str;	}	// --------------------------------	/**	* Clean Keys	* 过滤键值 	* This is a helper function. To prevent malicious users	* from trying to exploit keys we make sure that keys are	* only named with alpha-numeric text and a few other items.	*	* @access	private	* @param	string	* @return	string	*/	function _clean_input_keys($str)	{		if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str))		{			exit('Disallowed Key Characters.');		}		// Clean UTF-8 if supported		if (UTF8_ENABLED === TRUE)		{			$str = $this->uni->clean_string($str);		}		return $str;	}	// --------------------------------	/**	 * Request Headers	 * 返回请求头(header)数组。	 * In Apache, you can simply call apache_request_headers(), however for	 * people running other webservers the function is undefined.	 *	 * @param	bool XSS cleaning	 *	 * @return array	 */	public function request_headers($xss_clean = FALSE)	{		// Look at Apache go!		if (function_exists('apache_request_headers'))		{			$headers = apache_request_headers();		}		else		{			$headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');			foreach ($_SERVER as $key => $val)			{				if (strncmp($key, 'HTTP_', 5) === 0)				{					$headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);				}			}		}		// take SOME_HEADER and turn it into Some-Header		foreach ($headers as $key => $val)		{			$key = str_replace('_', ' ', strtolower($key));			$key = str_replace(' ', '-', ucwords($key));			$this->headers[$key] = $val;		}		return $this->headers;	}	// --------------------------------	/**	 * Get Request Header	 * 返回请求头(request header)数组中某一个元素的值	 * Returns the value of a single member of the headers class member	 *	 * @param 	string		array key for $this->headers	 * @param	boolean		XSS Clean or not	 * @return 	mixed		FALSE on failure, string on success	 */	public function get_request_header($index, $xss_clean = FALSE)	{		if (empty($this->headers))		{			$this->request_headers();		}		if ( ! isset($this->headers[$index]))		{			return FALSE;		}		if ($xss_clean === TRUE)		{			return $this->security->xss_clean($this->headers[$index]);		}		return $this->headers[$index];	}	// --------------------------------	/**	 * Is ajax Request? 	 * 判断是否为ajax请求	 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header	 *	 * @return 	boolean	 */	public function is_ajax_request()	{		return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest');	}	// --------------------------------	/**	 * Is cli Request?	 * 判断是否来自cli请求	 * Test to see if a request was made from the command line	 *	 * @return 	bool	 */	public function is_cli_request()	{		return (php_sapi_name() === 'cli' OR defined('STDIN'));	}}/* End of file Input.php *//* Location: ./system/core/Input.php */

  相关解决方案