PHP中的HTTP_HOST和SERVER_NAME有什么区别?

你什么时候考虑使用一个,为什么?

HTTP_HOST从HTTP请求头获得,这就是客户端实际用作请求的“目标主机”的东西。 SERVER_NAME在服务器configuration中定义。 哪一个使用取决于你需要什么。 但是,您现在应该意识到,这是客户端控制的价值,因此可能不适用于业务逻辑,另一个是服务器控制的值更可靠。 但是,您需要确保所涉及的Web服务器具有正确configuration的SERVER_NAME 。 以Apache HTTPD为例,下面是它的文档摘录:

如果未指定ServerName ,则服务器将尝试通过对IP地址执行反向查找来推断主机名。 如果ServerName没有指定端口,则服务器将使用传入请求中的端口。 为了获得最佳的可靠性和可预测性,您应该使用ServerName指令指定一个明确的主机名和端口。


更新 :检查Pekka的答案后,您的问题 ,其中包含一个链接到bobince的答案 ,PHP将始终返回SERVER_NAME HTTP_HOST的值,这违背了我自己的PHP 4.x + Apache HTTPD 1.2.x经验从几个几年前,我在Windows XP(Apache HTTPD 2.2.1,PHP 5.2.8)上使用了当前的XAMPP环境,并创build了一个打印这两个值的PHP页面,使用URLConnection创build了一个Javatesting应用程序来修改Host头和testing告诉我,这确实(不正确)的情况下。

在第一次怀疑PHP并且在关于这个主题的一些PHP错误报告中挖掘之后,我发现问题的根源在于使用了web服务器,当SERVER_NAME被请求时错误地返回了HTTP Host头。 所以我使用关于这个主题的各种关键字来挖掘Apache HTTPD错误报告 ,最后我发现了一个相关的错误 。 这个行为是从Apache HTTPD 1.3开始引入的。 您需要在httpd.conf中的ServerName<VirtualHost>条目中设置UseCanonicalName指令(也请查看文档底部的警告!)。

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

这对我有效。

总结一下, SERVER_NAME更可靠,但是您依赖于服务器configuration!

HTTP_HOST是客户端发送的目标主机。 它可以由用户自由操纵。 将请求发送到您的站点要求提供HTTP_HOST值是没有问题的。

SERVER_NAME来自服务器的VirtualHost定义,因此被认为更可靠。 但是,也可以在一定条件下从外部操纵,这些条件与您的Web服务器的设置有关:请参阅这个问题这个问题涉及两个变体的安全方面。

你不应该依靠或者是安全的。 也就是说,使用什么取决于你想要做什么。 如果你想确定你的脚本运行在哪个域,只要来自恶意用户的无效值不能破坏任何东西,就可以安全地使用HTTP_HOST

正如我在这个答案中提到的,如果服务器运行在80以外的端口上(如开发/内联网机器上常见的那样),那么HTTP_HOST包含端口,而SERVER_NAME则不包含端口。

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

(至less这是我在Apache基于端口的虚拟主机中注意到的)

请注意,在HTTPS上运行时, HTTP_HOST不包含:443 (除非您在非标准端口上运行,而我没有testing过)。

正如其他人所指出的那样,使用IPv6时两者也有所不同:

 $_SERVER['HTTP_HOST'] == '[::1]' $_SERVER['SERVER_NAME'] == '::1' 

请注意,如果您想使用IPv6,您可能需要使用HTTP_HOST而不是SERVER_NAME 。 如果你inputhttp://[::1]/ ,环境variables如下:

 HTTP_HOST = [::1] SERVER_NAME = ::1 

这意味着,如果你做一个mod_rewrite例如,你可能会得到一个讨厌的结果。 SSLredirect示例:

 # 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 ”的含义是什么。 我使用共享服务器,并且无法访问虚拟主机指令。 所以,我使用.htaccess mod_rewrite将不同的HTTP_HOST映射到不同的目录。 在这种情况下,它是有意义的HTTP_HOST

如果使用基于名称的虚拟主机,则情况类似:虚拟主机中的ServerName指令只是说明将哪个主机名映射到此虚拟主机。 底线是,在这两种情况下,客户端在请求( HTTP_HOST )期间提供的主机名必须与服务器内的名称相匹配,该名称本身映射到目录。 映射是用虚拟主机指令完成还是用htaccess mod_rewrite规则在这里是次要的。 在这些情况下, HTTP_HOST将与SERVER_NAME相同。 我很高兴Apache是​​这样configuration的。

但是,这种情况与基于IP的虚拟主机不同。 在这种情况下,只有在这种情况下, SERVER_NAMEHTTP_HOST可以不同,因为现在客户端通过IPselect服务器,而不是通过名称。 事实上,这可能是特殊的configuration,这是重要的。

所以,从现在开始,我将使用SERVER_NAME ,以防万一我的代码被移植到这些特殊的configuration中。

假设有一个简单的设置(CentOS 7,Apache 2.4.x和PHP 5.6.20),只有一个网站(不承担虚拟主机)…

在PHP的意义上, $_SERVER['SERVER_NAME']是一个元素PHP在$_SERVER超全球基础上注册在httpd.conf中的Apacheconfiguration(具有UseCanonicalName On **ServerName**指令)(来自包含的虚拟主机configuration文件,什么等等)。 HTTP_HOST来自HTTP host头。 将其视为用户input。 在使用之前过滤并validation。

以下是我使用$_SERVER['SERVER_NAME']作为比较基础的示例。 下面的方法是从一个名为ServerValidator的具体子类( Validator子类)中ServerValidatorServerValidator在使用$ _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元素的过滤和validation都会发生(以及相关的属性设置)。

线…

 ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME') 

…检查$_SERVER['HTTP_HOST']值(最终来自请求的host HTTP标头)与$_SERVER['SERVER_NAME']匹配。

现在,我用superglobal来解释我的例子,但这是因为有些人对于filter_input_array()不熟悉INPUT_GETINPUT_POSTINPUT_SERVER

底线是,除非满足所有四个条件,否则我不处理服务器上的POST请求。 因此,就POST请求而言,如果未能提供HTTP host头文件(前面已经testing过),那么对于严格的HTTP 1.0浏览器来说就是厄运了。 此外,所请求的主机必须与 httpd.conf中的 ServerName 值相匹配 ,并且必须与 $_SERVER超全局中的$_SERVER $_SERVER('SERVER_NAME') 的值相匹配 。 再次,我将使用INPUT_SERVER与PHP的过滤function,但你赶上我的漂移。

请记住,Apache经常在标准redirect中使用ServerName (例如,将尾部的斜杠离开一个URL:例如http://www.foo.com成为http://www.foo.com/ ),即使你是不使用URL重写。

我使用$_SERVER['SERVER_NAME']作为标准,而不是$_SERVER['HTTP_HOST'] 。 在这个问题上有很多来回。 $_SERVER['HTTP_HOST']可能是空的,所以这不应该是创build代码约定的基础,比如我上面的公共方法。 但是,仅仅因为两者都可能被设定并不能保证它们是平等的。 testing是确定知道的最好方法(记住Apache版本和PHP版本)。

由于balusC说SERVER_NAME是不可靠的,可以在apacheconfiguration中更改,可以在服务器和服务器之间的服务器和防火墙的服务器名称configuration。

以下function总是返回真正的主机(用户input主机)没有端口,它几乎可靠:

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