Webサイトを運営していると URLで指定されたファイルやディレクトリが無い場合に、特定のファイルを表示したい時があります。これをよく Apache httpd では mod_rewrite を使って、リライトされる条件(RewriteCond)に %{REQUEST_URI} -f や %{REQUEST_URI} -d を指定して実現するのですが、これがまったく条件にマッチしてくれません、、、そこで今回は、%{REQUEST_URI} -f や %{REQUEST_URI} -d がマッチしない時の対処法とその原因をまとめてみました。
対処法
お急ぎかもしれませんので先に対処法です。リライトされる条件(RewriteCond)に %{DOCUMENT_ROOT} を追加してください。
RewriteCond {REQUEST_URI} -d
↓
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
なぜ %{REQUEST_URI} だけではマッチしないのか?
なぜ %{REQUEST_URI} だけではマッチしないのか? その原因を簡単に説明いたします。
%{REQUEST_URI} だけの場合
例えば下のようなリライト設定をしていたとします。
RewriteCond %{REQUEST_URI} -f [OR](ファイルが存在する または)
RewriteCond %{REQUEST_URI} -d (ディレクトリが存在する)
RewriteRule ^(.*)$ - [L] (上記にマッチすればなにもしない)
RewriteRule ^(.*)$ /index.php [L] (マッチしなければ /index.php にリダイレクト)
そしてドキュメントルートは「/var/www/html/」で、その直下にリダイレクト先の「index.php」と「sample.html」が存在しています。
/var/www/html/sample.html
ブラウザで「sample.html」にアクセスすると、%{REQUEST_URI} -f(ファイルが存在する)の条件にマッチして、そのまま「sample.html」が表示されそうなのですが、残念ながらそうはなりません。Apache httpd のログを確認してみると「/sample.html」が、なぜか not-matched(マッチしない)になっています、、
%{DOCUMENT_ROOT}%{REQUEST_URI} の場合
では、リライトされる条件(RewriteCond)に %{DOCUMENT_ROOT} を追加してみましょう。
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^(.*)$ - [L]
RewriteRule ^(.*)$ /index.php [L]
ブラウザで「sample.html」にアクセスすると、意図した通りそのまま「sample.html」が表示され、Apache httpd のログは次のようになっています。
ここまでくればもうお分かりかと思いますが %{REQUEST_URI} だけでマッチしない原因は、mod_rewrite の -f(ファイルが存在する)や -d(ディレクトリが存在する) は、フルパスで判定しているからです。一方 RewriteRule で指定するリダイレクト先は(上の場合は「/index.php」)Apache httpd のドキュメントルートからのパスで指定します。
mod_rewrite のマニュアルにはしっかり例が示されていました。
For example:
RewriteCond /var/www/%{REQUEST_URI} !-f
RewriteRule ^(.+) /other/archive/$1 [R]
おわりに
Apache httpd は10年以上使っていますが、mod_rewrite はいまだ苦手です、、(^^;)
コメント