urlに+(plus)とapacheのrewriteRule
webサイトを開発していると、
SEOとか静的URLとか
リソース指向だとか
URIをどうするかいろいろ設計すると思います。
なんらかのフレームワークに乗っかっている場合、
そのフレームワークのルールのまんまいくときもあるとおもいます。
ただその場合、コントローラだのアクションだの名前がついてしまいますよね。
それ以外だとapacheのrewriteRuleを用いて、
URIを定義するかと思います。
で前置きはここまでにして、
http://delicious.com/toshifumi_tegu/apache+expires
こういうdeliciousみたいなQUERYをプラスでつなぐような
URIをつくらないといけなくなったときに
apacheのrewriteRuleをつかって
はまったことをまとめておきます。
そもそもプラスってURI的には「?」などと同じ予約文字でした。
出典 http://www.studyinghttp.net/cgi-bin/rfc.cgi?3986#Sec2.2
そりゃそうですよね。phpでurlencodeすると空白は+に変わります。(rawurlencodeなら%20ですが)
だから別にphp側で空白で取れようが、+で取れようが、どっちでもいいはずなんです。
しかしQUERYに+が含まれる場合(「C++」とか)、この場合区別できないといけません。
そこで諸所のサイトでは区切り文字ではない+はエンコードして渡すということになっていたりします。
で、別にapacheのリライトルールを使わなければ、普通にそれを区別して取得することができました。
でもクールなURIにはならないので
以下のようなルールを書くかと思います。(今回使用したフレームワークの場合)
^/path-to/([^/]+)$ /var/www/index.php?controller=foo&action=bar&query=$1
これでいいような感じがするんですが、
「A+」(エンコードするとA%2B)と「B」をqueryに渡そうとすると
http://domain/path-to/A%2B+B
$_GET['query']の中には「A B」とスペース二個に変換されています。
$_SERVER['REQUEST_URI']内では「A++B」として入っています。
なくなるか区別できなくなるか。
apacheのRewriteLogを見てみると
rewriteされている時点で$1はA++Bになっています。
こりゃ困った。簡単にできるような気がしていたのに全然あかんやんっていう。
そこで発想の転換。
以下の作者である先輩がRwriteしなきゃいいじゃんと教えてくれました。
http://freestyle.xrea.jp/blog/article.php?id=20
種々のフレームワークだと上記のように引数がPATHフォーマットでも大丈夫らしいです。
今回利用していたフレームワークはこちらには対応していなかったため、
対応するように変更。
1.まずエントリーポイントのindex.phpをpatht-toってファイル名でコピー
cp /www/var/index.php /www/var/path-to
2. apacheの.htaccessを以下のように変更
#^/path-to/([^/]+)$ /var/www/index.php?controller=foo&action=bar&query=$1 <Directory /var/www> <FilesMatch "^path-to$"> ForceType application/x-httpd-php </FilesMatch> </Directory>
3. さきほどコピーしたファイルpath-to内で
<?php $_GET['controller'] = 'foo'; $_GET['action'] = 'bar'; $_GET['query'] = explode('+', str_replace('/path-to/', '', $_SERVER['REQUEST_URI'])); //以下通常のフレームワークのエントリーポイントと同じ
このようにすることによって意図したqueryが得れます。
ただし$_SERVER['REQUEST_URI']はデコードされていない
よってqueryもデコードされておらず、自分でデコードする必要があります。
デコードした場合、
http://www.php.net/manual/ja/filter.filters.sanitize.php
フィルターなどを利用して普段はフィルターしていても
デコードされていないため、タグなども除去されていません。
自分でデコードしてあやまってscriptタグなどを表示しないよう
再度htmlspecialcharsを実行するなどして
http://php.net/manual/ja/function.htmlspecialchars.php
セキュリティ面に考慮する必要があります。
ということで上記のような対応で、deliciousのタグ検索みたいなURIのページが生成できました。