IPv4だけのときは、ip2long/long2ipでマスク長のビット演算をして比較すればよかったが、昨今IPv6も普通にあり得るのでそっちにも適用しなくちゃいけない。
IPv6は128ビットなので、longでは検査できないので、inet_ptonを使って検査するルーチンを書いてみた。
Github はこちら。
https://github.com/usoinfo/php_ipaddrmask_test
{
$iarr = str_split($src);
$marr = str_split($mask);
$ret = false;
for($i=0;$i<count($iarr);$i++){
$ret .= $iarr[$i] & $marr[$i];
}
return $ret;
}
function ipaddr_compare($srcaddr, $netaddr, $netmask)
{
if( !$netmask && ($pos = strpos($netaddr,"/")) !== FALSE ){
$netmask = intval( substr($netaddr, $pos+1) );
$netaddr = substr($netaddr, 0, $pos);
}
$addr = inet_pton($srcaddr);
$comp = inet_pton($netaddr);
$len = strlen($addr)*8;
if($netmask > $len) $netmask = $len;
$mask = str_repeat('f', $netmask>>2);
switch($netmask & 3){
case 3: $mask .= 'e'; break;
case 2: $mask .= 'c'; break;
case 1: $mask .= '8'; break;
}
$mask = pack('H*', str_pad($mask, $len>>2, '0') );
return ipaddr_mask($addr, $mask) == ipaddr_mask($comp, $mask);
}
/*
使用法サンプル
$srcaddr = "192.168.1.12";
$netaddr = "192.168.1.0";
$netmask = 24;
$r = ipaddr_compare($srcaddr, $netaddr, $netmask);
echo $srcaddr." compare ".$netaddr."/".$netmask." => ".($r ? "match" : "unmatch")."\n";
$srcaddr = "25ef:91:c540:1:a00:27fa:fce1:28c";
$netaddr = "25ef:91:c540:1::0";
$netmask = 64;
$r = ipaddr_compare($srcaddr, $netaddr, $netmask);
echo $srcaddr." compare ".$netaddr."/".$netmask." => ".($r ? "match" : "unmatch")."\n";
実行結果
192.168.1.12 compare 192.168.1.0/24 => match
25ef:91:c540:1:a00:27fa:fce1:28c compare 25ef:91:c540:1::0/64 => match
*/
タグ:PHP
▼レンタルサーバー・VPS比較表を見る▼