fc2ブログ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

mod_rewriteで動的ページを静的ページっぽいURLにする

http://hoge.jp/dir/appli/param1/1/param2/2/param3/3a/param3/3b/hogehogequery.html

http://hoge.jp/dir/appli?param1=1&param2=2&param3=3a&param3=3b&qeury=hogehogequery
に変換するようなmod_rewriteのルールを考える。

条件は、
1) param1、param2、param3、queryの各パラメータ名は固定。
2) 各パラメータとも必ずあるとは限らない。
3) param3は複数回出現する可能性がある。
4) queryはユーザがテキストボックスなどで入力した文字列をURLエンコードしたもの。
5) URIが/dir/配下限定でrewriteする。

そうすると↓をメインまたは<VirtualHost>ディレクティブのグローバルセクションに記述すれば良い。

AllowEncodedSlashes On … C1
<Directory "/usr/local/apache/htdocs/dir">
RewriteEngine On … C2

RewriteRule ^(appli/?.*/)(param1)/([^/]+)/(.*)$ $1$4?$2=$3 [QSA,PT]
RewriteRule ^(appli/?.*/)(param2)/([^/]+)/(.*)$ $1$4?$2=$3 [QSA,PT]
RewriteRule ^(appli/?.*/)(param3)/([^/]+)/(.*)$ $1$4?$2=$3 [QSA,PT,N] … C3
RewriteRule ^(appli/)(.+).html$ $1?query=$2&TMP_SEP=TMP_SEP [QSA,PT] … C4
RewriteCond %{QUERY_STRING} ^(.*)query=(.*)&(.*)(&TMP_SEP=TMP_SEP.*)$ … C5
RewriteRule ^(appli/)$ $1?%1query=%2\%26%3%4 [PT,N] … C6
RewriteCond %{QUERY_STRING} ^(.*)query=(.*)&TMP_SEP=TMP_SEP(.*)$ … C7
RewriteRule ^(appli/)$ $1?%1query=%2%3 [PT] … C8
</Directory>

【C1】まず、4)でユーザがスラッシュ"/"を入力するかもしれないから、AllowEncodedSlashes Onにしとく。

【C2】5)を実現するためにDirectoryディレクティブの中にRewriteEngine Onとルールを書く。こうしておけばhttp://hoge.jp/dir/…以外のURLではmod_rewriteは動作しないから、余計な負荷がかからない。

【C3】パラメータparam3は複数回出現する可能性があるからNオプションを付けてる。ただ、RewriteRuleをDirectoryディレクティブの中で使用する場合、Nオプションを付けても付けなくても、ルールにマッチしたら先頭からなめ直す動作をしている模様。なので、付けなくてもいいかもだけど、ルールを明確にしておく意味で付けておく。

やっかいなのはパラメータqueryの扱いで、アンパサンド"&"の入力を考慮しなきゃいけない。
Directoryディレクティブじゃなくてグローバルセクションなら、多分

RewriteRule ^(/dir/appli/)(.*)&(.*).html$ $1$2\%26$3.html [QSA,N]
RewriteRule ^(/dir/appli/)(.+).html$ $1?query=$2 [QSA]

でOK。じゃあ、これをDirectoryディレクティブ中に適用して

RewriteRule ^(appli/)(.*)&(.*).html$ $1$2\%26$3.html [QSA,PT,N]
RewriteRule ^(appli/)(.+).html$ $1?query=$2 [QSA,PT]

にすると無限ループになる。なぜかというと、Directoryディレクティブの場合は次みたいな動作になるから(RewriteLog抜粋)

例:http://hoge.jp/dir/appli/hoge&hoge.html

192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (3) [perdir /usr/local/apache/htdocs/dir/] applying pattern '^(appli/)(.*)&(.*).htm$' to uri 'appli/hoge&hoge.html'
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (2) [perdir /usr/local/apache/htdocs/dir/] rewrite 'appli/hoge&hoge.html' -> 'appli/hoge%26hoge.html'
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (3) [perdir /usr/local/apache/htdocs/dir/] add per-dir prefix: appli/hoge%26hoge.html -> /usr/local/apache/htdocs/dir/appli/hoge%26hoge.html
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (2) [perdir /usr/local/apache/htdocs/dir/] forcing '/usr/local/apache/htdocs/dir/appli/hoge%26hoge.html' to get passed through to next API URI-to-filename handler
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (2) [perdir /usr/local/apache/htdocs/dir/] strip document_root prefix: /usr/local/apache/htdocs/dir/appli/hoge%26hoge.html -> /dir/appli/hoge%26hoge.html
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6eaeb8/initial] (1) [perdir /usr/local/apache/htdocs/dir/] internal redirect with /dir/appli/hoge%26hoge.html [INTERNAL REDIRECT]
192.168.1.1 - - [02/Aug/2008:17:30:11 +0900] [hoge.jp/sid#672d58][rid#6f4760/initial/redir#1] (3) [perdir /usr/local/apache/htdocs/dir/] add path info postfix: /usr/local/apache/htdocs/dir/appli -> /usr/local/apache/htdocs/dir/appli/hoge&hoge.html

つまり、

a) applying pattern
b) rewrite
c) add per-dir prefix
d) forcing
e) strip document_root prefix
f) internal redirect with
g) add path info

という過程を経るわけだけど、せっかく"%26"にエンコードしたアンパサンドをg)のところで"&"に戻しちゃうから、無限ループになる。

なので、
【C4】まず1回QUERY_STRINGに query=hoge&hoge&TMP_SEP=TMP_SEP の形で追いやる。TMP_SEP=TMP_SEP は他の連結パラメータがある場合、境界を明確にするため。これがないとパラメータ連結文字列"&"とquery中の"&"の区別がつかなくなる。

次に、
【C5,C6】query=hoge&hoge&TMP_SEP=TMP_SEP を query=hoge%26hoge&TMP_SEP=TMP_SEP にエンコードする。queryに"&"が複数含まれている場合は、全部"%26"にエンコードするまで繰り返される。$1,$2,$3,… はRewriteRuleの後方参照で、%1,%2,%3,… はRewriteCondの後方参照。

最後に、
【C7,C8】TMP_SEP=TMP_SEP を取って、query=hoge%26hoge&TMP_SEP=TMP_SEP を query=hoge%26hoge にする。

ちなみにRewriteLogを取るにはhttpd.conf(または、httpd-vhosts.conf)に
RewriteLog logs/rewrite_log
RewriteLogLevel 4
を追加する。パフォーマンスが落ちるからデバッグ用に。

この記事のトラックバックURL

http://ysmt.blog21.fc2.com/tb.php/216-388de715

コメント

コメントする

管理者にだけ表示を許可する

Template Designed by DW99

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。