Я создаю класс для представления подсети IPv4. Я сохраняю сетевой адрес и маску подсети как 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;
Мне не нравится это из-за цикла - я уверен, что есть более интеллектуальный побитовый способ сделать это.
Есть ли более разумный способ выполнить любую из этих задач?
Мысли/предложения/общее насилие, пожалуйста...
EDIT:
Любые решения должны работать на PHP 4.3.10 и выше и должны работать как на 32-, так и на 64-битных платформах. Имейте в виду, что все целые числа в PHP подписаны, а на 32-битной платформе все >= 0x80000000
будет храниться как двойное (и поэтому не будет хорошо работать с побитовыми операциями).