关于URL路由的一些事儿

阅读更多
虽然有人抱怨使用Apache的mod_rewrite在访问量大的时候经常会出现CPU的占用率为 100%的情况,但是对于一些中小型网站来说,这样做毕竟会美化URL,有益于搜索引擎的收录。

因此CMSPAD 1.1的最后一个特性就是支持URL路由(或URL Rewrite?),以下称URLR。那么,CMSPAD是如何支持URLR的呢?下面我们来分析一下URL路径的一些特性。

一个URL由协议、主机、端口、访问路径组成,前三者忽略,说说访问路径吧,它是一个由“/”分隔的一个字符串,用来定位文件位置。正常的一个网站的URL模式为:
http://www.yourcompany.com/index.php

其中“/index.php”就是其访问路径(或叫URI?不知道,自己查查吧)。而好多网站为了隐藏整站程序的实现技术,一般都隐藏了文件后缀,例如:
http://www.yourcompany.com/hello/world/2007/12/20

通过某些URLR技术来进行路径重写到指定脚本文件中。Servlet路径模式匹配和RoR都是这样干的。

因此,如何使用CMSPAD把路径给优化成很不错的感觉呢?其实很简单。

1. 建立一个Dispatcher文件,是PHP的。
dispatch(isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:''); //使用PATH_INFO作为参数进行URLR转换。
?>
当然,如果你不想使用PATH_INFO作为路径转换,可以使用其他的数据,例如GET参数。将文件保存在网站目录下,例如 /index.php。

2. 增加 .htaccess 文件:就是写Apache的URL Rewrite规则,这里就不提了。

3. 新建一个Portlet,如果不知道什么叫Portlet,那就看看偶本博客中以前的文章。
class DefaultPortal extends Portlet{
  public function pageDefaultPortal($params){
    return 'This is home page: '.$params[0];
  }
  public function pageHelloWorld($params){
    return 'This is hello world page: '.print_r($params);
  }
}
看到了没有,所有的URLR方法都是以“page”开头的,并且有个类型为单项数组的参数($params),并返回输出的内容,将代码保存到Portlet主目录下的DefaultPortal.php文件中。

4. 本节就三个字:搞定鸟。

在测试之前,大家需要了解一下CMSPAD URLR的一些路径处理规则:

1. default: 默认的路径处理方法,格式为 /[PortletName]/[PageName]/[Param1[/Param2[...]]]

2. statics: 伪静态页的路径处理方法,格式为:/[PortletName]/[PageName]/[Param1[,Param2[...]]].html

在这里如果没有PageName,那么CMSPAD将自动匹配到与PortletName同名的方法,例如使用默认模式的路径 /SimplePortlet/100/200/300 将被转换为 /SimplePortlet/SimplePortlet/100/200/300。

如果连PortletName也没有,没事儿,CMSPAD可以通过配置信息变量 $_CONFIG['DISPATCH']['PORTAL'] 来作为默认的Portlet使用;如果连 $_CONFIG['DISPATCH']['PORTAL'] 变量都没有定义,也没事儿,系统会自动使用 DefaultPortal 作为Portlet名字来使用;如果连 DefaultPortal 也没定义,那没办法了,系统会返回404错误。

下面就开始测试了:

把Apache服务器打开,假设以上程序在web根目录下,在浏览器中敲入下列地址 http://localhost/index.php/DefaultPortal/100000,你将会看到以下内容:
This is home page: 100000
,而敲入 http://localhost/index.php/DefaultPortal/helloWorld/100/200,则会看到:
This is hello world page: Array([0] => 100, [1] => 200)


而如果使用statics模式,则路径分别为:http://localhost/index.php/DefaultPortal/100000.html 和 http://localhost/index.php/DefaultPortal/helloWorld/100,200.html

这就有个问题了,如果可以任意转换URLR处理器,那么在模板中使用路径时怎么样动态转换路径呢?答案当然是有的啦,哈哈

在模板中,使用hyperlink函数即可实现,例如:




URL Router Portal Test



">Portal Link 1
">Portal Link 2
">Portal Link 3
">Portal Link 4
">Portal Link 5
这样,当在后台转换URLR路径处理了方法时,则模板中自动应用了新的路径。

使用默认URLR处理器时输出为:




URL Router Portal Test


Portal Link 1
Portal Link 2
Portal Link 3
Portal Link 4
Portal Link 5
而使用statics处理器时输出为:




URL Router Portal Test


Portal Link 1
Portal Link 2
Portal Link 3
Portal Link 4
Portal Link 5


下面来看看如何开发URLR路径处理器吧:

创建一个名字为 cmspad_router_<文件名字>的类,实现 URLRouter接口,并实现接口里的两个函数:
class cmspad_router_myrule implements URLRouter{
  public function route($pathinfo){
    // 处理并输出路径所对应的内容。
  }

  public function hyperlink($portlet = null, $method = null, $parameters = array()){
    // 生成并返回该规则的URL路径。
  }
}
将以上代码保存到 inc/urlrouters/myrule.php 文件中。然后在创建Dispatcher文件的代码中将
$dispatcher = new Dispatcher('default'); 
改成
$dispatcher = new Dispatcher('myrule'); 
这样,你写的规则就应用上去了。

下面给出当前默认实现(default)的源代码:
portal = $portal;
  }

  public function route($pathinfo){
    while(strpos($pathinfo,'//') !== false){
      $pathinfo = str_replace('//','/',$pathinfo);
    }
    $pathinfo = trim($pathinfo,' /');
    if(empty($pathinfo)){
      $pathinfo = $this->portal . '/' . $this->portal;
    }
    $arr = explode('/',$pathinfo);
    if(count($arr) > 0){
      $portlet = $arr[0];
      $portletObj = PortletUtil::newObject($portlet);
      if($portletObj === null || $portletObj === false){
        $portletObj = PortletUtil::newObject($portlet = $this->portal);
      }else{
        array_shift($arr);
      }
    }
    if($portletObj === null || $portletObj === false){
      return false;
    }
    if(count($arr) > 0){
      $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($arr[0]));
      if($portletArr === null || $portletArr === false){
        $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($portlet));
      }else{
        array_shift($arr);
      }
      $portletArg = $arr;
    }else{
      $portletArr = PortletUtil::newMethod($portletObj,'page' . ucfirst($portlet));
      $portletArg = array();
    }
    if($portletArr === null || $portletArr === false){
      return false;
    }
    
    $contents = call_user_func($portletArr,$portletArg);
    if($contents){
      echo $contents;
    }
    return true;
  }

  public function hyperlink($portlet = null,$method = null,$params = null){
    global $_CONFIG;
    if(isset($_CONFIG['DISPATCH']['SCRIPT'])){
      $url = $_CONFIG['DISPATCH']['SCRIPT'];
    }else{
      $url = $_SERVER['SCRIPT_NAME'];
    }
    if(!$portlet){
      $portlet = $this->portal;
    }
    if($portlet){
      $url .= ($portlet == $this->portal?'':'/' . $portlet);
      if($method){
        $url .= ($method == $portlet?'':'/' . $method);
      }
      if($params){
        $url .= '/' . implode('/',$params);
      }
    }
    return $url;
  }
}
?>
此代码保存在 inc/urlrouters/default.php 中。

你可能感兴趣的:(PHP,Apache,应用服务器,HTML,浏览器)