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

Apache 禁止直接訪問 PHP 文件:Rewrite 規則遞歸陷阱與最佳實踐方案

     編輯:PHP 相關知識

想通過 Apache Rewrite 直接禁止 .php 後綴訪問,卻發現內部重寫也會觸發規則導致 403 死循環。本文剖析遞歸機制,提供環境變量判斷、PHP 端攔截、文件系統權限三種可行方案。

問題重現:遞歸陷阱

# ❌ 錯誤配置
RewriteEngine On
RewriteRule ^test$ /test.php [L]           # 外部 /test → 內部 /test.php
RewriteRule ^test\.php$ - [F,L]            # 直接訪問 .php → 403

# 實際流程:
# 1. 請求 /test → 匹配規則1 → 內部重定向到 /test.php
# 2. 內部重定向再次觸發 Rewrite 引擎
# 3. 匹配規則2 → 返回 403 Forbidden
# 結果:/test 也無法訪問!

方案一:環境變量 REDIRECT_STATUS 判斷(純 Apache 配置)

RewriteEngine On
RewriteRule ^test$ /test.php [L]

# 只有非內部重定向的直接請求才有 REDIRECT_STATUS 為空
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule \.php$ - [F,L]

原理:內部重定向後,Apache 設置 REDIRECT_STATUS=200,直接請求該變量不存在/為空。

方案二:PHP 端攔截(通用、靈活、推薦)

在統一入口文件或自動預加載文件中:

<?php
// 只允許內部重定向/框架路由訪問,直接請求 .php 返回 404
if (php_sapi_name() !== 'cli') {
    $realPath = realpath($_SERVER['SCRIPT_FILENAME'] ?? '');
    $docRoot = realpath($_SERVER['DOCUMENT_ROOT'] ?? '');
    $requestUri = $_SERVER['REQUEST_URI'] ?? '';

    // 檢查是否直接請求 .php 文件(非重寫、非入口文件)
    $isDirectPhp = 
        str_ends_with($requestUri, '.php') &&
        !$realPath || strpos($realPath, $docRoot) !== 0; // 簡化判斷

    // 更可靠:檢查 REDIRECT_URL (Apache) 或 REDIRECT_STATUS
    if (empty($_SERVER['REDIRECT_URL']) && empty($_SERVER['REDIRECT_STATUS'])) {
        // 直接請求 .php
        http_response_code(404);
        exit('Not Found');
    }
}
?>

配合框架單一入口(index.php),所有業務 .php 文件放在 public/ 外部,Web 根目錄只暴露 index.php + 靜態資源,從源頭杜絕直接訪問。

方案三:文件系統權限隔離(最徹底)


/var/www/project/
├── public/              # Web DocumentRoot
│   ├── index.php        # 唯一入口
│   ├── .htaccess        # Rewrite 規則
│   └── assets/          # 靜態資源
├── src/                 # PHP 源碼(不可直接訪問)
│   ├── Controller/
│   ├── Model/
│   └── ...
├── vendor/
└── config/

Apache/Nginx DocumentRoot 指向 public/,PHP 文件物理隔離在外部,無需任何 Rewrite 規則 即可防止直接訪問。

方案對比與選型建議

方案優點缺點推薦場景
REDIRECT_STATUS 判斷純配置、無代碼侵入Apache 專用、調試困難、易漏配legacy 項目快速修復
PHP 端攔截跨 Web 服務器、邏輯可控、可自定義響應需修改代碼、入口文件需放行現代框架項目(Laravel/Symfony/ThinkPHP)
文件系統隔離物理級安全、零配置、最佳實踐需調整目錄結構、部署流程所有新項目強制標準

Nginx 對應配置(參考)

location ~ \.php$ {
    # 只有通過內部重寫到 @php 才執行
    internal;  # 關鍵:標記為內部 location,外部無法直接匹配
    fastcgi_pass php-fpm;
    include fastcgi_params;
}

location / {
    try_files $uri $uri/ /index.php$is_args$args;
}

location @php {
    # 內部重寫目標
    fastcgi_pass php-fpm;
    include fastcgi_params;
}

internal 指令完美解決 Nginx 下的同類問題。

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