rewriteengine how enable php apache mod-rewrite environment-variables naming

php - enable - how to rewrite url apache



Al establecer variables de entorno en las directivas Apache RewriteRule, ¿qué causa el nombre de la variable con el prefijo "REDIRECT_"? (3)

Estoy tratando de establecer variables de entorno Apache (para usar en PHP) con el indicador [E=VAR:VAL] en reglas RewriteRule en un archivo .htaccess.

Ya he descubierto que se accede a las variables en PHP como las variables de servidor $_SERVER lugar de $_ENV (lo que tiene un cierto sentido). Sin embargo, mi problema es que para algunas reglas el indicador [E=VAR:VAL] funciona como se esperaba y termino con una variable $_SERVER[''VAR''] pero para otras reglas, termino con una variable $_SERVER[''REDIRECT_VAR''] o $_SERVER[''REDIRECT_REDIRECT_VAR''] , etc.

A. ¿Qué causa que una variable de entorno se establezca en Apache usando el indicador [E=VAR:VAL] para obtener el nuevo nombre al tener "REDIRECT_" antecedido al nombre de la variable?

B. ¿Qué puedo hacer para asegurarme de terminar con una variable de entorno con un nombre sin modificar para que pueda acceder a ella en PHP como $_SERVER[''VAR''] sin tener que recurrir a buscar variaciones del nombre de variable que tenga uno de ¿hay más instancias de "REDIRECT_" antes?

Solución parcial encontrada . Al agregar lo siguiente al comienzo de las reglas de reescritura, se recrea el ENV original: VAR en cada redirección (además de dejar las versiones REDIRECT_VAR allí) si se necesitan:

RewriteCond %{ENV:REDIRECT_VAR} !^$ RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}]


Como no quiero cambiar ninguno de mis códigos (ni puedo cambiar el código de las bibliotecas usadas) , utilicé el siguiente enfoque: mientras que cargaba mi aplicación, por ejemplo, en mi index.php , $_ENV trabajar con el $_ENV _ENV para las variables con prefijo REDIRECT_ se reescriben a su nombre intencional normal:

// Fix ENV vars getting prepended with `REDIRECT_` by Apache foreach ($_ENV as $key => $value) { if (substr($key, 0, 9) === ''REDIRECT_'') { $_ENV[str_replace(''REDIRECT_'', '''', $key)] = $value; putenv(str_replace(''REDIRECT_'', '''', $key) . ''='' . $value); } }

No solo lo configuramos directamente en $_ENV , sino que también lo almacenamos usando putenv() . De esta forma, el código y las bibliotecas existentes, que podrían usar getenv() , pueden funcionar bien.

En una nota al margen: si está extrayendo encabezados, como HTTP_AUTHORIZATION , en su código, debe hacer el mismo tipo de manipulación en $_SERVER :

foreach ($_SERVER as $key => $value) { if (substr($key, 0, 9) === ''REDIRECT_'') { $_SERVER[str_replace(''REDIRECT_'', '''', $key)] = $value; } }


Este comportamiento es desafortunado y ni siquiera parece estar documentado.

.htaccess por contexto dir

Esto es lo que parece suceder en el contexto de .htaccess por directorio (por directorio):

Supongamos que Apache procesa un archivo .htaccess que incluye directivas de reescritura.

  1. Apache rellena su mapa de variables de entorno con todas las variables CGI / Apache estándar

  2. La reescritura comienza

  3. Las variables de entorno se establecen en RewriteRule directivas RewriteRule

  4. Cuando Apache deja de procesar las directivas RewriteRule (debido a un indicador L o al final del conjunto de reglas) y la URL ha sido modificada por RewriteRule , Apache reinicia el proceso de solicitud.

    Si no está familiarizado con esta parte, consulte la documentación de la bandera L :

    por lo tanto, el conjunto de reglas se puede ejecutar nuevamente desde el principio. Lo más común es que esto suceda si una de las reglas provoca una redirección, ya sea interna o externa, lo que provoca que el proceso de solicitud comience nuevamente.
  5. Por lo que puedo observar, creo que cuando ocurre el # 4, el # 1 se repite, luego las variables de entorno que se establecieron en RewriteRule directivas RewriteRule se anteponen con REDIRECT_ y se agregan al mapa de vars del entorno (no necesariamente en ese orden, pero al final resultado que consiste en esa combinación).

    Este paso es donde se eliminan los nombres de las variables elegidas, y en un momento explicaré por qué es tan importante e inconveniente.

Restaurando nombres de variables

Cuando me encontré originalmente con este problema, estaba haciendo algo como lo siguiente en .htaccess (simplificado):

RewriteCond %{HTTP_HOST} (.+)/.projects/. RewriteRule (.*) subdomains/%1/docroot/$1 RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]

Si RewriteRule que establecer la variable de entorno en la primera RewriteRule , Apache reiniciaría el proceso de reescritura y precedería la variable con REDIRECT_ (pasos 4 y 5 anteriores), así perdería acceso a ella a través del nombre que asigné.

En este caso, la primera RewriteRule cambia la URL, así que después de que se RewriteRule ambas RewriteRule s, Apache reinicia el procedimiento y procesa el .htaccess nuevamente. La segunda vez, la primera RewriteRule se omite debido a la directiva RewriteCond , pero la segunda RewriteRule coincide, establece la variable de entorno (nuevamente) y, lo que es más importante, no cambia la URL . Por lo tanto, el proceso de solicitud / reescritura no comienza de nuevo, y el nombre de la variable que elegí se pega. En este caso, en realidad tengo tanto REDIRECT_EFFECTIVE_DOCUMENT_ROOT como EFFECTIVE_DOCUMENT_ROOT . Si RewriteRule que usar una bandera L en la primera RewriteRule , solo tendría EFFECTIVE_DOCUMENT_ROOT .

La solución parcial de @ trowel funciona de manera similar: las directivas de reescritura se procesan nuevamente, la variable renombrada se vuelve a asignar al nombre original y, si la URL no cambia, el proceso termina y el nombre de la variable asignada se mantiene.

Por qué esas técnicas son inadecuadas

Ambas técnicas adolecen de un defecto importante: cuando las reglas de reescritura en el archivo .htaccess donde configura variables de entorno reescriben la URL en un directorio anidado más profundamente que tiene un archivo .htaccess que realiza cualquier reescritura, se borra el nombre de la variable asignada Fuera denuevo.

Supongamos que tiene un diseño de directorio como este:

docroot/ .htaccess A.php B.php sub/ .htaccess A.php B.php

Y un docroot/.htaccess como este:

RewriteRule ^A/.php sub/B.php [L] RewriteRule .* - [E=MAJOR:flaw]

Entonces solicitas /A.php , y se reescribe a sub/B.php . Aún tienes tu variable MAJOR .

Sin embargo, si tiene directivas de reescritura en docroot/sub/.htaccess (incluso RewriteEngine Off o RewriteEngine On ), su variable MAJOR desaparece. Esto se debe a que una vez que la URL se reescribe en sub/B.php , se docroot/sub/.htaccess , y si contiene alguna directiva de reescritura, las directivas de reescritura en docroot/.htaccess no se procesan nuevamente. Si tenía un REDIRECT_MAJOR después de que se docroot/.htaccess (por ej., Si omite el indicador L de la primera RewriteRule ), aún lo tendrá, pero esas directivas no se ejecutarán nuevamente para establecer el nombre de la variable elegida.

Herencia

Entonces, di que quieres:

  1. establecer variables de entorno en directivas RewriteRule en un nivel particular del árbol de directorios (como docroot/.htaccess )

  2. tenerlos disponibles en scripts en niveles más profundos

  3. tenerlos disponibles con los nombres asignados

  4. poder tener directivas de reescritura en archivos .htaccess más profundamente anidados

Una posible solución es utilizar RewriteOptions inherit directivas en los archivos .htaccess más profundamente anidados. Eso le permite volver a ejecutar las directivas de reescritura en archivos anidados menos profundamente y utilizar las técnicas descritas anteriormente para establecer las variables con los nombres elegidos. Sin embargo, tenga en cuenta que esto aumenta la complejidad porque debe ser más cuidadoso al diseñar las directivas de reescritura en los archivos menos anidados para que no causen problemas cuando se vuelven a ejecutar desde los directorios anidados más profundamente. Creo que Apache elimina el prefijo por directorio para el directorio más profundamente anidado y ejecuta las directivas de reescritura en los archivos menos anidados en ese valor.

la técnica de @ paleta

Por lo que puedo ver, el soporte para usar una construcción como %{ENV:REDIRECT_VAR} en el componente de valor de una bandera RewriteRule E (por ejemplo [E=VAR:%{ENV:REDIRECT_VAR}] ) no parece estar documented :

VAL puede contener referencias hacia atrás ($ N o% N) que se expandirán.

Parece que funciona, pero si quieres evitar confiar en algo no documentado (corrígeme si me equivoco al respecto), se puede hacer fácilmente de esta manera:

RewriteCond %{ENV:REDIRECT_VAR} (.+) RewriteRule .* - [E=VAR:%1]

SetEnvIf

No recomiendo confiar en esto, porque no parece ser consistente con el comportamiento documentado (ver a continuación), pero esto (en docroot/.htaccess , con Apache 2.2.20) funciona para mí:

SetEnvIf REDIRECT_VAR (.+) VAR=$1

Solo las variables de entorno definidas por las directivas SetEnvIf [NoCase] ​​anteriores están disponibles para probarse de esta manera.

¿Por qué?

No sé cuál es la razón de anteponer estos nombres con REDIRECT_ , lo cual no es sorprendente, ya que no aparece mencionado en las secciones de documentación de Apache para las directivas mod_rewrite , documented o variables de entorno .

Por el momento, parece una gran molestia para mí, a falta de una explicación de por qué es mejor que dejar los nombres asignados solo. La falta de documentación solo contribuye a mi escepticismo al respecto.

Ser capaz de asignar variables de entorno en reglas de reescritura es útil, o al menos, lo sería. Pero la utilidad se ve muy disminuida por este comportamiento de cambio de nombre. La complejidad de esta publicación ilustra cuán loco es este comportamiento y los obstáculos que deben superarse para tratar de superarlo.


No he probado esto en absoluto y sé que no aborda los puntos A o B, pero hay una descripción de este problema en los comentarios en la documentación de PHP y algunas posibles soluciones para acceder a estas variables usando $_SERVER[''VAR'']

http://www.php.net/manual/en/reserved.variables.php#79811

EDITAR - algunas respuestas más a la pregunta ofrecida:

A: Apache renombra las variables de entorno si están involucradas en una redirección. Por ejemplo, si tiene la siguiente regla:

RewriteRule ^index.php - [E=VAR1:''hello'',E=VAR2:''world'']

Luego puede acceder a VAR1 y VAR2 usando $_SERVER[''VAR1''] y $_SERVER[''VAR2''] . Sin embargo, si redirige la página así:

RewriteRule ^index.php index2.php [E=VAR1:''hello'',E=VAR2:''world'']

Luego debe usar $_SERVER[''REDIRECT_VAR1''] , etc.

B: La mejor manera de superar este problema es procesar las variables que te interesen usando PHP. Cree una función que se ejecute a través de la matriz $_SERVER y encuentre los elementos que necesita. Incluso podría usar una función como esta:

function myGetEnv($key) { $prefix = "REDIRECT_"; if(array_key_exists($key, $_SERVER)) return $_SERVER[$key]; foreach($_SERVER as $k=>$v) { if(substr($k, 0, strlen($prefix)) == $prefix) { if(substr($k, -(strlen($key))) == $key) return $v; } } return null; }