$_SERVER['HTTP_HOST']不包含协议,因协议需根据请求头判断;应组合检查$_SERVER['HTTPS']、$_SERVER['REQUEST_SCHEME']及X-Forwarded-Proto,并校验Host防攻击。

PHP中用 $_SERVER['HTTP_HOST'] 为什么拿不到协议?
因为 $_SERVER['HTTP_HOST'] 只返回域名或IP(如 example.com 或 127.0.0.1:8080),它本身不包含协议信息——协议由客户端发起请求时决定,PHP需要主动判断。常见错误是直接拼 'http://' . $_SERVER['HTTP_HOST'],结果在HTTPS站点上生成了混合内容(Mixed Content)警告。
如何安全判断当前请求是 HTTP 还是 HTTPS?
不能只看端口或配置文件,必须依据实际请求头。最可靠的方式是检查 $_SERVER['HTTPS'] 和 $_SERVER['REQUEST_SCHEME'],但要注意它们的兼容性差异:
-
$_SERVER['HTTPS']:Apache/Nginx常用,值为"on"(字符串)或存在即表示HTTPS;但某些FastCGI环境可能未设置 -
$_SERVER['REQUEST_SCHEME']:PHP 5.6+ 原生支持,值为"http"或"https",更规范,但低版本不可用 - 备用方案:检查
$_SERVER['SERVER_PORT'] === '443',但自定义HTTPS端口(如8443)时会失效
推荐组合判断逻辑:
$scheme = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ||
(!empty($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https')
? 'https' : 'http';
构造完整URL时还要注意哪些细节?
光有协议和主机名还不够,真实场景常需补全路径、处理端口、过滤非法字符:
立即学习“PHP免费学习笔记(深入)”;
- 端口需显式添加:仅当非标准端口(HTTP 80 / HTTPS 443)时才拼入,否则浏览器默认处理
- 路径建议用
$_SERVER['REQUEST_URI']而非$_SERVER['PHP_SELF'],前者含查询参数,后者不含 - 若用于生成绝对链接(如邮件、API回调地址),应过滤掉用户可控的
Host头,防止 Host Header Attack —— 建议白名单校验$_SERVER['HTTP_HOST'] - 避免硬编码协议,尤其在反向代理(Nginx + PHP-FPM)环境下,
$_SERVER['HTTPS']可能为 false,需靠X-Forwarded-Proto补充判断
反向代理下如何正确识别 HTTPS?
Nginx/Apache 做反代时,PHP进程实际走的是 HTTP 内网通信,$_SERVER['HTTPS'] 会丢失。此时必须依赖代理传递的头:
- 确保代理配置了
proxy_set_header X-Forwarded-Proto $scheme;(Nginx)或对应 Apache 指令 - PHP 中检查:
!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' - 注意:
HTTP_X_FORWARDED_PROTO可被客户端伪造,生产环境务必在入口层(如Nginx)限制该头来源,或只信任内网IP传来的该头
协议补全这事看着简单,真正稳定运行得同时覆盖直连、反代、CLI模拟、多端口、旧PHP版本等场景——漏掉任意一环,都可能让生成的链接在某台服务器上突然变成 http:// 而触发安全拦截。











