Я создаю приложение 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 видит подчеркивание и почему-то делает его курсивом.
Обновлено: Исправлены пробелы.





Лично я использую $REQUEST_URI, поскольку он ссылается на введенный URI, а не на местоположение на диске сервера.
Как правило, вы можете столкнуться с проблемами с apache в Windows, но только для URI, которые не решаются.
Вы можете изучить Класс URI и использовать $ this-> uri-> uri_string ()
Возвращает строку с полным URI.
Например, если это ваш полный URL:
http://example.com/index.php/news/local/345
Функция вернет это:
/news/local/345
Или вы можете использовать сегменты для детализации определенных областей без необходимости придумывать значения синтаксического анализа / регулярного выражения.
Спасибо - это хорошая идея, но я использую их в предсистемной ловушке, которую необходимо запустить до того, как контроллер будет запущен.
Документация PHP может сказать вам разницу:
'PHP_SELF'
The filename of the currently executing script, relative to the document root. For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar would be /test.php/foo.bar. The __FILE__ constant contains the full path and filename of the current (i.e. included) file. If PHP is running as a command-line processor this variable contains the script name since PHP 4.3.0. Previously it was not available.
'SCRIPT_NAME'
Contains the current script's path. This is useful for pages which need to point to themselves. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.
'REQUEST_URI'
The URI which was given in order to access this page; for instance, '/index.html'.
PATH_INFO, похоже, не задокументирован ...
Скорее всего, речь идет не о документации PHP, а о CGI :) И там PATH_INFO задокументирован: tools.ietf.org/html/rfc3875#section-4 Но есть некоторые известные проблемы, которые Apache и nginx не всегда предоставляют этой переменной.
Ответ Одина ниже добавляет полезные объяснения, дополненные примерами. Мне трудно понять, что представляют собой эти переменные в общем контексте с path_info, строкой запроса, некоторым перенаправлением, некоторыми псевдонимами в разных операционных системах, от CLI к SERVER и т. д.
-1 Просто как объяснение того, почему я проголосовал против: вся причина, по которой я пришел к этому посту, заключается в том, что документация не ясна. Ответ Odin ниже дает четкое объяснение различий между этими переменными. Мне кажется, что это недостаточный ответ, чтобы просто скопировать и вставить легко найденную, но при этом недостаточную документацию. Я считаю, что большинству людей пришлось бы уже посетить документацию, чтобы хотя бы узнать о списке элементов в переменной $ _SERVER, упомянутой выше.
Некоторые практические примеры различий между этими переменными:
Пример 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):
[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
+1: «Пример - это не способ учиться, это единственный способ учиться». - Мне всегда приходится перепроверять этот материал, очень хорошее исследование ошибок 404. знак равно
+1: Первый раз в жизни я понял разницу. Они должны обновить документацию PHP вашим ответом
Example1: [SCRIPT_NAME] => /test.php/ В конце не должно быть символа "/": Example1: [SCRIPT_NAME] => /test.php В любом случае это то, что я вижу в PHP 5.3.6. Хорошие примеры.
Вы правы, 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 => / первый / второй
Я тестировал это и на 5.2.17, и в конце / нет SCRIPT_NAME. Это похоже на PHP 5.2-5.4, учитывая редактирование ответа, чтобы отразить это.
Вы пропустили REQUEST_URI и PHP_SELF, здесь они отличаются, если вы запрашиваете example.com: [REQUEST_URI] => / и [PHP_SELF] => /index.php
Это очень полезно, особенно часть обработки ошибок в Примере 4. Недавно я обнаружил, что некоторые программисты используют REQUEST_URI в качестве условий, а затем предоставляют другой верхний и нижний колонтитулы соответственно. Это работает в большинстве случаев, но будут проблемы со страницами 404/403. Я думаю, что лучший способ - использовать SCRIPT_NAME для получения РЕАЛЬНОЙ запрошенной страницы на Apache.
Я знаю, что это не часть вопроса, но полезно упомянуть, что [REQUEST_URI] определяется до перезаписи URL, включая перезапись mod_dir, как указано @ icc97. [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] определяется после mod_dir и mod_rewrite, но до разрешения псевдонимов. Псевдонимы могут изменить полный путь URL (который PHP называет [PHP_SELF]) для получения [SCRIPT_FILENAME], который является фактическим сценарием в файловой системе. Чтобы быть немного более полным, давайте добавим, что сценарий может включать другие файлы, а __FILE__ является текущим файлом.
Пример 1 также говорит, что [REQUEST_URI] отличается от [SCRIPT_NAME], когда [PATH_INFO] не пустой. Это было понято, но явно не написано. Пример [REQUEST_URI] => /test.php/foo.bar, [SCRIPT_NAME] => /test.php
стоит отметить эту ошибку apache: bz.apache.org/bugzilla/show_bug.cgi?id=40102
Также стоит привести пример обхода доменов, так как они тоже различаются. Например, в http://example.com/something/../test.php REQUEST_URI будет /something/../test.php, а SCRIPT_NAME будет /test.php. :)
Сделайте резервную копию секунды, вы с самого начала приняли неправильный подход. Почему бы просто не сделать это
RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php?url=$1 [L]
вместо? Тогда возьмите его с помощью $_GET['url'];
Зачем изобретать велосипед? Доступ к этим данным намного проще!
И есть дополнительная сложность, если ожидается, что исходный запрос будет содержать строку запроса. В текущем состоянии приведенный выше код просто перезапишет строку запроса. Если вы объединяете строки запроса (флаг QSA), то параметры строки запроса потенциально могут быть перезаписаны (например, если вам нужен параметр url в первоначальном запросе) или, что еще хуже, быть уязвимыми для XSS-атак.
PATH_INFO доступен только при использовании htaccess следующим образом:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]
[SCRIPT_NAME] => /index.php
[PHP_SELF] => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI] => /
[QUERY_STRING] =>
[PHP_SELF] => /index.php/test
[PATH_INFO] => /test
[REQUEST_URI] => /test
[QUERY_STRING] =>
[PHP_SELF] => /index.php/test
[PATH_INFO] => /test
[REQUEST_URI] => /test?123
[QUERY_STRING] => 123
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)
[REQUEST_URI] => /
[QUERY_STRING] =>
[REQUEST_URI] => /test
[QUERY_STRING] => url=test
[REQUEST_URI] => /test?123
[QUERY_STRING] => url=test&123
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]
или же
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
[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
[PHP_SELF] => /index.php/test
[PATH_INFO] => /test
[REQUEST_URI] => /test
[QUERY_STRING] =>
[REDIRECT_LANGUAGE] =>
[PHP_SELF] => /index.php/
[PATH_INFO] => /
[REQUEST_URI] => /en
[QUERY_STRING] =>
[REDIRECT_LANGUAGE] => en
[PHP_SELF] => /index.php/test
[PATH_INFO] => /test
[REQUEST_URI] => /en/test
[REDIRECT_LANGUAGE] => en
[PHP_SELF] => /index.php/test
[PATH_INFO] => /test
[REQUEST_URI] => /en/test?123
[QUERY_STRING] => 123
[REDIRECT_LANGUAGE] => en
Это было здорово. Спасибо за вашу помощь!
Этот ответ написан таким образом, что предполагает, что только перезапись URL-адреса может создать path_info, но, конечно, информацию о пути можно ввести непосредственно в исходный URL-адрес.
$_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, и может даже не соответствовать ни одному файлу/index.php?foo=bar, перед любой перезаписью URLREQUEST_URIPHP_SELFPHP_SELF на SCRIPT_FILENAME + PATH_INFOSCRIPT_FILENAME.__FILE__ относится к пути к текущему файлу.Это хорошо. Вот мои комментарии. Во-первых, и $ _SERVER ['SCRIPT_NAME'], и $ _SERVER ['SCRIPT_FILENAME'] - это имя сценария, за исключением того, что последнее - после выполнения псевдонимов. Во-вторых, $ _SERVER ['PHP_SELF'] - это не сценарий, а сценарий + информация о пути. Опять же, $ _SERVER ['SCRIPT_NAME'] - это сценарий (перед псевдонимами). Наконец, полезно знать, на каком этапе, после или до правил перезаписи, после или до псевдонимов, определяются эти переменные. Смотрите мой ответ.
@ Dominic108 Я пересмотрел свой ответ на основе ваших предложений, немного прибрался и добавил раздел Порядок работы. Дайте мне знать, что вы думаете. Спасибо!
В вашем заказе вы должны поменять местами $_SERVER['SCRIPT_NAME'] и $_SERVER['PHP_SELF'], потому что mod_rewrite создает весь путь, то есть $_SERVER['PHP_SELF']. Далее происходит разделение. Обратите внимание, что псевдонимы также учитывают весь путь для определения имени файла сценария, но разделение, которое определило имя_сценария и путь_инфо, уже произошло, поэтому они не будут затронуты.
@ Dominic108 Я снова пересмотрел свой ответ. По какой-то причине ваше предложение по редактированию было отклонено, хотя, насколько мне известно, вы правы в том, что два моих элемента вышли из строя. Я не так хорошо знаком с псевдонимами, поэтому полагаюсь на ваш опыт в этой части. Еще раз спасибо!
К ответу Одина добавить очень мало. Я просто хотел предоставить полный пример от 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 - это каталог.
Привет Dominic108, спасибо за доработку. Я действительно думаю, что полезно включить информацию о перезаписи. Для меня это подразумевалось, но для других это может быть не так интуитивно.
Если вы когда-нибудь забудете, какие переменные что делают, вы можете написать небольшой скрипт, который использует 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
Всегда ли это полный URI?