URI类主要处理地址字符串,将uri分解成对应的片段,存到segments数组中。querystring分解后存到$_GET数组,ROUTER路由类在之后的解析路由动作中,也主要依靠URI类的segments属性数组来获取当前上下文的请求URI信息。
$config['uri_protocol']配置不但决定以哪个函数处理URI,同时决定了从哪个全局变量里获取当前上下文的uri地址。对应关系是:
'REQUEST_URI' 使用 $_SERVER['REQUEST_URI']
'QUERY_STRING' 使用 $_SERVER['QUERY_STRING']
'PATH_INFO' 使用 $_SERVER['PATH_INFO']
那么这三个变量有什么区别呢?
$_SERVER['REQUEST_URI']获取的是url地址中主机头后面所有的字符
$_SERVER['QUERY_STRING']获取的url地址中"?"后面的部分
$_SERVER['PATH_INFO']获取的是url地址中脚本文 ($_SERVER['SCRIPT_NAME'])之后"?"之前的字符内容
1、构造函数_construct
功能流程:解析命令行或者请求url,获取querystring存入$_GET,uri存在segment数组
_parse_request_uri方法处理 AUTO,REQUEST_URI,PATH_INFO
_parse_query_string方法只处理QUERY_STRING
2、_parse_request_uri()方法
protected function _parse_request_uri()
{
if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
return '';
}
//从$_SERVER['REQUEST_URI']取值,解析成$uri和$query两个字符串,分别存储请求的路径和get请求参数
$uri = parse_url('http://dummy'.$_SERVER['REQUEST_URI']);
$query = isset($uri['query']) ? $uri['query'] : '';
$uri = isset($uri['path']) ? $uri['path'] : '';
if (isset($_SERVER['SCRIPT_NAME'][0]))
{
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
{
$uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
{
$uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
}
//对于请求服务器的具体URI包含在查询字符串这种情况。
//例如$uri以?/开头的 ,实际上if条件换种写法就是if(strncmp($uri, '?/', 2) === 0)),类似:
//http://www.citest.com/index.php?/welcome/index
if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
{
$query = explode('?', $query, 2);
$uri = $query[0];
$_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : '';
}
else
{
$_SERVER['QUERY_STRING'] = $query;
}
// 将查询字符串按照键名存入$_GET数组
parse_str($_SERVER['QUERY_STRING'], $_GET);
if ($uri === '/' OR $uri === '')
{
return '/';
}
//调用 _remove_relative_directory($uri)函数作安全处理
//移除$uri中的../相对路径字符和反斜杠
return $this->_remove_relative_directory($uri);
}
3、_parse_query_string()方法
protected function _parse_query_string()
{
$uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
if (trim($uri, '/') === '')
{
return '';
}
elseif (strncmp($uri, '/', 1) === 0)
{
$uri = explode('?', $uri, 2);
$_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : '';
$uri = $uri[0];
}
parse_str($_SERVER['QUERY_STRING'], $_GET);
return $this->_remove_relative_directory($uri);
}
4、_set_uri_string($str) 解析$url填充到$this->segment数组中
// 解析$url填充到$this->segments数组中
protected function _set_uri_string($str)
{
// 移除$str不可见字符
$this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');
if ($this->uri_string !== '')
{
// Remove the URL suffix, if present
if (($suffix = (string) $this->config->item('url_suffix')) !== '')
{
$slen = strlen($suffix);
if (substr($this->uri_string, -$slen) === $suffix)
{
$this->uri_string = substr($this->uri_string, 0, -$slen);
}
}
$this->segments[0] = NULL;
// Populate the segments array
foreach (explode('/', trim($this->uri_string, '/')) as $val)
{
$val = trim($val);
// Filter segments for security
$this->filter_uri($val);
if ($val !== '')
{
$this->segments[] = $val;
}
}
unset($this->segments[0]);
}
}