PHP域名过滤验证器误判有效/无效域名的问题该如何解决
问题成因
- 第一个问题(无顶级域名被判有效):PHP的
FILTER_VALIDATE_DOMAIN过滤器默认允许合法的内网主机名(比如localhost、自定义内网主机标识),不会强制要求域名必须包含.分隔的顶级域名段,所以stackoverflow这类纯字符串会被判定为有效。 - 第二个问题(正常域名被判无效+
$domain为空):parse_url函数的设计是用于解析完整URL(必须包含协议前缀,比如http://、https://),直接传入不带协议的stackoverflow.com时,函数无法识别出host部分,PHP_URL_HOST参数的返回值为null,空值传入过滤器自然会判定为无效,也不会有内容输出。
修复方案
- 预处理传入的域名/URL:如果传入的内容没有带协议前缀,自动补全
http://,保证parse_url可以正常解析出host部分。 - 补充公网域名校验规则:在
FILTER_VALIDATE_DOMAIN校验基础上,额外判断解析出的域名至少包含1个.,避免内网主机名被误判为公网有效域名。 - 增加异常判断:如果
parse_url解析不到host值,直接判定为无效域名。
正确校验代码
<?php function validatePublicDomain(string $input): bool { // 补全协议前缀,保证parse_url正常解析 if (!str_starts_with($input, 'http://') && !str_starts_with($input, 'https://')) { $input = 'http://' . $input; } // 解析host $domain = parse_url($input, PHP_URL_HOST); if (empty($domain)) { return false; } // 校验域名格式 + 必须包含.(公网域名强制要求) return filter_var($domain, FILTER_VALIDATE_DOMAIN) && str_contains($domain, '.'); } // 测试用例 var_dump(validatePublicDomain('http://stackoverflow')); // bool(false) var_dump(validatePublicDomain('stackoverflow.com')); // bool(true) var_dump(validatePublicDomain('www.baidu.com')); // bool(true) var_dump(validatePublicDomain('localhost')); // bool(false) ?>
如果使用PHP 8.0以下版本,可替换字符串判断逻辑兼容低版本:
// 替换str_starts_with判断 if (strpos($input, 'http://') !== 0 && strpos($input, 'https://') !== 0) { $input = 'http://' . $input; } // 替换str_contains判断 return filter_var($domain, FILTER_VALIDATE_DOMAIN) && strpos($domain, '.') !== false;
内容的提问来源于stack exchange,提问作者Nut Cracking Dude
相关产品推荐
相关产品推荐

