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

Ema*_*sev 520 php apache server-variables

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

Bal*_*usC 767

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

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


更新:在你的问题上检查Pekka的答案之后,其中包含一个指向bobince的答案的链接,PHP总是返回其HTTP_HOSTSERVER_NAME,这与我几年前自己的PHP 4.x + Apache HTTPD 1.2.x经验不符,我在Windows XP(使用PHP 5.2.8的Apache HTTPD 2.2.1)上吹掉了当前XAMPP环境中的一些灰尘,启动它,创建了一个打印这两个值的PHP页面,创建了一个URLConnection用于修改Host标题的Java测试应用程序和测试告诉我,这确实是(错误的)情况.

在首先怀疑PHP并挖掘一些有关该主题的PHP错误报告之后,我了解到问题的根源在于使用的Web服务器,它HostSERVER_NAME请求时错误地返回了HTTP 标头.所以我使用关于主题的各种关键字挖掘Apache HTTPD错误报告,我终于发现了一个相关的错误.从Apache HTTPD 1.3开始引入了这种行为.您需要设置指令,在该进入中(同时检查在底部的警告文件!).UseCanonicalNameon<VirtualHost>ServerNamehttpd.conf

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 
Run Code Online (Sandbox Code Playgroud)

这对我有用.

总结一下,SERVER_NAME更可靠,但你依赖于服务器配置!

  • 好的,这解决了我的问题,这与OP无关,但相关.通过使用浏览器可以提供的任何东西,我非常关注安全问题.这个答案是一个巨大的帮助.感谢您抽出宝贵时间将它放在一起. (4认同)
  • 为什么说HTTP_HOST不可靠?是的,它是由用户提供的,但如果用户给出了一些虚假值,您的服务器配置将自动返回503,您的PHP脚本甚至不会运行! (2认同)
  • 从 WinXP 欺骗 Apache 的一个简单方法是在“hosts”文件中添加一行,说明服务器的 IP 已分配给另一个域,例如:“127.0.0.1 mydomain.com”。我已经多次使用它来展示一个本地网站,欺骗我的观众认为我有互联网连接并且网站加载速度非常快。你可以走另一条路,用“173.194.41.5 localhost”欺骗Apache认为它在本地运行,所以除非你确定你的Apache配置良好,否则你永远不应该完全信任SERVER_NAME。 (2认同)

Pek*_*ica 65

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

SERVER_NAME来自服务器的VirtualHost定义,因此被认为更可靠.但是,它也可以在与您的Web服务器设置方式相关的某些条件下从外部进行操作:请参阅此SO问题,该问题涉及两种变体的安全性方面.

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

  • 是的,但是请求HTTP_HOST值为www.stackoverflow.com的请求将被大多数HTTP服务器拒绝,因此PHP脚本甚至不会看到请求! (7认同)
  • @Pacerier为true,但并非总是如果服务器配置不正确. (2认同)

Sim*_*ast 51

正如我在本回答中提到的,如果服务器在80以外的端口上运行(在开发/内联网机器上可能是常见的),则HTTP_HOST包含端口,而不包含端口SERVER_NAME.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'
Run Code Online (Sandbox Code Playgroud)

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

请注意,HTTP_HOST包含:443在HTTPS运行时(除非你是一个非标准端口,我没有测试运行).

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

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
Run Code Online (Sandbox Code Playgroud)

  • 他们什么时候才能解决这种阴险的行为? (2认同)

Dan*_*all 27

请注意,如果您想使用IPv6,您可能希望使用HTTP_HOST而不是SERVER_NAME.如果输入http://[::1]/环境变量将是以下内容:

HTTP_HOST = [::1]
SERVER_NAME = ::1
Run Code Online (Sandbox Code Playgroud)

这意味着,如果你做一个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}/
Run Code Online (Sandbox Code Playgroud)

这仅适用于访问没有主机名的服务器的情况.


小智 6

如果你想检查server.php或者你想用以下内容调用它:

<?php
    phpinfo(INFO_VARIABLES);
?>
Run Code Online (Sandbox Code Playgroud)

要么

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

    print_r($_SERVER);
?>
Run Code Online (Sandbox Code Playgroud)

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


Row*_*haw 5

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

  • 不是完全正确的Rowland,“ SERVER_NAME”通常是VirtualHost的名称,而不是服务器本身。在Apache中,“ SERVER_NAME”通常填充为与“ HTTP_HOST”相同的值(请参见BalusC的答案)。 (3认同)