我正在构建一个类来表示 IPv4 子网。我将网络地址和子网掩码存储为 4 字节二进制字符串,它们是在构造函数期间根据参数构建的。我希望构造函数接受的一种表示是CIDR notation。
我的按位运算有点生疏,我遇到的问题是将子网掩码的十进制整数 CIDR 表示形式转换为 4 字节二进制字符串,反之亦然。我还发现我无法在字符串上执行左/右移位 - 我确定我之前已经成功完成了吗?
我设法将转换为二进制字符串以使用以下代码:
// An example input value.
$mask = 24; // 255.255.255.0
if ($mask < 0 || $mask > 32) {
// Invalid prefix size
throw new RangeException('Invalid CIDR prefix size');
} else if ($mask === 0) {
// Handle 0
$mask = "\x00\x00\x00\x00";
} else {
// Left-pad a 4-byte string with $mask set bits
$mask = pack('N', (0x01 << 31) >> ($mask - 1));
}
我不喜欢这个逻辑有两个原因:
- 我不喜欢
0
当作特例 - 我不喜欢右移后左移
我确信有一种方法可以更有效地做到这一点,并且可以0
正确处理而不将其视为特殊情况。
将二进制字符串转换回 CIDR 前缀大小的十进制表示时,我目前正在使用下面的代码。在验证以其他格式提供的子网掩码以确保设置位是连续的时,我有另一个非常相似的代码块。
// An example input value.
$mask = "\xff\xff\xff\x00"; // /24
// Convert the binary string to an int so bit shifts will work
$mask = current(unpack('N', $mask));
// A counter to represent the CIDR
$cidr = 0;
// Loop and check each bit
for ($i = 31; $i > 0; $i--) {
if (($mask >> $i) & 0x01) {
$cidr++;
} else {
break;
}
}
// Return the result
return $cidr;
由于循环,我不喜欢这个 - 我确信有一种更智能的按位方式来做到这一点。
有没有更智能的方法来完成这些任务?
想法/建议/一般滥用请...
编辑:
任何解决方案都需要在 PHP 4.3.10 及更高版本上运行,并且必须在 32 位和 64 位平台上运行。请记住,PHP 中的所有整数都是有符号的,并且在 32 位平台上,任何东西>= 0x80000000
都将存储为双精度数(因此不能很好地使用按位运算)。