2012-04-15

Apache: RewriteBaseは書き換え後のパスのベース

mod_rewriteでURLの書き換えルールを書く機会は頻繁にあるわけではないので、いざルールを書くとなるといろいろ忘れていて結構時間を取られます…。今日はmod_rewriteのRewriteBaseとその周辺についてまとめておきたいと思います。

例えば

  1. サーバのドキュメントルートが /var/www/vhosts/example.local/
  2. サーバのURLが http://example.local/
  3. http://example.local/abc/def.html に来たアクセスを http://example.local/abc/ghi.html に書き換えたい
  4. そのためドキュメントルートの.htaccess(/var/www/vhosts/example.local/.htaccess)に書き換えルールを書く

とき、RewriteBase /abcとか/abc/にしてやれば下記のように書けるかな…と考えて

RewriteEngine On
RewriteBase /abc
RewriteRule ^def\.html$ ghi.html [L]

と書いても書き換えはできません。RewriteBaseは書き換え後のパス指定(例だとghi.html)が相対パスだった時にそこに使われる(例だと/abc/ghi.html)だけで、マッチパターン(例だと^def\.html$)には全く関係しないので下記のように書く必要があります。

RewriteEngine On
RewriteBase /abc
RewriteRule ^abc/def\.html$ ghi.html [L]

ところで下記は×です。

RewriteEngine On
RewriteBase /abc
RewriteRule ^/abc/def\.html$ ghi.html [L]

ネット上を調べると上記例のようにRewriteRuleのマッチパターンをスラッシュ(/)から始めている記述がありますが、RewriteRuleに渡ってくるパスがスラッシュから始まるのはhttpd.confにRewriteRuleを書いた時だけで、.htaccessに書いた時は.htaccessが置いてあるディレクトリからの相対パス(上記例だと abc/def.html。RewriteLogで「strip per-dir prefix」と書かれている箇所)がRewriteRuleに渡ってくるため最初のスラッシュがマッチしなくなります。

RewriteBaseを使わない場合

RewriteBaseを使わない場合は下記のように書けます。

RewriteEngine On
RewriteRule ^abc/def\.html$ /abc/ghi.html [L]

書き換え後のパス(例だと/abc/ghi.html)が相対パスではなくURLの絶対パスなのでRewriteBaseを気にする必要がありません。

ところでRewriteBaseを指定しなかった場合の既定値は.htaccessを置いたディレクトリの物理パスです。そしてRewriteBaseは書き換え後の相対パスのベースです。つまり上記例に加えて下記の3つはすべて結果的に同じです。

RewriteEngine On
RewriteRule ^abc/def\.html$ abc/ghi.html [L]
RewriteEngine On
RewriteBase /var/www/vhosts/example.local/abc
RewriteRule ^abc/def\.html$ ghi.html [L]
RewriteEngine On
RewriteRule ^abc/def\.html$ /var/www/vhosts/example.local/abc/ghi.html [L]

なぜURLでも物理パスでもいいのかはRewriteLogを見るとわかりますが、書き換え後のパスが物理パスだった場合RewriteRuleでパターンマッチして内部リダイレクトさせる前に「strip document_root prefix」という形でドキュメントルートの物理パスを取り除いているためです。

ただし外部リダイレクト(RewriteRuleにRフラグをつける)にすると話は変わってきて、例えば下記のようにすると

RewriteEngine On
RewriteRule ^abc/def\.html$ /var/www/vhosts/example.local/abc/ghi.html [R,L]

ドキュメントルートの物理パスを取り除かずに外部リダイレクトするので結果としてhttp://example.local/var/www/vhosts/example.local/abc/ghi.html にアクセスしてしまいます。

まとめ

まとめとしてはタイトルの通りですが、mod_rewriteはややこしいです。RewriteBase以外でもしょっちゅうはまります。RewriteLogを見れば内部でどうやって書き換えが行われているのかが記録されるので、mod_rewriteが意図しない動作をするときはRewriteLogを見ましょう(RewriteLogについてはできれば後日まとめたいと思いますが、RewriteLogLevel - Httpd Wiki にあるようなログが確認できます)。