PHP中提取域名后必须转小写,因DNS和服务器按小写处理;应先用parse_url()解析再对host部分调用strtolower(),而非直接处理HTTP_HOST,且IDN需用mb_strtolower()确保UTF-8安全。

PHP中用 parse_url() 提取域名后必须转小写
PHP本身不区分域名大小写,但实际访问时DNS解析和服务器配置(如Nginx虚拟主机)通常按小写处理。如果用户输入 HTTP://EXAMPLE.COM 或 https://MySite.NET,直接拿 $_SERVER['HTTP_HOST'] 会保留原始大小写,导致缓存、日志、白名单校验出错。
正确做法是先解析再强制小写:
$url = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';
$parsed = parse_url('http://' . ltrim($url, '.')); // 防止以.开头导致parse_url失败
$domain = strtolower($parsed['host'] ?? ''); // 只对host部分小写,不碰端口或子域逻辑注意:parse_url() 不支持纯域名(如 example.COM:8080),所以得补 http:// 前缀;ltrim($url, '.') 是为防某些CDN或代理传入带前导点的值。
用 mb_strtolower() 替代 strtolower() 更安全
遇到含非ASCII字符的国际化域名(IDN),比如 café.com 或中文域名转punycode后的 xn--caf-dma.com,strtolower() 可能出错或不生效。
立即学习“PHP免费学习笔记(深入)”;
稳妥方案:
- 如果是纯ASCII域名(绝大多数情况),
strtolower()足够快且可靠 - 如果业务明确支持IDN,且已将域名转为punycode(如通过
idn_to_ascii()),仍用strtolower() - 如果不确定输入来源,或需兼容原始Unicode域名(极少见),改用
mb_strtolower($host, 'UTF-8'),并确保mbstring扩展启用
别在 $_SERVER['HTTP_HOST'] 上直接调用 strtolower()
看似简单粗暴:strtolower($_SERVER['HTTP_HOST']),但有三个隐患:
- 可能包含端口号(如
example.com:8080),小写后变成example.com:8080—— 看似没变,但若后续用strpos()匹配.com,位置计算就乱了 - 某些代理会把
Host头设成[::1]或localhost,小写无意义还掩盖问题 - 没过滤空值或非法格式,
strtolower(null)返回空字符串,容易引发静默错误
真正该小写的只是域名主体,不是整个Host头。务必先提取、再转换、最后验证。
nginx/Apache配置里统一大小写没意义
有人想在Web服务器层做重定向(比如把大写Host 301跳转到小写),这不可行:
- HTTP/1.1 规定 Host 头大小写不敏感,服务器根本不会触发重定向
- nginx 的
map或if ($host ~* ...)只能匹配,不能修改请求头中的Host字段供PHP读取 - 即使强行用
proxy_set_header Host ...改写,也只影响转发给后端的值,不解决PHP层原始输入问题
域名大小写的归一化,必须在PHP业务逻辑里做,没有捷径。最容易被忽略的是:子域名(如 API.example.com)是否要保留原样?通常只需保证主域小写,子域按需处理 —— 这取决于你的路由或租户识别逻辑。











