PHP 中的 HTTP_HOST 和 SERVER_NAME 有什么区别?
-
21-09-2019 - |
题
您什么时候会考虑使用其中一种而不是另一种?为什么?
解决方案
这 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>
的条目 ServerName
在 httpd.conf
(另请检查底部的警告 该文件!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
这对我有用。
总结一下, SERVER_NAME
更可靠,但你 依赖的 在服务器配置上!
其他提示
HTTP_HOST
是由客户端发送的目标主机。它可以由用户自由地进行操作。这是没有问题的请求发送到您的网站要求HTTP_HOST
的www.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_HOST
s到不同的目录。在这种情况下,它是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
基于您的 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;
}