Обработка сетевых адресов средствами языка PHP

Раздел: -> Работа с сетью

Работа с IP адресами в PHP

Основное и наиболее эффективное решение

Для преобразования IPv4 адреса в целое число и обратно в PHP используются две нативные функции: ip2long и long2ip. Они работают крайне быстро и не требуют дополнительных расширений. Пример:

$ip = '192.168.1.1';
$long = ip2long($ip); // результат: -1062731519 (или 3232235777 при беззнаковом представлении)
echo $long;
-1062731519

Обратное преобразование:

$long = -1062731519;
$ip = long2ip($long); // '192.168.1.1'
echo $ip;
192.168.1.1

Возможная проблема:

На 32‑битных версиях PHP результат ip2long может быть отрицательным. Для получения беззнакового значения используется sprintf('%u', ip2long($ip)) или bindec(decbin(ip2long($ip))). Также ip2long не поддерживает IPv6.

Как проверить, является ли строка IP адресом?

Для проверки формата применяется filter_var() с константами FILTER_VALIDATE_IP и флагом FILTER_FLAG_IPV4 или FILTER_FLAG_IPV6.

$ip = '192.168.1.1';
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
    echo "Корректный IPv4";
} else {
    echo "Неверный IP";
}

Типичная ошибка:

По умолчанию filter_var допускает ведущие нули (например, 192.168.001.001), что не всегда желательно. Для строгой проверки применяется регулярное выражение.

Как работать с IPv6 адресами?

Для IPv6 используются функции inet_pton (преобразование адреса в бинарную строку) и inet_ntop (обратно). Они работают как с IPv4, так и с IPv6.

$ipv6 = '::1';
$binary = inet_pton($ipv6); // 16-байтовая строка
echo bin2hex($binary); // 00000000000000000000000000000001
$back = inet_ntop($binary); // ::1
echo $back;
00000000000000000000000000000001
::1

Как преобразовать IPv4 из строки в число без потери точности?

Используется комбинация ip2long и sprintf('%u', ...). Для IPv6 удобно применять unpack после inet_pton.

$ip = '10.0.0.1';
$unsigned = sprintf('%u', ip2long($ip)); // 167772161
echo $unsigned;
167772161

Как определить принадлежность IP диапазону (CIDR)?

Сначала адрес и маска преобразуются в числа, затем выполняется побитовое сравнение.

function ip_in_cidr($ip, $cidr) {
    list($subnet, $bits) = explode('/', $cidr);
    $ip_long = ip2long($ip);
    $subnet_long = ip2long($subnet);
    $mask = -1 << (32 - $bits);
    return ($ip_long & $mask) === ($subnet_long & $mask);
}
var_dump(ip_in_cidr('192.168.5.10', '192.168.0.0/16')); // true

Сложности:

Для IPv6 потребуется работать с 128‑битными числами, для чего применяется расширение GMP или ручной разбор бинарного представления.

Расширенные примеры работы с IP адресами

1. Извлечение IP пользователя из заголовков запроса

Пример
function getClientIP() {
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $ip = trim($ips[0]);
    } else {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    }
    return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
}
echo getClientIP();
192.168.1.100 (пример)

2. Преобразование IPv6 в десятичное представление с GMP

Пример
$ipv6 = '2001:db8::1';
$binary = inet_pton($ipv6);
// Разбор 16 байт как big-endian
$hex = bin2hex($binary);
$dec = gmp_init($hex, 16);
echo gmp_strval($dec); // 42540766411282592856903984951653826561
42540766411282592856903984951653826561

3. Сортировка списка IP адресов в естественном порядке

Пример
$ips = ['10.0.0.5', '192.168.0.2', '10.0.0.10', '172.16.0.1'];
usort($ips, function($a, $b) {
    return ip2long($a) - ip2long($b);
});
print_r($ips);
Array
(
    [0] => 10.0.0.5
    [1] => 10.0.0.10
    [2] => 172.16.0.1
    [3] => 192.168.0.2
)

4. Генерация всех IP адресов подсети /24

Пример
$network = '10.0.0.0';
$mask = 24;
$long = ip2long($network);
$hosts = 1 << (32 - $mask);
for ($i = 1; $i < $hosts - 1; $i++) {
    echo long2ip($long + $i) . "\n";
}
10.0.0.1
10.0.0.2
...
10.0.0.254

5. Конвертация IPv4 в IPv4‑mapped IPv6

Пример
$ipv4 = '192.168.1.1';
$ipv6 = '::ffff:' . $ipv4;
echo inet_ntop(inet_pton($ipv6)); // ::ffff:192.168.1.1
::ffff:192.168.1.1

6. Определение двухбайтового представления IPv4 адреса (для базы данных)

Пример
$ip = '8.8.8.8';
$bytes = inet_pton($ip); // 4 байта
// Сохранить как BINARY(4) или CHAR(4) – хороший способ
// Чтение обратно: inet_ntop($bytes)

Работа с IP-адресами в PHP - comments

En
Php ip (php)