mod_rewriteでRewriteCond %{REQUEST_FILENAME}

CakePHPやWordpressでお馴染のmod_rewrite。ルールの前にRewriteCondを書くことが多いでしょう。CakePHPやWordpressでファイルやディレクトリが実在する場合はルールを適用しないとする以下のような2行が書かれています。CakePHPやWordpressのファイル以外のファイルと共存させる場合などはこの2行が重要になってきます。

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

しかし、このRewriteCond %{REQUEST_FILENAME}が効かない、実際にファイルやディレクトリが実在するのにルールが適用されてしまう、CakePHPやWordpressで.htaccessをいじっているとそんな感じでハマることがあります。 実は見落としがちなのですが「RewriteCondはすぐ下のルールにしか適用されない」ということです。以下のCakePHPの.htaccessを例にするとRewriteRule ^$ app/webroot/ [L]に適用されても(.*) app/webroot/$1 [L]には条件が効かず、ファイルやディレクトリが実在しても(.*) app/webroot/$1 [L]を実行してしまいます。

RewriteEngine on 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^$ app/webroot/ [L] 
RewriteRule (.*) app/webroot/$1 [L]

冗長ですが以下のように書けば条件が適用され実在するファイルやディレクトリにアクセスできます。

RewriteEngine on 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^$ app/webroot/ [L] 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule (.*) app/webroot/$1 [L]