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

时间:2010-02-19 15:29:55

标签: php apache server-variables

你什么时候考虑使用一个而不是为什么?

10 个答案:

答案 0 :(得分:757)

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

  

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


更新:在检查the answer of Pekka on your question后,其中包含指向bobince's answer的链接,PHP始终会返回HTTP_HOST SERVER_NAME的值{与几年前我自己的PHP 4.x + Apache HTTPD 1.2.x体验背道而驰,我在Windows XP(使用PHP 5.2.8的Apache HTTPD 2.2.1)上从我当前的XAMPP环境中吹了一些灰尘,启动它,创建了一个打印这两个值的PHP页面,使用URLConnection创建了一个Java测试应用程序来修改Host标题,测试告诉我这确实(错误地)是这样的。

在第一次怀疑PHP并挖掘了一些关于这个主题的PHP bug reports之后,我了解到问题的根源在于使用的Web服务器,它在{{1}时错误地返回了HTTP Host标头被要求了。所以我使用Apache HTTPD bug reports挖掘various keywords关于这个主题,我终于找到了related bug。从Apache HTTPD 1.3开始引入了这种行为。您需要在SERVER_NAME on的{​​{1}}条目中将UseCanonicalName指令设为<VirtualHost>(同时检查the document底部的警告}!)。

ServerName

这对我有用。

总结一下,httpd.conf更可靠,但您在服务器配置上依赖

答案 1 :(得分:63)

HTTP_HOST是客户端发送的目标主机。它可以由用户自由操作。向您的网站发送请求HTTP_HOST值为www.stackoverflow.com的请求没有问题。

SERVER_NAME来自服务器的VirtualHost定义,因此被认为更可靠。但是,在与Web服务器设置方式相关的某些条件下,也可以从外部操纵它:请参阅此This SO question,其中涉及两种变体的安全方面。

你不应该依赖任何一个是安全的。也就是说,使用什么取决于你想做什么。如果要确定运行脚本的域,只要来自恶意用户的无效值不会破坏任何内容,就可以安全地使用HTTP_HOST

答案 2 :(得分:51)

正如我在this answer中提到的,如果服务器在80以外的端口上运行(在开发/内联网机器上可能是常见的),那么HTTP_HOST包含端口,而SERVER_NAME没有。

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

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

请注意,HTTP_HOST在HTTPS上运行时包含:443(除非您在非标准端口上运行,我尚未测试过)。

正如其他人所说,使用IPv6时两者也有所不同:

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

答案 3 :(得分:26)

请注意,如果您要使用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}/

仅在访问没有主机名的服务器时才适用。

答案 4 :(得分:6)

如果您想通过server.php查看或者想要使用以下内容调用它:

<?php

phpinfo(INFO_VARIABLES);

?>

<?php

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

print_r($_SERVER);

?>

然后使用您网站的所有有效网址访问它,并查看差异。

答案 5 :(得分:4)

取决于我想要找到的东西。 SERVER_NAME是服务器的主机名,而HTTP_HOST是客户端连接的虚拟主机。

答案 6 :(得分:2)

我花了一段时间才明白“SERVER_NAME更可靠”的含义。我使用共享服务器,无法访问虚拟主机指令。因此,我在.htaccess中使用mod_rewrite将不同的HTTP_HOST映射到不同的目录。在这种情况下,HTTP_HOST是有意义的。

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

但是,基于IP的虚拟主机的情况不同。在这种情况下,仅在这种情况下,SERVER_NAMEHTTP_HOST可以不同,因为现在客户端通过IP选择服务器,而不是名称。确实,可能有特殊的这很重要的配置。

因此,从现在开始,我将使用SERVER_NAME,以防我的代码移植到这些特殊配置中。

答案 7 :(得分:2)

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

在PHP意义上,$_SERVER['SERVER_NAME']是PHP在$_SERVER超全局中注册的元素,基于您在httpd.conf中的Apache配置(**ServerName**指令UseCanonicalName On)(无论是来自包含的虚拟主机配置文件,等等......)。 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']匹配。

现在,我正在使用superglobal说话来解释我的例子,但这仅仅是因为有些人对filter_input_array()INPUT_GETINPUT_POST不熟悉{{3} }。

最重要的是,除非满足所有四个条件,否则我不会在我的服务器上处理POST请求。因此,就POST请求而言,未能提供HTTP INPUT_SERVER标头(先前已经过测试)会对严格的 HTTP 1.0 浏览器产生 doom 。此外,请求的主机必须与 httpd.conf host 的值匹配,并且,通过扩展名, ServerName超全球中的$_SERVER('SERVER_NAME')。再次,我将$_SERVER与PHP过滤器功能一起使用,但是你抓住了我的漂移。

请记住,Apache经常在标准重定向中使用INPUT_SERVER(例如将结尾的斜杠从网址中删除:示例, http://www.foo.com 成为 http://www.foo.com/ ),即使您没有使用URL重写。

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

答案 8 :(得分:0)

由于balusC表示SERVER_NAME不可靠,可以在apache配置,服务器名称配置和服务器名称配置中更改,可以在您和服务器之间。

以下功能总是返回没有端口的真实主机(用户键入的主机),它几乎可靠:

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

答案 9 :(得分:0)

$ _ SERVER ['SERVER_NAME'] 基于您的Web服务器配置。 $ _ SERVER ['HTTP_HOST'] 基于客户端的请求。