PHPで、ネットワークアドレスの計算をする
プログラムを作ってみる。
○ネットワークアドレスとは
ネットワークセグメント自体を表すIPアドレス。
2進数で書いた時、ホスト部が全て”0″。
逆に、ホスト部が全て”1″のものが、
ブロードキャストアドレス。
例) IPアドレス:192.168.1.10/24の場合
ネットワークアドレス:192.168.1.0
ブロードキャストアドレス:192.168.1.255
参考:http://www.infraexpert.com/study/ip4.html
○ネットワークアドレスの求め方
ネットワークアドレスは、
IPアドレスとサブネットマスクのANDで求める。
ブロードキャストアドレスは、
はっきりした求め方はわからないんですが・・・
サブネットマスクのビットを反転させて、
IPアドレスとのORをとれば求められるじゃん。
という発想で作っていきます。
それと、2つのIPアドレスが
同じネットワークセグメントかどうかを
チェックする部分も作りたいと思います。
両者のネットワークアドレスを求めて、
比較するだけw
○PHPで書いてみる
とりあえず、こんな感じで作ってみました。
<?php // IPアドレス、サブネットマスクの定義 // 要素の配列として定義 $ip_addr1 = [192, 168, 1, 10]; $ip_addr2 = [192, 168, 1, 154]; $netmask = [255, 255, 255, 0]; // IPアドレス、サブネットマスクの表示 print_address("IP address 1", $ip_addr1); print_address("Subnet Mask", $netmask); print "</br>\n"; // ネットワーク、ブロードキャストアドレスの計算 for ( $i = 0; $i < 4; $i++ ){ $net_addr1[] = $ip_addr1[$i] & $netmask[$i]; $net_addr2[] = $ip_addr2[$i] & $netmask[$i]; $broad_addr[] = $ip_addr1[$i] | ($netmask[$i] ^ 255); } // ネットワーク、ブロードキャストアドレスの表示 print_address("Network address 1", $net_addr1); print_address("Broadcast address 1", $broad_addr); print "</br>\n"; // IPアドレス1、2のセグメントの比較 print_address("IP address 2", $ip_addr2); print 'IP address 1 and 2 are in <b>'; print $net_addr1 === $net_addr2 ? 'same' : 'different'; print '</b> Network segment.'; // IPアドレス配列を表示する関数 function print_address(string $str, array $addr){ print $str." is "; for ( $i = 0; $i < count($addr); $i++ ){ print $i === 0 ? $addr[$i] : '.'.$addr[$i]; } print "</br>\n"; } ●実行結果 IP address 1 is 192.168.1.10</br> Subnet Mask is 255.255.255.0</br> </br> Network address 1 is 192.168.1.0</br> Broadcast address 1 is 192.168.1.255</br> </br> IP address 2 is 192.168.1.154</br> IP address 1 and 2 are in <b>same</b> Network segment.
IPアドレスの4つのオクテットを、
配列の各要素としてANDやORを計算、
表示させる形にしてみました。
文章が、英語的に正しいかどうかは、
わかりませんが・・・
ブロードキャストアドレスの計算で、
"($netmask[$i] ^ 255)"としたのは、
ビット反転の演算子(~)では、上手くいかないから。
符号付きint型なので、ビット反転すると、
"-256"とかになるので、255とのXORをとることでうまくいった。
ちなみに、$netmaskを[255.255.255.128]にすると、
最後の行で'different'が表示されることを、
確認しましたよ。
○もっといい方法
あとから調べたんですが、
実際には、IPアドレスは文字列で定義して、
long型に変換するのが一般的なやり方のようです。
参考:
http://itpro.nikkeibp.co.jp/article/COLUMN/20070507/270104/
http://php.net/manual/ja/function.ip2long.php
そのやり方でも作ってみました。
<?php // IPアドレス、サブネットマスクの定義 // 文字列として定義 $ip_addr1 = "192.168.1.10"; $ip_addr2 = "192.168.1.154"; $netmask = "255.255.255.0"; // 文字列からlong型への変換 $ip_long1 = ip2long($ip_addr1); $ip_long2 = ip2long($ip_addr2); $mask_long = ip2long($netmask); // ネットワーク、ブロードキャストアドレスの計算 $net_long1 = $ip_long1 & $mask_long; $broad_long1 = $ip_long1 | ~$mask_long; // long型から文字列への変換 $net_addr1 = long2ip($net_long1); $broad_addr1 = long2ip($broad_long1); // IPアドレス1、2のセグメントの比較 $net_long2 = $ip_long2 & $mask_long; $switch = $net_long1 === $net_long2 ? 'same' : 'different'; // 書き出す内容 $msg = <<<EOD IP address 1 is {$ip_addr1}</br> Subnet Mask is {$netmask}</br> </br> Network address 1 is {$net_addr1}</br> Broadcast address 1 is {$broad_addr1}</br> </br> IP address 2 is {$ip_addr2}</br> IP address 1 and 2 are in <b>{$switch}</b> Network segment. EOD; // 表示 print $msg;
IPアドレスを文字列で定義し、
ip2longを使って、long型に変換して、
ネットワーク・ブロードキャストアドレスを計算し、
long2ipを使って元に戻して表示。
今回はただの文字列なので、
表示部分はヒアドキュメントで、
きれいにまとめました。
このやり方だと、
ブロードキャストアドレスの計算の時、
(~$netmask)でもうまくいきますね。
結果は、↑↑のプログラムと一緒です。
○その他
その他のIPアドレスに関連する関数をいくつか。
・gethostbyname(string "host名");
ホスト名からIPアドレスを取得する。
返り値は文字列型のIPアドレス。
参考:
http://php.net/manual/ja/function.gethostbyname.php
例) $ip = gethostbyname('localhost'); print $ip; ●結果:127.0.0.1
・gethostbyaddr(string "IPアドレス");
逆に、IPアドレスからホスト名を取得する。
返り値は文字列型でホスト名。
参考:
http://php.net/manual/ja/function.gethostbyaddr.php
※追記
配列を区切り文字でつなげて文字列に変換する、
"implode"関数があることがわかったので、
1つ目のプログラムを修正してみた。
<?php // IPアドレス、サブネットマスクの定義 // 要素の配列として定義 $ip_addr1 = [192, 168, 1, 10]; $ip_addr2 = [192, 168, 1, 154]; $netmask = [255, 255, 255, 0]; // ネットワーク、ブロードキャストアドレスの計算 for ( $i = 0; $i < 4; $i++ ){ $net_addr1[] = $ip_addr1[$i] & $netmask[$i]; $net_addr2[] = $ip_addr2[$i] & $netmask[$i]; $broad_addr[] = $ip_addr1[$i] | ($netmask[$i] ^ 255); } // 配列を'.'で結合して文字列に変換 $ip_string1 = implode('.', $ip_addr1); $ip_string2 = implode('.', $ip_addr2); $netmask_string = implode('.', $netmask); $net_string1 = implode('.', $net_addr1); $broad_string = implode('.', $broad_addr); // IPアドレス1、2のセグメントの比較 $switch = $net_addr1 === $net_addr2 ? 'same' : 'different'; // 書き出す内容 $msg = <<<EOD IP address 1 is {$ip_string1}</br> Subnet Mask is {$netmask_string}</br> </br> Network address 1 is {$net_string1}</br> Broadcast address 1 is {$broad_string}</br> </br> IP address 2 is {$ip_string2}</br> 'IP address 1 and 2 are in <b>{$switch}</b> Network segment. EOD; // 表示 print $msg;