我正在构建一个表示IPv4子网的类。我将网络地址和子网掩码存储为4字节二进制字符串,并在构造函数中根据参数构建它们。其中一个我希望构造函数接受的表示是CIDR表示法。
我的位操作有点生疏,我卡在了将子网掩码的十进制整数CIDR表示转换为4字节二进制字符串以及反之上。我还发现我无法对字符串执行左/右移操作 - 尽管我肯定以前成功过?
当将二进制字符串转换回CIDR前缀大小的十进制表示时,我目前正在使用下面的代码。我还有另一个非常相似的代码块,用于验证以其他格式提供的子网掩码,以确保设置的位是连续的。
我的位操作有点生疏,我卡在了将子网掩码的十进制整数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
的值将被存储为double(因此无法与位运算良好地配合使用)。
& 0xffffffff
- 特别是,在32位平台上,这是否会导致它出现问题,因为0xffffffff
将被视为浮点数,并且这可能会从按位操作中产生意外结果(如果我没记错的话)? - DaveRandom0xffffffff
的问题,这仍然无法正常工作,因为log(2, 2) == 1
和log(1, 2) == 0
- 这就是昨天你所说的,只是我当时没有理解。 - DaveRandom