IPv4 サブネットを表すクラスを作成しています。ネットワーク アドレスとサブネット マスクを 4 バイトのバイナリ文字列として格納しています。これは、引数に基づいてコンストラクター中に構築されます。コンストラクターに受け入れてもらいたい表現の 1 つはCIDR 表記法です。
私のビット単位の操作は少し錆びており、サブネット マスクの 10 進数の 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));
}
このロジックは、次の 2 つの理由から好きではありません。
0
特別なケースとして扱いたくない- 右シフトの後に左シフトが続くのは好きではない
0
特別なケースとして扱わずに正しく処理する方法で、これをより効率的に行う方法があると確信しています。
バイナリ文字列を CIDR プレフィックス サイズの 10 進数表現に戻す場合、現在、以下のコードを使用しています。セットのビットが連続していることを確認するために、他の形式で提供されたサブネット マスクを検証するときに、非常によく似た別のコード ブロックがあります。
// 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 として格納されることに注意してください (したがって、ビット単位の操作では適切に動作しません)。