天天看點

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