$_SERVER['HTTP_HOST']和$_SERVER['SERVER_NAME']在PHP中的区别是什么?
什么时候你会考虑使用其中一种而不是另一种,为什么?
$_SERVER['HTTP_HOST']和$_SERVER['SERVER_NAME']在PHP中的区别是什么?
什么时候你会考虑使用其中一种而不是另一种,为什么?
当前回答
请注意,如果你想使用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_NAME是服务器的主机名,而HTTP_HOST是客户端连接到的虚拟主机。
The HTTP_HOST is obtained from the HTTP request header and this is what the client actually used as "target host" of the request. The SERVER_NAME is 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_NAME correctly configured. Taking Apache HTTPD as an example, here's an extract from its documentation:
如果没有指定ServerName,那么服务器将尝试通过对IP地址执行反向查找来推断主机名。如果在ServerName中没有指定端口,那么服务器将使用传入请求的端口。为了获得最佳的可靠性和可预测性,您应该使用ServerName指令指定显式的主机名和端口。
Update: after checking the answer of Pekka on your question which contains a link to bobince's answer that 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 URLConnection to modify the Host header and tests taught me that this is indeed (incorrectly) the case.
After first suspecting PHP and digging in some PHP bug reports regarding the subject, I learned that the root of the problem is in web server used, that it incorrectly returned HTTP Host header when SERVER_NAME was requested. So I dug into Apache HTTPD bug reports using various keywords regarding the subject and I finally found a related bug. This behaviour was introduced since around Apache HTTPD 1.3. You need to set UseCanonicalName directive to on in the <VirtualHost> entry of the ServerName in httpd.conf (also check the warning at the bottom of the document!).
<VirtualHost *>
ServerName example.com
UseCanonicalName on
</VirtualHost>
这对我很管用。
总之,SERVER_NAME更可靠,但您依赖于服务器配置!
正如我在回答中提到的,如果服务器运行在不是80的端口上(在开发/intranet机器上可能很常见),那么HTTP_HOST包含端口,而SERVER_NAME不包含端口。
$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
(至少这是我在Apache基于端口的虚拟主机中注意到的)
注意在HTTPS上运行时HTTP_HOST不包含:443(除非您在非标准端口上运行,我没有测试过)。
正如其他人所指出的,这两者在使用IPv6时也有所不同:
$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
HTTP_HOST是客户端发送的目标主机。用户可以自由操作。向站点发送请求请求HTTP_HOST值www.stackoverflow.com是没有问题的。
SERVER_NAME来自服务器的VirtualHost定义,因此被认为更可靠。然而,它也可以在与您的web服务器设置相关的某些条件下从外部操纵:请看这个SO问题,处理这两种变体的安全方面。
你不应该依赖任何一个来保证安全。也就是说,用什么真的取决于你想做什么。如果你想确定你的脚本在哪个域上运行,只要来自恶意用户的无效值不能破坏任何东西,你就可以安全地使用HTTP_HOST。
正如balusC所说,SERVER_NAME是不可靠的,可以在apache配置中更改,服务器的服务器名配置以及您和服务器之间的防火墙。
以下函数总是返回没有端口的真实主机(用户键入的主机),几乎是可靠的:
function getRealHost(){
list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
return $realHost;
}