ブログトップ 記事一覧 ログイン 無料ブログ開設

理想未来はどうなった? このページをアンテナに追加 RSSフィード

2009-12-24

mod_rewriteでGETパラメータ名を変更する。

mod_rewriteのお話。

旧システムから新システムの以降など、システムの仕様が変わる時でも古いURLを引き継ぎたい場合に役に立つ小技。

問題1

GETパラメータの名前aaaをbbbに変更したい場合はどのようにすれば良いか?

ついつい以下のように設定してしまうかと思いますが、うまく動きません。

RewriteRule filename.html\?aaa=(.*) filename.html?bbb=$1 [L]

RewriteCondを使い、QUERY_STRINGの条件を指定すると、うまく動きます。

RewriteCond %{QUERY_STRING}     aaa=(.+)
RewriteRule filename.html filename.html?bbb=%1 [L]

%1で、RewriteCondでマッチしたパターンを取得できる。

問題2

GETパラメータの名前aaaをbbbに変更したいが、aaa以外のパラメータはそのまま残したい場合はどのようにすれば良いか?

解答1

QSAをつける。

RewriteCond %{QUERY_STRING}     aaa=(.+)
RewriteRule filename.html filename.html?bbb=%1 [L,QSA]

aaa=○○&ccc=△△だった場合、bbb=○○&aaa=○○&ccc=△△のように、古いパラメータもそのままついてしまう。

解答2

以下の場合、aaaのみbbbに書き換える事ができる。

RewriteCond %{QUERY_STRING}     ^(.*)aaa=(.+)$
RewriteRule filename.html filename.html?%1bbb=%2 [L]


オマケ

『上記試してみましたが、うまく動きません!』という場合

上から順に評価されるので、こんな事しているとうまく動かない。

#ファイルが存在する場合はそれを表示する
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d 
RewriteRule ^.* - [L]
# ↑ファイルが存在した時点で、上記が評価されて終わってしまう。

#パラメータ名を書き換える。
RewriteCond %{QUERY_STRING}     ^(.*)aaa=(.+)$
RewriteRule filename.html filename.html?%1bbb=%2 [L]


順番を変更する事でうまく動く。

#パラメータ名を書き換える。
RewriteCond %{QUERY_STRING}     ^(.*)aaa=(.+)$
RewriteRule filename.html filename.html?%1bbb=%2 [L]
#↑先に評価される。

#ファイルが存在する場合はそれを表示する
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d 
RewriteRule ^.* - [L]


そんな感じで、お役に立てれば幸いです。

関連記事

[Apache][mod_rewrite]続:存在するファイルはスルーしたい

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)

2009-06-07

続:存在するファイルはスルーしたい

mod_rewriteのお話。
以前に書いた挙動の疑問が解決したので再掲載。

ファイルが存在する場合はそのファイルを表示し、存在しない場合はindex.phpを表示するようにしたい。
よくある例が以下のようになっているが、実際にはうまく動かない。

RewriteEngine on
RewriteBase /
#ファイルが存在しない且つ、ディレクトリが存在しない場合は、index.phpを表示
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^$ /index.php [L,QSA]
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]

上記の例がなぜうまく動かないかというと、RewriteCondは直下のRewriteRuleにしか通じないのです。
つまり、存在するファイルに対して、

RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]

のルールが適応されてしまうことになります。
これを回避する為の解決策は下記の例の通りです。

解決策1:RewriteRuleの順番を変える

上記の例では順番を変えることで解決します。

RewriteEngine on
RewriteBase /

RewriteRule ^$ /index.php [L,QSA]
#ファイルが存在しない且つ、ディレクトリが存在しない場合は、index.phpを表示
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]


解決策2:RewriteRule毎に、RewriteCondを書く

RewriteRule毎に、RewriteCondを1つ1つ書くことで回避できます。

RewriteEngine on
RewriteBase /

#^$用のRewriteCondとRewriteRule
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^$ /index.php [L,QSA]

#^(.*)$用のRewriteCondとRewriteRule
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]


解決3:存在するファイルに対してRewriteRuleを先に適応する

先に存在するファイルに対してルールを適応してしまう。
こっちの方が楽かもしれません。

RewriteEngine on
RewriteBase /
#ファイルが存在するか、ディレクトリが存在する場合は、そのファイルを表示する
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.* - [L]

#ファイルが存在しない場合に以下のルールを適用
RewriteRule ^$ /index.php [L,QSA]
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]


解決策4:ルールを良く見直す。

実は、.*を.+に変えるだけで、1行目のルールは必要なかったりします。
途中で気がついたのですが、説明が書けなくなるので最後に回しました。

RewriteEngine on
RewriteBase /

#ファイルが存在しない且つ、ディレクトリが存在しない場合は、index.phpを表示
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /index.php?jb=$1 [L,QSA]


そんな感じで、RewriteCondは直下のRewriteRuleにのみ適用されます。
RewriteRuleを書く時は、後から見る人が勘違いしないように一行あけて書くようにしましょう。


関連記事

[Apache][mod_rewrite]存在するファイルはスルーしたい

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)

2009-02-07

存在するファイルはスルーしたい

mod_rewriteのお話。
ファイルが存在する場合はそのファイルを表示し、存在しない場合はindex.phpを表示するようにしたい。
よくある例が以下のようになっているが、実際にはうまく動かない。

RewriteEngine on
RewriteBase /
#ファイルが存在しない且つ、ディレクトリが存在しない場合は、index.phpを表示
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^$ /index.php [L,QSA]
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]

修正(2009/06/07)

挙動について解決しました。
[Apache][mod_rewrite]続:存在するファイルはスルーしたい


以下のように書くと期待通りに動作する。

RewriteEngine on
RewriteBase /
#ファイルが存在するか、ディレクトリが存在する場合は、そのファイルを表示する
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.* - [L]
#ファイルが存在しない且つ、ディレクトリが存在しない場合は、index.phpを表示
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^$ /index.php [L,QSA]
RewriteRule ^(.*)$ /index.php?jb=$1 [L,QSA]

これで目的は達成されるのだが、最初の例でなぜうまくいかないかが納得いかない。
この挙動について説明できる方がおられれば、ご教授いただけると幸いです。

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)

The Definitive Guide to Apache Mod_rewrite (Definitive Guides)