【mod_rewrite】「.htaccess」での設定時の注意点
サーバーApacheのモジュールmod_rewriteでURL書き換えを行うとき、「httpd.conf」ではなく「.htaccess」で設定する場合が多いと思います。
しかしこの場合、注意点があります。
スポンサードリンク
最初に戻ってマッチングされる
mod_rewriteでURL書き換えを行う際、RewriteRuleを一つだけ記述する場合は特に気にしなくてよいのですが、複数個記述する場合は注意が必要です。
それは、マッチングが終了した際、再度最初からマッチングされるからです。
例えば、以下を記述した「.htaccess」をルートディレクトリに設置したとします。
RewriteEngine On
RewriteRule ^index.html index2.html ・・・①
RewriteRule ^index3.html index4.html ・・・②
RewriteRule ^index2.html index3.html ・・・③
この場合、「http://○○○.com/index.html」でアクセスした場合、「index3.html」が出力されそうです。
しかし、実際は「index4.html」が出力されます。
書き換えの挙動
URL書き換えの挙動を追っていくと、このようになります。
「http://○○○.com/index.html」でアクセスがあった場合、RewriteRuleに「index.html」が渡される。
↓
①ではパターンマッチして「index2.html」に書き換えられる
↓
②ではパターンマッチしない
↓
③でパターンマッチして「index3.html」に書き換えられる
↓
ここで書き換え終了かと思いきや、最初に戻る
↓
①ではパターンマッチしない
↓
②ではパターンマッチして「index4.html」に書き換えられる
↓
これ以降はパターンマッチしないのでここで終了
このように、いったんマッチが終了したあと、再度最初からマッチングされていきます。
何度も最初に戻ってマッチングされる
では、次の場合はどうでしょうか。
RewriteEngine On
RewriteRule ^index.html index2.html ・・・①
RewriteRule ^index4.html index5.html ・・・②
RewriteRule ^index3.html index4.html ・・・③
RewriteRule ^index2.html index3.html ・・・④
この場合、先ほどの例に沿って「index4.html」かな?と思いますが、「index5.html」が出力されます。
書き換えの挙動
書き換えの挙動を追うと、このようになります。
「http://○○○.com/index.html」でアクセスがあった場合、RewriteRuleに「index.html」が渡される。
↓
①ではパターンマッチして「index2.html」に書き換えられる
↓
②ではパターンマッチしない
↓
③ではパターンマッチしない
↓
④でパターンマッチして「index3.html」に書き換えられる
↓
これ以降はマッチングされないが、終了せずに最初に戻る
↓
①ではパターンマッチしない
↓
②ではパターンマッチしない
↓
③ではパターンマッチして「index4.html」に書き換えられる
↓
これ以降はマッチングされないが、さらに最初に戻る
↓
①ではパターンマッチしない
↓
②ではパターンマッチして「index5.html」に書き換えられる
↓
これ以降はパターンマッチしないので、さらに最初に戻る
↓
これ以降はマッチングしないので「index5.html」でフィニッシュ
このように、「.htaccess」でのmod_rewriteは、何度も何度も最初に戻ってマッチングしていき、何もマッチされなくなるまで書き換え処理が行われます。
永久ループの危険性
「何度も何度も最初に戻ってマッチングする」というmod_rewriteの仕様のせいで、永久ループに陥る危険性がグンとあがります。
例えば、次のような場合は永久ループになります。
RewriteEngine On
RewriteRule ^index.html index2.html
RewriteRule ^index3.html index4.html
RewriteRule ^index2.html index3.html
RewriteRule ^index4.html index.html
この場合、「500 Internal Server Error」が返され、ページ閲覧が不能になります。
対処法
このように永久ループになる危険性がある場合は、 「何度も何度も最初に戻ってマッチングする」というmod_rewriteの仕様を見越して記述を工夫しなければなりません。
例えば、以下のようにフラグ「L」を仕込んでおくなどです。
RewriteEngine On
RewriteRule ^index.html index2.html
RewriteRule ^index3.html index4.html
RewriteRule ^index4.html - [L]
RewriteRule ^index2.html index3.html
RewriteRule ^index4.html index.html
また、これまではRewriteRuleのパターン部分はシンプルなものを記述しましたが、「^(.*)$」などの大雑把な正規表現を使うと永久ループの危険性が高まります。
こういう場合は、ディレクトリを含めて書いたり( ^abc/(.*)$ )、拡張子を指定したり( ^(.*\.html)$ )して対策を講じます。
追記
「.htaccess」でのmod_rewrite設定は、Lフラグ(パターンマッチした場合に、それ以降の書き換えはしないように指定するフラグ)を記述しても意味がないようです(詳しくは「.htaccess」でのLフラグは意味がない?を参照)。
また、httpd.confに記述しても、記述場所がDirectoryセクションであった場合は、「.htaccess」での設定と同様に最初に戻ってマッチングされます(詳しくは「httpd.conf」での設定方法を参照)。
そのため、RewriteCondを用いるのが最も簡単な対処法だと思います。
なお、外部にリダイレクト、つまりRフラグとLフラグを指定しておけば、その時点でリダイレクトされますので最初に戻って・・・みたいなことにはなりません。
まとめ
「.htaccess」での設定(および「httpd.conf」での設定であってもDirectoryセクションに記述した場合)は処理が終わっても最初に戻ってマッチングされる。
永久ループにならないよう工夫する必要がある(RewriteCondを使ってルール条件を定義するのが最もよい)。
参考サイト
Warning: count(): Parameter must be an array or an object that implements Countable in /home/yskymk/www/000web/ysklog/mod-rewrite/wp-includes/class-wp-comment-query.php on line 405
コメント
まだコメントはありません。