HTTP_HOST vs SERVER_NAME在PHP中:有什么猫腻?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP 侦探:HTTP_HOST 和 SERVER_NAME 背后隐藏着什么?

\n\n

如果你曾经查看过 PHP 中的超全局数组 $_SERVER,你一定会看到两个非常相似的键:HTTP_HOST 和 SERVER_NAME。乍一看,它们似乎是同一个东西——服务器名称。但经验丰富的开发者知道:魔鬼藏在细节中。这个话题在 Stack Overflow 上获得了数千次浏览,这并非偶然。错误的选择可能导致重定向错误、跨域请求失败,甚至安全漏洞。

\n

在本文中,我们不会仅仅罗列枯燥的定义。我们将进行一次真正的调查:分析这些值从何而来,它们在不同服务器(Apache、Nginx)上的行为如何,以及最重要的是——何时使用哪个选项。系好安全带,这将非常有趣。

\n\n

什么是 HTTP_HOST?

\n

HTTP_HOST 是浏览器(或任何其他 HTTP 客户端)在请求中发送给服务器的 Host 标头的值。此标头在 HTTP/1.1 中是必需的,包含域名以及可能的端口号。

\n

浏览器请求示例:

\n
GET /page.php HTTP/1.1\nHost: pythonlib.ru:8080\nUser-Agent: Mozilla/5.0\n...
\n

在 PHP 中,该值会进入 $_SERVER['HTTP_HOST']。请注意:这是一个未经验证的值。客户端可以在 Host 标头中发送任意文本,例如 evil-site.com 或 192.168.1.1。这正是主要风险所在。

\n\n

什么是 SERVER_NAME?

\n

SERVER_NAME 是 Web 服务器根据其自身配置设置的值。通常,它来自 Apache 中的 ServerName 指令或 Nginx 中的 server_name 指令。这是处理请求的虚拟主机的名称。

\n

Apache 配置示例:

\n
<VirtualHost *:80>\n    ServerName pythonlib.ru\n    DocumentRoot /var/www/pythonlib\n</VirtualHost>
\n

在这种情况下,$_SERVER['SERVER_NAME'] 将等于 pythonlib.ru。与 HTTP_HOST 不同,此值由服务器管理员控制,而非客户端。但有一个细微差别:SERVER_NAME 可能不包含端口(取决于 UseCanonicalName 设置)。

\n\n

表格中的关键区别

\n

为了清晰起见,我们将其汇总到表格中:

\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
参数HTTP_HOSTSERVER_NAME
来源来自客户端的 HTTP 请求标头Web 服务器配置
控制权客户端(可能被伪造)服务器管理员
端口如果端口非标准,则包含端口(例如 site.com:8080)通常不带端口(取决于 UseCanonicalName)
可靠性低(未经检查请勿信任)高(但并非绝对)
用途重定向、面向用户的链接内部逻辑、安全
\n\n

何时使用什么?实用示例

\n

现在进入最重要的部分——代码。让我们考虑三个典型场景。

\n\n

1. 重定向到同一域名(例如,带 www

博客

书籍推荐