PHP_SELF frente a PATH_INFO frente a SCRIPT_NAME frente a REQUEST_URI


105

Estoy construyendo una aplicación PHP en CodeIgniter. CodeIgniter envía todas las peticiones al controlador principal: index.php. Sin embargo, no me gusta ver index.phpen el URI. Por ejemplo, http://www.example.com/faq/whateverse enrutará a http://www.example.com/index.php/faq/whatever. Necesito una forma confiable para que un script sepa cuál es su dirección, para que sepa qué hacer con la navegación. He usado mod_rewrite, según la documentación de CodeIgniter.

La regla es la siguiente:

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L] 

Normalmente, lo comprobaría php_self, pero en este caso siempre es así index.php. Puedo obtener de REQUEST_URI, PATH_INFO, etc, pero estoy tratando de decidir cuál será la más fiable. ¿Alguien sabe (o saber dónde encontrar) la diferencia real entre PHP_SELF, PATH_INFO, SCRIPT_NAMEy REQUEST_URI? ¡Gracias por tu ayuda!

Nota : Tuve que agregar espacios, ya que SO ve el guión bajo y lo pone en cursiva por alguna razón.

Actualizado : Se corrigieron los espacios.

Respuestas:


51

La documentación de PHP puede decirle la diferencia:

'PHP_SELF'

El nombre de archivo del script que se está ejecutando actualmente, relativo a la raíz del documento. Por ejemplo, $ _SERVER ['PHP_SELF'] en un script en la dirección http://example.com/test.php/foo.bar sería /test.php/foo.bar . La constante __FILE__ contiene la ruta completa y el nombre de archivo del archivo actual (es decir, incluido). Si PHP se ejecuta como un procesador de línea de comandos, esta variable contiene el nombre del script desde PHP 4.3.0. Anteriormente no estaba disponible.

'SCRIPT_NAME'

Contiene la ruta del script actual. Esto es útil para páginas que necesitan apuntar a sí mismas. La constante __FILE__ contiene la ruta completa y el nombre de archivo del archivo actual (es decir, incluido).

"REQUEST_URI"

El URI que se proporcionó para acceder a esta página; por ejemplo, '/index.html' .

PATH_INFO no parece estar documentado ...


3
Lo más probable es que no se trate de la documentación de PHP sino del CGI :) Y allí está documentado PATH_INFO: tools.ietf.org/html/rfc3875#section-4 Pero hay algunos problemas conocidos que Apache y nginx no siempre dan a esta variable.
SimonSimCity

1
La respuesta de Odin a continuación agrega explicaciones útiles que se complementan con ejemplos. Me resulta difícil entender qué representan estas variables en un contexto general con path_info, una cadena de consulta, alguna redirección, algunos alias, en diferentes sistemas operativos, desde CLI vs SERVER, etc.

3
-1 Solo como una explicación de por qué voté en contra: la razón completa por la que vine a esta publicación es porque la documentación no es clara. La respuesta de Odin a continuación proporciona una explicación clara de las diferencias entre estas variables. Siento que es una respuesta insuficiente copiar y pegar fácilmente, pero también documentación insuficiente. Creo que la mayoría de la gente ya habría tenido que visitar la documentación para conocer la lista de elementos en la variable $ _SERVER mencionada anteriormente.
dallin

229

Algunos ejemplos prácticos de las diferencias entre estas variables:
Ejemplo 1. PHP_SELF es diferente de SCRIPT_NAME solo cuando la URL solicitada tiene el formato:
http://example.com/test.php/foo/bar

[PHP_SELF] => /test.php/foo/bar
[SCRIPT_NAME] => /test.php

(Este parece ser el único caso en el que PATH_INFO contiene información sensible [PATH_INFO] => / foo / bar) Nota: esto solía ser diferente en algunas versiones anteriores de PHP (<= 5.0?).

Ejemplo 2. REQUEST_URI es diferente de SCRIPT_NAME cuando se ingresa una cadena de consulta no vacía:
http://example.com/test.php?foo=bar

[SCRIPT_NAME] => /test.php
[REQUEST_URI] => /test.php?foo=bar

Ejemplo 3. REQUEST_URI es diferente de SCRIPT_NAME cuando la redirección del lado del servidor está en efecto (por ejemplo, mod_rewrite en apache):

http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /test2.php

Ejemplo 4. REQUEST_URI es diferente de SCRIPT_NAME cuando se manejan errores HTTP con scripts.
Usando la directiva de apache ErrorDocument 404 /404error.php
http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /404error.php

En el servidor IIS usando páginas de error personalizadas
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php

21
+1, "Un ejemplo no es una forma de aprender, es la única forma de aprender". - Siempre tengo que volver a comprobar estas cosas, muy buena investigación sobre los errores 404. =)
Alix Axel

16
+1: Primera vez en mi vida que entendí la diferencia. Deberían actualizar la documentación de PHP con su respuesta
Marco Demaio

Example1: [SCRIPT_NAME] => /test.php/ No debería haber "/" al final: Example1: [SCRIPT_NAME] => /test.php De todos modos, eso es lo que veo en PHP 5.3.6. Buenos ejemplos.
Dawid Ohia

Estás en lo correcto JohnM2, ahora he verificado PHP 5.4 y el resultado de la URL /pinfo.php/first/second?third=fourth es el siguiente: QUERY_STRING => third = 4th REQUEST_URI => /pinfo.php/first/second ? tercero = cuarto SCRIPT_NAME => /pinfo.php PATH_INFO => / primero / segundo
Odin

También probé esto en 5.2.17 y no hay /al final del SCRIPT_NAME. Esto parece ser consistente en PHP 5.2-5.4 entonces, considerando editar la respuesta para reflejar eso.
Fabrício Matté

24

PATH_INFO solo está disponible cuando se usa htaccess de esta manera:

Ejemplo 1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Sigue siendo el mismo

[SCRIPT_NAME] => /index.php

Raíz

http://dominio.com/

[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]  => /
[QUERY_STRING] => 

Camino

http://domain.com/test

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test
[QUERY_STRING] => 

Cadena de consulta

http://domain.com/test?123

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test?123
[QUERY_STRING] => 123

Ejemplo 2

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

Sigue siendo el mismo

[SCRIPT_NAME]  => /index.php
[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)

Raíz

http://dominio.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Camino

http://domain.com/test

[REQUEST_URI]  => /test
[QUERY_STRING] => url=test

Cadena de consulta

http://domain.com/test?123

[REQUEST_URI]  => /test?123
[QUERY_STRING] => url=test&123

Ejemplo 3

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(([a-z]{2})|(([a-z]{2})/)?(.*))$ index.php/$5 [NC,L,E=LANGUAGE:$2$4]

o

RewriteRule ^([a-z]{2})(/(.*))?$ $3 [NC,L,E=LANGUAGE:$1]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Sigue siendo el mismo

[SCRIPT_NAME] => /index.php

Raíz

http://dominio.com/

[PHP_SELF]          => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]       => /
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] IS NOT AVAILABLE

Camino

http://domain.com/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /test
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => 

Idioma

http://domain.com/en

[PHP_SELF]          => /index.php/
[PATH_INFO]         => /
[REQUEST_URI]       => /en
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => en

Ruta del idioma

http://domain.com/en/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test
[REDIRECT_LANGUAGE] => en

Cadena de consulta de idioma

http://domain.com/en/test?123

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test?123
[QUERY_STRING]      => 123
[REDIRECT_LANGUAGE] => en

Esto fue genial. ¡Gracias por tu ayuda!
Feria Gabriel

1
Esta respuesta está escrita de una manera que sugiere que solo la reescritura de la URL puede crear un path_info, pero, por supuesto, la información de la ruta se puede ingresar directamente en la URL original.

12

Rutas PHP

    $_SERVER['REQUEST_URI']    = Ruta web, URI solicitada
    $_SERVER['PHP_SELF']    = Ruta web, archivo solicitado + información de
    $_SERVER['SCRIPT_NAME']    ruta
    $_SERVER['SCRIPT_FILENAME']   = Ruta web, archivo solicitado = Ruta de archivo, archivo solicitado
    __FILE__    = Ruta de archivo, archivo actual

Dónde

  • La ruta del archivo es una ruta de archivo del sistema como /var/www/index.php, después de la resolución de alias
  • La ruta web es una ruta de documento del servidor como /index.phpdesde http://foo.com/index.php , y puede que ni siquiera coincida con ningún archivo
  • Archivo actual significa el archivo de script incluido , no cualquier script que lo incluya
  • El archivo solicitado significa el archivo de secuencia de comandos includer , no el incluido
  • URI es la solicitud HTTP como /index.php?foo=bar, antes de cualquier reescritura de URL
  • La información de ruta es cualquier dato Apache adicional ubicado después del nombre del script pero antes de la cadena de consulta

Orden de operación

  1. El cliente envía al servidor una solicitud HTTP REQUEST_URI
  2. El servidor realiza cualquier reescritura de URL desde archivos .htaccess, etc. para obtenerPHP_SELF
  3. El servidor se separa PHP_SELFen SCRIPT_FILENAME+PATH_INFO
  4. El servidor realiza la resolución de alias y convierte la ruta de URL completa en una ruta de archivo del sistema para obtenerSCRIPT_FILENAME
  5. El archivo de script resultante puede incluir otros, donde se __FILE__refiere a la ruta al archivo actual

Esto es bueno. Aquí están mis comentarios. Primero, tanto $ _SERVER ['SCRIPT_NAME'] como $ _SERVER ['SCRIPT_FILENAME'] son ​​nombres de script, excepto que el último es después de que se ejecutan los alias. En segundo lugar, $ _SERVER ['PHP_SELF'] no es el script, sino el script + la información de la ruta. Nuevamente, $ _SERVER ['SCRIPT_NAME'] es el script (antes de los alias). Finalmente, es útil saber en qué etapa, después o antes de rewrite-rules, después o antes de los alias, se definen estas variables. Mira mi respuesta.

@ Dominic108 Revisé mi respuesta en base a sus sugerencias, arreglé un poco las cosas y agregué una sección de Orden de operación. Déjame saber lo que piensas. ¡Gracias!
Beejor

En su orden, debe intercambiar $_SERVER['SCRIPT_NAME']y   $_SERVER['PHP_SELF'], debido a que mod_rewrite crea la ruta completa, que es $_SERVER['PHP_SELF']. La separación ocurre a continuación. Tenga en cuenta que los alias también consideran la ruta completa para definir el nombre del archivo del script, pero la separación que definió el script_name y path_info ya ocurrió, por lo que no se verán afectados.

@ Dominic108 Revisé mi respuesta nuevamente. Por alguna razón, su propuesta de edición fue rechazada, aunque hasta donde yo sé, tiene razón en que dos de mis elementos estaban fuera de servicio. No estoy tan familiarizado con los alias, así que confío en su experiencia para esa parte. ¡Gracias de nuevo!
Beejor

5

Es posible que desee examinar la clase URI y hacer uso de $ this-> uri-> uri_string ()

Devuelve una cadena con el URI completo.

Por ejemplo, si esta es su URL completa:

http://example.com/index.php/news/local/345

La función devolvería esto:

/news/local/345

O puede hacer uso de los segmentos para profundizar en áreas específicas sin tener que generar valores de análisis / expresión regular


Gracias, esta es una buena idea, pero los estoy usando en un enlace previo al sistema que deberá ejecutarse antes de que el controlador esté en funcionamiento.
Eli

4

Personalmente utilizo el $REQUEST_URIya que hace referencia al URI ingresado y no a la ubicación en el disco del servidor.


¿Es siempre el URI completo?
Eli

Por lo general, puede tener problemas con apache en Windows, pero es solo para URI que no se resuelven.
Xenph Yan

4

Hay muy poco que agregar a la respuesta de Odin. Solo sentí proporcionar un ejemplo completo de la solicitud HTTP al archivo real en el sistema de archivos para ilustrar los efectos de la reescritura de URL y los alias. En el sistema de archivos, el script /var/www/test/php/script.phpes

<?php
include ("script_included.php")
?>

donde /var/www/test/php/script_included.phpesta

<?php
echo "REQUEST_URI: " .  $_SERVER['REQUEST_URI'] . "<br>"; 
echo "PHP_SELF: " .  $_SERVER['PHP_SELF'] . "<br>";
echo "QUERY_STRING: " .  $_SERVER['QUERY_STRING'] . "<br>";
echo "SCRIPT_NAME: " .  $_SERVER['SCRIPT_NAME'] . "<br>";
echo "PATH_INFO: " .  $_SERVER['PATH_INFO'] . "<br>";
echo "SCRIPT_FILENAME: " . $_SERVER['SCRIPT_FILENAME'] . "<br>";
echo "__FILE__ : " . __FILE__ . "<br>";  
?>

y /var/www/test/.htaccess es

RewriteEngine On
RewriteRule before_rewrite/script.php/path/(.*) after_rewrite/script.php/path/$1 

y el archivo de configuración de Apache incluye el alias

Alias /test/after_rewrite/ /var/www/test/php/

y la solicitud http es

www.example.com/test/before_rewrite/script.php/path/info?q=helloword

La salida será

REQUEST_URI: /test/before_rewrite/script.php/path/info?q=helloword
PHP_SELF: /test/after_rewrite/script.php/path/info
QUERY_STRING: q=helloword
SCRIPT_NAME: /test/after_rewrite/script.php
PATH_INFO: /path/info
SCRIPT_FILENAME: /var/www/test/php/script.php
__FILE__ : /var/www/test/php/script_included.php

Lo siguiente siempre es válido

PHP_SELF = SCRIPT_NAME + PATH_INFO = full url path between domain and query string. 

Si no hay mod_rewrite, mod_dir, ErrorDocument rewrite o cualquier forma de reescritura de URL, también tenemos

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

Los alias afectan las rutas de los archivos del sistema SCRIPT_FILENAMEy __FILE__no las rutas URL, que se definieron anteriormente; consulte las excepciones a continuación. Los alias pueden utilizar toda la ruta de la URL, incluido PATH_INFO. No puede haber ninguna conexión entre SCRIPT_NAMEy SCRIPT_FILENAME.

No es totalmente exacto que los alias no se resuelvan en el momento en que [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] se define la ruta URL , porque se considera que los alias buscan en el sistema de archivos y sabemos por el ejemplo 4 en la respuesta de Odin que se busca en el sistema de archivos para determinar si el archivo existe. pero esto solo es relevante cuando no se encuentra el archivo. De manera similar, mod_dir llama a mod_alias para buscar en el sistema de archivos, pero esto solo es relevante si tiene un alias como Alias \index.php \var\www\index.phpy la solicitud uri es un directorio.


Hola Dominic108, gracias por la revisión. Creo que es útil incluir la información de reescritura. Para mí estaba implícito, pero para otros puede que no sea tan intuitivo.
Beejor

1

Si alguna vez olvida qué variables hacen qué, puede escribir un pequeño script que use phpinfo () y llamarlo desde una URL con una cadena de consulta. Dado que las instalaciones de software de servidor presentan las variables que devuelve PHP, siempre es una buena idea comprobar la salida de la máquina en caso de que las reescrituras en el archivo de configuración del servidor provoquen resultados diferentes a los esperados. Guárdelo como algo como _inf0.php:

<?php
    $my_ip = '0.0.0.0';

   if($_SERVER['REMOTE_ADDR']==$my_ip){
     phpinfo();
   } else {
     //something
   }

Entonces llamarías /_inf0.php?q=500


-1

Retrocede un segundo, has tomado el enfoque equivocado para empezar. ¿Por qué no hacer esto?

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php?url=$1 [L]

¿en lugar? Entonces agárralo con$_GET['url'];


¿Por qué reinventar la rueda? ¡Se puede acceder a estos datos mucho más fácilmente!
Kenneth

Y existe una complejidad adicional si se espera que la solicitud original tenga una cadena de consulta. En su estado actual, el código anterior simplemente sobrescribirá la cadena de consulta. Si fusiona cadenas de consulta ( QSAmarca), los parámetros de la cadena de consulta pueden potencialmente sobrescribirse (por ejemplo, si necesita un urlparámetro en la solicitud inicial) o peor aún, ser vulnerable a ataques XSS.
MrWhite
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.