2015-11-26
임의의 ip 주소 192.168.0.1가 있고, 해당 아이피의 서브넷 마스크가 255.255.192.0(18) 이라면,
해당 아이피의 범위는 192.168.0.1 ~ 192.168.63.254이다.

위의 설명을 2진수로 바꾸어 보면,

임의의 ip 주소 11000000101010000000000000000001가 있고, 해당 아이피의 서브넷 마스크가 11111111111111111100000000000000(18) 이라면,
해당 아이피의 범위는 11000000101010000000000000000001 ~ 11000000101010000011111111111110이다.

그럼 이걸 소스로 표현해 보면, 아래와 같다.

일단 들어가기에 앞서서 3가지 php내장함수를 알아둘 필요가 있다.
ip2long() - 아이피를 long타입으로 바꿔준다.
decbin() - 10진수를 2진수로 바꿔준다.
sprintf() - http://b1ix.net/36 참조

/* 192.168.0.1/18*/

$ip = '192.168.0.1';
$subnet = '255.255.192.0';  /* 18 */
$max = ip2long('255.255.255.255');

$desc_ip = ip2long($ip);
$bin_ip_32 = sprintf('%032s',decbin($desc_ip));

$desc_subnet = ip2long($subnet);
$bin_subnet_32 = sprintf('%032s',decbin($desc_subnet));

$long_nor = $desc_ip ^ $desc_subnet;
$long_nor_32 = sprintf('%032s',decbin($long_nor));

$range_from = ($desc_ip & $desc_subnet) +1;
$range_from_32 = sprintf('%032s',decbin($range_from));

$range_bo = $desc_subnet ^ $max;
$range_bo_32 = sprintf('%032s',decbin($range_bo));

$range_to = ($desc_ip | $range_bo) - 1;
$range_to_32 = sprintf('%032s',decbin($range_to));

아래는 위에서 쓰인 모든 변수들의 값이다.
[ip] => 192.168.0.1
[subnet] => 255.255.192.0
[max] => -1
[desc_ip] => -1062731775
[bin_ip_32] => 11000000101010000000000000000001
[desc_subnet] => -16384
[bin_subnet_32] => 11111111111111111100000000000000
[long_nor] => 1062715393
[long_nor_32] => 00111111010101111100000000000001
[range_from] => -1062731775
[range_from_32] => 11000000101010000000000000000001
[range_bo] => 16383
[range_bo_32] => 00000000000000000011111111111111
[range_to] => -1062715394
[range_to_32] => 11000000101010000011111111111110

아래는 위의 소스를 이용하여 실제로 ip범위 체크를 해보는 함수를 하나 만들어 보았다.
function ip_chk( $ip, $subnet, $chk_ip)
{
    $long_ip = ip2long($ip);
    $long_subnet = ip2long($subnet);
    $long_max = ip2long('255.255.255.255');
    $long_chk_ip = ip2long($chk_ip);

    $range_from = ($long_ip & $long_subnet);

    $range_bo = $long_subnet ^ $long_max;
    $range_to = ($long_ip | $range_bo);

    if( $long_chk_ip > $range_from && $long_chk_ip < $range_to ) return 1;
    else return 0;
}

echo ip_chk('192.168.123.1', '255.255.255.252', '192.168.123.3')."<br>";
echo ip_chk('192.168.123.1', '255.0.0.0', '192.158.11.1');
0
1