周梦康 发表于 2014-05-14 17452 次浏览 标签 : OneThink

先说明下:我的代码环境是虚拟机linux环境,实际开发环境是window,D:\code是我设置的虚拟机共享文件夹

OneThink提供多种URL模式,配置位置在D:\code\onethink\Application\Common\Conf\config.php里面的URL_MODEL,这里是覆盖了ThinkPHP的默认配置(D:\code\onethink\ThinkPHP\Conf\convention.php)。

OneThink的URL相关学习笔记

通过在首页里加了这么一句做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的情况

兼容模式,默认的情况

评论列表