IPアドレスをデータベースに保存する場合に、文字列で保存してないでしょうか。IPアドレスは32bitの数値なので、そのまま数値として保存することができます。

一般的にIPアドレスはxxx.xxx.xxx.xxxというような4つの数値をドットで区 切った文字列で表されることが多いと思います。この文字列は32bitの整数を 8bitずつに区切った数値を並べたもので、この数値から32bitの整数を取得する ことができます。

PHPでは、ip2long と long2ip という2つの関数を使って、文字列形式から数値 に、数値から文字列形式に変換することができます。例えば、Webページにアク セスしてきた端末のIPアドレスを数値形式で取得する場合、以下のようにします。

$ip_address = $_SERVER["REMOTE_ADDR"];
$ip_long = ip2long($ip_address);

この$ip_longが数値としてのIPアドレスになるわけです。

データベースにIPアドレスを保存する場合、最大15文字の文字列を整数で保存で きるので、データ量はかなり減らすことができます。(最近ではデータサイズを 気にすることはないかもしれませんが。。。

また、検索を行う場合はビット演算を行うことになります。完全一致の場合は等 号「=」での検索になるので、あまり関係ないかもしれませんが、ネットワーク アドレスでの検索を行う場合は部分一致になります。

たとえば、あるIPアドレスが192.168.100.0/24 のネットワークに含まれるかど うかを検索する場合は以下のようになります。

$ip_address = $_SERVER["REMOTE_ADDR"];
$ip_long = ip2long($ip_address);

$network = ip2long("192.168.100.0");
$netmask = 24;

if ( $ip_long >> (32 - $netmask) == $network >> (32 - $netmask) ) {
  // $network のネットワークに含まれない
} else {
  // $network のネットワークに含まれる
}

ネットマスクが24のネットワークなので後半8ビットは比較対象には含まれませ ん。そのため、右シフトをその回数分して、同様に右シフトしたネットワークア ドレスと一致するかどうかを見れば判定することができます。

少々ややこしいのですが、192.168.100.0/25 のネットワークなど、中途半端な ネットワークアドレスについての検索を行う場合はビット演算でないと難しいで しょう。

また、ビット演算は色々な場面で使うことができます。例えば、曜日を表す場合 にも使用することができます。あるデータに対して曜日ごとに on/off の状態を 付加することを考えると、7bitの数値として考えることができます。日曜日を0 土曜日を2 ^ 6とすると、平日は 0111110 の2進数で表すことができます。月曜 日は 0000010 となります。

こうすると、月曜日が含まれるかどうかは & を使用して判定することができます。

$week = decbin("0111101");
if ($week & decbin("0000010")) {
  // 月曜日が含まれる
} else {
  // 含まれない
}

このようにビット演算では32bitがintのビット数であれば、32種類までフラグの on/off を1つの数値で表すことができます。


(アシアル 森川穣)

この記事は、アシアルが運営するPHP開発者のためのポータル&コミュニティサイト「PHPプロ!」で毎週配信しているPHP・TIPSメーリングリストを再録したものです。
同サイトでは、他にもPHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座など、PHP開発者をサポートする情報を掲載しています。