先说明下:我的代码环境是虚拟机linux环境,实际开发环境是window,D:\code
是我设置的虚拟机共享文件夹
OneThink提供多种URL模式,配置位置在D:\code\onethink\Application\Common\Conf\config.php
里面的URL_MODEL
,这里是覆盖了ThinkPHP的默认配置(D:\code\onethink\ThinkPHP\Conf\convention.php
)。
通过在首页里加了这么一句做U函数的输出测试
根据U函数(D:\code\onethink\ThinkPHP\Common\functions.php
)822行,对URL_MODEL
做了判断。
如果URL_MODEL
设置的是0,那么最后得到的地址就是参数对的形式,类似于/index.php?m=Home&c=Article&a=detail&id=1
如果URL_MODEL
设置的是1,那么最后得到的地址就是参数对的形式,类似于/index.php/Home/Article/detail/id/1.html
,这是分隔符URL_PATHINFO_DEPR
设置的为'/'的情况。
如果URL_MODEL
设置的是2,那么最后得到的地址就是参数对的形式,类似于/Home/Article/detail/id/1.html
,类似于上面的,只是隐藏了index.php
。
如果URL_MODEL
设置的是3,那么最后得到的地址就是参数对的形式,类似于/index.php?s=/Home/Article/detail/id/1.html
。
URL_MODEL为0的情况
此种情况下,就是传统的$_GET
获取各个参数的值。传统的GET传参方式来指定当前访问的模块和操作,其实本人最习惯于使用该方式,可能是之前受thinkSNS的路由的影响吧。Thinkphp的框架里没有对此种情况做伪静态和路由的相关配置。如果想走这种方式并且想使用伪静态的话,需要自己重写下U函数,和增加一些路由相关函数。而且需要服务器apache或者nginx增加相关的伪静态规则,所以方便不懂服务器的开发者也能快速配置,伪静态。所以ThinkPHP没有对该种模式下的伪静态和路由做开发。
下面是本人对U函数里的URL_MODEL为0的情况的改造,可以实现满足一般的路由需求!代码基本参考之前自己写的一篇博客(http://mengkang.net/17.html)然后和ThinkPHP3.2融合了下。
增加了1个路由规则文件(D:\code\onethink\Application\Common\Conf\route.php)示例代码如下:
/** * URL_MODEL为0的情况下,自定义路由规则文件 * @author ZhouMengkang < zhoumengkang@php.net > */ return array( //一级路由 'home/index/about'=>'about', //二级路由 'home/article/detail' =>array( 1=>'[id]', 2=>'[id]-[p]' ), //三级路由 'home/article/category'=>array( 'category'=>array( '1'=>array( 1=>'note', 2=>'note-[p]', ), '2'=>array( 1=>'news', 2=>'news-[p]', ), '3'=>array( 1=>'blog', 2=>'blog-[p]', ), ) ) );增加了一个配置项(D:\code\onethink\Application\Common\Conf\config.php)
'DIY_ROUTE' => true,
修改了ThinkPHP框架中函数文件(D:\code\onethink\ThinkPHP\Common\functions.php)里面的U函数,并在其中增加了三个函数
修改后的U函数
function U($url='',$vars='',$suffix=true,$domain=false) { // 解析URL $info = parse_url($url); $url = !empty($info['path'])?$info['path']:ACTION_NAME; if(isset($info['fragment'])) { // 解析锚点 $anchor = $info['fragment']; if(false !== strpos($anchor,'?')) { // 解析参数 list($anchor,$info['query']) = explode('?',$anchor,2); } if(false !== strpos($anchor,'@')) { // 解析域名 list($anchor,$host) = explode('@',$anchor, 2); } }elseif(false !== strpos($url,'@')) { // 解析域名 list($url,$host) = explode('@',$info['path'], 2); } // 解析子域名 if(isset($host)) { $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.')); }elseif($domain===true){ $domain = $_SERVER['HTTP_HOST']; if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署 $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); // '子域名'=>array('模块[/控制器]'); foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) { $rule = is_array($rule)?$rule[0]:$rule; if(false === strpos($key,'*') && 0=== strpos($url,$rule)) { $domain = $key.strstr($domain,'.'); // 生成对应子域名 $url = substr_replace($url,'',0,strlen($rule)); break; } } } } // 解析参数 if(is_string($vars)) { // aaa=1&bbb=2 转换成数组 parse_str($vars,$vars); }elseif(!is_array($vars)){ $vars = array(); } if(isset($info['query'])) { // 解析地址里面参数 合并到vars parse_str($info['query'],$params); $vars = array_merge($params,$vars); } // URL组装 $depr = C('URL_PATHINFO_DEPR'); $urlCase = C('URL_CASE_INSENSITIVE'); if($url) { if(0=== strpos($url,'/')) {// 定义路由 $route = true; $url = substr($url,1); if('/' != $depr) { $url = str_replace('/',$depr,$url); } }else{ if('/' != $depr) { // 安全替换 $url = str_replace('/',$depr,$url); } // 解析模块、控制器和操作 $url = trim($url,$depr); $path = explode($depr,$url); $var = array(); $varModule = C('VAR_MODULE'); $varController = C('VAR_CONTROLLER'); $varAction = C('VAR_ACTION'); $var[$varAction] = !empty($path)?array_pop($path):ACTION_NAME; $var[$varController] = !empty($path)?array_pop($path):CONTROLLER_NAME; if($maps = C('URL_ACTION_MAP')) { if(isset($maps[strtolower($var[$varController])])) { $maps = $maps[strtolower($var[$varController])]; if($action = array_search(strtolower($var[$varAction]),$maps)){ $var[$varAction] = $action; } } } if($maps = C('URL_CONTROLLER_MAP')) { if($controller = array_search(strtolower($var[$varController]),$maps)){ $var[$varController] = $controller; } } if($urlCase) { $var[$varController] = parse_name($var[$varController]); } $module = ''; if(!empty($path)) { $var[$varModule] = array_pop($path); }else{ if(C('MULTI_MODULE')) { if(MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')){ $var[$varModule]= MODULE_NAME; } } } if($maps = C('URL_MODULE_MAP')) { if($_module = array_search(strtolower($var[$varModule]),$maps)){ $var[$varModule] = $_module; } } if(isset($var[$varModule])){ $module = $var[$varModule]; unset($var[$varModule]); } } } if(C('URL_MODEL') == 0) { // 普通模式URL转换 /*$url = __APP__.'?'.C('VAR_MODULE')."={$module}&".http_build_query(array_reverse($var)); if($urlCase){ $url = strtolower($url); } if(!empty($vars)) { $vars = http_build_query($vars); $url .= '&'.$vars; }*/ //modified by ZhouMengkang if(C('DIY_ROUTE')){ //重新获取路由规则里面里面的键 if(!$module){$module = MODULE_NAME;} $key = $module.'/'.$var[$varController].'/'.$var[$varAction]; static $router_ruler = array(); if(empty($router_ruler)){ $router_ruler = include(CONF_PATH.'route.php'); } $url = '/'.route($router_ruler,$key,$vars,$suffix); }else{ $url = __APP__.'?'.C('VAR_MODULE')."={$module}&".http_build_query(array_reverse($var)); if($urlCase){ $url = strtolower($url); } if(!empty($vars)) { $vars = http_build_query($vars); $url .= '&'.$vars; } } }else{ // PATHINFO模式或者兼容URL模式 if(isset($route)) { $url = __APP__.'/'.rtrim($url,$depr); }else{ $module = defined('BIND_MODULE') ? '' : $module; $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var)); } if($urlCase){ $url = strtolower($url); } if(!empty($vars)) { // 添加参数 foreach ($vars as $var => $val){ if('' !== trim($val)) $url .= $depr . $var . $depr . urlencode($val); } } if($suffix) { $suffix = $suffix===true?C('URL_HTML_SUFFIX'):$suffix; if($pos = strpos($suffix, '|')){ $suffix = substr($suffix, 0, $pos); } if($suffix && '/' != substr($url,-1)){ $url .= '.'.ltrim($suffix,'.'); } } } if(isset($anchor)){ $url .= '#'.$anchor; } if($domain) { $url = (is_ssl()?'https://':'http://').$domain.$url; } return $url; }
增加的三个函数
/** * 路由匹配函数 * @author Zhoumengkang < zhoumengkang@php.net > * @param array $router_ruler 路由表 * @param string $url 路由键 * @param array $params 参数列表 * @return string $real_url URL地址 */ function route($router_ruler,$url,$params,$suffix){ //路由规则里全写成小写吧 $router_ruler = array_change_key_case($router_ruler); $router_key = strtolower(trim(trim($url),'/')); if(isset($router_ruler[$router_key])){ //一级路由 $real_url = $router_ruler[$router_key]; //由于规定参数格式必须是数组,所以这里只存在是数组和不是数组(为空)的情况 if(is_array($real_url)){ //看其是不是索引数组 if(array_product(array_map('is_numeric', array_keys($real_url)))==1){ //二级路由 if(is_array($params)){ $real_url = routeMatch($real_url[count($params)],$params); } }else{ //三级路由 foreach($params as $k =>$v){ if(array_key_exists($k,$real_url)){ $routeReg = $real_url[$k][$v][count($params)]; unset($params[$k]); $real_url = routeMatch($routeReg,$params); } } } } if($suffix) { $suffix = $suffix===true?C('URL_HTML_SUFFIX'):$suffix; if($pos = strpos($suffix, '|')){ $suffix = substr($suffix, 0, $pos); } if($suffix && '/' != substr($url,-1)){ $real_url .= '.'.ltrim($suffix,'.'); } } }else{ $real_url = urlBuild($url,$params); } return $real_url; } /** * 配合http_build_query实现正常的动态地址,类似于index.php?m=xxx&a=xxx&id=xxx&p=xxx * @author Zhoumengkang < zhoumengkang@php.net > * @param string $url 控制器和方法 * @param array $params 参数列表 * @return string $real_url 实际地址 */ function urlBuild($url,$params){ $url=explode('/',trim($url,'/')); $real_url = '?'.C('VAR_MODULE').'='.$url[0].'&'.C('VAR_CONTROLLER').'='.$url[1].'&'.C('VAR_ACTION').'='.$url[2]; if($params){ if(is_array($params)){ $params = http_build_query($params); $params = urldecode($params); } $real_url .= '&'.$params; } return $real_url; } /** * 路由匹配 * @author Zhoumengkang < zhoumengkang@php.net > * @param string $routeReg 路由规则字符串,类似于'tag'=>'tag_[tag].html' * @param string $params 需要替换正则字符串里面的关键字的实际参数值 * @return string $routeReg 返回最终匹配完的伪静态地址 */ function routeMatch($routeReg,$params){ foreach($params as $key =>$value){ if(strstr($routeReg,'['.$key.']')){ $routeReg = str_replace('['.$key.']',$value,$routeReg); } } return $routeReg; }
URL_MODEL为1的情况
生成的路径类似于/index.php/Article/detail/id/1.html
nginx服务器无法打开,比较适合于apache服务器,如果非要使得nginx支持pathinfo模式需要做些修改,可以网上搜下。
URL_MODEL为2的情况
生成的路径类似于/Home/Article/lists/category/default_blog.html
这是对pathinfo和pathinfo兼容模式的一种伪静态处理,需要在nginx稍微做下rewrite即可
location / { if (!-e $request_filename){ rewrite ^/(.*)$ /index.php?s=/$1 last; } }
这样就实现了http://onethink.us/Home/Article/detail/id/1.html
转发到http://onethink.us/index.php?s=/Home/Article/detail/id/1.html
的情况。
URL_MODEL为3的情况
兼容模式,默认的情况