檢查文件是否存在於子目錄中,否則將所有內容重定向到主控制器
我想在 Apache 下
mod_rewrite
的.htaccess
文件中執行以下操作:
如果收到對任何文件或路徑的請求,例如
foo.txt
orfoo/bar
,請檢查該文件是否存在於public
子目錄中,例如public/foo.txt
orpublic/foo/bar
。如果是這樣,只需顯示該文件。除此以外
- 將所有內容重定向到主控制器
index.php
我對解決方案的嘗試是這樣的:
<IfModule mod_rewrite.c> RewriteEngine On # Don't rewrite requests for files in the 'public' directory RewriteRule ^(public)($|/) - [L] # For all other files first check if they exist in 'public' RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f RewriteRule ^ public%{REQUEST_URI} [L] # Let 'index.php' handle everything else RewriteRule . index.php [L] </IfModule>
不幸的是,有一個重大缺陷:它在子目錄中不起作用,即當
.htaccess
和所有其他文件從 移動/
到 時/sub/
。理想情況下,它當然可以在任意子文件夾中工作。有人可以幫忙嗎?如何修復
.htaccess
以消除該缺陷?
我有一個類似的問題,我想分發一個行為如您所描述的網路應用程序:特定目錄中有一堆靜態文件,可以像在網路應用程序根目錄上一樣訪問它們(即嘗試
/images/pic.png
獲取圖像inpublic/images/pic.png
) ,其他所有內容都映射到控制器腳本。我遇到的第一個問題是
-f
inRewriteCond
不適用於相對路徑 - 即如果“TestPattern”字元串可以解析為相對於指定條件的目錄的文件(使用.htaccess
),-f
仍將返回“不匹配” (1)。因此,我們需要嘗試“理解”
.htaccess
文件所在的每個目錄前綴是什麼,並mod_rewrite
實際上為我們解決了這個問題,並確保RewriteRule
始終相對於每個目錄前綴.htaccess
文件進行評估 - 但不幸的是它沒有不要以任何可以訪問的方式公開該資訊RewriteCond
(他們真的應該讓我們擁有它)。話雖這麼說,顯然你可以做一些奇怪的事情來強制“CondPattern”梳理出與輸入
RewriteCond
之間的關係- 閱讀這個問題的答案,了解你可以實現的所有奇怪的事情。%{REQUEST_URI}``RewriteRule
但是將這些技巧縮短到手頭的問題(
-f
匹配到相對於 .htaccess 的正確路徑,無論它可能在哪裡),我們得到了這個相當簡單的東西:RewriteEngine On RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2 RewriteCond %{DOCUMENT_ROOT}%1static/%2 -f RewriteRule ^(.*)$ static/$1 [END] RewriteRule . index.php [END,QSA]
解釋:
中的正則表達式
RewriteCond
非常有限,因為它不能解析變數和擷取的文本,但它可以使用\<number>
語法使用對自身的反向引用。所以我們首先創建一個由以下組成的字元串:
- 原始請求 URI
- 我們不希望出現在 URL(
::
部分)中的硬編碼分隔符。- 將匹配的 URI 的本地(每個目錄)部分
RewriteRule
- 這是$1
部分:RewriteCond
可以查看目標RewriteRule
(2)的擷取組,因此我們擷取整個輸入。然後我們應用一個正則表達式來解釋該請求 URI 和
RewriteRule
輸入之間的關係 - 請求 URI 由兩部分組成(第一個和第二個擷取),其中第一個以 a 結尾,/
第二個與出現在::
delimiter -\2
只是在同一個正則表達式中引用第二個擷取,並說它必須是相同的。結果是我們將請求 URI 分解為兩個擷取組——第一個是
mod_rewrite
私有的本地每個目錄前綴,第二個是我們要檢查的目錄下的本地路徑。第二個條件用於引用這些在文件根(3)%<number>
下建構絕對路徑的擷取。請注意,它擷取前綴 URI 的前導和尾隨斜杠。%1
最後,請注意我使用的是
END
標誌而不是L
(last),因為它更快並且mod_rewrite
立即存在。這允許我刪除與RewriteRule … - [L]
which 存在的行,只是為了停止L
實際上並沒有停止處理的行為:它只是回到開頭或使用新 URL 重寫規則。END
簡單得多。腳註:
- 實際上,相對路徑解析在某些條件下確實有效,如該問題的錯誤報告中所述。只是它沒有按預期工作,並且在大多數常見配置中根本無法工作。
- 這種看起來怪異的向後行為實際上非常簡單:Apache 總是首先解析 ,
RewriteRule
然後才檢查條件是否允許應用它。- 順便說一句,如果您使用
Alias
或類似的方法將伺服器 URI 空間的一部分映射到不在文件根目錄下的其他位置,這將不起作用。請參閱文件CONTEXT_DOCUMENT_ROOT
以了解如何解決此問題。