[PHP] ネットワークアドレスの計算

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;

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です