合法cidr需满足三条件:ip为有效ipv4、掩码长度1–32、网段地址主机位全为0;正则仅作初步格式校验,必须配合ip2long()与位运算验证语义合法性。

PHP 正则匹配 CIDR 格式必须校验网段合法性
单纯用正则匹配 192.168.1.0/24 这种字符串很容易,但真正有效的 CIDR 校验不能只看“长得像”——192.168.1.1/24 或 10.0.0.128/25 这类主机位非零的写法,从网络语义上就是非法的。正则只能做初步格式筛查,后续必须用位运算验证。
- 合法 CIDR 要求:网段地址的主机位全为 0(例如
192.168.1.0/24✅,192.168.1.1/24❌) - 掩码长度必须是 1–32 的整数(
/0、/33都非法) - 点分十进制部分必须是有效 IPv4(不能是
999.1.1.1/24)
推荐正则:先筛格式,再用 ip2long() 做位校验
用这个正则做第一道过滤:/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([1-9]|[1-2]\d|3[0-2])$/
它能拦住明显错误,比如 256.1.1.1/24、192.168.1.0/33、192.168.1/24。但注意:192.168.1.1/24 也能过这个正则——它只是语法合法,语义不合法。
所以必须紧接着做位运算校验:
function is_valid_cidr($cidr) {
if (!preg_match('/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([1-9]|[1-2]\d|3[0-2])$/', $cidr)) {
return false;
}
list($ip, $bits) = explode('/', $cidr);
$ip_long = ip2long($ip);
$mask = -1 <h3>
<code>cidr_match()</code> 函数里最容易漏掉的兼容性坑</h3><p>PHP 的 <code>ip2long()</code> 在 32 位系统下对高位 IP(如 <code>192.168.128.1</code>)会返回负数,直接参与位运算是错的。必须用 <code>sprintf('%u', ip2long($ip))</code> 强转为无符号整型。</p>
- 错误写法:
$ip & $mask—— 若$ip是负数,结果不可靠 - 正确写法:
(sprintf('%u', ip2long($ip)) & sprintf('%u', $mask)) === sprintf('%u', ip2long($subnet)) - 或者统一用
gmp_init()处理大数(但多数场景没必要)
别把正则当最终判断,filter_var() 不支持 CIDR
filter_var($cidr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) 只认纯 IP,不认识 /24。试图加 FILTER_FLAG_NO_PRIV_RANGE 也没用——它根本不解析 CIDR。
所以你得自己拆解:explode('/', $cidr) 分出 IP 和掩码,分别校验 IP 段 + 掩码长度,再做位运算。没有捷径,也没有内置函数能一步到位。
最常被忽略的是:CIDR 合法性 ≠ 字符串格式合法。主机位是否为 0,必须通过 ip2long() + 位与操作才能确认——这点绕不开,也藏不住。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











