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_NAME
和HTTP_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
子类)中ServerValidator
。 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元素的过滤和validation都会发生(以及相关的属性设置)。
线…
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
…检查$_SERVER['HTTP_HOST']
值(最终来自请求的host
HTTP标头)与$_SERVER['SERVER_NAME']
匹配。
现在,我用superglobal来解释我的例子,但这是因为有些人对于filter_input_array()
不熟悉INPUT_GET
, INPUT_POST
和INPUT_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; }