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

Nginx 完美支援 ThinkPHP:從 rewrite 到 fastcgi_split_path_info 進階配置

     編輯:PHP 相關知識

背景:Apache 遷移 Nginx 的 ThinkPHP 陷阱

將 ThinkPHP 專案從 Apache 遷移至 Nginx 時,最常見的問題是 PATH_INFO 模式下的路由失效。ThinkPHP 預設依賴 /index.php/模組/控制器/方法 這類帶路徑資訊的 URL,而 Nginx 預設不將 PATH_INFO 傳給 PHP-FPM,導致框架無法正確解析路由。

方案一:傳統 if + rewrite 寫法 (舊版常見)

server {
    listen 80;
    server_name example.com;
    root /path/to/web-root;

    location / {
        # 核心:若檔案不存在,轉發至 index.php 並保留 PATH_INFO
        if (!-e $request_filename) {
            rewrite ^/(.*)$ /index.php/$1 last;
            break;
        }
    }

    location ~ \.php($|/) {
        fastcgi_pass unix:/run/php/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;

        # 手動解析 PATH_INFO
        set $script $uri;
        set $path_info "/";
        if ($uri ~ "^(.+\.php)(/.*)") {
            set $script $1;
            set $path_info $2;
        }

        fastcgi_param PATH_INFO $path_info;
        fastcgi_param SCRIPT_FILENAME /path/to/web-root$script;
    }
}

缺點: 使用 if 在 location 區塊中被 Nginx 官方視為「邪惡」做法,易產生不可預期行為;邏輯分散、維護困難。

方案二:現代最佳實踐 —— try_files + fastcgi_split_path_info (推薦)

Nginx 0.7.31+ 內建 fastcgi_split_path_info 指令,專門依正則分離腳本名與 PATH_INFO,配合 try_files 取代 if,配置更乾淨、效能更好。

server {
    listen 80;
    server_name example.com;
    root /path/to/web-root;
    index index.php index.html;

    location / {
        # 取代 if (!-e ...) rewrite ...
        # 依序嘗試:原始 URI -> /index.php$uri (帶 PATH_INFO)
        try_files $uri $uri/ /index.php$uri;
    }

    location ~ \.php($|/) {
        fastcgi_pass unix:/run/php/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;

        # 核心:自動分離 $fastcgi_script_name 與 $fastcgi_path_info
        # 正則:^(.+\.php)(/.*)$  → 群組1=腳本  群組2=PATH_INFO
        fastcgi_split_path_info ^(.+\.php)(/.*)$;

        # 關鍵參數傳給 PHP-FPM
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        
        # ThinkPHP 可能需要的額外參數
        fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";
    }
}

關鍵指令深度解析

指令作用備註
try_files $uri $uri/ /index.php$uri;依序嘗試靜態檔、目錄、最後落入 index.php 並保留完整 URI 作為 PATH_INFO單行取代整段 if/rewrite
fastcgi_split_path_info ^(.+\.php)(/.*)$;依正則將 $uri 切分為 $fastcgi_script_name (群組1) 與 $fastcgi_path_info (群組2)需搭配 location ~ \.php($|/)
fastcgi_param PATH_INFO $fastcgi_path_info;將解析出的 PATH_INFO 傳給 PHP ($_SERVER['PATH_INFO'])ThinkPHP 路由核心依賴此變數
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;指定實際執行的 PHP 腳本絕對路徑避免寫死路徑,提升可移植性

ThinkPHP 專屬優化建議

  1. 關閉 cgi.fix_pathinfo:在 php.ini 設定 cgi.fix_pathinfo=0,避免安全風險並確保 PATH_INFO 解析一致性。
  2. 統一入口檔:若專案有多個入口 (如 admin.php),在 location 區塊增寫 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 即可自動適配。
  3. 快取靜態資源:在 server 區塊加入 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { expires 30d; access_log off; } 減輕 PHP-FPM 壓力。
  4. 啟用 Opcache:生產環境務必開啟 Zend Opcache,配合 Nginx + PHP-FPM 可大幅提升吞吐量。

常見問題排查清單

  • 404 Not Found:確認 root 指向專案 public 或入口檔所在目錄;檢查 SCRIPT_FILENAME 路徑是否正確。
  • 路由全部導向首頁:PATH_INFO 未正確傳遞 → 檢查 fastcgi_split_path_info 正則與 location 匹配順序。
  • 「No input file specified」:SCRIPT_FILENAME 路徑錯誤或權限不足 → 確認 $document_root 變數與實際路徑一致,PHP-FPM 執行使用者對目錄有讀取權限。

結語

放棄 if + rewrite 的舊時代包袱,擁抱 try_files 與 fastcgi_split_path_info,不僅配置檔行數減半,更能獲得 Nginx 原生級的效能與穩定度。下次遷移 ThinkPHP、Laravel、CodeIgniter 等需 PATH_INFO 的框架時,直接套用此範本即可輕鬆上線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved