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)
- Host: GitHub
- URL: https://github.com/ilya-ruk/php-ipv4-filter
- Owner: Ilya-Ruk
- License: mit
- Created: 2025-03-05T11:14:13.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-06T08:39:09.000Z (over 1 year ago)
- Last Synced: 2025-03-06T09:38:13.697Z (over 1 year ago)
- Language: PHP
- Homepage:
- Size: 5.86 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
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));
```