type - ¿Cómo codificar caracteres especiales usando mod_rewrite y Apache?
rewriterule htaccess (5)
Me gustaría tener URL bonitas para mi sistema de etiquetado junto con todos los caracteres especiales: +
, &
, #
, %
y =
. ¿Hay alguna manera de hacer esto con mod_rewrite sin tener que doblar los enlaces?
Noté que delicious.com y stackoverflow parecen ser capaces de manejar caracteres especiales codificados individualmente. ¿Cuál es la fórmula mágica?
Aquí hay un ejemplo de lo que quiero que suceda:
http://www.foo.com/tag/c%2b%2b
Desencadenaría la siguiente RewriteRule:
RewriteRule ^tag/(.*) script.php?tag=$1
y el valor de la etiqueta sería "c ++"
La operación normal de apache / mod_rewrite no funciona así, ya que parece convertir los signos más en espacios. Si codigo doblemente el signo más para ''% 252B'', entonces obtengo el resultado deseado; sin embargo, es una URL desordenada y me parece bastante chistoso.
La operación normal de apache / mod_rewrite no funciona así, ya que parece convertir los signos más en espacios.
No creo que eso sea exactamente lo que está sucediendo. Apache está decodificando el% 2Bs a + s en la parte de la ruta ya que + es un carácter válido allí. Hace esto antes de dejar que mod_rewrite mire la solicitud.
Entonces, mod_rewrite cambia su solicitud ''/ tag / c ++'' a ''script.php? Tag = c ++''. Pero en un componente de cadena de consulta en el formato application / x-www-form-encoded, las reglas de escape son muy ligeramente diferentes a las que se aplican en las partes de ruta. En particular, ''+'' es una abreviatura de espacio (que bien podría codificarse como ''% 20'', pero este es un comportamiento antiguo que nunca podremos cambiar ahora).
Por lo tanto, el código de lectura de formulario de PHP recibe el ''c ++'' y lo deposita en su _GET como C-space-space.
Parece que la forma de evitar esto es usar la regla de reescritura ''B''. Ver http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteflags - ¡curiosamente usa más o menos el mismo ejemplo!
RewriteRule ^tag/(.*)$ /script.php?tag=$1 [B]
El problema subyacente es que se está moviendo de una solicitud que tiene una codificación (específicamente, un signo más es un signo más) en una solicitud que tiene una codificación diferente (un signo más representa un espacio). La solución es eludir la descodificación que hace mod_rewrite y convertir su ruta directamente desde la solicitud en bruto a la cadena de consulta.
Para eludir el flujo normal de las reglas de reescritura, cargaremos la cadena de solicitud sin procesar directamente en una variable de entorno y modificaremos la variable de entorno en lugar de la ruta de reescritura normal. Ya estará codificado, por lo que generalmente no tenemos que preocuparnos por codificarlo cuando lo movemos a la cadena de consulta. Sin embargo, lo que sí queremos es codificar porcentualmente los signos más para que se transmitan correctamente como signos más y no como espacios.
Las reglas son increíblemente simples:
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]
Este script.php trivial confirma que funciona:
<input readonly type="text" value="<?php echo $_GET[''tag'']; ?>" />
Finalmente lo hice funcionar con la ayuda de RewriteMap.
Se agregó el mapa de escape en el archivo httpd.conf RewriteMap es int: escape
y lo usé en la regla Reescribir
RewriteRule ([^?.]*) /abc?arg1=${es:$1}&country_sniff=true [L]
Me encuentro con el problema similar para mod_rewrite con + url de inicio de sesión. El escenario como a continuación:
tenemos una url con signo + necesidad de reescribir como http://deskdomain/2013/08/09/a+b+c.html
RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1
Los struts action urlRedirect obtienen el parámetro url, hacen algunos cambios y usan la url para otra redirección. Pero en req.getParameter ("url") el signo + cambia a vacío, el contenido de la URL del parámetro es http://deskdomain/2013/08/09/ab c.html
, que causa el redireccionamiento 404 no encontrado. Para resolverlo (obtenga ayuda de la respuesta anterior) usamos la bandera de reescritura B (referencias de escape), y NE (noescape)
RewriteRule ^/(.*) http://mobiledomain/do/urlRedirect?url=http://%{HTTP_HOST}/$1 [B,NE]
La B escapará + a% 2B, NE evitará mod_write escape% 2B a% 252B (doble escape + signo), así que en req.getParameter("url")=http://deskdomain/2013/08/09/a+b+c.html
Creo que la razón es req.getParameter ("url") hará unescape para nosotros, el signo + puede unescape para vaciarse. Puedes probar unescape% 2B una vez para +, luego unescape + nuevamente para vaciar.
"%2B" unescape-> "+" unescape-> " "
No estoy seguro de entender lo que estás preguntando, pero el indicador NE
(noescape) de la directiva RewriteRule
de Apache puede ser de tu interés. Básicamente, evita que mod_rewrite
escape automáticamente a los caracteres especiales en el patrón de sustitución que proporciones. El ejemplo dado en la documentación de Apache 2.2 es
RewriteRule /foo/(.*) /bar/arg=P1/%3d$1 [R,NE]
que convertirá, por ejemplo, /foo/zed
en una redirección a /bar/arg=P1%3dzed
, de modo que el script /bar
verá un parámetro de consulta llamado arg
con un valor P1=zed
, si se ve en su PATH_INFO
(de acuerdo, ese no es un parámetro de consulta real , entonces sígame ;-P).
Al menos, creo que así es como funciona. . . Nunca he usado esa bandera en particular.