Когда вы подумаете об использовании одного над другим и почему?
HTTP_HOST
получается из заголовка HTTP-запроса, и именно это клиент фактически использовал в качестве «целевого хоста» запроса. SERVER_NAME
определяется в конфигурации сервера. Какой из них зависит от того, для чего вам это нужно. Теперь вы должны понимать, что это контролируемое клиентом значение, которое, таким образом, не может быть надежным для использования в бизнес-логике, а другое является контролируемым сервером значением, которое является более надежным. Тем не менее, вам необходимо убедиться, что сервер веб-сервера имеет правильную конфигурацию SERVER_NAME
. Взяв Apache HTTPD в качестве примера, вот выдержка из его документации :
Если имя
ServerName
не указано, сервер пытается вывести имя хоста, выполнив обратный поиск по IP-адресу. Если вServerName
не указан порт, сервер будет использовать порт из входящего запроса. Для обеспечения оптимальной надежности и предсказуемости вы должны указать явное имя хоста и порт, используя директивуServerName
.
Обновление : после проверки ответа Pekka на ваш вопрос, который содержит ссылку на ответ bobince, что PHP всегда будет возвращать значение SERVER_NAME
для SERVER_NAME
, что противоречит моему собственному опыту PHP 4.x + Apache HTTPD 1.2.x от нескольких лет назад я сдул пыль с моей текущей среды XAMPP в Windows XP (Apache HTTPD 2.2.1 с PHP 5.2.8), запустил ее, создал страницу PHP, которая печатает оба значения, создал тестовое приложение Java, используя URLConnection
чтобы изменить заголовок и тесты 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
от конфигурации сервера!
HTTP_HOST
– целевой хост, отправленный клиентом. Пользователь может свободно манипулировать пользователем. Это не проблема, чтобы отправить запрос на ваш сайт с запросом HTTP_HOST
значение HTTP_HOST
.
SERVER_NAME
исходит из определения VirtualHost
сервера и поэтому считается более надежным. Тем не менее, он может управляться извне при определенных условиях, связанных с настройкой вашего веб-сервера: см. Этот вопрос, который относится к аспектам безопасности обоих вариантов.
Вы не должны полагаться на то, чтобы быть в безопасности. Тем не менее, что использовать, действительно зависит от того, что вы хотите сделать. Если вы хотите определить, в каком домене работает ваш скрипт, вы можете безопасно использовать HTTP_HOST
если недопустимые значения, поступающие от злоумышленника, не могут сломать что-либо.
Как я упоминал в этом ответе , если сервер работает на порту, отличном от 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}/
Это применяется ТОЛЬКО, если вы получаете доступ к серверу без имени хоста.
если вы хотите проверить через server.php или что вы хотите назвать его следующим:
<?php phpinfo(INFO_VARIABLES); ?>
или
<?php header("Content-type: text/plain"); print_r($_SERVER); ?>
Затем обращайтесь к нему со всеми действительными URL-адресами для вашего сайта и проверьте разницу.
Зависит от того, что я хочу узнать. SERVER_NAME – это имя хоста сервера, а HTTP_HOST – это виртуальный хост, к которому подключен клиент.
Мне потребовалось некоторое время, чтобы понять, что люди подразумевают под « SERVER_NAME
, более надежным ». Я использую общий сервер и не имею доступа к директивам виртуального хоста. Итак, я использую mod_rewrite в .htaccess
для сопоставления различных HTTP_HOST
s с разными каталогами. В этом случае это имеет HTTP_HOST
.
Ситуация аналогична, если вы используете виртуальные хосты на основе имени: директива ServerName
в виртуальном хосте просто говорит, какое имя хоста будет сопоставлено с этим виртуальным хостом. Суть в том, что в обоих случаях имя хоста, предоставленное клиентом во время запроса ( HTTP_HOST
), должно совпадать с именем на сервере, которое само отображается в каталог. Независимо от того, выполняется ли сопоставление с директивами виртуального хоста или с правилами htaccess mod_rewrite, здесь вторично. В этих случаях HTTP_HOST
будет таким же, как SERVER_NAME
. Я рад, что Apache настроен таким образом.
Однако ситуация отличается от виртуальных хостов на базе IP. В этом случае и только в этом случае SERVER_NAME
и HTTP_HOST
могут быть разными, потому что теперь клиент выбирает сервер по IP, а не по имени. Действительно, могут быть специальные конфигурации, где это важно.
Итак, начиная с этого SERVER_NAME
, я буду использовать SERVER_NAME
, на всякий случай мой код будет перенесен в эти специальные конфигурации.
Предполагая, что у вас есть простая настройка (CentOS 7, Apache 2.4.x и PHP 5.6.20) и только один веб-сайт (не предполагающий виртуальный хостинг) …
С точки $_SERVER['SERVER_NAME']
PHP, $_SERVER['SERVER_NAME']
– это элемент PHP, зарегистрированный в $_SERVER['SERVER_NAME']
$_SERVER
на основе вашей конфигурации Apache ( **ServerName**
с UseCanonicalName On
) в httpd.conf (будь то из включенного виртуального хоста файл конфигурации, что угодно и т. д.). HTTP_HOST получен из заголовка host
HTTP. Рассматривайте это как пользовательский ввод. Фильтрация и проверка перед использованием.
Вот пример того, где я использую $_SERVER['SERVER_NAME']
в качестве основы для сравнения. Следующий метод относится к конкретному дочернему классу, который я сделал с именем ServerValidator
(дочерний 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']
.
Теперь я использую superglobal, чтобы объяснить мой пример, но это только потому, что некоторые люди не знакомы с INPUT_GET
, INPUT_POST
и INPUT_SERVER
в отношении filter_input_array()
.
Суть в том, что я не обрабатываю запросы POST на моем сервере, если не выполняются все четыре условия. Следовательно, с точки зрения запросов POST отказ предоставить HTTP- host
заголовок (присутствие проверен для более ранних) вызывает заклинания для строгих браузеров HTTP 1.0 . Кроме того, запрашиваемый хост должен соответствовать значению для ServerName
в httpd.conf , а по расширению – значение $_SERVER('SERVER_NAME')
в $_SERVER('SERVER_NAME')
$_SERVER
. Опять же, я буду использовать INPUT_SERVER
с функциями фильтра PHP, но вы поймаете мой дрейф.
Имейте в виду, что Apache часто использует ServerName
в стандартных переадресациях (например, оставляя конечную косую черту URL-адресом: например, http://www.foo.com становится http://www.foo.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; }