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