PHP_SELF против PATH_INFO против SCRIPT_NAME против REQUEST_URI

Я создаю приложение PHP в CodeIgniter. CodeIgniter отправляет все запросы на главный контроллер: index.php. Однако мне не нравится видеть index.php в URI. Например, http://www.example.com/faq/whatever направит на http://www.example.com/index.php/faq/whatever. Мне нужен надежный способ, чтобы сценарий узнал свой адрес, чтобы он знал, что делать с навигацией. Я использовал mod_rewrite, согласно документации CodeIgniter.

Правило таково:

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

Обычно я бы просто проверял php_self, но в данном случае всегда index.php. Я могу получить его от REQUEST_URI, PATH_INFO и т. Д., Но пытаюсь решить, какой из них будет наиболее надежным. Кто-нибудь знает (или знает, где найти) настоящую разницу между PHP_SELF, PATH_INFO, SCRIPT_NAME и REQUEST_URI? Спасибо за вашу помощь!

Примечание: мне пришлось добавить пробелы, так как SO видит подчеркивание и почему-то делает его курсивом.

Обновлено: исправлены пробелы.


person Eli    schedule 11.11.2008    source источник


Ответы (9)


В документации PHP можно узнать разницу:

'PHP_SELF'

Имя файла исполняемого в данный момент скрипта относительно корня документа. Например, $ _SERVER ['PHP_SELF'] в скрипте по адресу http://example.com/test.php/foo.bar будет /test.php/foo.bar. Константа __FILE__ содержит полный путь и имя файла текущего ( т.е. включен) файл. Если PHP работает как процессор командной строки, эта переменная содержит имя сценария, начиная с PHP 4.3.0. Раньше не было в наличии.

"SCRIPT_NAME"

Содержит путь к текущему сценарию. Это полезно для страниц, которые должны указывать сами на себя. Константа __FILE__ содержит полный путь и имя файла текущего ( т.е. включен) файл.

'REQUEST_URI'

URI, который был предоставлен для доступа к этой странице; например, '/index.html'.

PATH_INFO, похоже, не задокументирован ...

person Paige Ruten    schedule 11.11.2008
comment
Скорее всего, речь идет не о документации PHP, а о CGI :) И там PATH_INFO задокументирован: tools.ietf.org/html/rfc3875#section-4 Но есть некоторые известные проблемы, из-за которых Apache и nginx не всегда предоставляют эту переменную. - person SimonSimCity; 17.02.2012
comment
Ответ Одина ниже добавляет полезные объяснения, дополненные примерами. Мне трудно понять, что эти переменные представляют в общем контексте с path_info, строкой запроса, некоторым перенаправлением, некоторыми псевдонимами в разных операционных системах, от CLI к SERVER и т. Д. - person ; 16.12.2015
comment
-1 Просто как объяснение того, почему я проголосовал против: вся причина, по которой я пришел к этому сообщению, заключается в том, что документация не ясна. Ответ Одина ниже дает четкое объяснение различий между этими переменными. Я чувствую, что этого недостаточно, чтобы просто скопировать и вставить легко найденную, но при этом недостаточную документацию. Я считаю, что большинству людей пришлось бы уже посетить документацию, чтобы хотя бы узнать о списке элементов в переменной $ _SERVER, упомянутой выше. - person dallin; 15.08.2018

Некоторые практические примеры различий между этими переменными:
Пример 1. PHP_SELF отличается от SCRIPT_NAME только, когда запрашиваемый URL имеет форму:
http://example.com/test.php/foo/bar

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

(кажется, это единственный случай, когда PATH_INFO содержит разумную информацию [PATH_INFO] => / foo / bar) Примечание: это раньше было другим в некоторых старых версиях PHP (‹= 5.0?).

Пример 2. REQUEST_URI отличается от SCRIPT_NAME, когда вводится непустая строка запроса:
http://example.com/test.php?foo=bar

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

Пример 3. REQUEST_URI отличается от SCRIPT_NAME, когда действует перенаправление на стороне сервера (например, mod_rewrite на apache):

http://example.com/test.php

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

Пример 4. REQUEST_URI отличается от SCRIPT_NAME при обработке ошибок HTTP с помощью скриптов.
Использование директивы apache ErrorDocument 404 /404error.php
http://example.com/test.php

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

На сервере IIS с использованием настраиваемых страниц ошибок
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php
person Odin    schedule 28.11.2008
comment
+1, пример - это не способ учиться, это единственный способ учиться. - Мне всегда приходится перепроверять этот материал, очень хорошее исследование ошибок 404. знак равно - person Alix Axel; 09.05.2010
comment
+1: Первый раз в жизни я понял разницу. Им следует обновить документацию PHP, указав ваш ответ. - person Marco Demaio; 23.03.2011
comment
Example1: [SCRIPT_NAME] = ›/test.php/ Не должно быть / в конце: Example1: [SCRIPT_NAME] =› /test.php В любом случае это то, что я вижу в PHP 5.3.6. Хорошие примеры. - person Dawid Ohia; 21.03.2012
comment
Вы правы, JohnM2, теперь я проверил PHP 5.4, и результат для URL /pinfo.php/first/second?third=fourth выглядит следующим образом: QUERY_STRING = ›третий = четвертый REQUEST_URI =› /pinfo.php/first/second ? третий = четвертый SCRIPT_NAME = ›/pinfo.php PATH_INFO =› / первый / второй - person Odin; 10.04.2012
comment
Я тестировал это и на 5.2.17, и там нет / в конце SCRIPT_NAME. Это похоже на PHP 5.2-5.4, учитывая редактирование ответа, чтобы отразить это. - person Fabrício Matté; 07.09.2012
comment
Вы пропустили REQUEST_URI и PHP_SELF, здесь они отличаются, если вы запрашиваете example.com: [REQUEST_URI] => / и [PHP_SELF] => /index.php - person icc97; 19.12.2013
comment
Это очень полезно, особенно часть обработки ошибок в Примере 4. Недавно я обнаружил, что некоторые программисты используют REQUEST_URI в качестве условий, а затем предоставляют другой верхний и нижний колонтитулы соответственно. Это работает в большинстве случаев, но будут проблемы со страницами 404/403. Я думаю, что лучший способ - использовать SCRIPT_NAME для получения РЕАЛЬНОЙ запрошенной страницы на Apache. - person ChandlerQ; 11.10.2014
comment
Я знаю, что это не часть вопроса, но полезно упомянуть, что [REQUEST_URI] определяется до перезаписи URL, включая перезапись mod_dir, как указано @ icc97. [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] определяется после mod_dir и mod_rewrite, но до разрешения псевдонимов. Псевдонимы могут изменить полный путь URL (который PHP называет [PHP_SELF]) для получения [SCRIPT_FILENAME], который является фактическим сценарием в файловой системе. Чтобы быть немного более полным, добавим, что сценарий может включать другие файлы, а __FILE__ - это текущий файл. - person ; 19.12.2015
comment
В примере 1 также говорится, что [REQUEST_URI] отличается от [SCRIPT_NAME], когда [PATH_INFO] не пусто. Это было понято, но явно не написано. Пример [REQUEST_URI] => /test.php/foo.bar, [SCRIPT_NAME] => /test.php - person ; 19.12.2015
comment
стоит отметить эту ошибку apache: bz.apache.org/bugzilla/show_bug.cgi? id = 40102 - person Brad Kent; 21.12.2018
comment
Также стоит привести пример обхода доменов, так как они тоже различаются. Например, в http://example.com/something/../test.php REQUEST_URI будет /something/../test.php, а SCRIPT_NAME будет /test.php. :) - person Jamie Robinson; 26.04.2019

PATH_INFO доступен только при использовании htaccess следующим образом:

Пример 1

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

Остается такой же

[SCRIPT_NAME] => /index.php

Корень

http://domain.com/

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

Дорожка

http://domain.com/test

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

Строка запроса

http://domain.com/test?123

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

Пример 2

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

Остается такой же

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

Корень

http://domain.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Дорожка

http://domain.com/test

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

Строка запроса

http://domain.com/test?123

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

Пример 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]

or

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]

Остается такой же

[SCRIPT_NAME] => /index.php

Корень

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

Дорожка

http://domain.com/test

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

Язык

http://domain.com/en

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

Языковой путь

http://domain.com/en/test

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

Строка языкового запроса

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
person Mike    schedule 07.03.2012
comment
Это было прекрасно. Спасибо за вашу помощь! - person Gabriel Fair; 29.04.2012
comment
Этот ответ написан таким образом, что предполагает, что только перезапись URL-адреса может создать path_info, но, конечно, информацию о пути можно ввести непосредственно в исходный URL-адрес. - person ; 25.12.2015

Пути PHP

  $_SERVER['REQUEST_URI']    = Веб-путь, запрошенный URI
  $_SERVER['PHP_SELF']    = Веб-путь, запрошенный файл + информация о пути
  $_SERVER['SCRIPT_NAME']    = Веб-путь, запрошенный файл
  $_SERVER['SCRIPT_FILENAME']   = Путь к файлу, запрошенный файл
  __FILE__    = Файл путь, текущий файл

Где

  • Путь к файлу - это путь к системному файлу, например /var/www/index.php, после разрешения псевдонима.
  • Веб-путь - это путь к документу на сервере, например /index.php из http://foo.com/index.php, и может даже не совпадать с каким-либо файлом
  • Текущий файл означает включенный файл сценария, а не любой сценарий, который его включает.
  • Запрошенный файл означает файл сценария включения, а не включенный.
  • URI - это HTTP-запрос, например /index.php?foo=bar, перед любой перезаписью URL.
  • Информация о пути - это любые дополнительные данные Apache, расположенные после имени скрипта, но перед строкой запроса.

Порядок работы

  1. Клиент отправляет серверу HTTP-запрос REQUEST_URI
  2. Сервер выполняет любое перезапись URL из файлов .htaccess и т. Д., Чтобы получить PHP_SELF
  3. Сервер разделяет PHP_SELF на SCRIPT_FILENAME + PATH_INFO
  4. Сервер выполняет разрешение псевдонимов и преобразует весь путь URL в путь к системному файлу, чтобы получить SCRIPT_FILENAME
  5. Результирующий файл сценария может включать другие файлы, где __FILE__ указывает путь к текущему файлу.
person Beejor    schedule 10.04.2015
comment
Это хорошо. Вот мои комментарии. Во-первых, и $ _SERVER ['SCRIPT_NAME'], и $ _SERVER ['SCRIPT_FILENAME'] - это имя сценария, за исключением того, что последнее - после выполнения псевдонимов. Во-вторых, $ _SERVER ['PHP_SELF'] - это не сценарий, а сценарий + информация о пути. Опять же, $ _SERVER ['SCRIPT_NAME'] - это сценарий (перед псевдонимами). Наконец, полезно знать, на каком этапе, после или до правил перезаписи, после или до псевдонимов, определяются эти переменные. Смотрите мой ответ. - person ; 16.12.2015
comment
@ Dominic108 Я пересмотрел свой ответ на основе ваших предложений, немного привел порядок и добавил раздел Порядок работы. Дайте мне знать, что вы думаете. Спасибо! - person Beejor; 17.12.2015
comment
В вашем заказе вы должны поменять местами $_SERVER['SCRIPT_NAME'] и $_SERVER['PHP_SELF'], потому что mod_rewrite создает весь путь, который равен $_SERVER['PHP_SELF']. Далее происходит разделение. Обратите внимание, что псевдонимы также учитывают весь путь для определения имени файла сценария, но разделение, которое определило имя_сценария и путь_инфо, уже произошло, поэтому они не будут затронуты. - person ; 17.12.2015
comment
@ Dominic108 Я снова пересмотрел свой ответ. По какой-то причине ваше предложение по редактированию было отклонено, хотя, насколько мне известно, вы правы в том, что два моих элемента вышли из строя. Я не так хорошо знаком с псевдонимами, поэтому полагаюсь на ваш опыт в этой части. Еще раз спасибо! - person Beejor; 18.01.2016

Вы можете изучить класс URI и использовать $ this-> uri- > uri_string ()

Возвращает строку с полным URI.

Например, если это ваш полный URL:

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

Функция вернет это:

/news/local/345

Или вы можете использовать сегменты для детализации определенных областей без необходимости придумывать значения синтаксического анализа / регулярного выражения.

person Adam    schedule 11.11.2008
comment
Спасибо - это хорошая идея, но я использую их в предсистемной ловушке, которую необходимо запустить до того, как контроллер будет запущен. - person Eli; 11.11.2008

Лично я использую $REQUEST_URI, поскольку он ссылается на введенный URI, а не на расположение на диске сервера.

person Xenph Yan    schedule 11.11.2008
comment
Всегда ли это полный URI? - person Eli; 11.11.2008
comment
Как правило, вы можете столкнуться с проблемами с apache в Windows, но только для URI, которые не решаются. - person Xenph Yan; 11.11.2008

К ответу Одина добавить очень мало. Я просто хотел предоставить полный пример от HTTP-запроса к фактическому файлу в файловой системе, чтобы проиллюстрировать эффекты перезаписи URL-адресов и псевдонимов. В файловой системе сценарий /var/www/test/php/script.php

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

где /var/www/test/php/script_included.php

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

и /var/www/test/.htaccess

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

а файл конфигурации Apache включает псевдоним

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

а HTTP-запрос

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

Выход будет

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

Всегда верно следующее

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

Если нет перезаписи mod_rewrite, mod_dir, ErrorDocument или любой формы перезаписи URL, у нас также есть

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

Псевдонимы влияют на пути к системным файлам SCRIPT_FILENAME и __FILE__, а не на пути URL, которые были определены ранее - см. Исключения ниже. Псевдонимы могут использовать весь путь URL, включая PATH_INFO. Между SCRIPT_NAME и SCRIPT_FILENAME не могло быть никакой связи.

Не совсем точно, что псевдонимы не разрешаются во время определения URL-пути [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO], потому что псевдонимы считаются для поиска в файловой системе, и из примера 4 в ответе Odin мы знаем, что в файловой системе выполняется поиск, чтобы определить, существует ли файл. , но это актуально только в том случае, если файл не найден. Точно так же mod_dir вызывает mod_alias для поиска в файловой системе, но это актуально только в том случае, если у вас есть псевдоним, например Alias \index.php \var\www\index.php, а запрос uri - это каталог.

person Community    schedule 16.12.2015
comment
Привет Dominic108, спасибо за доработку. Я действительно думаю, что полезно включить информацию о перезаписи. Для меня это подразумевалось, но для других это могло быть не так интуитивно. - person Beejor; 17.12.2015

Если вы когда-нибудь забудете, какие переменные что делают, вы можете написать небольшой скрипт, который использует phpinfo () и вызовите его по URL-адресу со строкой запроса. Поскольку установки серверного программного обеспечения представляют переменные, которые возвращает PHP, всегда рекомендуется проверять вывод машины на случай, если перезапись в файле конфигурации сервера приведет к другим результатам, чем ожидалось. Сохраните это как-то вроде _inf0.php:

<?php
    $my_ip = '0.0.0.0';

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

Тогда вы бы позвонили /_inf0.php?q=500

person AbsoluteƵERØ    schedule 23.07.2018

Сделайте резервную копию секунды, вы с самого начала приняли неправильный подход. Почему бы просто не сделать это

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

вместо? Затем возьмите его с помощью $_GET['url'];

person Community    schedule 28.12.2008
comment
Зачем изобретать велосипед? Доступ к этим данным намного проще! - person Kenneth; 10.10.2011
comment
И есть дополнительная сложность, если ожидается, что исходный запрос будет содержать строку запроса. В текущем состоянии приведенный выше код просто перезапишет строку запроса. Если вы объединяете строки запроса (флаг QSA), то параметры строки запроса потенциально могут быть перезаписаны (например, если вам нужен параметр url в начальном запросе) или, что еще хуже, могут быть уязвимы для атак XSS. - person MrWhite; 23.01.2017