PHP
ビット演算

PHPのビット演算で詰まったから書置き

あらまし

 PHPの中で、IPアドレスとサブネットマスクをチェックする機能を作ろうとしが、その際にビット演算が上手く出来なかった。ビット演算を初めてやる自分が理解してないだけかもしれないけど、同じような人がいたときのためにここに置いておく。

(チェッカのソースは)ないです

やりたかったこと

 IPアドレスをip2long()で数値に変換 → 変換された数値をさらにdecbin()を使って2進数に変換 → ビット演算

作業環境

 ・Win10のIISとPHP7.2
 ・一応Ubuntuでも同じことを確認したけど、バージョンとか忘れた

実際にやったこと

php中に以下のようなコードを書いた。

<?php
//IPを数値とビットに変換
  $IP = "192.168.1.1";
  $lIP = ip2long($IP);
  $bIP = decbin($lIP);
  echo "IP:" . $IP . "\n";
  echo "lIP:" . $lIP . "\n";
  echo "bIP:" . $bIP . "\n";

//Maskを数値とビットに変換
  $Mask = "255.255.255.0";
  $lMask = ip2long($Mask);
  $bMask = decbin($lMask);
  echo "M:" . $Mask . "\n";
  echo "lM:" . $lMask . "\n";
  echo "bM:" . $bMask . "\n";

//なんか色々計算
  $nBMask = ~$bMask;
  echo "nBM:" . $nBMask . "\n";

  $and = $bIP & $bMask;
  $or = $bIP | $bMask;
  $xor = $bIP ^ $bMask;
  echo "&:" . $and . "\n";
  echo "|:" . $or . "\n";
  echo "^:" . $xor . "\n";
?>

実行結果1

IP:192.168.1.1
lIP:3232235777
bIP:11000000101010000000000100000001
M:255.255.255.0
lM:4294967040
bM:11111111111111111111111100000000
nBM:��������������������������������
&:11000000101010000000000100000000
|:11111111111111111111111100000001
^:�������������

ご覧の通り、notとxorの結果が化け化けである。
それでは修正しましょう。

修正

あらかじめ修正しておいたものをこちらに用意しました。

<?php
  $IP = "192.168.1.1";
  $lIP = ip2long($IP);
  $bIP = decbin($lIP);
  echo "IP:" . $IP . "\n";
  echo "lIP:" . $lIP . "\n";
  echo "bIP:" . $bIP . "\n";

  $Mask = "255.255.0.0";
  $lMask = ip2long($Mask);
  $bMask = decbin($lMask);
  echo "M:" . $Mask . "\n";
  echo "lM:" . $lMask . "\n";
  echo "bM:" . $bMask . "\n";

  $nLMask = ~$lMask;
  $nBMask = decbin($nLMask); //数値をビット反転させてから、2進数に変換
  echo "nLM:" . $nLMask . "\n";
  echo "nBM:" . $nBMask . "\n";

  $and = $bIP & $bMask;
  $or = $bIP | $bMask;
  $xor = decbin($bIP ^ $bMask); //数値の排他的論理和を計算してから、2進数に変換
  echo "&:" . $and . "\n";
  echo "|:" . $or . "\n";
  echo "^:" . $xor . "\n";
?>

実行結果2

IP:192.168.1.1
lIP:3232235777
bIP:11000000101010000000000100000001
M:255.255.0.0
lM:4294901760
bM:11111111111111110000000000000000
nLM:-4294901761
nBM:1111111111111111111111111111111100000000000000001111111111111111
&:11000000101010000000000000000000
|:11111111111111110000000100000001
^:0

まとめ

なんか実際のコードは$nBMaskの値もうちょっと短かったけど、とりあえず修正できた。
phpのビット演算は、2進数では計算できない。10進数で計算してから、2進数に変換させよう。
この後、nBMaskからわざわざIPに戻す操作もしたような気がするけど忘れた。思い出したら書くかも。