31

+タグ付けシステム用に、すべての特殊文字 ( 、&#%、および)を含むきれいな URL を用意したいと考えています=。リンクを二重にエンコードせずに mod_rewrite でこれを行う方法はありますか?

私は、delicious.com と stackoverflow が単独でエンコードされた特殊文字を処理できるように見えることに気付きました。魔法の公式とは?

これが私がしたいことの例です:

http://www.example.com/tag/c%2b%2b

次の RewriteRule をトリガーします。

RewriteRule ^tag/(.*)   script.php?tag=$1

タグの値は「c++」になります

apache/mod_rewrite の通常の操作は、プラス記号をスペースに変換するように見えるため、このようには機能しません。 プラス記号を「%252B」に二重エンコードすると、目的の結果が得られますが、 URL が乱雑になり、かなりハックされているように見えます。

4

5 に答える 5

28

apache/mod_rewrite の通常の操作は、プラス記号をスペースに変換するように見えるため、このようには機能しません。

私はそれが起こっていることだとは思いません。+ は有効な文字であるため、Apache はパス部分で %2Bs を +s にデコードしています。これは、mod_rewrite がリクエストを確認する前に行われます。

したがって、mod_rewrite はリクエスト '/tag/c++' を 'script.php?tag=c++' に変更します。ただし、application/x-www-form-encoded 形式のクエリ文字列コンポーネントでは、エスケープ ルールがパス部分に適用されるルールとわずかに異なります。特に、'+' はスペースの短縮形です (これは '%20' と同じようにエンコードできますが、これは古い動作であり、現在変更することはできません)。

したがって、PHP のフォーム読み取りコードは「c++」を受け取り、それを C-space-space として _GET にダンプします。

これを回避する方法は、rewriteflag 'B' を使用することです。http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteflagsを参照してください- 不思議なことに、多かれ少なかれ同じ例を使用しています!

RewriteRule ^tag/(.*)$ /script.php?tag=$1 [B]
于 2009-01-20T01:36:37.490 に答える
5

あなたが何を求めているのかよくわかりませんが、NEApache のディレクティブへの (noescape) フラグにRewriteRule興味があるかもしれません。基本的に、指定した置換パターンで特殊文字を自動的にエスケープすることを防ぎmod_rewriteます。Apache 2.2 のドキュメントに記載されている例は次のとおりです。

RewriteRule /foo/(.*) /bar/arg=P1\%3d$1 [R,NE]

これは、たとえば、/foo/zedへのリダイレクトに変わります。/bar/arg=P1%3dzedそのため、スクリプトは、その中を見れば、 value/barという名前のクエリ パラメータを認識します(わかりました、それは実際のクエリ パラメータではないので、私を訴えてください ;-P)。argP1=zedPATH_INFO

少なくとも、そのように機能すると思います。. . 私はその特定のフラグを自分で使用したことはありません。

于 2009-01-20T00:11:26.617 に答える
1

根本的な問題は、1 つのエンコーディング (具体的にはプラス記号はプラス記号) を持つリクエストから、別のエンコーディング (プラス記号はスペースを表す) を持つリクエストに移行しようとしていることです。解決策は、mod_rewrite が行うデコードをバイパスし、生のリクエストから直接パスをクエリ文字列に変換することです。

書き換えルールの通常の流れをバイパスするには、生のリクエスト文字列を環境変数に直接ロードし、通常の書き換えパスの代わりに環境変数を変更します。既にエンコードされているため、通常、クエリ文字列に移動するときにエンコードについて心配する必要はありません。ただし、プラス記号がスペースではなくプラス記号として適切に中継されるように、プラス記号をパーセント エンコードする必要があります。

ルールは信じられないほど単純です。

RewriteEngine On

RewriteRule ^script.php$ - [L]

# Move the path from the raw request into _rq
RewriteCond %{ENV:_rq} =""
RewriteCond %{THE_REQUEST} "^[^ ]+ (/path/[^/]+/[^? ]+)"
RewriteRule .* - [E=_rq:%1]

# encode the plus signs (%2B)  (Loop with [N])
RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)\+(.*)$"
RewriteRule .* - [E=_rq:/path/%1/%2\%2B%3,N]

# finally, move it from the path to the query string
# ([NE] says to not re-code it)
RewriteCond %{ENV:_rq} "/path/([^/]+)/(.*)$"
RewriteRule .* /path/script.php?%1=%2 [NE]

この簡単な script.php は、それが機能することを確認します:

<input readonly type="text" value="<?php echo $_GET['tag']; ?>" />
于 2011-09-15T09:13:00.667 に答える
1

RewriteMap の助けを借りて、ようやく機能するようになりました。

httpd.conf ファイルにエスケープ マップを追加 RewriteMap es int:escape

そしてそれを書き換えルールで使用しました

RewriteRule ([^?.]*) /abc?arg1=${es:$1}&country_sniff=true [L]
于 2011-04-29T09:26:40.380 に答える