В чем разница между хостом HTTP и именем сервера в PHP?

когда вы рассмотрите возможность использования одного над другим и почему?

9 ответов


на HTTP_HOST полученные от заголовок HTTP-запроса и это то, что клиент фактически использовал в качестве" целевого хоста " запроса. The SERVER_NAME определен в конфигурации сервера. Какой из них использовать, зависит от того, для чего он вам нужен. Однако теперь вы должны понимать, что одно из них-контролируемое клиентом значение, которое может быть ненадежным для использования в бизнес-логике, а другое-контролируемое сервером значение, которое является более надежным. Однако вам необходимо убедиться, что веб-сервер в вопрос имеет SERVER_NAME правильно настроен. Принимая Apache HTTPD в качестве примера, вот выдержка из документация:

, если не ServerName указывается, затем сервер пытается вывести имя хоста, выполнив обратный поиск по IP-адресу. Если порт не указан в 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 с помощью 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 более надежно, но вы зависимая на настройки сервера!


HTTP_HOST - целевой хост, отправленный клиентом. Им может свободно манипулировать пользователь. Это не проблема, чтобы отправить запрос на ваш сайт, прошу HTTP_HOST стоимостью www.stackoverflow.com.

SERVER_NAME происходит от сервера VirtualHost определение и поэтому считается более надежным. Однако им также можно управлять извне при определенных условиях, связанных с настройкой вашего веб-сервера: см. Это это так вопрос что касается аспекты безопасности обоих вариантов.

вы не должны полагаться ни на то, ни на другое, чтобы быть в безопасности. Что сказал, что использовать зависит от того, что вы хотите сделать. Если вы хотите определить, на каком домене работает ваш скрипт, вы можете безопасно использовать HTTP_HOST пока недопустимые значения, поступающие от вредоносного пользователя, ничего не могут сломать.


как я уже упоминал в ответ, если сервер работает на порту, отличном от 80 (как это может быть распространено на машине разработки / интрасети), то HTTP_HOST содержит порт, в то время как SERVER_NAME нет.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(по крайней мере, это то, что я заметил в virtualhosts на основе портов 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}/

это применимо только при доступе к серверу без имени хоста.


Если вы хотите проверить через сервер.php или как вы хотите его назвать со следующим:

<?php

phpinfo(INFO_VARIABLES);

?>

или

<?php

header("Content-type: text/plain");

print_r($_SERVER);

?>

затем открыть его с допустимым URL-адреса для вашего сайта и проверить разницу.


зависит от того, что я хочу узнать. ИМЯ_СЕРВЕРА - это имя хоста сервера, а HTTP_HOST-виртуальный хост, к которому подключен клиент.


SERVER_NAME более надежный. Я использую общий сервер и не имею доступа к директивам виртуального хоста. Итак, я использую mod_rewrite в .htaccess для отображения различных HTTP_HOSTs в разных каталогах. В таком случае, это 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 superglobal на основе вашей конфигурации Apache (. Рассматривайте это как user вход. Фильтровать и проверять перед использованием.

вот пример того, где я использую $_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'].

теперь я использую superglobal 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).


как balusC сказал ИМЯ_СЕРВЕРА не является надежным и может быть изменен в конфигурации apache , имя сервера конфигурации сервера и брандмауэра, который может быть между вами и сервером.

следующая функция всегда возвращает реальный хост (типизированный пользователем хост) без порта, и это почти надежно:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}