An open API service indexing awesome lists of open source software.

https://github.com/ilya-ruk/php-ipv4-filter

Определение принадлежности IP к РФ (зона RU)
https://github.com/ilya-ruk/php-ipv4-filter

Last synced: 27 days ago
JSON representation

Определение принадлежности IP к РФ (зона RU)

Awesome Lists containing this project

README

          

# Определение принадлежности IP к РФ (зона RU)

## load_data.php

1. Загружает список IPv4 относящихся к РФ (зона RU) по API из [RIPE](https://stat.ripe.net/data/country-resource-list/data.json?resource=RU).
2. Дополняет список IP частных сетей (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 и 127.0.0.0/8).
3. Преобразует во внутренний формат (см. описание формата ниже).
4. Сохраняет в файле ip_ru.bin (ровно 512 Мб.).

## test_ip.php

Проверяет указанный в параметре IP на принадлежность к РФ (зона RU) или к частной сети (см. описание алгоритма проверки ниже).
Если IP не указан, выводит проверку для нескольких тестовых IP указанных в скрипте.
В выводе присутствует отладочная информация: IP, его целочисленное представление, номер блока, номер байта, номер бита, а также время проверки в микросекундах.

## Внутренний формат файла ip_ru.bin

Для IPv4 всего может быть 2^32 IP адресов или 4294967296.
Так как нам требуется ответить на вопрос "относится IP к РФ (частной сети) или нет?", нам достаточно хранить 0 или 1 для каждого возможного IP (0 - не относится, 1 - относится).
Соответственно, нам достаточно одного бита на каждый IP адрес.
Все адреса, не относящиеся к РФ (частной сети), заполняем 0.
Все адреса, относящиеся к РФ (частной сети), заполняем 1.
Упаковываем в байты (беззнаковый char) и сохраняем на диске.
Размер файла составит ровно 512 Мб (4294967296 адресов / 8 бит).

Для проверки достаточно будет проверить нужный бит, который расположен в файле со смещением равным IP (предварительно преобразованным к беззнаковому int).

Для выполнения проверки за минимальное время, чтение с диска (HDD) должно осуществляться блоком с размером, как правило, 4096 байт.
Для SSD можно читать только нужный байт.

## Алгоритм проверки

1. Открываем файл ip_ru.bin

```php
$fileName = 'ip_ru.bin';

$fd = fopen($fileName, 'rb');
```

2. Преобразуем тестируемый IP к беззнаковому int

```php
$ipInt = ipToInt($ip);
```

3. Определяем номер блока, который нужно прочитать с диска

```php
$blockSize = 4096;

$bitsPerBlock = $blockSize * 8;

$blockNumber = (int)floor((float)$ipInt / $bitsPerBlock);
```

4. Смещаемся в файле к началу нужного блока

```php
fseek($fd, $blockNumber * $blockSize)
```

5. Читаем блок с диска

```php
$blockData = fread($fd, $blockSize);
```

6. Определяем номер байта в блоке

```php
$blockOffset = $ipInt - $blockNumber * $bitsPerBlock;

$byteNumber = (int)floor((float)$blockOffset / 8);
```

7. Получаем значение нужного байта и распаковываем его из формата хранения на диске (беззнаковый char)

```php
$byte = unpack('C', $blockData[$byteNumber])[1];
```

8. Определяем номер бита в байте

```php
$bitNumber = $blockOffset - $byteNumber * 8;
```

9. Проверяем нужный бит

```php
return ($byte & (1 << $bitNumber));
```