首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

自製 PHP 框架系列(四):URL 路由管理系統設計與實現

     編輯:PHP 相關知識

自製 PHP 框架系列(四):URL 路由管理系統設計與實現

路由系統負責將 URL 映射至具體業務模塊、控制器與動作方法。本框架支援三種路由模式,滿足不同場景需求。

三種路由模式

模式URL 範例參數解析適用場景
普通模式?_a=web&_u=index.index_a=模塊, _u=控制器.動作後台管理、API、快速開發
Easy 模式?_easy=web.default.index.index模塊.模板.控制器.動作靜態展示頁、無需邏輯直接渲染模板
Rewrite 模式/rewrite/web/index/index.html
/rewrite/web/index/index/uid/1.html
偽靜態路徑,支援目錄式與參數編碼SEO、微信回調、支付通知、靜態資源偽裝

核心解析代碼

1. 普通模式

$a = (!empty($_REQUEST['_a']) && is_string($_REQUEST['_a'])) ? $_REQUEST['_a'] : 'web';
if (!preg_match('/^[\\w\\.]+$/', $a)) exit('invalid _app name! ' . htmlspecialchars($a));
$GLOBALS['_UCT']['APP'] = strtolower($a);

$u = (!empty($_REQUEST['_u']) && is_string($_REQUEST['_u'])) ? $_REQUEST['_u'] : 'index.index';
if (!preg_match('/^[\\w\\.]+$/', $u)) exit('invalid _url name! ' . htmlspecialchars($u));
$u = explode('.', $u, 2);
$GLOBALS['_UCT']['CTL'] = !empty($u[0]) ? strtolower($u[0]) : 'index';
$GLOBALS['_UCT']['ACT'] = !empty($u[1]) ? strtolower($u[1]) : 'index';

2. Easy 模式

if (!empty($_REQUEST['_easy']) && is_string($_REQUEST['_easy'])) {
    $easy = explode('.', $_REQUEST['_easy']);
    switch (count($easy)) {
        case 4: // app.tpl.ctl.act
            $_GET['_u'] = $_REQUEST['_u'] = $easy[2] . '.' . $easy[3];
            if (preg_match('/^[\\w\\.]+$/', $easy[1])) $GLOBALS['_UCT']['TPL'] = $easy[1];
            $_GET['_a'] = $_REQUEST['_a'] = $easy[0];
            break;
        case 3: // app.ctl.act
            $_GET['_u'] = $_REQUEST['_u'] = $easy[1] . '.' . $easy[2];
            $_GET['_a'] = $_REQUEST['_a'] = $easy[0];
            break;
        case 2: // app.ctl (act 默認 index)
            $_GET['_u'] = $_REQUEST['_u'] = $easy[1];
            $_GET['_a'] = $_REQUEST['_a'] = $easy[0];
            break;
        case 1: // 僅 app
            $_GET['_a'] = $_REQUEST['_a'] = $easy[0];
            break;
        default:
            exit('invalid _easy param! ' . htmlspecialchars($_REQUEST['_easy']));
    }
}

3. Rewrite 模式

需 Nginx/Apache 重寫規則:

# Apache
RewriteRule ^rewrite[./](.*)$ /index.php?_rewrite=$1 [R,QSA]
# Nginx
rewrite ^/rewrite[./](.*)$ /index.php?_rewrite=$1 last;

PHP 解析:

if (!empty($_REQUEST['_rewrite']) && is_string($_REQUEST['_rewrite'])) {
    // Apache 環境下 QUERY_STRING 可能丟失參數,手動從 SERVER 取回
    if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') === false) {
        $_REQUEST['_rewrite'] = urldecode(substr($_SERVER['QUERY_STRING'], strlen('_rewrite=')));
    }
    // 去除副檔名
    $rewrite = substr($_REQUEST['_rewrite'], 0, strrpos($_REQUEST['_rewrite'], '.'));

    // 自動檢測分隔符 . 或 /
    $sp = '.';
    for ($i = 0; $i < strlen($rewrite); $i++) {
        if (in_array($rewrite[$i], ['.', '/'])) { $sp = $rewrite[$i]; break; }
    }
    $rewrite = explode($sp, $rewrite, 4);

    switch (count($rewrite)) {
        case 3: case 4: // app.ctl.act[.params]
            $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0];
            $_GET['_u'] = $_REQUEST['_u'] = $rewrite[1] . '.' . $rewrite[2];
            if (!empty($rewrite[3])) {
                // 解析參數:支援 key/val/... 或 key=val&...
                if (strpos($rewrite[3], '/') !== false) {
                    $params = explode('/', $rewrite[3]);
                    for ($i = 0; $i + 1 < count($params); $i += 2) {
                        $_REQUEST[urldecode($params[$i])] = urldecode($params[$i+1]);
                    }
                } else {
                    foreach (explode('&', $rewrite[3]) as $p) {
                        list($k, $v) = explode('=', $p, 2);
                        $_REQUEST[urldecode($k)] = urldecode($v);
                    }
                }
            }
            break;
        case 2: // app.ctl
            $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0];
            $_GET['_u'] = $_REQUEST['_u'] = $rewrite[1];
            break;
        case 1: // 僅 app
            $_GET['_a'] = $_REQUEST['_a'] = $rewrite[0];
            break;
    }
}

Rewrite 模式實戰場景

  1. QQ OAuth 回調:rewrite.thirdlogin.index.qqcallback.sp_uid%3D1.php 避免 ? & 干擾驗證。
  2. 靜態資源偽裝:rewrite.upload.index.out.uidm%3D310ef4b.png 實際由 PHP 輸出圖片。
  3. 支付異步通知:rewrite.pay.weixin.native2_notify.php 隱藏真實路由。
  4. 微信開放平台事件:rewrite/web/component/message/_app_id/xxxxxxx.php 目錄式參數。

設計亮點

  • 統一入口 index.php,全局 _UCT 註冊表傳遞路由上下文。
  • 正則白名單驗證參數,防注入。
  • Easy 模式約定優於配置,自動渲染同名模板。
  • Rewrite 模式支援雙分隔符、URL 編碼參數、副檔名偽裝,極高兼容性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved