Расчет CIDR по диапазону ip-адресов
У замечательного сервера nginx есть очень полезный модуль ngx_http_geo_module, который позволяет в зависимости от ip посетителя присваивать переменной различные значения. Диапазоны ip в его настройках надо указывать в формате CIDR (127.0.0.1/31), доступные же базы geo-ip содержат диапазоны в формате 127.0.0.0-127.0.0.1. В связи с чем возникла необходимость все это конвертировать.
Идя по пути наименьшего сопротивления, попытался найти существующие реализации этого простого алгоритма, но, к сожалению, поиски не увенчались успехом. Пришлось разбираться самому. Ниже привожу простую реализацию этой задачи.
class cidr_converter{
static function convert($ip1, $ip2){
$l_ip1 = ip2long($ip1);
$l_ip2 = ip2long($ip2);
$m2a = array();
for($i = 0; $i<32; $i++){
$m2a[32-$i] = pow(2, $i);
}
$masks = array();
$addr = $l_ip1;
do{
$bit_mask = self::get_ip_bitmask($addr);
if($addr+pow(2, 32 - $bit_mask)>$l_ip2){
$bit_mask = self::get_nearest_in_array($m2a, $l_ip2-$addr+1);
}
$masks[] = long2ip($addr).'/'.$bit_mask;
$addr += pow(2, 32 - $bit_mask);
}while ($addr<=$l_ip2);
return $masks;
}
static function get_ip_bitmask($long_ip){
$lb = 0;
while($long_ip!=0){
$long_ip = $long_ip<<1;
$lb++;
}
return $lb;
}
static function get_nearest_in_array($haystack, $needle){
$prev_addr = 0;
$prev_m = 0;
foreach ($haystack as $m=>$addr){
if($needle>$addr){
$prev_m = $m;
$prev_addr = $addr;
}elseif($addr==$needle){
return $m;
}elseif($needle<$addr){
return $prev_m?$prev_m:-1;
}
}
return $prev_m?$prev_m:-1;
}
}
print_r(cidr_converter::convert('127.0.0.0', '127.255.0.1'));




http://www.irbs.net/internet/postfix/0401/3032.html
С его помощью сделал вот это:
http://ip2cidr.savesoul.ru/