Когда вы считаете, что используете один над другим и почему?В чем разница между HTTP_HOST и SERVER_NAME в PHP?
ответ
HTTP_HOST
получен из HTTP request header, и это то, что клиент фактически использовал в качестве «целевого хоста» запроса. SERVER_NAME
определяется в конфигурации сервера. Какой из них зависит от того, для чего вам это нужно. Теперь вы должны понимать, что это контролируемое клиентом значение, которое, таким образом, не может быть надежным для использования в бизнес-логике, а другое является контролируемым сервером значением, которое является более надежным. Тем не менее, вам необходимо убедиться, что сервер webserver правильно настроил SERVER_NAME
. Принимая Apache HTTPD в качестве примера, вот выдержка из its documentation:
Если ни
ServerName
не указано, то сервер пытается вывести имя хоста, выполняя обратный поиск на IP-адрес. Если порт не указан вServerName
, сервер будет использовать порт из входящего запроса. Для обеспечения оптимальной надежности и предсказуемости вы должны указать явное имя хоста и порт, используя директивуServerName
.
Update: после проверки the answer of Pekka on your question, которая содержит ссылку на bobince's answer, что PHP всегда будет возвращать значение HTTP_HOST
«s для 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 bug reports относительно предмета, я узнал, что корень проблемы в вебе-сервере, который используется, что он неправильно возвращается HTTP Host
заголовка при SERVER_NAME
был предложен. Итак, я выкопал в Apache HTTPD bug reports, используя various keywords по предмету, и наконец нашел related bug. Это поведение было введено, так как вокруг Apache HTTPD 1.3. Вам необходимо установить UseCanonicalName
директиву on
в <VirtualHost>
запись ServerName
в httpd.conf
(также проверьте предупреждение внизу the document!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
Это сработало для меня.
Подведено, SERVER_NAME
надежнее, но вы где находятся зависимые от в сообществе config!
Хорошо, это решает мою проблему, которая не связана с OP, но актуальна. Я был очень обеспокоен проблемами безопасности, используя все, что может предложить браузер. Этот ответ был ОГРОМНОЙ помощью. Спасибо, что нашли время, чтобы собрать его вместе. – Yitzhak
Почему вы говорите HTTP_HOST не надежна? Да, он предоставляется пользователем, но если пользователь дает какое-то фиктивное значение, ваша конфигурация сервера автоматически вернет 503, и ваш PHP-скрипт даже не будет запущен! – Pacerier
@ Pacerier: на момент написания этого ответа это не так. Версии упоминаются в ответе. Я больше не буду в курсе PHP, поэтому не могу сказать, изменилось ли оно в более новой версии. – BalusC
Зависит от того, что я хочу узнать. SERVER_NAME - это имя хоста сервера, а HTTP_HOST - это виртуальный хост, к которому подключен клиент.
Не совсем верно, Rowland, 'SERVER_NAME' обычно является именем VirtualHost, а не сервера. А в Apache «SERVER_NAME» часто заполняется тем же значением, что и «HTTP_HOST» (см. Ответ BalusC). –
@Simon, поскольку большинство хостов теперь VirtualHost, что бы вы имели в виду под названием «сам сервер»? – Pacerier
Если вы используете виртуальный частный сервер (VPS) с одним веб-сайтом, вам не нужно предполагать, что 'SERVER_NAME' применяется к виртуальному хосту. Тем не менее, по-прежнему можно использовать настройку виртуального хоста для одного сайта. Многие люди используют общий хостинг, поэтому я вижу вашу точку зрения. –
HTTP_HOST
- целевой хост, отправленный клиентом. Пользователь может свободно манипулировать пользователем. Не стоит посылать запрос на ваш сайт с запросом HTTP_HOST
значение www.stackoverflow.com
.
SERVER_NAME
получен из определения VirtualHost
сервера и поэтому считается более надежным.Его также можно манипулировать снаружи при определенных условиях, связанных с настройкой вашего веб-сервера: см. Этот This SO question, который посвящен аспектам безопасности обоих вариантов.
Вы не должны полагаться на то, чтобы быть в безопасности. Тем не менее, что использовать, действительно зависит от того, что вы хотите сделать. Если вы хотите определить, в каком домене работает ваш скрипт, вы можете безопасно использовать HTTP_HOST
, если недопустимые значения, исходящие от злоумышленника, не могут ничего сломать.
Да, но запрос, запрашивающий значение HTTP_HOST www.stackoverflow.com, будет отклонен большинством HTTP-серверов впереди, поэтому PHP-скрипт даже не увидит запрос! – Pacerier
@Pacerier true, но не всегда, если сервер настроен неправильно. –
Как упоминалось в сообщении BalusC, при доступе к виртуальному хосту Apache по IP, * оба * этих переменных содержат IP (по умолчанию), а не фактическое имя сервера. Вы должны использовать 'UseCanonicalName on' в httpd.conf, чтобы заставить SERVER_NAME быть фактическим именем сервера. –
, если вы хотите, чтобы проверить через server.php или то, что вы хотите назвать его следующим:
<?php
phpinfo(INFO_VARIABLES);
?>
или
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
Тогда доступ к нему со всем действующим адресом для ваш сайт и проверьте разницу.
Мне понадобилось время, чтобы понять, что люди подразумевают под "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
, на всякий случай мой код портируется в этих специальных конфигурациях.
Обратите внимание, что если вы хотите использовать 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}/
Это относится ТОЛЬКО, если вы обращаетесь к серверу без имени хоста.
Как я уже говорил в this answer, если сервер работает на порту, а не 80 (как это может быть общим на развитие/интранет машины), то HTTP_HOST
содержит порт, в то время как SERVER_NAME
нет.
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(По крайней мере, это то, что я заметил в Apache на основе портов VirtualHosts)
HTTP_HOST
Обратите внимание, что делает не содержат :443
при работе на HTTPS (если вы не работаете на не- стандартный порт, который я не тестировал).
Как уже отмечалось, два также отличаются при использовании IPv6:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
Когда они исправит это коварное поведение? – Pacerier
Как balusC сказал SERVER_NAME не является надежным и может быть изменен в апача конфигурации, имя сервера конфигурации сервера и брандмауэра, которые могут быть между вы и сервер.
Следующая функция всегда возвращает реальный хозяин (пользователь вводит хост) без порта, и это почти надежно:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}
Предполагая, что один имеет простую установку (CentOS 7, Apache 2.4.x и PHP 5.6.20) и только один сайт (не предполагая виртуальный хостинг) ...
в том смысле, PHP, $_SERVER['SERVER_NAME']
является элементом PHP регистрирует в $_SERVER
суперглобальной в зависимости от конфигурации Apache (**ServerName**
директива с UseCanonicalName On
) в httpd.conf (будь то из включенного файла конфигурации виртуального хоста, что угодно, e tc ...). 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']
(в конечном счете, получена из запрашиваемого host
заголовка HTTP) соответствует $_SERVER['SERVER_NAME']
.
Теперь я использую суперглобальном Speak объяснить мой пример, но это только потому, что некоторые люди не знакомы с INPUT_GET
, INPUT_POST
и INPUT_SERVER
в отношении к filter_input_array()
.
Суть в том, что я не обрабатываю запросы POST на моем сервере, если только все выполнены четыре условия. Следовательно, с точки зрения запросов POST отказ в предоставлении HTTP-заголовка host
(присутствие проверено для более ранних) заклинаний doom для строгого HTTP 1.0 браузеров.Кроме того, запрашиваемый хост должен совпадать со значением для ServerName
в httpd.conf, и, расширение, значение для $_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).
«Обычно я использую HTTP_HOST, так что пользователь остается на том точном имени хоста, на котором они начали. Например, если у меня есть тот же сайт в домене .com и .org, я не хочу отправлять кого-либо из .org на .com, особенно если у них могут быть маркеры входа в .org, которые они потеряют, если отправятся в другой домен ». - Этот и некоторые другие интересные моменты из http://stackoverflow.com/questions/1459739/php-serverhttp-host-vs-serverserver-name-am-i-understanding-the-ma/1461430#1461430 – Yarin
@ Ярин, Дон Не забудьте [whitelist - проверить результаты «HTTP_HOST») (http://stackoverflow.com/a/28889208/632951). В противном случае злоумышленник может вставить *** любое значение *** в запросе HTTP «Хост:» и заставить сервер принять его. – Pacerier
Начинающие: этот вопрос относится к значениям, обычно полученным с помощью '$ _SERVER ['HTTP_HOST']' или '$ _SERVER ['SERVER_NAME']' –