您什么时候会考虑使用其中一种而不是另一种?为什么?

有帮助吗?

解决方案

HTTP_HOST 是从获得 HTTP 请求头 这就是客户端实际用作请求的“目标主机”的主机。这 SERVER_NAME 在服务器配置中定义。使用哪一种取决于您需要它的用途。然而,您现在应该意识到,一个是客户端控制的值,因此在业务逻辑中使用可能不可靠,而另一个是更可靠的服务器控制的值。但是,您需要确保相关网络服务器具有 SERVER_NAME 正确配置。以 Apache HTTPD 为例,以下是摘录 它的文档:

如果不 ServerName 指定后,服务器会尝试通过对 IP 地址执行反向查找来推断主机名。如果没有指定端口 ServerName, ,那么服务器将使用传入请求中的端口。为了获得最佳的可靠性和可预测性,您应该使用以下命令指定显式的主机名和端口: ServerName 指示。


更新:检查后 佩卡对你问题的回答 其中包含一个链接 鲍宾斯的回答 PHP 总是会返回 HTTP_HOST的价值为 SERVER_NAME, ,这违背了我自己几年前的 PHP 4.x + Apache HTTPD 1.2.x 经验,我从 Windows XP 上当前的 XAMPP 环境(Apache HTTPD 2.2.1 和 PHP 5.2.8)中吹掉了一些灰尘,开始它创建了一个打印这两个值的 PHP 页面,使用创建了一个 Java 测试应用程序 URLConnection 修改 Host 标头和测试告诉我,情况确实如此(错误地)。

在第一次怀疑 PHP 并深入研究一些内容之后 PHP 错误报告 关于这个主题,我了解到问题的根源在于使用的 Web 服务器,它错误地返回了 HTTP Host 标题时 SERVER_NAME 被要求。所以我深入研究 Apache HTTPD 错误报告 使用 各种关键词 关于这个主题,我终于找到了 相关错误. 。此行为是从 Apache HTTPD 1.3 左右开始引入的。你需要设置 UseCanonicalName 指示 on 在里面 <VirtualHost> 的条目 ServerNamehttpd.conf (另请检查底部的警告 该文件!).

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

这对我有用。

总结一下, SERVER_NAME 更可靠,但你 依赖的 在服务器配置上!

其他提示

HTTP_HOST是由客户端发送的目标主机。它可以由用户自由地进行操作。这是没有问题的请求发送到您的网站要求HTTP_HOSTwww.stackoverflow.com值。

SERVER_NAME来自服务器的VirtualHost定义,并且因此被认为是更可靠的。它可以,但是,也可以从外面下起关系到你的Web服务器是如何设置一定的条件下操作:请参阅本的 :该SO问题 与两个变化的安全方面的交易。

您不应该依赖要么是安全的。这就是说,有什么真正的使用取决于你想要做什么。如果你想确定你的脚本运行在哪个域,您可以放心使用HTTP_HOST只要恶意用户来无效值不能破坏任何东西。

正如我在此答案提到的,如果80以外的端口上的服务器运行(如可能是共同的显影/内部网机)然后HTTP_HOST包含该端口,而SERVER_NAME没有。

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

(至少这是我在Apache的基于端口的virtualhosts已经注意到)

请注意HTTP_HOST做的的HTTPS上运行时,包含:443(除非你是一个非标准端口,我没有测试运行)。

正如其他人指出,两个使用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_HOSTs到不同的目录。在这种情况下,它是HTTP_HOST有意义。

如果一个用途名称为基础的虚拟主机的情况是相似的:虚拟主机内的ServerName指令简单地说,该主机名将被映射到该虚拟主机。底线是,在两种情况下,请求(HTTP_HOST)期间由客户端提供的主机名,必须用服务器内的名称,它是本身映射到目录相匹配。无论映射与虚拟主机的指令或htaccess的mod_rewrite的规则是次要在这里完成。在这些情况下,HTTP_HOST将是相同的SERVER_NAME。我很高兴的Apache配置的方式。

<强>然而,该情况是与基于IP的虚拟主机不同。在这种情况下,只有在这种情况下,SERVER_NAMEHTTP_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'] 值(最终从请求的 host HTTP 标头)匹配 $_SERVER['SERVER_NAME'].

现在,我使用超全局语言来解释我的例子,但这只是因为有些人不熟悉 INPUT_GET, INPUT_POST, , 和 INPUT_SERVER 关于 filter_input_array().

最重要的是,我不会在我的服务器上处理 POST 请求,除非 全部 满足四个条件。因此,就 POST 请求而言,无法提供 HTTP host 标头(早期测试的存在)咒语 厄运 为了严格 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所述SERVER_NAME是不可靠的,并且可以在Apache的配置被改变,服务器的服务器名的配置和防火墙,可以是你和服务器之间。

随着功能始终没有恢复端口的真实主机(用户输入的主机),它几乎是可靠的:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top