PHP 中的 HTTP_HOST 和 SERVER_NAME 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2297403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between HTTP_HOST and SERVER_NAME in PHP?
提问by Emanuil Rusev
What is the difference between HTTP_HOSTand SERVER_NAMEin PHP?
PHP 中的HTTP_HOST和 有什么区别SERVER_NAME?
where:
在哪里:
HTTP_POST===$_SERVER['HTTP_HOST']SERVER_NAME===$_SERVER['SERVER_NAME']
HTTP_POST===$_SERVER['HTTP_HOST']SERVER_NAME===$_SERVER['SERVER_NAME']
When would you consider using one over the other and why?
您什么时候会考虑使用一种而不是另一种,为什么?
回答by BalusC
The HTTP_HOSTis obtained from the HTTP request headerand this is what the client actually used as "target host" of the request. The SERVER_NAMEis defined in server config. Which one to use depends on what you need it for. You should now however realize that the one is a client-controlled value which may thus not be reliable for use in business logic and the other is a server-controlled value which is more reliable. You however need to ensure that the webserver in question has the SERVER_NAMEcorrectly configured. Taking Apache HTTPD as an example, here's an extract from its documentation:
所述HTTP_HOST从得到的HTTP请求报头,这就是在客户端实际使用作为请求的“目标主机”。将SERVER_NAME在服务器配置定义。使用哪一种取决于你需要它做什么。但是,您现在应该意识到,一个是客户端控制的值,因此在业务逻辑中的使用可能不可靠,而另一个是服务器控制的值,它更可靠。但是,您需要确保所讨论的网络服务器已SERVER_NAME正确配置。以 Apache HTTPD 为例,以下是其文档的摘录:
If no
ServerNameis specified, then the server attempts to deduce the hostname by performing a reverse lookup on the IP address. If no port is specified in theServerName, then the server will use the port from the incoming request. For optimal reliability and predictability, you should specify an explicit hostname and port using theServerNamedirective.
如果未
ServerName指定,则服务器尝试通过对 IP 地址执行反向查找来推断主机名。如果在 中未指定端口ServerName,则服务器将使用传入请求中的端口。为了获得最佳的可靠性和可预测性,您应该使用ServerName指令指定显式的主机名和端口。
Update: after checking the answer of Pekka on your questionwhich contains a link to bobince's answerthat PHP would always return HTTP_HOST's value for SERVER_NAME, which goes against my own PHP 4.x + Apache HTTPD 1.2.x experiences from a couple of years ago, I blew some dust from my current XAMPP environment on Windows XP (Apache HTTPD 2.2.1 with PHP 5.2.8), started it, created a PHP page which prints the both values, created a Java test application using URLConnectionto modify the Hostheader and tests taught me that this is indeed (incorrectly) the case.
更新:在检查Pekka 对您的问题的回答后,其中包含指向bobince 回答的链接,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标题和测试告诉我,情况确实(不正确)。
After first suspecting PHP and digging in some PHP bug reportsregarding the subject, I learned that the root of the problem is in web server used, that it incorrectly returned HTTP Hostheader when SERVER_NAMEwas requested. So I dug into Apache HTTPD bug reportsusing various keywordsregarding the subject and I finally found a related bug. This behaviour was introduced since around Apache HTTPD 1.3. You need to set UseCanonicalNamedirective to onin the <VirtualHost>entry of the ServerNamein httpd.conf(also check the warning at the bottom of the document!).
在第一次怀疑 PHP 并挖掘有关该主题的一些PHP 错误报告后,我了解到问题的根源在于所使用的 Web 服务器,它Host在SERVER_NAME被请求时错误地返回了 HTTP标头。因此,我使用有关该主题的各种关键字深入研究了Apache HTTPD 错误报告,我终于找到了一个相关的错误。这种行为是从 Apache HTTPD 1.3 开始引入的。你需要设置指令,在该进入中(同时检查在底部的警告文件!)。UseCanonicalNameon<VirtualHost>ServerNamehttpd.conf
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
This worked for me.
这对我有用。
Summarized, SERVER_NAMEis more reliable, but you're dependenton the server config!
总结,SERVER_NAME更可靠,但你依赖于服务器配置!
回答by Pekka
HTTP_HOSTis the target host sent by the client. It can be manipulated freely by the user. It's no problem to send a request to your site asking for a HTTP_HOSTvalue of www.stackoverflow.com.
HTTP_HOST是客户端发送的目标主机。它可以由用户自由操作。这是发送请求到您的网站要求一个没有问题HTTP_HOST的值www.stackoverflow.com。
SERVER_NAMEcomes from the server's VirtualHostdefinition and is therefore considered more reliable. It can, however, also be manipulated from outside under certain conditions related to how your web server is set up: See this This SO questionthat deals with the security aspects of both variations.
SERVER_NAME来自服务器的VirtualHost定义,因此被认为更可靠。但是,在与您的 Web 服务器的设置方式相关的某些条件下,它也可以从外部进行操作:请参阅此 SO 问题,该问题涉及两种变体的安全方面。
You shouldn't rely on either to be safe. That said, what to use really depends on what you want to do. If you want to determine which domain your script is running on, you can safely use HTTP_HOSTas long as invalid values coming from a malicious user can't break anything.
你不应该依赖任何一个来确保安全。也就是说,使用什么实际上取决于您想要做什么。如果您想确定您的脚本在哪个域上运行,HTTP_HOST只要来自恶意用户的无效值不能破坏任何内容,您就可以安全地使用。
回答by Simon East
As I mentioned in this answer, if the server runs on a port other than 80 (as might be common on a development/intranet machine) then HTTP_HOSTcontains the port, while SERVER_NAMEdoes not.
正如我在这个答案中提到的,如果服务器在 80 以外的端口上运行(在开发/内联网机器上可能很常见),则HTTP_HOST包含该端口,而SERVER_NAME没有。
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(At least that's what I've noticed in Apache port-based virtualhosts)
(至少这是我在基于 Apache 端口的虚拟主机中注意到的)
Note that HTTP_HOSTdoes notcontain :443when running on HTTPS (unless you're running on a non-standard port, which I haven't tested).
请注意,HTTP_HOST它不包含:443在HTTPS运行时(除非你是一个非标准端口,我没有测试运行)。
As others have noted, the two also differ when using IPv6:
正如其他人所指出的,两者在使用 IPv6 时也有所不同:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
回答by Daniel Marschall
Please note that if you want to use IPv6, you probably want to use HTTP_HOSTrather than SERVER_NAME. If you enter http://[::1]/the environment variables will be the following:
请注意,如果您想使用 IPv6,您可能想使用HTTP_HOST而不是SERVER_NAME. 如果输入http://[::1]/环境变量将如下:
HTTP_HOST = [::1]
SERVER_NAME = ::1
This means, that if you do a mod_rewrite for example, you might get a nasty result. Example for a SSL redirect:
这意味着,例如,如果您执行 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}/
This applies ONLY if you access the server without an hostname.
这仅适用于您在没有主机名的情况下访问服务器。
回答by stevewh
If you want to check through a server.php or whatever, you want to call it with the following:
如果你想通过 server.php 或其他东西检查,你想用以下命令调用它:
<?php
phpinfo(INFO_VARIABLES);
?>
or
或者
<?php
header("Content-type: text/plain");
print_r($_SERVER);
?>
Then access it with all the valid URLs for your site and check out the difference.
然后使用您网站的所有有效 URL 访问它并检查差异。
回答by Rowland Shaw
Depends what I want to find out. SERVER_NAME is the host name of the server, whilst HTTP_HOST is the virtual host that the client connected to.
取决于我想了解什么。SERVER_NAME 是服务器的主机名,而 HTTP_HOST 是客户端连接到的虚拟主机。
回答by Dominic108
It took me a while to understand what people meant by 'SERVER_NAMEis more reliable'. I use a shared server and does not have access to virtual host directives. So, I use mod_rewrite in .htaccessto map different HTTP_HOSTs to different directories. In that case, it is HTTP_HOSTthat is meaningful.
我花了一段时间才理解人们所说的“SERVER_NAME更可靠”是什么意思。我使用共享服务器并且无权访问虚拟主机指令。因此,我使用 mod_rewrite in.htaccess将不同的HTTP_HOSTs映射到不同的目录。在那种情况下,它HTTP_HOST是有意义的。
The situation is similar if one uses name-based virtual hosts: the ServerNamedirective within a virtual host simply says which hostname will be mapped to this virtual host. The bottom line is that, in both cases, the hostname provided by the client during the request (HTTP_HOST), must be matched with a name within the server, which is itself mapped to a directory. Whether the mapping is done with virtual host directives or with htaccess mod_rewrite rules is secondary here. In these cases, HTTP_HOSTwill be the same as SERVER_NAME. I am glad that Apache is configured that way.
如果使用基于名称的虚拟主机,情况也类似:虚拟主机中的ServerName指令只是说明哪个主机名将映射到该虚拟主机。最重要的是,在这两种情况下,客户端在请求期间提供的主机名 ( HTTP_HOST) 必须与服务器中的名称匹配,该名称本身映射到目录。映射是使用虚拟主机指令还是使用 htaccess mod_rewrite 规则完成的在这里是次要的。在这些情况下,HTTP_HOST将与SERVER_NAME. 我很高兴 Apache 是这样配置的。
However, the situation is different with IP-based virtual hosts. In this case and only in this case, SERVER_NAMEand HTTP_HOSTcan be different, because now the client selects the server by the IP, not by the name.Indeed, there might be special configurations where this is important.
但是,基于 IP 的虚拟主机的情况有所不同。在这种情况下并且仅在这种情况下,SERVER_NAME并且HTTP_HOST可以不同,因为现在客户端通过 IP 而不是名称来选择服务器。事实上,可能有一些特殊的配置,这很重要。
So, starting from now, I will use SERVER_NAME, just in case my code is ported in these special configurations.
所以,从现在开始,我将使用SERVER_NAME,以防我的代码被移植到这些特殊配置中。
回答by Anthony Rutledge
Assuming one has a simple setup (CentOS 7, Apache 2.4.x, and PHP 5.6.20) and only one website (not assuming virtual hosting) ...
假设有一个简单的设置(CentOS 7、Apache 2.4.x 和 PHP 5.6.20)并且只有一个网站(不假设虚拟主机)......
In the PHP sense, $_SERVER['SERVER_NAME']is an element PHP registers in the $_SERVERsuperglobal based on your Apache configuration (**ServerName**directive with UseCanonicalName On) in httpd.conf (be it from an included virtual host configuration file, whatever, etc ...). HTTP_HOSTis derived from the HTTP hostheader. Treat this as user input. Filter and validate before using.
在 PHP 的意义上,$_SERVER['SERVER_NAME']是 PHP$_SERVER根据您在 httpd.conf 中的Apache 配置(**ServerName**指令 with UseCanonicalName On)在超全局中注册的元素(无论是来自包含的虚拟主机配置文件,等等……)。HTTP_HOST派生自 HTTPhost标头。将此视为用户输入。使用前过滤和验证。
Here is an example of where I use $_SERVER['SERVER_NAME']as the basis for a comparison. The following method is from a concrete child class I made named ServerValidator(child of Validator). ServerValidatorchecks six or seven elements in $_SERVER before using them.
这是我$_SERVER['SERVER_NAME']用作比较基础的示例。以下方法来自我创建的名为ServerValidator(child of Validator)的具体子类。ServerValidator在使用它们之前检查 $_SERVER 中的六个或七个元素。
In determining if the HTTP request is POST, I use this method.
在确定 HTTP 请求是否为 POST 时,我使用此方法。
public function isPOST()
{
return (($this->requestMethod === 'POST') && // Ignore
$this->hasTokenTimeLeft() && // Ignore
$this->hasSameGETandPOSTIdentities() && // Ingore
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}
By the time this method is called, all filtering and validating of relevant $_SERVER elements would have occurred (and relevant properties set).
到调用此方法时,相关 $_SERVER 元素的所有过滤和验证都会发生(并设置相关属性)。
The line ...
线...
($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')
... checks that the $_SERVER['HTTP_HOST']value (ultimately derived from the the requested hostHTTP header) matches $_SERVER['SERVER_NAME'].
... 检查$_SERVER['HTTP_HOST']值(最终派生自请求的hostHTTP 标头)是否匹配$_SERVER['SERVER_NAME']。
Now, I am using superglobal speak to explain my example, but that is just because some people are unfamiliar with INPUT_GET, INPUT_POST, and INPUT_SERVERin regards to filter_input_array().
现在,我使用超全局发言,解释我的例子,但这只是因为有些人不熟悉INPUT_GET,INPUT_POST以及INPUT_SERVER在问候filter_input_array()。
The bottom line is, I do not handle POST requests on my server unless allfour conditions are met. Hence, in terms of POST requests, failure to provide an HTTP hostheader (presence tested for earlier) spells doomfor strict HTTP 1.0browsers. Moreover, the requested host must match the valuefor ServerNamein the httpd.conf, and, by extention, the value for $_SERVER('SERVER_NAME')in the $_SERVERsuperglobal. Again, I would be using INPUT_SERVERwith the PHP filter functions, but you catch my drift.
最重要的是,除非满足所有四个条件,否则我不会在我的服务器上处理 POST 请求。因此,就 POST 请求而言,未能提供 HTTPhost标头(早先的存在性测试)对于严格的HTTP 1.0浏览器来说意味着厄运。此外,该请求的主机必须与价值相匹配的在httpd.conf中通过extention的值,并且,在超全局。同样,我将使用PHP 过滤器函数,但您会发现我的想法。ServerName$_SERVER('SERVER_NAME')$_SERVERINPUT_SERVER
Keep in mind that Apache frequently uses ServerNamein standard redirects(such as leaving the trailing slash off a URL: Example, http://www.foo.combecoming http://www.foo.com/), even if you are not using URL rewriting.
请记住,Apache 经常ServerName在标准重定向中使用(例如保留 URL 的尾部斜杠:例如,http://www.foo.com变为http://www.foo.com/),即使您不是使用 URL 重写。
I use $_SERVER['SERVER_NAME']as the standard, not $_SERVER['HTTP_HOST']. There is a lot of back and forth on this issue. $_SERVER['HTTP_HOST']could be empty, so this should not be the basis for creating code conventions such as my public method above. But, just because both may be set does not guarantee they will be equal. Testing is the best way to know for sure (bearing in mind Apache version and PHP version).
我使用$_SERVER['SERVER_NAME']作为标准,而不是$_SERVER['HTTP_HOST']. 在这个问题上有很多来回。 $_SERVER['HTTP_HOST']可能是空的,所以这不应该是创建代码约定的基础,比如我上面的公共方法。但是,仅仅因为两者都可以设置并不能保证它们相等。测试是确定的最好方法(记住 Apache 版本和 PHP 版本)。
回答by Vitalie
$_SERVER['SERVER_NAME']is based on your web servers configuration. $_SERVER['HTTP_HOST']is based on the request from the client.
$_SERVER['SERVER_NAME']基于您的 Web 服务器配置。 $_SERVER['HTTP_HOST']基于客户端的请求。
回答by MSS
As balusC said SERVER_NAME is not reliable and can be changed in apache config , server name config of server and firewall that can be between you and server.
正如 balusC 所说 SERVER_NAME 不可靠,可以在 apache config 中更改,服务器和防火墙的服务器名称配置可以在你和服务器之间。
Following function always return real host (user typed host) without port and it's almost reliable:
以下函数总是返回没有端口的真实主机(用户输入的主机),它几乎是可靠的:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}

