Подтвердить что ты не робот

Как кодировать специальные символы с помощью mod_rewrite & Apache?

Я хотел бы иметь красивые URL-адреса для моей системы тегов вместе со всеми специальными символами: +, &, #, % и =. Есть ли способ сделать это с помощью mod_rewrite без двойного кодирования ссылок?

Я замечаю, что delicious.com и stackoverflow, похоже, способны обрабатывать отдельные кодированные символы. Какая магическая формула?

Вот пример того, что я хочу:

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

Вызов следующего RewriteRule:

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

и значение тега будет "С++"

Нормальная работа apache/mod_rewrite не работает так, как будто она превращает знаки плюса в пробелы. Если я дважды закодирую знак плюса на "% 252B", тогда я получу желаемый результат - однако он вызывает беспорядочные URL-адреса и кажется мне довольно взломанным.

4b9b3361

Ответ 1

Нормальная работа apache/mod_rewrite не работает так, как будто она превращает знаки плюса в пробелы.

Я не думаю, что это происходит совсем. Apache расшифровывает% 2Bs на + s в части пути, так как + является допустимым символом. Он делает это, прежде чем позволить mod_rewrite посмотреть запрос.

Итак, mod_rewrite изменяет ваш запрос '/tag/С++' на 'script.php? tag = С++'. Но в компоненте строки запроса в формате application/x-www-form-encoded правила экранирования очень немного отличаются от правил, применяемых в частях пути. В частности, "+" является сокращением пространства (которое также может быть закодировано как "%20", но это старое поведение, которое мы никогда не сможем изменить сейчас).

Таким образом, код чтения форм PHP получает "С++" и выгружает его в _GET как C-пространство-пространстве.

Похоже, что вокруг этого стоит использовать rewriteflag 'B'. См. http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteflags - любопытно, что он использует более или менее тот же пример!

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

Ответ 2

Я не уверен, что понимаю, что вы просите, но флаг NE (noescape) для директивы Apache RewriteRule может вас заинтересовать. В принципе, он предотвращает mod_rewrite от автоматического экранирования специальных символов в шаблоне замещения, который вы предоставляете. Пример, приведенный в документации Apache 2.2,

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

который превратит, например, /foo/zed в перенаправление на /bar/arg=P1%3dzed, так что script /bar будет видеть параметр запроса с именем arg со значением P1=zed, если он выглядит в его PATH_INFO (хорошо, что это не реальный параметр запроса, так что мне нужно: -P).

По крайней мере, я думаю, что это работает., Я никогда не использовал этот особый флаг.

Ответ 3

Я, наконец, сделал это с помощью RewriteMap.

Добавлена ​​карта escape в файле httpd.conf RewriteMap es int: escape

и использовал его в правиле Rewrite

RewriteRule ([^?.]*) /abc?arg1=${es:$1}&country_sniff=true [L]

Ответ 4

Основная проблема заключается в том, что вы переходите от запроса, который имеет одну кодировку (в частности, знак плюса - знак плюса) в запрос, который имеет различную кодировку (знак плюса обозначает пробел). Решение состоит в том, чтобы обойти декодирование, которое делает 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']; ?>" />

Ответ 5

Я встречаю аналогичную проблему для mod_rewrite с + знаком в url. Сценарий, как показано ниже:

у нас есть url со знаком +, нужно переписать как http://deskdomain/2013/08/09/a+b+c.html

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1

Действие struts urlRedirect получает параметр url, делает некоторые изменения и использует URL для другого перенаправления. Но в req.getParameter( "url" ) знак + меняется на пустой, содержимое URL-адреса параметра http://deskdomain/2013/08/09/a b c.html, которые вызывают перенаправление 404, не найдены. Для решения проблемы (получить помощь из предыдущего ответа) мы используем флаг перезаписи B (escape-обратные ссылки) и NE (noescape)

RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1 [B,NE]

В B выйдет + на% 2B, NE предотвратит переход от mod_write% 2B к% 252B (двойной escape + знак), поэтому в req.getParameter("url")=http://deskdomain/2013/08/09/a+b+c.html

Я думаю, причина в том, что req.getParameter( "url" ) сделает unescape для нас, знак + может unescape пустым. Вы можете попробовать unescape% 2B один раз на +, затем unescape + снова на пустой.

"%2B" unescape-> "+" unescape-> " "