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

修正 ThinkPHP U() 函式支援路由模式下的分頁連結生成

     編輯:PHP 綜合知識

問題根因

ThinkPHP 3.1/3.2 啟用 URL_ROUTER_ON 後,Page 類產生的分頁連結為原始 module/action/param/value 格式,而非路由規則定義的優美 URL (如 /article/list/cate/3/page/2),導致分頁點擊後無法匹配路由、參數遺失或 404。

解決方案:重寫 U() 函式處理路由規則反向解析

修改 ThinkPHP/Common/functions.php 中的 U() 函式 (約第 287 行 if(!empty($vars)) 之後) 插入以下程式碼:

/***** 路由模式下分頁連結修正開始 *****/
if (C('URL_ROUTER_ON')) {
    $routeRules = C('URL_ROUTE_RULES');
    if (!empty($routeRules)) {
        // 組裝當前群組前綴 (若有)
        $groupPrefix = defined('GROUP_NAME') ? GROUP_NAME . '/' : '';
        $currentUrl = $groupPrefix . $url; // 如 Admin/Article/index/cate/3
        
        foreach ($routeRules as $pattern => $rule) {
            // $pattern: 路由規則 (如 'article/:cate/:page')
            // $rule:    目標模組/動作 (如 'Article/index')
            
            // 將規則轉為正則 (支援 :var 參數)
            $regex = '@^' . str_replace('/', '\/', $pattern) . '$@';
            $regex = preg_replace('@:([\w]+)@', '([^/]+)', $regex); // :cate → ([^/]+)
            
            if (preg_match($regex, $currentUrl, $matches)) {
                // 符合路由規則,重建 URL
                $newUrl = $rule;
                // 替換規則中的參數
                $paramNames = [];
                preg_match_all('@:([\w]+)@', $pattern, $paramNames);
                
                foreach ($paramNames[1] as $i => $name) {
                    $newUrl = str_replace(':' . $name, $matches[$i + 1], $newUrl);
                }
                
                // 處理分頁參數 __PAGE__ (Page 類會插入)
                if (strpos($newUrl, '__PAGE__') !== false) {
                    // 保留 __PAGE__ 讓 Page 類後續替換
                } else {
                    // 附加剩餘參數
                    $usedParams = array_slice($matches, 1);
                    $allParams = [];
                    // 從原 URL 解析所有參數
                    preg_match_all('@/(\w+)/([^/]+)@', $url, $urlParams);
                    foreach ($urlParams[1] as $i => $key) {
                        if (!in_array($key, $paramNames[1])) {
                            $allParams[$key] = $urlParams[2][$i];
                        }
                    }
                    if ($allParams) {
                        $newUrl .= '/' . implode('/', array_map(function($k, $v) {
                            return $k . '/' . $v;
                        }, array_keys($allParams), array_values($allParams)));
                    }
                }
                
                $url = $newUrl;
                break; // 只匹配第一條符合規則
            }
        }
    }
}
/***** 路由模式下分頁連結修正結束 *****/

路由規則配置範例 (config.php)

'URL_ROUTER_ON'   => true,
'URL_ROUTE_RULES' => [
    // 文章列表分頁
    'article/:cate/:page'   => 'Article/index',      // /article/3/2 → Article/index/cate/3/page/2
    'article/:cate'         => 'Article/index',      // /article/3 → Article/index/cate/3
    
    // 文章詳情
    'article/view/:id'      => 'Article/view',       // /article/view/123
    
    // 後台管理
    'admin/user/:status/:page' => 'Admin/User/index',
    
    // 靜態頁面
    'page/:name'            => 'Page/view',
],

Page 類配合調整

// 控制器
$page = new Page($count, 20);
$page->parameter = 'cate/3'; // 傳遞路由所需參數 (非 query string)
// 或
foreach ($_GET as $k => $v) {
    if ($k !== 'p') $page->parameter .= "$k/$v/";
}
// Page 類產生連結:/article/3/__PAGE__ → U() 解析 → /article/3/2

完整流程示意

sequenceDiagram
    participant Controller
    participant Page類
    participant U函式
    participant 路由規則
    
    Controller->>Page類: new Page($count, 20)
    Controller->>Page類: parameter = 'cate/3'
    Page類->>Page類: 產生連結 '/article/3/__PAGE__'
    Page類->>U函式: U('Article/index', 'cate/3/page/__PAGE__')
    U函式->>路由規則: 遍歷匹配 'article/:cate/:page'
    路由規則-->>U函式: 匹配成功,重建 '/article/3/2'
    U函式-->>Page類: 返回修正後 URL
    Page類-->>View: 輸出正確分頁連結

注意事項與限制

  1. 路由規則順序:陣列順序決定優先級,詳細規則 (含參數) 應置於通用規則之前。
  2. 分頁參數名:Page 類預設 p,路由規則需對應 :page 或 :p。
  3. 多群組/模組:GROUP_NAME 常數需正確定義,否則前綴錯誤導致匹配失敗。
  4. 效能考量:每個分頁連結皆遍歷路由規則,規則過多 ( > 50 ) 可能影響效能。優化:編譯期快取路由正則、或僅在分頁頁面載入修正。
  5. ThinkPHP 5/6/8:內建路由系統完整支援反向生成 Url::build(),無需此 Hack。

替代方案:分頁類擴充

// 建立自訂分頁類 Extend/Org/Util/PageRouter.class.php
class PageRouter extends Page {
    public function show() {
        $originalUrl = $this->url; // 父類生成的原始 URL
        // 呼叫 U() 修正 (需確保 U() 可用)
        $this->url = U($originalUrl); 
        return parent::show();
    }
}

// 使用
import('ORG.Util.PageRouter');
$page = new PageRouter($count, 20);
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved