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


105

Я будую додаток 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? Спасибі за вашу допомогу!

Примітка : мені довелося додати пробіли, оскільки ТАК бачить підкреслення і робить його курсивом з якоїсь причини.

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

Відповіді:


51

Документація 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 не здається документально підтвердженим ...


3
Це , швидше за все , нема про документації PHP , але CGI :) І PATH_INFO документовано: tools.ietf.org/html/rfc3875#section-4 Але є деякі відомі проблеми , які Apache і Nginx не завжди дають це змінному.
SimonSimCity

1
Відповідь Одіна нижче додає корисні пояснення, доповнені прикладами. Мені важко зрозуміти, що представляють ці змінні в загальному контексті з path_info, рядком запиту, деяким перенаправленням, деякими псевдонімами, на різних операційних системах, від CLI vs SERVER тощо.

3
-1 Тільки як пояснення того, чому я подав депозит: вся причина, коли я прийшов на цю посаду, полягає в тому, що документація не зрозуміла. Відповідь Одіна нижче дає чітке пояснення відмінностей між цими змінними. Я відчуваю, що це недостатня відповідь, щоб просто скопіювати та вставити легко знайдені, але ще й недостатню документацію. Я вважаю, що більшості людей довелося б вже відвідати документацію, щоб навіть знати про перелік елементів у змінній $ _SERVER, згаданій вище.
Даллін

229

Деякі практичні приклади відмінностей між цими змінними:
Приклад 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

21
+1, "Приклад - це не спосіб вчитися, це єдиний спосіб вчитися". - Мені завжди доводиться повторно перевіряти цей матеріал, дуже приємне дослідження 404 помилок. =)
Алікс Аксель

16
+1: 1 раз у житті я зрозумів різницю. Вони повинні оновити документацію PHP з вашою відповіддю
Marco Demaio

Приклад1: [SCRIPT_NAME] => /test.php/ У кінці не повинно бути "/": Example1: [SCRIPT_NAME] => /test.php Так чи інакше, це я бачу в PHP 5.3.6. Приємні приклади.
Dawid Ohia

Ви правильний 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 тоді, розглядаючи можливість редагування відповіді, щоб це відобразити.
Фабріціо Матте

24

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]

або

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/uk

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

Мовний шлях

http://domain.com/uk/test

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

Рядок мовного запиту

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

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

Це було чудово. Спасибі за вашу допомогу!
Ярмарок Габріеля

1
Ця відповідь написана таким чином, що говорить про те, що лише переписування URL-адреси може створювати path_info, але, звичайно, інформацію про шлях можна вводити безпосередньо в оригінальну URL-адресу.

12

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__йдеться про шлях до поточного файлу

Це добре. Ось мої коментарі. По-перше, і $ _SERVER ['SCRIPT_NAME'], і $ _SERVER ['SCRIPT_FILENAME'] є ім'ям сценарію, за винятком того, що пізніше відбувається після псевдонімів. По-друге, $ _SERVER ['PHP_SELF'] - це не скрипт, а сценарій + інформація про шлях. Знову ж, $ _SERVER ['SCRIPT_NAME'] - це сценарій (перед псевдонімами). Нарешті, корисно знати, на якому етапі, після або перед правилами переписання, після або перед псевдонімами, ці змінні визначаються. Дивіться мою відповідь.

@ Dominic108 Я переглянув свою відповідь, грунтуючись на ваших пропозиціях, трохи прилаштував речі та додав розділ Порядок роботи. Дайте мені знати, що ви думаєте. Дякую!
Beejor

У своєму порядку ви повинні поміняти місцями $_SERVER['SCRIPT_NAME']і   $_SERVER['PHP_SELF'], оскільки mod_rewrite створить весь шлях, який є $_SERVER['PHP_SELF']. Розділення відбувається далі. Зауважте, що псевдоніми також розглядають весь шлях для визначення імені файлу сценарію, але розділення, яке визначало ім'я сценарію та шлях_інфо, вже відбулося, тому на них не впливатиме.

@ Dominic108 Я ще раз переглянути свою відповідь. Чомусь вашу пропозицію щодо редагування було відхилено, хоча, наскільки я знаю, ви вірні, що два мої пункти вийшли з ладу. Я не так знайомий з псевдонімами, тому в цій частині я покладаюся на вашу експертизу. Знову дякую!
Beejor

5

Ви можете заглянути в клас URI і скористатися $ this-> uri-> uri_string ()

Повертає рядок із повним URI.

Наприклад, якщо це ваша повна URL-адреса:

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

Функція повертає це:

/news/local/345

Або ви можете скористатися сегментами для деталізації конкретних областей, не потребуючи розбору значень / регексу


Дякую - це гарна ідея, але я використовую їх у передсистемному гачку, який потрібно запустити перед запуском та запуском контролера.
Елі

4

Особисто я використовую так, $REQUEST_URIяк він посилається на введений URI, а не про місце на диску сервера.


Чи завжди це повний URI?
Елі

Як правило, ви можете зіткнутися з проблемами з apache на Windows, але це не виключено лише для URI.
Ксенф Ян

4

До відповіді Одіна дуже мало додати. Я просто відчув на собі повний приклад із запиту 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 у відповіді Одіна, що шукається файлова система, щоб визначити, чи існує файл, але це актуально лише тоді, коли файл не знайдено. Аналогічно, mod_dir викликає mod_alias для пошуку файлової системи, але це актуально лише в тому випадку, якщо у вас є псевдонім, наприклад, Alias \index.php \var\www\index.phpі uri запиту - це каталог.


Привіт Домінік108, дякую за доопрацювання Я думаю, що корисно включити інформацію про перезапис. Мені це малося на увазі, але для інших це може бути не так інтуїтивно.
Beejor

1

Якщо ви коли-небудь забудете, які змінні роблять те, ви можете написати невеликий сценарій, який використовує 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


-1

Завантажте секунду, ви почали неправильно підходити. Чому б просто не зробити цього

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

натомість? Потім схопіть його$_GET['url'];


Навіщо винаходити колесо? До цих даних набагато легше отримати доступ!
Кеннет

І є додаткова складність, якщо очікується, що в початковому запиті буде рядок запиту. У своєму поточному стані вищевказаний код просто замінить рядок запиту. Якщо ви об'єднаєте рядки запиту ( QSAпрапор), то парами рядків запиту потенційно можуть бути перезаписані (наприклад, якщо вам потрібен urlпарам на початковий запит) або ще гірше, бути вразливими до атак XSS.
MrWhite
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.