PHP_SELF vs PATH_INFO vs SCRIPT_NAME vs REQUEST_URI

105

Buduję aplikację PHP w CodeIgniter. CodeIgniter wysyła wszystkie żądania do głównego kontrolera: index.php. Jednak nie lubię widzieć index.phpw URI. Na przykład http://www.example.com/faq/whateverprzekieruje do http://www.example.com/index.php/faq/whatever. Potrzebuję wiarygodnego sposobu, aby skrypt wiedział, jaki jest adres, aby wiedział, co zrobić z nawigacją. Użyłem mod_rewrite, zgodnie z dokumentacją CodeIgniter.

Zasada jest następująca:

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

Normalnie po prostu sprawdziłbym php_self, ale w tym przypadku tak jest zawsze index.php. Mogę dostać od REQUEST_URI, PATH_INFOitp, ale staram się zdecydować, który będzie najbardziej wiarygodne. Czy ktoś wie (lub wie gdzie znaleźć) prawdziwa różnica pomiędzy PHP_SELF, PATH_INFO, SCRIPT_NAME, i REQUEST_URI? Dzięki za pomoc!

Uwaga : musiałem dodać spacje, ponieważ SO widzi podkreślenie i z jakiegoś powodu czyni go kursywą.

Zaktualizowano : Naprawiono spacje.

Eli
źródło

Odpowiedzi:

50

Dokumentacja PHP może ci powiedzieć różnicę:

„PHP_SELF”

Nazwa pliku aktualnie wykonywanego skryptu względem katalogu głównego dokumentu. Na przykład $ _SERVER ['PHP_SELF'] w skrypcie pod adresem http://example.com/test.php/foo.bar będzie wyglądać następująco: /test.php/foo.bar . __FILE__ stała zawiera pełną ścieżkę i nazwę pliku prądu (czyli włączone) pliku. Jeśli PHP działa jako procesor wiersza poleceń, zmienna ta zawiera nazwę skryptu od wersji PHP 4.3.0. Wcześniej nie był dostępny.

„SCRIPT_NAME”

Zawiera ścieżkę do aktualnego skryptu. Jest to przydatne w przypadku stron, które muszą wskazywać na siebie. __FILE__ stała zawiera pełną ścieżkę i nazwę pliku prądu (czyli włączone) pliku.

„REQUEST_URI”

URI, który został podany w celu uzyskania dostępu do tej strony; na przykład „/index.html” .

PATH_INFO nie wydaje się być udokumentowane ...

Jeremy Ruten
źródło
3
Najprawdopodobniej nie dotyczy to dokumentacji PHP, ale CGI :) I tam jest udokumentowana PATH_INFO: tools.ietf.org/html/rfc3875#section-4 Ale są pewne znane problemy, które Apache i nginx nie zawsze dają tę zmienną.
SimonSimCity,
1
Poniższa odpowiedź Odyna zawiera przydatne wyjaśnienia, które są uzupełnione przykładami. Trudno mi zrozumieć, co te zmienne reprezentują w ogólnym kontekście z path_info, ciągiem zapytania, pewnym przekierowaniem, niektórymi aliasami, w różnych systemach operacyjnych, od CLI vs SERVER itp.
4
-1 Tak samo jak wyjaśnienie, dlaczego przegłosowałem: cały powód, dla którego trafiłem do tego posta, jest taki, że dokumentacja nie jest jasna. Poniższa odpowiedź Odyna zawiera jasne wyjaśnienie różnic między tymi zmiennymi. Wydaje mi się, że to niewystarczająca odpowiedź, aby po prostu skopiować i wkleić łatwo znalezione, ale także niewystarczającą dokumentację. Wydaje mi się, że większość ludzi musiałaby już zajrzeć do dokumentacji, aby dowiedzieć się chociażby o liście elementów w zmiennej $ _SERVER wspomnianej powyżej.
dallin
230

Kilka praktycznych przykładów różnic między tymi zmiennymi:
Przykład 1. PHP_SELF różni się od SCRIPT_NAME tylko wtedy, gdy żądany adres URL ma postać:
http://example.com/test.php/foo/bar

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

(wydaje się, że jest to jedyny przypadek, gdy PATH_INFO zawiera sensowne informacje [PATH_INFO] => / foo / bar) Uwaga: kiedyś było inaczej w niektórych starszych wersjach PHP (<= 5.0?).

Przykład 2. REQUEST_URI różni się od SCRIPT_NAME, gdy wprowadzono niepusty ciąg zapytania:
http://example.com/test.php?foo=bar

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

Przykład 3. REQUEST_URI różni się od SCRIPT_NAME, gdy działa przekierowanie po stronie serwera (na przykład mod_rewrite w apache):

http://example.com/test.php

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

Przykład 4. REQUEST_URI różni się od SCRIPT_NAME podczas obsługi błędów HTTP w skryptach.
Korzystanie z dyrektywy Apache ErrorDocument 404 /404error.php
http://example.com/test.php

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

Na serwerze IIS przy użyciu niestandardowych stron błędów
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php
Odyn
źródło
21
+1, „Przykład nie jest sposobem na naukę, to jedyny sposób na naukę”. - Zawsze muszę to sprawdzić, bardzo fajnie wyszukuję błędy 404. =)
Alix Axel
16
+1: pierwszy raz w życiu zrozumiałem różnicę. Powinni zaktualizować dokumentację PHP twoją odpowiedzią
Marco Demaio
Przykład1: [SCRIPT_NAME] => /test.php/ Na końcu nie powinno być znaku „/”: Przykład1: [SCRIPT_NAME] => /test.php Tak czy inaczej widzę w PHP 5.3.6. Niezłe przykłady.
Dawid Ohia
Masz rację JohnM2, sprawdziłem teraz w PHP 5.4, a wynik dla adresu URL /pinfo.php/first/second?third=fourth jest następujący: QUERY_STRING => third = 4th REQUEST_URI => /pinfo.php/first/second ? trzeci = czwarty SCRIPT_NAME => /pinfo.php PATH_INFO => / first / second
Odin
Przetestowałem to również w 5.2.17 i nie ma /na końcu SCRIPT_NAME. Wydaje się to być spójne w PHP 5.2-5.4, biorąc pod uwagę edycję odpowiedzi, aby to odzwierciedlić.
Fabrício Matté,
24

PATH_INFO jest dostępne tylko podczas korzystania z htaccess w następujący sposób:

Przykład 1

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

Pozostaje takie samo

[SCRIPT_NAME] => /index.php

Korzeń

http://domain.com/

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

Ścieżka

http://domain.com/test

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

Ciąg zapytania

http://domain.com/test?123

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

Przykład 2

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

Pozostaje takie samo

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

Korzeń

http://domain.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Ścieżka

http://domain.com/test

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

Ciąg zapytania

http://domain.com/test?123

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

Przykład 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]

lub

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]

Pozostaje takie samo

[SCRIPT_NAME] => /index.php

Korzeń

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

Ścieżka

http://domain.com/test

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

Język

http://domain.com/en

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

Ścieżka językowa

http://domain.com/en/test

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

Ciąg zapytania językowego

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
Mikrofon
źródło
To było świetne. Dzięki za pomoc!
Gabriel Fair
1
Ta odpowiedź jest napisana w sposób, który sugeruje, że tylko przepisanie adresu URL może utworzyć path_info, ale oczywiście informacje o ścieżce można wprowadzić bezpośrednio w oryginalnym adresie URL.
12

Ścieżki PHP

    $_SERVER['REQUEST_URI']    = Ścieżka sieciowa, żądany URI
    $_SERVER['PHP_SELF']    = ścieżka sieciowa, żądany plik + ścieżka info
    $_SERVER['SCRIPT_NAME']    = ścieżka sieciowa, żądany plik
    $_SERVER['SCRIPT_FILENAME']   = ścieżka do pliku, żądany plik
    __FILE__    = ścieżka do pliku, bieżący plik

Gdzie

  • Ścieżka do pliku jest ścieżką do pliku systemowego, podobnie jak /var/www/index.phppo rozwiązaniu aliasu
  • Ścieżka internetowa to ścieżka dokumentu serwera, taka jak /index.phpz http://foo.com/index.php, i może nawet nie pasować do żadnego pliku
  • Bieżący plik oznacza dołączony plik skryptu , a nie żaden skrypt, który go zawiera
  • Żądany plik oznacza plik skryptu dołączanego , a nie dołączony
  • URI to żądanie HTTP, podobnie jak /index.php?foo=barprzed przepisaniem adresu URL
  • Informacje o ścieżce to wszelkie dodatkowe dane Apache znajdujące się po nazwie skryptu, ale przed ciągiem zapytania

Kolejność operacji

  1. Klient wysyła do serwera żądanie HTTP REQUEST_URI
  2. Serwer wykonuje przepisywanie adresów URL z plików .htaccess itp., Aby je pobraćPHP_SELF
  3. Serwer rozdziela się PHP_SELFna SCRIPT_FILENAME+PATH_INFO
  4. Serwer wykonuje rozdzielczości alias i zamienia całą ścieżkę URL do ścieżki pliku systemu , aby uzyskaćSCRIPT_FILENAME
  5. Wynikowy plik skryptu może zawierać inne, gdzie __FILE__odnosi się do ścieżki do bieżącego pliku
Beejor
źródło
To jest dobre. Oto moje komentarze. Po pierwsze, zarówno $ _SERVER ['SCRIPT_NAME'], jak i $ _SERVER ['SCRIPT_FILENAME'] to nazwa skryptu, z tą różnicą, że późniejsza jest po wykonaniu aliasów. Po drugie, $ _SERVER ['PHP_SELF'] nie jest skryptem, ale skryptem + informacją o ścieżce. Ponownie, $ _SERVER ['SCRIPT_NAME'] to skrypt (przed aliasami). Na koniec warto wiedzieć, na jakim etapie, po lub przed regułami przepisywania, po lub przed aliasami, te zmienne są definiowane. Zobacz moją odpowiedź.
@ Dominic108 Poprawiłem swoją odpowiedź na podstawie twoich sugestii, trochę uporządkowałem i dodałem sekcję Kolejność operacji. Powiedz mi co myślisz. Dzięki!
Beejor
W swoim zamówieniu musisz zamienić $_SERVER['SCRIPT_NAME']i   $_SERVER['PHP_SELF']ponieważ mod_rewrite tworzysz całą ścieżkę, czyli $_SERVER['PHP_SELF']. Następuje separacja. Należy zauważyć, że aliasy uwzględniają również całą ścieżkę do zdefiniowania nazwy pliku skryptu, ale separacja, która zdefiniowana nazwa_skryptu i informacje_ścieżki już wystąpiła, nie będzie miała na nie wpływu.
@ Dominic108 Ponownie poprawiłem odpowiedź. Z jakiegoś powodu Twoja propozycja edycji została odrzucona, chociaż o ile wiem, masz rację, że dwa z moich elementów były niesprawne. Nie znam aliasów, więc w tej kwestii polegam na twojej wiedzy. Dzięki jeszcze raz!
Beejor
5

Możesz zajrzeć do klasy URI i skorzystać z $ this-> uri-> uri_string ()

Zwraca ciąg z pełnym identyfikatorem URI.

Na przykład, jeśli to jest Twój pełny adres URL:

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

Funkcja zwróci to:

/news/local/345

Możesz też wykorzystać segmenty do drążenia określonych obszarów bez konieczności opracowywania analizowania / wartości wyrażenia regularnego

Adam
źródło
Dziękuję - to dobry pomysł, ale używam ich w haku przed systemem, który będzie musiał zostać uruchomiony, zanim kontroler zostanie uruchomiony.
Eli
4

Osobiście używam, $REQUEST_URIponieważ odwołuje się do wprowadzonego URI, a nie do lokalizacji na dysku serwera.

Xenph Yan
źródło
Czy jest to zawsze pełny identyfikator URI?
Eli
Zwykle możesz napotkać problemy z apache w systemie Windows, ale dotyczy to tylko identyfikatorów URI, które nie rozwiązują.
Xenph Yan
4

Do odpowiedzi Odyna można dodać bardzo niewiele. Po prostu poczułem, że mogę podać kompletny przykład z żądania HTTP do rzeczywistego pliku w systemie plików, aby zilustrować skutki przepisywania adresów URL i aliasów. W systemie plików skrypt /var/www/test/php/script.phpto

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

gdzie /var/www/test/php/script_included.phpjest

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

i /var/www/test/.htaccess jest

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

a plik konfiguracyjny Apache zawiera alias

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

a żądanie http to

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

Wynik będzie

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

Zawsze obowiązuje

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

Jeśli nie ma mod_rewrite, mod_dir, przepisywania ErrorDocument lub jakiejkolwiek formy przepisywania adresu URL, mamy również

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

Aliasy wpływają na systemowe ścieżki plików, SCRIPT_FILENAMEa __FILE__nie na ścieżki URL, które zostały wcześniej zdefiniowane - zobacz wyjątki poniżej. Aliasy mogą wykorzystywać całą ścieżkę adresu URL, w tym PATH_INFO. W ogóle nie mogło być żadnego połączenia między SCRIPT_NAMEa SCRIPT_FILENAME.

Nie jest całkowicie dokładne, że aliasy nie są rozwiązywane w momencie [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] definiowania ścieżki URL , ponieważ uważa się, że aliasy przeszukują system plików, a wiemy z przykładu 4 w odpowiedzi Odyna, że ​​system plików jest przeszukiwany w celu ustalenia, czy plik istnieje, ale ma to znaczenie tylko wtedy, gdy plik nie zostanie znaleziony. Podobnie, mod_dir wywołuje mod_alias w celu przeszukania systemu plików, ale ma to znaczenie tylko wtedy, gdy masz alias taki jak, Alias \index.php \var\www\index.phpa uri żądania jest katalogiem.


źródło
Cześć Dominic108, dzięki za korektę. Myślę, że warto dołączyć informacje o przepisaniu. Dla mnie było to zasugerowane, ale dla innych może nie być tak intuicyjne.
Beejor
1

Jeśli kiedykolwiek zapomnisz, które zmienne co robią, możesz napisać mały skrypt, który używa phpinfo () i wywołać go z adresu URL z ciągiem zapytania. Ponieważ instalacje oprogramowania serwera przedstawiają zmienne zwracane przez PHP, zawsze dobrym pomysłem jest sprawdzenie danych wyjściowych maszyny na wypadek, gdyby ponowne zapisywanie w pliku konfiguracyjnym serwera powodowało inne wyniki niż oczekiwano. Zapisz to jako coś takiego _inf0.php:

<?php
    $my_ip = '0.0.0.0';

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

Wtedy byś zadzwonił /_inf0.php?q=500

Zero absolutne
źródło
-1

Zrób kopię zapasową na sekundę, na początku wybrałeś niewłaściwe podejście. Dlaczego po prostu tego nie zrobić

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

zamiast? Następnie złap go$_GET['url'];

Kate Gregory
źródło
Po co odkrywać koło na nowo? Dostęp do tych danych jest znacznie łatwiejszy!
Kenneth,
Dodatkowa złożoność występuje, jeśli oczekuje się, że pierwotne żądanie zawiera ciąg zapytania. W obecnym stanie powyższy kod po prostu nadpisze ciąg zapytania. Jeśli scalisz ciągi zapytań ( QSAflaga), parametry ciągu zapytania mogą zostać potencjalnie nadpisane (na przykład, jeśli potrzebujesz urlparametru w początkowym żądaniu) lub, co gorsza, być podatnym na ataki XSS.
MrWhite