PHP_SELF vs PATH_INFO vs SCRIPT_NAME vs REQUEST_URI

105

Estou construindo um aplicativo PHP no CodeIgniter. CodeIgniter envia todos os pedidos para o controlador principal: index.php. No entanto, não gosto de ver index.phpno URI. Por exemplo, http://www.example.com/faq/whateverirá direcionar para http://www.example.com/index.php/faq/whatever. Preciso de uma maneira confiável para um script saber qual é o seu endereço, para que ele saiba o que fazer com a navegação. Eu usei mod_rewrite, de acordo com a documentação do CodeIgniter.

A regra é a seguinte:

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

Normalmente, eu apenas verificaria php_self, mas neste caso é sempre index.php. Posso obtê-lo em REQUEST_URI, PATH_INFOetc., mas estou tentando decidir qual será o mais confiável. Alguém sabe (ou sabe onde encontrar) a real diferença entre PHP_SELF, PATH_INFO, SCRIPT_NAME, e REQUEST_URI? Obrigado pela ajuda!

Nota : Tive de adicionar espaços, pois o SO vê o sublinhado e o deixa em itálico por algum motivo.

Atualizado : Corrigidos os espaços.

Eli
fonte

Respostas:

51

A documentação do PHP pode dizer a diferença:

'PHP_SELF'

O nome do arquivo do script atualmente em execução, relativo à raiz do documento. Por exemplo, $ _SERVER ['PHP_SELF'] em um script no endereço http://example.com/test.php/foo.bar seria /test.php/foo.bar . A constante __FILE__ contém o caminho completo e o nome do arquivo do arquivo atual (ou seja, incluído). Se o PHP estiver rodando como um processador de linha de comando, esta variável contém o nome do script desde o PHP 4.3.0. Anteriormente, não estava disponível.

'SCRIPT_NAME'

Contém o caminho do script atual. Isso é útil para páginas que precisam apontar para si mesmas. A constante __FILE__ contém o caminho completo e o nome do arquivo do arquivo atual (ou seja, incluído).

'REQUEST_URI'

O URI que foi fornecido para acessar esta página; por exemplo, '/index.html' .

PATH_INFO não parece estar documentado ...

Jeremy Ruten
fonte
3
Provavelmente não se trata da documentação do PHP, mas do CGI :) E lá PATH_INFO está documentado: tools.ietf.org/html/rfc3875#section-4 Mas existem alguns problemas conhecidos que o Apache e o nginx nem sempre fornecem essa variável.
SimonSimCity
1
A resposta de Odin abaixo adiciona explicações úteis que são complementadas com exemplos. Acho difícil entender o que essas variáveis ​​representam em um contexto geral com um path_info, uma string de consulta, alguns redirecionamentos, alguns aliases, em sistemas operacionais diferentes, de CLI vs SERVER, etc.
3
-1 Apenas como uma explicação de porque eu votei contra: todo o motivo pelo qual vim para este post é porque a documentação não é clara. A resposta de Odin abaixo fornece uma explicação clara das diferenças entre essas variáveis. Eu sinto que é uma resposta insuficiente apenas copiar e colar facilmente encontrada, mas também documentação insuficiente. Acredito que a maioria das pessoas já teria que visitar a documentação para saber sobre a lista de elementos na variável $ _SERVER mencionada acima.
dallin
229

Alguns exemplos práticos das diferenças entre essas variáveis:
Exemplo 1. PHP_SELF é diferente de SCRIPT_NAME apenas quando a url solicitada está no formato:
http://example.com/test.php/foo/bar

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

(este parece ser o único caso em que PATH_INFO contém informações importantes [PATH_INFO] => / foo / bar) Nota: isso costumava ser diferente em algumas versões anteriores do PHP (<= 5.0?).

Exemplo 2. REQUEST_URI é diferente de SCRIPT_NAME quando uma string de consulta não vazia é inserida:
http://example.com/test.php?foo=bar

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

Exemplo 3. REQUEST_URI é diferente de SCRIPT_NAME quando o redirecionamento do lado do servidor está em vigor (por exemplo, mod_rewrite no apache):

http://example.com/test.php

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

Exemplo 4. REQUEST_URI é diferente de SCRIPT_NAME ao lidar com erros HTTP com scripts.
Usando a diretiva do apache ErrorDocument 404 /404error.php
http://example.com/test.php

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

No servidor IIS usando páginas de erro personalizadas
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php
Odin
fonte
21
+1, "Um exemplo não é uma maneira de aprender, é a única maneira de aprender." - Eu sempre tenho que verificar novamente essas coisas, uma pesquisa muito boa sobre os erros 404. =)
Alix Axel
16
+1: 1ª vez na minha vida entendi a diferença. Eles devem atualizar a documentação PHP com sua resposta
Marco Demaio
Exemplo1: [SCRIPT_NAME] => /teste.php/ Não deve haver nenhum "/" no final: Exemplo1: [SCRIPT_NAME] => /teste.php De qualquer forma é o que vejo no PHP 5.3.6. Bons exemplos.
Dawid Ohia
Você está correto JohnM2, agora verifiquei no PHP 5.4 e o resultado para URL /pinfo.php/first/second?third=fourth é o seguinte: QUERY_STRING => terceiro = quarto REQUEST_URI => /pinfo.php/first/second ? terceiro = quarto SCRIPT_NAME => /pinfo.php PATH_INFO => / primeiro / segundo
Odin
Eu testei isso em 5.2.17 também e não há /no final do SCRIPT_NAME. Isso parece ser consistente no PHP 5.2-5.4 então, considerando editar a resposta para refletir isso.
Fabrício Matté
24

PATH_INFO só está disponível ao usar htaccess desta forma:

Exemplo 1

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

Continua o mesmo

[SCRIPT_NAME] => /index.php

Raiz

http://domain.com/

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

Caminho

http://domain.com/test

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

String de consulta

http://domain.com/test?123

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

Exemplo 2

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

Continua o mesmo

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

Raiz

http://domain.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Caminho

http://domain.com/test

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

String de consulta

http://domain.com/test?123

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

Exemplo 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]

ou

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]

Continua o mesmo

[SCRIPT_NAME] => /index.php

Raiz

http://domain.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

Caminho

http://domain.com/test

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

Língua

http://domain.com/en

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

Caminho da linguagem

http://domain.com/en/test

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

String de consulta de linguagem

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
Mike
fonte
Isso foi ótimo. Obrigado pela ajuda!
Gabriel Fair
1
Esta resposta foi escrita de uma forma que sugere que apenas a reescrita de url pode criar um path_info, mas, é claro, as informações do caminho podem ser inseridas diretamente no URL original.
12

Caminhos PHP

    $_SERVER['REQUEST_URI']    = Caminho da Web, URI solicitado
    $_SERVER['PHP_SELF']    = Caminho da Web, arquivo solicitado + informações do caminho
    $_SERVER['SCRIPT_NAME']    = Caminho da Web, arquivo solicitado
    $_SERVER['SCRIPT_FILENAME']   = Caminho do arquivo, arquivo solicitado
    __FILE__    = Caminho do arquivo, arquivo atual

Onde

  • O caminho do arquivo é um caminho de arquivo do sistema como /var/www/index.php, após a resolução do alias
  • O caminho da Web é um caminho de documento do servidor como /index.phpde http://foo.com/index.phpe pode nem corresponder a nenhum arquivo
  • Arquivo atual significa o arquivo de script incluído , não qualquer script que o inclua
  • Arquivo solicitado significa o arquivo de script includer , não o incluído
  • URI é a solicitação HTTP como /index.php?foo=bar, antes de qualquer regravação de URL
  • A informação do caminho é qualquer dado Apache extra localizado após o nome do script, mas antes da string de consulta

Ordem de Operação

  1. O cliente envia ao servidor uma solicitação HTTP REQUEST_URI
  2. O servidor executa qualquer reescrita de URL a partir de arquivos .htaccess, etc. para obterPHP_SELF
  3. Servidor separa PHP_SELFem SCRIPT_FILENAME+PATH_INFO
  4. O servidor executa a resolução de alias e converte todo o caminho do url em um caminho de arquivo do sistema para obterSCRIPT_FILENAME
  5. O arquivo de script resultante pode incluir outros, onde __FILE__se refere ao caminho para o arquivo atual
Beejor
fonte
Isso é bom. Aqui estão meus comentários. Primeiro, tanto $ _SERVER ['SCRIPT_NAME'] e $ _SERVER ['SCRIPT_FILENAME'] são nomes de script, exceto que o último é após a execução de aliases. Em segundo lugar, $ _SERVER ['PHP_SELF'] não é o script, mas o script + a informação do caminho. Novamente, $ _SERVER ['SCRIPT_NAME'] é o script (antes dos apelidos). Finalmente, é útil saber em que estágio, depois ou antes das regras de reescrita, depois ou antes dos aliases, essas variáveis ​​são definidas. Veja minha resposta.
@ Dominic108 Revisei minha resposta com base em suas sugestões, arrumei um pouco as coisas e adicionei uma seção de Ordem de Operação. Diz-me o que pensas. Obrigado!
Beejor
Em seu pedido, você tem que trocar $_SERVER['SCRIPT_NAME']e   $_SERVER['PHP_SELF'], porque mod_rewrite criar o caminho inteiro, que é $_SERVER['PHP_SELF']. A separação ocorre a seguir. Observe que os aliases também consideram o caminho inteiro para definir o nome do arquivo do script, mas a separação que definiu script_name e path_info já ocorreu, portanto, eles não serão afetados.
@ Dominic108 Revisei minha resposta novamente. Por algum motivo, sua proposta de edição foi rejeitada, embora, pelo que eu saiba, você está correto ao dizer que dois de meus itens estavam fora de ordem. Não estou tão familiarizado com aliases, então conto com sua experiência para essa parte. Obrigado novamente!
Beejor de
5

Você pode querer olhar para a classe URI e fazer uso de $ this-> uri-> uri_string ()

Retorna uma string com o URI completo.

Por exemplo, se este for o seu URL completo:

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

A função retornaria este:

/news/local/345

Ou você pode usar os segmentos para detalhar áreas específicas sem ter que criar valores de análise / regex

Adão
fonte
Obrigado - esta é uma boa ideia, mas estou usando isso em um gancho pré-sistema que precisará ser executado antes que o controlador esteja instalado e funcionando.
Eli
4

Pessoalmente, eu uso o $REQUEST_URIporque ele faz referência ao URI inserido e não ao local no disco do servidor.

Xenph Yan
fonte
É sempre o URI completo?
Eli
Normalmente, você pode ter problemas com o apache no Windows, mas é apenas para URIs que não resolvem.
Xenph Yan
4

Há muito pouco a acrescentar à resposta de Odin. Eu acabei de fornecer um exemplo completo da solicitação HTTP para o arquivo real no sistema de arquivos para ilustrar os efeitos da regravação de URL e aliases. No sistema de arquivos, o script /var/www/test/php/script.phpé

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

onde /var/www/test/php/script_included.phpestá

<?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>";  
?>

e /var/www/test/.htaccess é

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

e o arquivo de configuração do Apache inclui o alias

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

e a solicitação http é

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

A saída 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

O seguinte sempre é válido

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

Se não houver mod_rewrite, mod_dir, reescrita de ErrorDocument ou qualquer forma de reescrita de URL, também temos

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

Os aliases afetam os caminhos de arquivo do sistema SCRIPT_FILENAMEe __FILE__não os caminhos de URL, que são definidos antes - consulte as exceções abaixo. Os aliases podem usar todo o caminho do URL, incluindo PATH_INFO. Não poderia haver nenhuma conexão entre SCRIPT_NAMEe SCRIPT_FILENAME.

Não é totalmente exato que os aliases não são resolvidos no momento em que o caminho da URL [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] é definido, porque os aliases são considerados para pesquisar o sistema de arquivos e sabemos pelo exemplo 4 na resposta de Odin que o sistema de arquivos é pesquisado para determinar se o arquivo existe, mas isso só é relevante quando o arquivo não é encontrado. Da mesma forma, mod_dir chama mod_alias para pesquisar o sistema de arquivos, mas isso só é relevante se você tiver um alias como Alias \index.php \var\www\index.phpe o uri de solicitação for um diretório.


fonte
Olá, Dominic108, obrigado pela revisão. Eu acho que é útil incluir as informações de reescrita. Para mim estava implícito, mas para outros pode não ser tão intuitivo.
Beejor
1

Se você esquecer quais variáveis ​​fazem o quê, você pode escrever um pequeno script que use phpinfo () e chamá-lo de um URL com uma string de consulta. Uma vez que as instalações de software de servidor apresentam as variáveis ​​que o PHP retorna, é sempre uma boa ideia verificar a saída da máquina, caso reescritas no arquivo de configuração do servidor estejam causando resultados diferentes do esperado. Salve-o como algo como _inf0.php:

<?php
    $my_ip = '0.0.0.0';

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

Então você ligaria /_inf0.php?q=500

Zero absoluto
fonte
-1

Faça backup por um segundo, você escolheu a abordagem errada para começar. Por que não apenas fazer isso

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

em vez de? Então pegue com$_GET['url'];

Kate Gregory
fonte
Por que reinventar a roda? Esses dados são acessados ​​muito mais facilmente!
Kenneth,
E haverá complexidade adicional se a solicitação original tiver uma string de consulta. Em seu estado atual, o código acima simplesmente substituirá a string de consulta. Se você mesclar strings de consulta ( QSAsinalizador), os parâmetros de string de consulta podem ser substituídos (por exemplo, se você precisar de um urlparâmetro na solicitação inicial) ou, pior, ficar vulnerável a ataques XSS.
MrWhite