PHP

Проверка принадлежности IP-адреса заданному диапазону

Проверка вхождения IP в заданный диапазон может применяться во многих ситуациях. Например бан всей подсетки злоумышленника, принудительное ограничение скорости для зарубежного трафика, переадресация на различные разделы сайта в зависимости от провайдера пользователя и т.д. Я использую такие функции:
// ------------------------------------------------------------
// Проверка вхождения IP в заданный диапазон
// На входе:
// $ip - массив октетов проверяемого IP
// $ip_start - массив октетов начала интервала
// $ip_end - массив октетов конца интервала
// В интервалах допускаются маски '*'
// На выходе: TRUE или FALSE, входит IP или нет в диапазон
// ------------------------------------------------------------
function chk_ips($ip,$ip_start,$ip_end) {
  for ($i=0; $i<4; $i++) {
    if ($ip_start[$i]=='*') { $ip_start[$i]='0'; }
    if ($ip_end[$i]=='*') { $ip_end[$i]='255'; }
  }
  $ip_num=ip2long(join('.',$ip));
  if ($ip_num>=ip2long(join('.',$ip_start)) 
      && $ip_num<=ip2long(join('.',$ip_end))) {
    // IP входит в интервал
    return true;
  }
  else {
    // IP не входит в интервал
    return false;
  }
}

Функция универсальная, позволяет обрабатывать одиночные IP-адреса, точно заданные диапазоны и диапазоны с маской "*" в любом октете. Дополнительных проверок на корректность диапазонов не производится.

Для разворачивания маски подсети используется вспомогательная функция:
// ------------------------------------------------------------
// Функция разворачивания маски подсети
// На входе:
// $ip - массив октетов начала диапазона
// $mask - маска
// На выходе:
// массив IP конца диапазона
// ------------------------------------------------------------
function addip($ip,$mask) {
  // Количество IP в каждой маске
  $ip_count=Array(32=>0, 31=>1, 30=>3, 29=>7, 28=>15, 27=>31, 26=>63,
                25=>127, 24=>255, 23=>511, 22=>1023, 21=>2047, 20=>4095,
                19=>8191, 18=>16383, 17=>32767, 16=>65535, 15=>131071,
                14=>262143, 13=>524287, 12=>1048575, 11=>2097151,
                10=>4194303, 9=>8388607, 8=>16777215, 7=>33554431,
                6=>67108863, 5=>134217727, 4=>268435455, 3=>536870911,
                2=>1073741823);
  $x=Array();
  $ips=$ip_count[$mask];
 
  $x[0]=$ip[0]+intval($ips/(256*256*256));
  $ips=($ips%(256*256*256));
 
  $x[1]=$ip[1]+intval($ips/(256*256));
  $ips=($ips%(256*256));
 
  $x[2]=$ip[2]+intval($ips/(256));
  $ips=($ips%256);
 
  $x[3]=$ip[3]+$ips;
 
  return ($x);
}

И еще один небольшой вспомогательный парсер для разбора диапазона:
// ------------------------------------------------------------
// Парсер диапазонов IP
// На входе:
// $range - строка диапазона
// На выходе:
// Массив из двух массивов ([0]=>ip_start, [1]=>ip_end)
// или FALSE если строка не является допустимым диапазоном
// ------------------------------------------------------------
function range_parser($range) {
  $range=trim($range);
  // Проверка диапазона вида x.x.x.x-y.y.y.y
  if (strpos($range,"-")) {
    $tmp=explode("-",$range);
    $ip_start=explode(".",trim($tmp[0]));
    $ip_end=explode(".",trim($tmp[1]));
  }
  // Проверка диапазона вида x.x.x.x/y
  elseif (strpos($range,"/")) {
    $tmp=explode("/",$range);
    $ip_start=explode(".",$tmp[0]);
    // Развернуть маску подсети
    $ip_end=addip($ip_start,$tmp[1]);
  }
  // Проверка диапазона вида x.x.*.* или одиночного IP
  else {
    $ip_start=$ip_end=explode(".",$range);
  }
  // Простенькая проверка на корректность полученных диапазонов
  if (count($ip_start)==4 && count($ip_end)==4) {
    return array($ip_start, $ip_end);
  }
  else {
    return false;
  }
}

И рабочий пример с использованием всех этих функций:
$ip="127.0.12.7";                  // IP для проверки
$test_ip=explode(".",$ip);
 
$range="127.0.0.0/22";             // Маска подсети
$chk=range_parser($range);
chk_ips($test_ip,$chk[0],$chk[1]); // FALSE
 
$range="127.0.0.0-127.1.0.255";    // Интервал IP-адресов
$chk=range_parser($range);
chk_ips($test_ip,$chk[0],$chk[1]); // TRUE
 
$range="127.0.12.2";               // Одиночный IP
$chk=range_parser($range);
chk_ips($test_ip,$chk[0],$chk[1]); // FALSE
 
$range="127.*.*.*";                // Маска IP
$chk=range_parser($range);
chk_ips($test_ip,$chk[0],$chk[1]); // TRUE
Теги:
IP-адрес
Добавлено: 21 Сентября 2013 06:15:40 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...