В чем разница между $_SERVER['HTTP_HOST']
и $_SERVER['SERVER_NAME']
в PHP?
Когда вы могли бы подумать об использовании одного вместо другого и почему?
В чем разница между $_SERVER['HTTP_HOST']
и $_SERVER['SERVER_NAME']
в PHP?
Когда вы могли бы подумать об использовании одного вместо другого и почему?
HTTP_HOST
получается из заголовка HTTP-запроса и этого это то, что клиент фактически использовал в качестве «целевого хоста» запроса. SERVER_NAME
определяется в конфигурации сервера. Какой из них использовать, зависит от того, для чего он вам нужен. Однако теперь вы должны понимать, что одно значение, управляемое клиентом, поэтому может быть ненадежным для использования в бизнес-логике, а другое - значение, управляемое сервером, которое более надежно. Однако вам необходимо убедиться, что на рассматриваемом веб-сервере правильно настроен SERVER_NAME
. Взяв в качестве примера Apache HTTPD, вот выдержка из его документации :
Если
ServerName
не указан, сервер пытается определить имя хоста, выполняя обратный поиск по IP-адресу. Если вServerName
не указан порт, то сервер будет использовать порт из входящего запроса. Для оптимальной надежности и предсказуемости вы должны указать явное имя хоста и порт с помощью директивыServerName
.
Обновление: после проверки ответа Пекки на ваш вопрос, который содержит ссылку на ответ Bobince, что PHP всегда будет возвращать значение HTTP_HOST
для SERVER_NAME
, что противоречит моему собственному опыту PHP 4.x + Apache HTTPD 1.2.x за пару лет назад я сдул пыль из моей текущей среды XAMPP в Windows XP (Apache HTTPD 2.2.1 с PHP 5.2.8), запустил ее, создал страницу PHP, которая печатает оба значения, создал тестовое приложение Java с использованием _ 9_, чтобы изменить заголовок Host
, и тесты научили меня, что это действительно (неправильно) дело.
После первого подозрения на PHP и покопания в некоторых отчетах об ошибках PHP Что касается предмета, я узнал, что корень проблемы в используемом веб-сервере, что он неправильно возвращал заголовок HTTP Host
, когда был запрошен SERVER_NAME
. Поэтому я покопался в отчетах об ошибках Apache HTTPD используя различные ключевые слова по теме и я наконец нашел связанную ошибку. Это поведение было введено примерно с Apache HTTPD 1.3. Вам необходимо установить для директивы UseCanonicalName
значение on
в записи <VirtualHost>
файла ServerName
в httpd.conf
(также проверьте предупреждение внизу документа а>!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
Это сработало для меня.
Подводя итог, SERVER_NAME
более надежен, но вы зависите от конфигурации сервера!
server_name
. Особенно, если server_name
не установлен, также _SERVER["SERVER_NAME"]
будет пустым.
- person white_gecko; 05.06.2014
SERVER_NAME
также захватывает значения ServerAlias
, установленные в файле VirtualHost?
- person Abhishek Madhani; 30.09.2014
SERVER_NAME
более надежен. Это не правда. Оба одинаково надежны и оба зависят от конфигурации сервера. Действительно, HTTP_HOST
может быть более надежным , потому что его поведение более четко определено, чем $_SERVER['SERVER_NAME']
.
- person Pacerier; 06.03.2015
SERVER_NAME
установлен правильно, иначе все развалится. Полагаться на предположение об использовании пользовательских агентов HTTP 1.1 под вопросом.
- person Anthony Rutledge; 09.03.2017
<VirtualHost *.example.com>
, клиенты обращаются к вашему сайту как admin.example.com
и site.example.com
, в PHP + Apache вы получаете доменные имена в SERVER_NAME
, но в PHP + Nginx вы получаете *.example.com
в SERVER_NAME
. Если вы делаете что-либо программно в зависимости от этого, вам нужно это учитывать.
- person endo64; 06.02.2020
HTTP_HOST
- это целевой хост, отправленный клиентом. Пользователь может свободно манипулировать им. Нет проблем отправить запрос на ваш сайт с указанием HTTP_HOST
значения www.stackoverflow.com
.
SERVER_NAME
происходит из определения VirtualHost
сервера и поэтому считается более надежным. Однако им также можно управлять извне при определенных условиях, связанных с настройкой вашего веб-сервера: см. Это Этот вопрос SO, который касается аспектов безопасности обоих вариантов.
Вы не должны полагаться ни на что, чтобы быть в безопасности. Тем не менее, то, что использовать, действительно зависит от того, что вы хотите делать. Если вы хотите определить, в каком домене работает ваш скрипт, вы можете безопасно использовать HTTP_HOST
, если недопустимые значения, поступающие от злонамеренного пользователя, ничего не сломают.
UseCanonicalName on
в httpd.conf, чтобы SERVER_NAME
было фактическим именем сервера.
- person Simon East; 20.08.2013
$_SERVER['SERVER_NAME']
не будет работать. Плохо сконфигурированный сервер установит$_SERVER['SERVER_NAME']
в зависимости от значения Host:
запроса клиента. Оба равны.
- person Pacerier; 06.03.2015
Как я уже упоминал в этом ответе, если сервер работает на порту, отличном от 80 (что может быть обычным для разработки / машина интрасети), то HTTP_HOST
содержит порт, а SERVER_NAME
- нет.
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(По крайней мере, это то, что я заметил в виртуальных хостах на основе портов Apache)
Обратите внимание, что HTTP_HOST
не содержит :443
при работе по HTTPS (если вы не используете нестандартный порт, который я не тестировал).
Как отмечали другие, они также различаются при использовании IPv6:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
Обратите внимание, что если вы хотите использовать IPv6, вы, вероятно, захотите использовать HTTP_HOST
, а не SERVER_NAME
. Если вы введете http://[::1]/
, переменные среды будут следующими:
HTTP_HOST = [::1]
SERVER_NAME = ::1
Это означает, что, например, если вы выполните mod_rewrite, вы можете получить неприятный результат. Пример перенаправления SSL:
# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/
# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/
Это применимо ТОЛЬКО в том случае, если вы обращаетесь к серверу без имени хоста.
https://%{SERVER_NAME}%{REQUEST_URI}
- person IXN; 02.04.2018
Если вы хотите проверить через server.php или что-то еще, вы хотите вызвать его следующим образом:
<?php
phpinfo(INFO_VARIABLES);
?>
or
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
Затем войдите в него со всеми действующими URL-адресами вашего сайта и проверьте разницу.
Зависит от того, что я хочу узнать. SERVER_NAME - это имя хоста сервера, а HTTP_HOST - это виртуальный хост, к которому подключился клиент.
SERVER_NAME
- обычно имя VirtualHost, а не сам сервер. А в Apache SERVER_NAME
часто заполняется тем же значением, что и HTTP_HOST
(см. Ответ BalusC).
- person Simon East; 20.08.2013
SERVER_NAME
применяется к виртуальному хосту. Однако можно по-прежнему использовать настройку виртуального хоста для одного сайта. Многие люди пользуются виртуальным хостингом, поэтому я понимаю вашу точку зрения.
- person Anthony Rutledge; 09.03.2017
Мне потребовалось время, чтобы понять, что люди имели в виду под словом «SERVER_NAME
более надежен». Я использую общий сервер и не имею доступа к директивам виртуального хоста. Итак, я использую mod_rewrite в .htaccess
, чтобы отображать разные HTTP_HOST
в разные каталоги. В этом случае значение имеет HTTP_HOST
.
Ситуация аналогична, если вы используете виртуальные хосты на основе имен: директива ServerName
внутри виртуального хоста просто говорит, какое имя хоста будет сопоставлено с этим виртуальным хостом. Суть в том, что в обоих случаях имя хоста, предоставленное клиентом во время запроса (HTTP_HOST
), должно совпадать с именем на сервере, которое само отображается в каталог. Независимо от того, выполняется ли сопоставление с помощью директив виртуального хоста или правил htaccess mod_rewrite, здесь вторично. В этих случаях HTTP_HOST
будет таким же, как SERVER_NAME
. Я рад, что Apache настроен именно так.
Однако с виртуальными хостами на основе IP ситуация иная. В этом случае и только в этом случае SERVER_NAME
и HTTP_HOST
могут быть разными, потому что теперь клиент выбирает сервер по IP, а не по имени. Действительно, могут быть особые конфигурации, где это важно.
Итак, с этого момента я буду использовать SERVER_NAME
, на всякий случай, если мой код будет перенесен в эти специальные конфигурации.
Предполагая, что у вас простая установка (CentOS 7, Apache 2.4.x и PHP 5.6.20) и только один веб-сайт (не предполагая виртуального хостинга) ...
В смысле PHP $_SERVER['SERVER_NAME']
- это элемент, который PHP регистрирует в $_SERVER
суперглобале на основе вашей конфигурации Apache (директива **ServerName**
с UseCanonicalName On
) в httpd.conf (будь то из включенного файла конфигурации виртуального хоста и т. Д.). HTTP_HOST является производным от заголовка HTTP host
. Считайте это вводом пользователя. Отфильтруйте и проверьте перед использованием.
Вот пример того, как я использую $_SERVER['SERVER_NAME']
в качестве основы для сравнения. Следующий метод взят из конкретного дочернего класса, который я создал с именем ServerValidator
(дочерний элемент Validator
). ServerValidator
проверяет шесть или семь элементов в $ _SERVER перед их использованием.
Чтобы определить, является ли HTTP-запрос POST, я использую этот метод.
public function isPOST()
{
return (($this->requestMethod === 'POST') && // Ignore
$this->hasTokenTimeLeft() && // Ignore
$this->hasSameGETandPOSTIdentities() && // Ingore
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}
К моменту вызова этого метода вся фильтрация и проверка соответствующих элементов $ _SERVER должны были произойти (и были установлены соответствующие свойства).
Линия ...
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
... проверяет, соответствует ли значение $_SERVER['HTTP_HOST']
(в конечном итоге полученное из запрошенного HTTP-заголовка host
) $_SERVER['SERVER_NAME']
.
Теперь я использую суперглобальный язык, чтобы объяснить свой пример, но это просто потому, что некоторые люди не знакомы с INPUT_GET
, INPUT_POST
и INPUT_SERVER
в отношении _ 18_.
Суть в том, что я не обрабатываю запросы POST на своем сервере, если не выполняются все четыре условия. Следовательно, с точки зрения запросов POST, отказ предоставить заголовок HTTP host
(наличие проверено ранее) означает гибель для браузеров со строгим HTTP 1.0. Кроме того, запрошенный хост должен соответствовать значению для ServerName
в httpd.conf и, в зависимости от расширения, значению для $_SERVER('SERVER_NAME')
в $_SERVER
суперглобальный. Опять же, я бы использовал INPUT_SERVER
с функциями фильтра PHP, но вы уловили мой уклон.
Имейте в виду, что Apache часто использует ServerName
в стандартных перенаправлениях (например, оставляя косую черту в конце URL-адреса: например, http://www.example.com становится http://www.example.com/), даже если вы не используете перезапись URL.
Я использую $_SERVER['SERVER_NAME']
как стандарт, а не $_SERVER['HTTP_HOST']
. По этому вопросу много споров. $_SERVER['HTTP_HOST']
может быть пустым, поэтому это не должно быть основанием для создания соглашений о коде, таких как мой публичный метод выше. Но то, что оба могут быть установлены, не гарантирует, что они будут равны. Тестирование - лучший способ узнать наверняка (имея в виду версию Apache и версию PHP).
Как сказал balusC, SERVER_NAME ненадежен и может быть изменен в конфигурации apache, конфигурации имени сервера и брандмауэра, который может находиться между вами и сервером.
Следующая функция всегда возвращает реальный хост (хост, введенный пользователем) без порта, и это почти надежно:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}
$ _SERVER ['SERVER_NAME'] зависит от конфигурации вашего веб-сервера. $ _SERVER ['HTTP_HOST'] основан на запросе от клиента.
HTTP_HOST
. В противном случае злоумышленник может ввести любое значение вHost:
запрос HTTP и заставить сервер его принять. - person Pacerier   schedule 06.03.2015$_SERVER['HTTP_HOST']
или$_SERVER['SERVER_NAME']
- person Gregory Cosmo Haun   schedule 25.03.2017