天天看点

php url 调度

1, 支持非rewrite即:

http://localhost/index.php/blog/view/5456-asdf.html

也可以被正确解析。。

-----------------------------------

2,增加:绝对地址生成 只要 

rurl('myFirstRouter', array('id' => '33', 'name' => 'thename'), true);

最后多加一个true,默认为false即相对地址。

生成绝对地址如:网站根目录/fleaphp/test/blog/view/33-thename.html

修改自ZendFramework的Router_Regexp类。

花了点时间整理的,水平有限,希望有高人能完善一下。

定义一个路由跟定义DSN一样的方法:

return array(

'routers' =>array(

  'myFirstRouter' => array(

   'blog/view(?:/(\d+)-(.+))\.html',

   array(

    'id'   => '1',

    'controller'  => 'default',

    'action'  => 'index'

   ),

    1 => 'id',

    2 => 'name'

   'blog/view/%d-%s.html'

  ),

  'mySecondRouter' => array(

   'blog(?:/(\d+)-(.+))\.html',

   'blog/%d-%s.html'

  'myThirdRouter' => array(

   '([a-z0-9]+)/([a-z0-9]+)',

   array(),

    1 => 'controller',

    2 => 'action'

  )  

)

);

复制代码

是一个二维数组,每一个值为一条路由规则。

其中第一项是正则表达式,第二项为:参数默认值(这里可以设置controller,action,及其它参数的默认值。)

第三项为:参数的对应关系,与第一项的正则表达里面匹配元素对应。

第四项用于生成链接时候使用的格式。如果没看明白,可以看ZF的Router一节。

先发改的My_Dispatcher_Regexp类的代码:

<?php

/**

* Zend Framework

*

* LICENSE

* This source file is subject to the new BSD license that is bundled

* with this package in the file LICENSE.txt.

* It is also available through the world-wide-web at this URL:

* http://framework.zend.com/license/new-bsd

* If you did not receive a copy of the license and are unable to

* obtain it through the world-wide-web, please send an email

* to [email protected] so we can send you a copy immediately.

* @package    Zend_Controller

* @subpackage Router

* @copyright  Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)

* @version    $Id$

* @license    http://framework.zend.com/license/new-bsd     New BSD License

*/

// {{{ includes

FLEA::loadClass('FLEA_Dispatcher_Simple');

// }}}

* My_Dispatcher_Regexp

* @package My_Dispatcher

* @author tg8866

* @version 0.01

class My_Dispatcher_Regexp extends FLEA_Dispatcher_Simple

{

    /**

     * 保存路由信息的数组(二级数组)

     *

     * @var array

     */

    var $_routers;

     * 当前浏览页面的路由信息

     * @var array (一维数组)

    var $_curRouter;

     * 保存baseurl信息

     * @var string

    var $_baseUrl;

     * 保存requestURI信息

    var $_requestUri;

     * 可用的路径信息 不包括 子目录信息 

     * 比如:http://localhost/index.php 是主页

     * 则 http://localhost/blog/view/123-abc.html

     * 的路径信息为: /blog/view/123-abc.html

     * @var unknown_type

    var $_pathInfo;

     * 构造函数

     * @param array $request

     * @return My_Dispatcher_Regexp

    function My_Dispatcher_Regexp(& $request)

    {

        parent::FLEA_Dispatcher_Simple($request);

        $this->loadRouters();

        if (! is_array($this->_routers)) return false;

        if (!$this->_pathInfo) $this->getPathInfo();

        foreach (array_reverse($this->_routers) as $router) {

         if (! is_array($router)) continue;

         if ($router[0] == '' || !is_string($router[0])) continue;

         $regexp = '#^' . $router[0]. '$#i';

   if (! isset($router[1])) $router[1] = array();

         if (! isset($router[2])) $router[2] = array();

         if ($args = $this->match($regexp, $this->_pathInfo, $router[1], $router[2])) {

          $this->_curRouter = $router;

          $data['controller'] = $args['controller'];

          $data['action'] = $args['action'];

          $_GET = array_merge($_GET, $args);

          break;

         }

        }

        $this->_request = $data;

    }

     * 载入路由数据信息

    function loadRouters() {

     static $routerLoaded;

     if ($routerLoaded) return;

     $routerLoaded = false;

     $routerConfig = FLEA::getAppInf('routerConfig');

        FLEA::loadAppInf($routerConfig);

        $this->_routers = FLEA::getAppInf('routers');

        $routerLoaded = true;

     * 根据服务器环境不同,取得RequestUri信息

     * @return unknown

    function getRequestUri() {

     if ($this->_requestUri) return $this->_requestUri;

        if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch

            $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];

        } elseif (isset($_SERVER['REQUEST_URI'])) {

            $requestUri = $_SERVER['REQUEST_URI'];

        } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI

            $requestUri = $_SERVER['ORIG_PATH_INFO'];

            if (!empty($_SERVER['QUERY_STRING'])) {

                $requestUri .= '?' . $_SERVER['QUERY_STRING'];

            }

        } else {

         $requestUri = null;

        $this->_requestUri = $requestUri;

        return $requestUri;

    function getBaseUrl() {

     if ($this->_baseUrl) return $this->_baseUrl;

        $filename = basename($_SERVER['SCRIPT_FILENAME']);

        if (basename($_SERVER['SCRIPT_NAME']) === $filename) {

            $baseUrl = $_SERVER['SCRIPT_NAME'];

        } elseif (basename($_SERVER['PHP_SELF']) === $filename) {

            $baseUrl = $_SERVER['PHP_SELF'];

        } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) {

            $baseUrl = $_SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility

            // Backtrack up the script_filename to find the portion matching

            // php_self

            $path    = $_SERVER['PHP_SELF'];

            $segs    = explode('/', trim($_SERVER['SCRIPT_FILENAME'], '/'));

            $segs    = array_reverse($segs);

            $index   = 0;

            $last    = count($segs);

            $baseUrl = '';

            do {

                $seg     = $segs[$index];

                $baseUrl = '/' . $seg . $baseUrl;

                ++$index;

            } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));

        // Does the baseUrl have anything in common with the request_uri?

        $requestUri = $this->getRequestUri();

        if (0 === strpos($requestUri, $baseUrl)) {

            // full $baseUrl matches

            $this->_baseUrl = $baseUrl;

            return $this->_baseUrl;

        if (0 === strpos($requestUri, dirname($baseUrl))) {

            // directory portion of $baseUrl matches

            $baseUrl = rtrim(dirname($baseUrl), '/');

        if (!strpos($requestUri, basename($baseUrl))) {

            // no match whatsoever; set it blank

            $this->_baseUrl = '';

        // If using mod_rewrite or ISAPI_Rewrite strip the script filename

        // out of baseUrl. $pos !== 0 makes sure it is not matching a value

        // from PATH_INFO or QUERY_STRING

        if ((strlen($requestUri) >= strlen($baseUrl))

            && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))

        {

            $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));

       $baseUrl = rtrim($baseUrl, '/'); 

       $this->_baseUrl = $baseUrl; 

       return $this->_baseUrl;    

    function getPathInfo () {

        $baseUrl = $this->getBaseUrl();

        if (null === ($requestUri = $this->getRequestUri())) {

            return null;

        // Remove the query string from REQUEST_URI

        if ($pos = strpos($requestUri, '?')) {

            $requestUri = substr($requestUri, 0, $pos);

        if ((null !== $baseUrl)

            && (false === ($pathInfo = substr($requestUri, strlen($baseUrl)))))

            // If substr() returns false then PATH_INFO is set to an empty string

            $pathInfo = '';

        } elseif (null === $baseUrl) {

            $pathInfo = $requestUri;

        $this->_pathInfo = $pathInfo;

        return $pathInfo;

     * Matches a user submitted path with a previously defined route.

     * Assigns and returns an array of defaults on a successful match.

     * @param string Path used to match against this routing map

     * @return array|false An array of assigned values or a false on a mismatch

    function match($regex, $path, $defaults, $map)

        $path = trim(urldecode($path), '/');

        $res = preg_match($regex, $path, $values);

        if ($res === 0) return false;

        foreach ($values as $i => $value) {

            if (!is_int($i) || $i === 0) {

                unset($values[$i]);

        $values = $this->_getMappedValues($map, $values);

        $defaults = $this->_getMappedValues($map, $defaults, false, true);

        $return = $values + $defaults;

        return $return;

     * Maps numerically indexed array values to it's associative mapped counterpart.

     * Or vice versa. Uses user provided map array which consists of index => name

     * parameter mapping. If map is not found, it returns original array.

     * Method strips destination type of keys form source array. Ie. if source array is

     * indexed numerically then every associative key will be stripped. Vice versa if reversed

     * is set to true.

     * @param array Indexed or associative array of values to map

     * @param boolean False means translation of index to association. True means reverse.

     * @param boolean Should wrong type of keys be preserved or stripped.

     * @return array An array of mapped values

    function _getMappedValues($map, $values, $reversed = false, $preserve = false)

        if (count($map) == 0) {

            return $values;

        $return = array();

        foreach ($values as $key => $value) {

            if (is_int($key) && !$reversed) {

                if (array_key_exists($key, $map)) {

                    $index = $map[$key];

                } elseif (false === ($index = array_search($key, $map))) {

                    $index = $key;

                }

                $return[$index] = $values[$key];

            } elseif ($reversed) {

                $index = (!is_int($key)) ? array_search($key, $map, true) : $key;

                if (false !== $index) {

                    $return[$index] = $values[$key];

            } elseif ($preserve) {

                $return[$key] = $value;

     * Assembles a URL path defined by this route

     * @param array An array of name (or index) and value pairs used as parameters

     * @return string Route path with user submitted parameters

    function assemble($defaults, $map = array(), $reverse, $data = array())

        if ($reverse === null) {

            return '构建网址失败!路由参数错误!';   

        }     

        $data = $this->_getMappedValues($map, $data, true, false);

        $data += $this->_getMappedValues($map, $defaults, true, false);

        //$data += $this->_values;

        ksort($data);

        $return = @vsprintf($reverse, $data);

        if ($return === false) {

            return '构建网址失败!';  

     * 使用路由构建网址

    function url($routerName, $urlOptions, $absolute) {

     $this->loadRouters();

     if (isset($this->_routers[$routerName])) $curRouter = $this->_routers[$routerName];

     elseif (isset($this->_curRouter)) $curRouter = $this->_curRouter;

  if (is_array($curRouter) && count($curRouter) == 4 && is_string($curRouter[3])) {

   $defaults = $curRouter[1];

   $map = $curRouter[2];

   $reverse = $curRouter[3];

  } else {

   return '构建网址失败!路由参数错误!';

  }

     if (is_array($map) && is_string($reverse))

      if (!$absolute) return $this->assemble($defaults, $map, $reverse, $urlOptions);

      else {

       if (!$this->_baseUrl) $this->getBaseUrl();

       return $this->_baseUrl . '/' .$this->assemble($defaults, $map, $reverse, $urlOptions);

      }

}

这里要说一个比较好的自定义类的命名规则及文件放置位置。

在FLEA下面建一个My的目录里面放自已的类。比如My_Dispatcher_Regexp放在:

My/Dispatcher/Regexp.php

同时为方便写一个生成网址助手:

My_Helper_Router

My/Helper/Router.php

代码如下:

* 路由网址助手

function rurl($routerName, $urlOptions, $absolute = false) {

$routerHelper =& FLEA::getSingleton('My_Dispatcher_Regexp');

echo $routerHelper->url($routerName, $urlOptions, $absolute);

使用方法:

/* 修改默认的Dispatcher为自定义的Dispatcher类*/

FLEA::setAppInf('dispatcher','My_Dispatcher_Regexp');

/* 设置路由配置信息的文件位置*/

FLEA::setAppInf('routerConfig', './APP/config/router.php');

其它代码跟任何一个普通的例子一样。

controller里面代码如下:

class Controller_Default extends FLEA_Controller_Action

function actionIndex()

FLEA::loadFile('My_Helper_Router');

include('APP/View/PostIndex.php');

我们在view中用下面代码:

dump($_GET);

rurl('myFirstRouter', array('id' => '33', 'name' => 'thename'));

就可以看到$_GET得到正确的参数,

rurl也生成我们期望的网址:

blog/view/33-thename.html

绝对网址生成方法如下:

rurl('myFirstRouter', array('id' => '33', 'name' => 'thename'),true);

//将生成如下的网址:

/other/fleaphp/test/blog/view/33-thename.html

如果没有使用apache的mod_rewrite功能生成的网址如下:

/fleaphp/test/index.php/blog/view/33-thename.html