Fast Site Engine
Высокопроизводительный движок для сайтов
Заказать сайт на основе движка
О движкеПроизводительностьБезопасностьТехнические требованияSEO 
Лицензионное соглашение
Демо
Установка
Панель управления
Модули
Документация
Шаблоны
Тесты производительности php
Планы на будущее
Список изменений
Отзывы и пожелания
Переходим на Линукс
Всякое разное
Документация  »  PHP класс для обработки IP адресов

PHP класс для обработки IP адресов

В классе заложены все минимально необходимые функции для обработки IP адресов на PHP (Internet Protocol address (IP address)), по умолчанию приводит адреса к короткому(сжатому) виду, в том числе переводя IPv4 адреса зашифрованные в IPv6 адресе к чистому IPv4 виду. Дополнительно преобразовывает в long числа для удобного хранения и сравнения.

В конце страницы приведу функцию благодаря которой проверял работоспособность и сгенерировал диапазоны масок IP адресов разной версии, дополнительно в них объясню как банить IPv4 и IPv6 адреса. На странице преобразования IP адресов, демонстрирующих работу библиотеки, можно проверить как будет распознана та или иная запись..

PHP класс сделан в большей части статическим и самодостаточным, для возможности использования без создания объекта и в любом месте. Для сравнения диапазонов используется расширение PHP BCMath из-за диапазонов выходящих за пределы int64 (IPv6). Насколько могу судить, в данный момент BCMath по умолчанию установлено на большинстве серверов.

Функции класса ip

Подключение библиотеки:
require D.'deny/ip.php';
Служебные функции помечены таким цветом.

public переменные

$ip->cidr='' //CIDR
$ip->first='' //IP v4 или v6 в сжатой форме
$ip->last='' //Если задан диапазон - второй адрес (конец диапазона)
$ip->firstlong='' //IP в виде long числа
$ip->lastlong='' 

Переменные станут доступны после создания экземпляра класса
$ip=new ip('127.0.0.1');
$ip=new ip('ffff::f0f0');

ссылка-якорь на переменные

new ip($s) - создание объекта

$s - строка содержащая IP адрес/а.

Вызов метода __construct() класса.
Всеяден, принимает как единичные IP адреса в любой форме, 
так и диапазоны через минус(тире) - или сидр(CIDR).
Сжимает IPv6 к короткому виду, преобразует IPv4 закодированные в IPv6 к их IPv4 виду.

Примеры:
Равнозначны и приведут IP к виду 192.168.1.2
$ip=new ip('0000:0000:0000:0000:0000:ffff:c0a8:0102');
$ip=new ip('0:0:0:0:0:ffff:c0a8:102'); //Укороченный
$ip=new ip('::ffff:c0a8:102'); //IPv6 Compressed address (short) сжатый уплотненный
$ip=new ip('::ffff:192.168.1.2'); //Mapped address
$ip=new ip('2002:c0a8:58fe::'); //Маршрутизация IPv6 в IPv4 - 
  маршрутный адрес роутеров/маршрутизаторов..
echo $ip->first; //192.168.1.2

$ip=new ip('fe80:0000:0000:0000:c1f5:6fc7:eef9:3341');
echo $ip->first; //fe80::c1f5:6fc7:eef9:3341

Диапазон адресов
$ip=new ip('192.168.0.0 - 192.168.255.255');
$ip=new ip('192.168.');
$ip=new ip('192.168');
echo $ip->first,' - ',$ip->last; //192.168.0.0 - 192.168.255.255

$ip=new ip('fe80::c1f5:6fc7:eef9:3341 - fe80::c1f5:6fc7:eef9:3341');
$ip=new ip('fe80:ff:c1f5:6fc7:* - fe80:ff:c1f5:6fc7:eef9:3341');
$ip=new ip('fe80:ff:c1f5:6fc7:*');
$ip=new ip('fe80:ff:c1f5:6fc7');

И в виде long
$ip=new ip('2130706431 - 22312312312321334534534');

CIDR диапазон адресов
$ip=new ip('192.168.1.2/16'); //mask = 255.255.0.0
$ip=new ip('192.168/16');
echo $ip->first,' - ',$ip->last; //192.168.0.0 - 192.168.255.255

$ip=new ip('fe80:1111:1222:1333:c1f5:6fc7:eef9:3341/64');
//mask = ffff:ffff:ffff:ffff:0000:0000:0000:0000
//fe80:1111:1222:1333:0000:0000:0000:0000 - fe80:1111:1222:1333:ffff:ffff:ffff:ffff
echo $ip->first,' - ',$ip->last; 
//fe80:1111:1222:1333:: - fe80:1111:1222:1333:ffff:ffff:ffff:ffff

Как уже заметили, IP адреса можно сокращать, избегайте употреблять
  с сокращением IPv6 :: функция не будет его дополнять до полной формы, 
  что приведёт к ошибке в обработке.
Например, если мы захотим заблокировать одну из подсетей Роскомнадзора, 
 равнозначно можно записать это так:
217.106.0.0 - 217.106.255.255 = 217.106.0.0/16 = 217.106./16 = 217.106/16 = 217.106.* = 
217.106 = 217.106.0 - 217.106.255

Ещё примеры:
10.0.0.0 - 10.255.255.255 = 10/8 = 10. = 10
192.168.0.0 - 192.168.255.255 = 192.168/16 = 192.168
1.0.0.15 - 1.255.255.25 = 1.* = 1. - 1. =  1.*.*.15 - 1.*.*.25
1.2.3.0 - 1.2.3.255 = 1.2.3.0/24 = 1.2.3/24 = 1.2.3.*
1.2.0.0 - 1.2.255.255 = 1.2.0.0/16 = 1.2/16 = 1.2.*
1.0.0.0 - 1.255.255.255 = 1.0.0.0/8  = 1/8 = 1.*

ссылка-якорь на конструктор new ip

ip::cidr2bin($i,$v=4) - преобразует CIDR с бинарный вид

$i - число, CIDR.
$v - число, версия протокола IPv4 или IPv6.

CIDR - Classless Inter-Domain Routing - Бесклассовая междоменная маршрутизация

echo ip::cidr2bin(16); //11111111111111110000000000000000 [32]
echo ip::cidr2bin(16,6); //11111111111111110000...00000000 [128]

ссылка-якорь на функцию cidr2bin

ip::cidr2mask($i,$v=4) - преобразует CIDR в маску сети

$i - число, CIDR.
$v - число, версия протокола IPv4 или IPv6.

CIDR - Classless Inter-Domain Routing - Бесклассовая междоменная маршрутизация

echo ip::cidr2mask(16); //255.255.0.0
echo ip::cidr2mask(16,6); //ffff::

ссылка-якорь на функцию cidr2mask

ip::cidrverify($i,$v=4) - проверяет корректность CIDR

$i - число, CIDR.
$v - число, версия протокола IPv4 или IPv6.

Приводит и возвращает $i к int, 
  проверяет диапазон возможных значений CIDR в зависимости от протокола.
Необходима во избежание последующих ошибок при преобразовании, 
  в случае некорректного CIDR - inet_pton начнёт сыпать предупреждениями.

echo ip::cidrverify(16,4); //16
echo ip::cidrverify(160,4); //32
echo ip::cidrverify(16,6); //16
echo ip::cidrverify(160,6); //128

ссылка-якорь на функцию cidrverify

ip::clear($s,$f=0,$a=[]) - восстанавливает форму IP

$s - строка, IP адрес в виде строки или числа, или сокращённого IP адреса.
$f - дополнить нулями в конце или 1 - максимальным значением 255 / ffff.
$a - массив символов после которых обрезать адрес (включая символ). 

Приводит IP адрес к чистой/полной форме, если это IPv4 в форме IPv6 - вернёт IPv4.
Если IP в виде числа, преобразует к обычной форме 127.0.0.1 итп.
Если IP адрес сокращён, дополняет "хвост" .0.0.. или .255 / :ffff (параметр $f).

Возвращает массив [0=>'восстановленный IP адрес', 1=>4/6 (версия протокола)];

$a=ip::clear('172.16.*',0,['/','*']);
echo $a[0],' version = ',$a[1]; //172.16.0.0 version = 4

$a=ip::clear('ffff:ffff',0,['/']);
echo $a[0],' version = ',$a[1]; //ffff:ffff:: version = 6

ссылка-якорь на функцию clear

ip::compress($s,$m=1) - сжимает IP адрес

$s - IP адрес в виде строки.
$m - преобразовывать IPv4 в mapped address форму,
(по умолчанию inet_ntop(inet_pton($s)) вернёт mapped - ::ffff:192.168.1.2)

Вернёт строку - IPv6 Compressed address (short) сжатый уплотненный
Допускает наличие CIDR в адресе.

echo ip::compress('192.168.1.2/16'); //92.168.1.2/16
echo ip::compress('0000:0000:0000:0000:0000:ffff:b934:01ed'); //::ffff:192.168.1.2
echo ip::compress('0000:0000:0000:0000:0000:ffff:b934:01ed',0); //::ffff:c0a8:102
echo ip::compress('2002:b934:01ed::'); //2002:b934:1ed::
echo ip::compress('2002:b934:01ed::',0); //2002:b934:1ed::
echo ip::compress('0:0:0:0:0:ffff:b934:1ed',0); //::ffff:c0a8:102
echo ip::compress('2001:0:0:0:6dcd:0:0:0'); //2001::6dcd:0:0:0

ссылка-якорь на функцию compress

ip::count($f,$l=0) - подсчитывает количество адресов

$f - начальный IP адрес (или в виде числа long (в строке)).
$l - конечный IP адрес.
Возвращает строку с числом.
//max: IPv4=4294967296; IPv6=340282366920938463463374607431768211456

echo ip::count('192.168.1.0'); //3232235777
echo ip::count('192.168.1.0','192.168.1.0'); //1
echo ip::count('192.168.1.1','192.168.1.0'); //2
echo ip::count('192.168.1.10','192.168.1.20'); //11
echo ip::count('::ffff:192.168.1.2','::ffff:192.168.1.8'); //7
echo ip::count('192.168.1.2','::ffff:192.168.1.3'); //281470681743362
echo ip::count('192.168.1.2','ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'); 
  //340282366920938463463374607428535975678
echo ip::count('68719476736','125544568719476736'); //125544500000000001

ссылка-якорь на функцию count

ip::expand($s,$f=1) - разворачивает IP адрес

$s - IP адрес.
$f - 1 в полной или 0 в сокращённой форме.

echo ip::expand('192.168.1.2'); //192.168.1.2
echo ip::expand('192.168.1.2',0); //192.168.1.2
echo ip::expand('::ffff:192.168.1.2'); //0000:0000:0000:0000:0000:ffff:c0a8:0102
echo ip::expand('::ffff:192.168.1.2',0); //0:0:0:0:0:ffff:c0a8:102
echo ip::expand('ffff::c0a8:0102'); //ffff:0000:0000:0000:0000:0000:c0a8:0102
echo ip::expand('ffff::c0a8:0102',0); //ffff:0:0:0:0:0:c0a8:102

//преобразование к маршрутному типу 2002:... IPv4 не делал, если необходимо, то:
echo str_replace('0:0:0:0:0:ffff','2002',ip::expand(ip::v4to6('192.168.1.2'),0)).'::';
//2002:c0a8:102::

ссылка-якорь на функцию expand

ip::fill($s,$f=0) - заполняет IP адрес

$s - IP адрес.
$f - дополнить конец 0 = 0; 1 = 255|ffff.
Возвращает массив [0=>'ip адрес', 1=>0|1 изменён ли ip];

Функция дополняет до полного количества разрядов IP адрес.
Допускает наличие CIDR в адресе.

$a=ip::fill('10/8');
echo $a[0],', ip изменён: ',$a[1]; //10.0.0.0/8, изменён: 1
$a=ip::fill('192.168/8',1);
echo $a[0],', ip изменён: ',$a[1]; //192.168.255.255/8, изменён: 1
$a=ip::fill('ffff::c0a8:0102');
echo $a[0],', ip изменён: ',$a[1]; //ffff::c0a8:0102, изменён: 0
$a=ip::fill('ffff:c0a8');
echo $a[0],', ip изменён: ',$a[1]; //ffff:c0a8:0:0:0:0:0:0, изменён: 1
$a=ip::fill('ffff:c0a8',1);
echo $a[0],', ip изменён: ',$a[1]; //ffff:c0a8:ffff:ffff:ffff:ffff:ffff:ffff, изменён: 1

ссылка-якорь на функцию fill

ip::frombin($s) - преобразует бинарную запись в IP

$s - IP адрес в бинарной форме.

echo ip::frombin('11111111111100111111111111111100'); //255.243.255.252

ссылка-якорь на функцию frombin

ip::fromlong($s) - преобразует число в IP

$s - IP адрес в виде числа long.

echo ip::fromlong('3232235778'); //192.168.1.2 
echo ip::fromlong('281473913979138'); //::ffff:192.168.1.2
echo ip::fromlong('281473913979138'); //::ffff:192.168.1.2
echo ip::fromlong('28147391123434273453979138'); //::17:4871:215a:c5d2:71f1:3602

ссылка-якорь на функцию fromlong

$ip->in($s) - сравнение диапазонов адресов

$s - IP адрес, диапазон итп. Через запятую , или точку с запятой ;

Функция станет доступна после создания экземпляра класса
$ip=new ip('127.0.0.1');

echo $ip->in('10000000 - 281473911234342734, 128.0.0.0 - 10.255.255.255; 10/8'); //1
echo $ip->in('100.100./16'); //0
echo $ip->in('127.0-::17:4871:215a:c5d2:71f1:3602'); //1

ссылка-якорь на функцию in

ip::inlong($i,$f,$l='') - сравнение адресов

Все адреса в виде числовой строки в виде long.
$i - проверяемый IP адрес.
$f - начало диапазона.
$l - конец диапазона, не обязателен.

echo ip::inlong('23434567676756','234563453734567','45634565678696789'); //0

Более быстрый способом проверки - хранить в long все IP адреса:
require D.'deny/ip.php';
$banned=0;
$testip=ip::tolong(IP);
$banips='2130706431 - 22312312312321334534534; 3434523453452345';
$a=explode(';',str_replace(' ','',$banips));
foreach($a as $k=>$v){
  if(ip::sp($v,'-'))$b=explode('-',$v);
  else $b=[0=>$v,1=>''];
  if(ip::inlong($testip,$b[0],$b[1])){$banned=1;break;}
}
if($banned){header('HTTP/1.1 403 Forbidden');exit('banned');}

ссылка-якорь на функцию inlong

ip::isint($v) - является ли переменная целым числом

$v - проверяемая переменная.

echo var_dump(ip::isint('23434567676756')); //bool(true)
echo var_dump(ip::isint(23434567676756)); //bool(true)
echo var_dump(ip::isint('2343456.00')); //bool(false)
echo var_dump(ip::isint(2343456.00)); //bool(true), хвост .00 срежет PHP
  (особенности хранения переменных).

ссылка-якорь на функцию isint

$ip->get($f=1,$l=0) - вернуть ip адрес

$f - 1 первый адрес $ip->first. 0|2 - Последний $ip->last. 
$l - вернуть числом - $ip->firstlong, $ip->lastlong;
Возвращает строку, пустую если ip нет.

Функция станет доступна после создания экземпляра класса
$ip=new ip('127.0.0.1 - ffff::');

echo $ip->get(); //127.0.0.1
echo $ip->get(2); //ffff::
echo $ip->get(1,1); //2130706433
echo $ip->get(2,1); //340277174624079928635746076935438991360

ссылка-якорь на функцию get

ip::long2bin($s,$v=4) - преобразует число в бинарный вид

$s - число, long IP адрес.
$v - версия протокола, можно пропускать - необходима исключительно для 
  правильного отображения 0 адреса.

//127.0.0.1
echo ip::long2bin('2130706433',4); //01111111000000000000000000000001
echo ip::long2bin('2130706433',6); //01111111000000000000000000000001

echo ip::frombin(ip::long2bin('340277174624079928635746076935438991360',4)); //ffff::
echo ip::frombin(ip::long2bin('340277174624079928635746076935438991360',6)); //ffff::

echo ip::long2bin(0); //00000000000000000000000000000000 [32]
echo ip::long2bin('',4); //00000000000000000000000000000000 [32]
echo ip::long2bin('',6); //00000000000000...000000000000000 [128]

ссылка-якорь на функцию long2bin

ip::tobin($s,$v=4) - преобразует IP в бинарный вид

$s - IP адрес.
$v - версия протокола, можно пропускать - необходима исключительно для 
  правильного отображения 0 адреса.

echo ip::tobin('127.0.0.1'); //01111111000000000000000000000001

echo ip::tobin(0); //00000000000000000000000000000000 [32]
echo ip::tobin('',4); //00000000000000000000000000000000 [32]
echo ip::tobin('',6); //00000000000000...000000000000000 [128]

ссылка-якорь на функцию tobin

ip::tolong($s,$v=0) - преобразует IP в число

$s - IP адрес.
$v - версия протокола, если не задана - функция сама определит, 
  оставлена для внешней оптимизации.

echo ip::tolong('192.168.1.2'); //3232235778
echo ip::tolong('::ffff:192.168.1.2'); //281473913979138
echo ip::tolong('0000:0000:0000:0000:0000:ffff:c0a8:0102'); //281473913979138
echo ip::tolong('ffff::'); //340277174624079928635746076935438991360

ссылка-якорь на функцию tolong

ip::shorten($s) - преобразует IP в укороченную форму

$s - IP адрес.
Производит подвызов функции ip::expand($s,0);

echo ip::shorten('192.168.1.2'); //192.168.1.2
echo ip::shorten('::ffff:192.168.1.2'); //0:0:0:0:0:ffff:c0a8:102
echo ip::shorten('0000:0000:0000:0000:0000:ffff:c0a8:0102'); //0:0:0:0:0:ffff:c0a8:102
echo ip::shorten('0:0:0:0:0:ffff:c0a8:102'); //0:0:0:0:0:ffff:c0a8:102
echo ip::shorten('::ffff:b934:1ed'); //0:0:0:0:0:ffff:b934:1ed

ссылка-якорь на функцию shorten

ip::sp($s,$f) - проверяет вхождение строки в другую

$s - строка.
$f - что ищем.
Производит подвызов mb_strpos.

echo var_dump(ip::sp('string b','%b')); //bool(false)
echo var_dump(ip::sp('string %b','%b')); //bool(true)

ссылка-якорь на функцию sp

ip::v4to6($s,$m=1) - преобразует IPv4 в IPv6

$s - IP адрес.
$m - преобразовывать IPv4 в mapped address форму

echo ip::v4to6('192.168.1.2'); //::ffff:192.168.1.2
echo ip::v4to6('192.168.1.2',0); //::ffff:c0a8:102

//По факту система адресов разная и выделение провайдером/роутером 
  дополнительного IPv6 адреса, вовсе не значит что он хоть как-то будет равен IPv4.

ссылка-якорь на функцию v4to6

ip::v6to4($s) - преобразует IPv6 в IPv4

$s - IP адрес.
Вернёт пустую строку в случае неудачи.

echo ip::v6to4('ffff:b934:1ed:ffc::'); //''
echo ip::v6to4('::ffff:192.168.1.2'); //192.168.1.2
echo ip::v6to4('2002:c0a8:102:0000:0000:0000:0000:0000'); //192.168.1.2
echo ip::v6to4('2002:c0a8:102:0:0:0:0:0'); //192.168.1.2 
  2002: = Маршрутизация IPv6 в IPv4  - маршрутный адрес роутеров..

//По факту система адресов разная и выделение провайдером/роутером 
  дополнительного IPv6 адреса, вовсе не значит что он хоть как-то будет равен IPv4.

ссылка-якорь на функцию v6to4

ip::ver($s) - определяет версию протокола IP

$s - IP адрес в виде строки или long.
Вернёт пустую строку в случае неудачи.

echo ip::ver('abracadabra'); //0
echo ip::ver('192.168.1.2'); //4
echo ip::ver('3232235778'); //4
echo ip::ver('ffff:b934:1ed:ffc::'); //6
echo ip::ver('::ffff:192.168.1.2'); //6
echo ip::ver('281473913979138'); //6
echo ip::ver(281473913979138); //6
echo ip::ver('::ffff:c0a8:0102'); //6
echo ip::ver('281473913979138'); //6

ссылка-якорь на функцию ver

В SQL базе данных можно хранить ip адреса в запакованном(inet_pton) виде, в виде бинарных данных BINARY(16), но при этом необходимо понимать в битовых операциях для выборок и сравнения, плюс встаёт вопрос дампов базы данных и возможном попадании туда некорректных данных и последующих проблем "на ровном месте". И это противоречит заложенному постулату о простоте движка, поэтому хранить ip в базе рекомендую как DECIMAL(39,0), при этом можно будет делать выборку по диапазонам средствами SQL и используя long функции (ip::tolong(), ip::fromlong()).
ip DECIMAL(39,0) NOT NULL DEFAULT 0,
136111847226264995686342697210517200896 =39

Ещё вариант хранения в VAR/CHAR(39), число или IPv6 поместится:
ip char(39) NOT NULL DEFAULT '',
0000:0000:0000:0000:0000:0000:0000:0000 =39

Функция генерации диапазонов масок IP

require D.'deny/ip.php';
//$v=ver(4|6); f=format (d - symbols space); $r=revers
function maskmap($v=4,$f='/%i %s = %b; %m; %n<br>',$r=1){
  $b=ip::sp($f,'%b');//bin
  $c=ip::sp($f,'%c');//compacted mask v6
  $l=ip::sp($f,'%l');//long
  $m=ip::sp($f,'%m');//mask
  $n=ip::sp($f,'%n');//ip count
  if(4==$v){$z=33;$q='';}else{$z=129;$q='&nbsp;';}
  $k=$r?$z-1:0;
  $a=$t=$s=$u=$p='';
  for($i=0;$i<$z;$i++){
    if(10>$k)$s=$q.'&nbsp;';
    elseif(100>$k)$s=$q;
    else $s='';
    $u=str_replace('%i',$k,$f);
    $u=str_replace('%s',$s,$u);
    $a=ip::cidr2bin($k,$v);
    if($b)$u=str_replace('%b',$a,$u);
    $p=ip::frombin($a);
    if($c)$u=str_replace('%c',$p,$u);
    $p=ip::expand(ip::frombin($a));
    if($m)$u=str_replace('%m',ip::expand($p),$u);
    if($n){
      $y=ip::tolong($p);
      $j=inet_pton($p);
      $e=ip::tolong(inet_ntop($j|~$j));
      $u=str_replace('%n',bcadd(bcsub($e,$y),1),$u);
    }
    if($l)$u=str_replace('%l',ip::tolong($p,$v),$u);
    $t.=$u;
    $k=$r?$k-1:$k+1;
  } return $t;
}
echo '<h2>Таблица сетевых масок IPv4</h2>',maskmap(4);
echo '<h2>Таблица сетевых масок IPv6</h2>',maskmap(6);
Страница сгенерирована за 0.005674 секунды
На один процесс веб-сервера: 176 стр./сек.
Всего Apache может отдать: 45 056 стр./сек.
Выделено php памяти: 494.88 KB, real_usage: 2 MB

© Все права защищены 2004 - 2021
Карта сайта
Отслеживать изменения в Твиттере
Политика конфиденциальности

Браузер построил за сек.
Полное время сек.

С момента выгрузки предыдущей страницы из памяти браузера: сек.