codeigniter源代码分析之URI处理类 URI.php

对http请求的uri进行解析处理

Router中uri请求为get的时候是不会调用到这里

这里处理的是默认请求跟path_info形式的请求


代码注释如下

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CI_URI {

	var	$keyval			= array();
	var $uri_string;
	var $segments		= array();
	var $rsegments		= array();
	function __construct()
	{
		$this->config =& load_class('Config', 'core');
		log_message('debug', "URI Class Initialized");
	}
	function _fetch_uri_string()
	{
		if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')//自动识别
		{
			if (php_sapi_name() == 'cli' or defined('STDIN'))//命令行
			{
				$this->_set_uri_string($this->_parse_cli_args());
				return;
			}
			if ($uri = $this->_detect_uri())//detect_uri 获取
			{
				$this->_set_uri_string($uri);// 设置uri_string
				return;
			}
			// PATH_INFO
			$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
			if (trim($path, '/') != '' && $path != "/".SELF)
			{
				$this->_set_uri_string($path);
				return;
			}
			// QUERY_STRING
			$path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
			if (trim($path, '/') != '')
			{
				$this->_set_uri_string($path);
				return;
			}
			// url?arg1
			if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
			{
				$this->_set_uri_string(key($_GET));
				return;
			}
			// 设置为空
			$this->uri_string = '';
			return;
		}
		$uri = strtoupper($this->config->item('uri_protocol'));
		if ($uri == 'REQUEST_URI')
		{
			$this->_set_uri_string($this->_detect_uri());
			return;
		}
		elseif ($uri == 'CLI')
		{
			$this->_set_uri_string($this->_parse_cli_args());
			return;
		}

		$path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
		$this->_set_uri_string($path);
	}
	function _set_uri_string($str)
	{
		// 这里意味着 如果uri参数部分为空 或者为GET请求 不过一般情况GET请求是过不来的
		// Router先处理GET 成功就return了
		// it means 参数部分为空就会返回 空的 uri_string 这样在Router中会调用set_default_controller
		$str = remove_invisible_characters($str, FALSE);//过滤看不见的字符 不过滤URL
		$this->uri_string = ($str == '/') ? '' : $str; //if (uri_string == '/') uri_string = '';
	}
	private function _detect_uri()
	{
		if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
		{//REQUEST_URI SCRIPT_NAME 不存在很可能是命令行 ?
			return '';
		}

		// 获取URL的参数部分 赋值给 uri 变量
		$uri = $_SERVER['REQUEST_URI'];
		if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
		{
			$uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
		}
		elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
		{
			$uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
		}

		if (strncmp($uri, '?/', 2) === 0)
		{//如果uri是以 ?/ 开始的 说明这个请求可能是 Nginx 去除url中的'?/'
			$uri = substr($uri, 2);
		}
		$parts = preg_split('#\?#i', $uri, 2);//用?将uri切割成两部分
		$uri = $parts[0];
		// GET请求的 parts[0] 为空 参数列在 parts[1]
		// PATH_INFO 请求 parts[0] 就是参数列 /var1/var2...
		if (isset($parts[1]))
		{
			$_SERVER['QUERY_STRING'] = $parts[1];
			parse_str($_SERVER['QUERY_STRING'], $_GET);
		}
		else
		{
			$_SERVER['QUERY_STRING'] = '';
			$_GET = array();
		}
		if ($uri == '/' || empty($uri))
		{
			// GET请求 和默认请求都将执行这里
			return '/';
		}
		$uri = parse_url($uri, PHP_URL_PATH);
		return str_replace(array('//', '../'), '/', trim($uri, '/'));
	}
	// 解析CLI模式的参数
	private function _parse_cli_args()
	{
		$args = array_slice($_SERVER['argv'], 1);
		return $args ? '/' . implode('/', $args) : '';
	}
	function _filter_uri($str)
	{
		// permitted_uri_chars 可以指定uri中允许出现的字符
		if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
		{
			if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
			{
				show_error('The URI you submitted has disallowed characters.', 400);
			}
		}
		$bad	= array('$',		'(',		')',		'%28',		'%29');
		$good	= array('$',	'(',	')',	'(',	')');
		// 用good(对应字符的HTML形式的十进制编码)替换uri中出现的bad 字符
		return str_replace($bad, $good, $str);
	}
	function _remove_url_suffix()
	{
		// 去除uri后缀
		if  ($this->config->item('url_suffix') != "")
		{
			$this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
		}
	}
	function _explode_segments()
	{
		foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
		{//PATH_INFO模式生成segments
			$val = trim($this->_filter_uri($val));
			if ($val != '')
			{
				// 为URI的segments赋值
				$this->segments[] = $val;
			}
		}
	}
	// 将数组的0index unset 数组从1开始索引
	function _reindex_segments()
	{
		array_unshift($this->segments, NULL);
		array_unshift($this->rsegments, NULL);
		unset($this->segments[0]);
		unset($this->rsegments[0]);
	}
	// 返回指定的uri段
	function segment($n, $no_result = FALSE)
	{
		return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
	}
	function rsegment($n, $no_result = FALSE)
	{
		return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
	}

	function uri_to_assoc($n = 3, $default = array())
	{
		return $this->_uri_to_assoc($n, $default, 'segment');
	}
	function ruri_to_assoc($n = 3, $default = array())
	{
		return $this->_uri_to_assoc($n, $default, 'rsegment');
	}
	function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
	{
		if ($which == 'segment')
		{
			$total_segments = 'total_segments';
			$segment_array = 'segment_array';
		}
		else
		{
			$total_segments = 'total_rsegments';
			$segment_array = 'rsegment_array';
		}

		if ( ! is_numeric($n))
		{
			return $default;
		}

		if (isset($this->keyval[$n]))
		{
			return $this->keyval[$n];//keyval中存在就返回索取的值
		}

		if ($this->$total_segments() < $n)//总segments数小于请求的索引
		{
			if (count($default) == 0)
			{
				return array();
			}

			$retval = array();
			foreach ($default as $val)
			{
				$retval[$val] = FALSE;//用default array 设置
			}
			return $retval;
		}

		$segments = array_slice($this->$segment_array(), ($n - 1));//取出n后面的数据

		$i = 0;
		$lastval = '';
		$retval  = array();
		/*
			
		*/
		foreach ($segments as $seg)
		{
			if ($i % 2)
			{
				$retval[$lastval] = $seg;
			}
			else
			{
				$retval[$seg] = FALSE;
				$lastval = $seg;
			}

			$i++;
		}

		if (count($default) > 0)
		{
			foreach ($default as $val)
			{
				if ( ! array_key_exists($val, $retval))
				{
					$retval[$val] = FALSE;
				}
			}
		}

		// Cache the array for reuse
		$this->keyval[$n] = $retval;
		return $retval;
	}
	// 将segments数组拼接成 uri字符串
	function assoc_to_uri($array)
	{
		$temp = array();
		foreach ((array)$array as $key => $val)
		{
			$temp[] = $key;
			$temp[] = $val;
		}

		return implode('/', $temp);
	}
	function slash_segment($n, $where = 'trailing')
	{
		return $this->_slash_segment($n, $where, 'segment');
	}
	function slash_rsegment($n, $where = 'trailing')
	{
		return $this->_slash_segment($n, $where, 'rsegment');
	}
	function _slash_segment($n, $where = 'trailing', $which = 'segment')
	{
		$leading	= '/';
		$trailing	= '/';

		if ($where == 'trailing')
		{
			$leading	= '';
		}
		elseif ($where == 'leading')
		{
			$trailing	= '';
		}

		return $leading.$this->$which($n).$trailing;
	}
	function segment_array()
	{
		return $this->segments;
	}
	function rsegment_array()
	{
		return $this->rsegments;
	}
	function total_segments()
	{
		return count($this->segments);
	}
	function total_rsegments()
	{
		return count($this->rsegments);
	}

	function uri_string()
	{
		return $this->uri_string;
	}
	function ruri_string()
	{
		return '/'.implode('/', $this->rsegment_array());
	}

}

总结:

_fetch_uri_string 获取uri string

_detect_uri 通过REQUEST_URI处理 uri的参数部分

_explode_segments 切割uri中(path_info)参数部分

下面很多对segments的操作

Code Tips:

1、方法 _uri_to_assoc 还有点没弄懂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值