应通过$_server多字段组合判断协议:优先https==='on',其次http_x_forwarded_proto==='https',最后server_port==443;域名取http_host或server_name后用parse_url清洗;完整url用$scheme.'://'.$clean_host.$_server['request_uri']拼接。

PHP 获取域名后不能直接拼接出完整 URL,必须结合当前请求协议、端口、路径等上下文信息;硬编码 http:// 或忽略 HTTPS 会导致跳转失败或混合内容警告。
如何安全获取当前请求的协议(HTTP/HTTPS)
不能依赖 $_SERVER['SERVER_PROTOCOL'](返回 HTTP/1.1),也不能用 $_SERVER['REQUEST_SCHEME'](部分 Nginx + PHP-FPM 环境为空)。可靠方式是检查 $_SERVER 中多个字段:
- 优先看
$_SERVER['HTTPS'] === 'on'(Apache 常见) - 其次查
$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'(反向代理场景,如 Nginx 或 CDN) - 再 fallback 到
$_SERVER['SERVER_PORT'] == 443
示例判断逻辑:
$scheme = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') ||
(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http';
如何准确提取当前域名(不含 www、不带端口)
$_SERVER['HTTP_HOST'] 最常用,但它可能含端口(如 example.com:8080)或前缀(如 www.example.com),需清洗:
立即学习“PHP免费学习笔记(深入)”;
- 用
parse_url()解析$_SERVER['HTTP_HOST']并取host部分可去端口 - 若需统一去
www.,可用ltrim($host, 'www.'),但注意不要误删www2.example.com这类子域 - 更稳妥的是用
$_SERVER['SERVER_NAME'](配置中定义的主域名),但该值可能未设置或与实际访问域名不一致
推荐做法(兼顾兼容性):
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
$clean_host = parse_url('http://' . $host, PHP_URL_HOST) ?: $host;
拼接完整 URL 的标准写法(含路径和查询参数)
仅拼域名和协议不够,真实需求常要还原当前完整 URL(如生成分享链接、重定向回原页)。关键字段来自:
-
$_SERVER['REQUEST_URI']:包含路径 + 查询字符串(如/user/profile?id=123),最直接 - 避免用
$_SERVER['PHP_SELF']+$_SERVER['QUERY_STRING']拼接,因前者可能被篡改,且空查询时需额外判空 - 如果只需「首页 URL」(不含路径),就用
$scheme . '://' . $clean_host
完整 URL 示例:
$full_url = $scheme . '://' . $clean_host . ($_SERVER['REQUEST_URI'] ?? '/');
常见陷阱和兼容性提醒
本地开发(localhost)、Docker、CLI 模式下 $_SERVER 变量缺失或不可靠,$_SERVER['HTTP_HOST'] 可能为空。此时硬拼会出错:
- 不要在 CLI 脚本里调用该逻辑(无 HTTP 上下文)
- 测试环境建议加兜底:
$clean_host = $clean_host ?: 'localhost'; - 某些 CDN(如 Cloudflare)会改写
HTTP_HOST,应以HTTP_X_ORIGINAL_HOST为备用 - PHP 8.1+ 对未定义
$_SERVER键触发E_WARNING,务必用??或isset()判断
真正难的不是拼字符串,而是判断「这个请求到底算哪个 URL」——它取决于你用在哪:重定向?生成 API 回调地址?还是邮件里的点击链接?每种场景对协议、域名、路径的精度要求都不同。











