PHP获取带端口域名需判断协议和端口:HTTPS时默认443、HTTP时默认80,非默认端口才显式拼接;优先用$_SERVER['SERVER_NAME']和$_SERVER['SERVER_PORT'],反向代理下应读取X-Forwarded-Port等头并校验来源。

PHP 获取带端口的域名,关键看是否启用 HTTPS 和端口是否为默认值(80/443)——非默认端口必须显式拼接,否则 $_SERVER['HTTP_HOST'] 通常不包含端口。
为什么 $_SERVER['HTTP_HOST'] 有时没端口?
浏览器在请求默认端口(HTTP 的 80、HTTPS 的 443)时,Host 请求头会省略端口。所以即使你访问 http://example.com:80,$_SERVER['HTTP_HOST'] 也只返回 example.com;同理 https://example.com:443 也只返回 example.com。
只有当端口非默认时(如 :8080、:8443),$_SERVER['HTTP_HOST'] 才会包含端口。
- 安全起见,不要直接信任
$_SERVER['HTTP_HOST']—— 它可能被客户端伪造 - 若需构造绝对 URL(如重定向、生成链接),应主动判断协议和端口
- 反向代理(如 Nginx + PHP-FPM)环境下,
$_SERVER['SERVER_PORT']可能是代理端口(如 80),而非真实后端端口,此时需依赖X-Forwarded-Port等头
手动拼接带端口域名的可靠方法
组合 $_SERVER['SERVER_NAME'] 或可信的域名配置 + $_SERVER['SERVER_PORT'],再根据 $_SERVER['HTTPS'] 或 $_SERVER['SERVER_PORT'] 判断协议。
立即学习“PHP免费学习笔记(深入)”;
示例代码:
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || $_SERVER['SERVER_PORT'] == 443 ? 'https' : 'http'; $host = $_SERVER['SERVER_NAME']; // 更可信,比 HTTP_HOST 少受伪造影响 $port = $_SERVER['SERVER_PORT']; $domain_with_port = $scheme . '://' . $host . ($port == 80 || $port == 443 ? '' : ':' . $port); // 结果如:http://example.com:8080 或 https://example.com
- 用
$_SERVER['SERVER_NAME']替代$_SERVER['HTTP_HOST']可规避 Host 头注入风险(前提是已在 PHP 配置或虚拟主机中正确定义ServerName) - 端口判断逻辑必须排除 80/443,否则会产生
http://example.com:80这类冗余写法 - 若应用部署在反向代理后,需优先检查
$_SERVER['HTTP_X_FORWARDED_PROTO']和$_SERVER['HTTP_X_FORWARDED_PORT']
处理反向代理(Nginx/Apache)下的端口获取
当 PHP 运行在 Nginx 或 Apache 后方时,$_SERVER['SERVER_PORT'] 是代理监听的端口,不是用户实际访问的端口。此时应读取代理添加的转发头。
- 检查
$_SERVER['HTTP_X_FORWARDED_PORT']是否存在且非空 - 用
$_SERVER['HTTP_X_FORWARDED_PROTO']判断协议,比$_SERVER['HTTPS']更准确 - 务必校验转发头来源(如只接受来自内网 IP 的请求),防止伪造
- 示例片段:
$port = $_SERVER['HTTP_X_FORWARDED_PORT'] ?? $_SERVER['SERVER_PORT'];
真正容易被忽略的是环境一致性:本地开发(php -S)、Apache、Nginx、Docker 中的端口暴露方式各不相同,$_SERVER 变量行为也会变化。硬编码端口或盲目信任某个字段,上线后极易出错。











