Php конвертировать ipv6 в число

В Ipv4 мы можем использовать ip2long чтобы преобразовать его в число,

Как преобразовать ipv6, сжатый в число в PHP?

Я пробовал inet_pton, и он не работает.

 $ip_1='2001:0db8:85a3:0000:0000:8a2e:0370:7334'; $ip_2='2001:11ff:ffff:f';//Compressed echo inet_pton($ip_1); //OUTPUT ИЃ.ps4 echo inet_pton($ip_2); //OUTPUT Warning: inet_pton(): Unrecognized address 2001:11ff:ffff:f 

$ ip_2 не является допустимым адресом IPv6. Вам нужно «::» где-то там, чтобы указать нулевую точку пропуска.

Если у вас есть это как один из

 $ip_2='2001::11ff:ffff:f'; $ip_2='2001:11ff::ffff:f'; $ip_2='2001:11ff:ffff::f'; 

то inet_pton () должен работать нормально.

Как уже намекнул, PHP не имеет целочисленного типа 128, поэтому лучше всего получить цифровую строку из двоичной строки inet_pton (), которая дает вам … да, вот что это такое, и поэтому выглядит странно , Если вы посмотрите на биты этих строк, вы увидите, что они именно то, что вы ожидаете.

Вот как развернуть двоичную строку в числовую строку (аргумент «0» отсутствовал из str_pad () изначально):

 /** * @param string $ip A human readable IPv4 or IPv6 address. * @return string Decimal number, written out as a string due to limits on the size of int and float. */ function ipv6_numeric($ip) { $binNum = ''; foreach (unpack('C*', inet_pton($ip)) as $byte) { $binNum .= str_pad(decbin($byte), 8, "0", STR_PAD_LEFT); } return base_convert(ltrim($binNum, '0'), 2, 10); } 

Использование:

 $ip = 'fe80:0:0:0:202:b3ff:fe1e:8329'; $dec = ip2long_v6($ip); $ip2 = long2ip_v6($dec); // $ip = fe80:0:0:0:202:b3ff:fe1e:8329 // $dec = 338288524927261089654163772891438416681 // $ip2 = fe80::202:b3ff:fe1e:8329 

Функции:

С включенным расширением GMP или BCMATH .

 function ip2long_v6($ip) { $ip_n = inet_pton($ip); $bin = ''; for ($bit = strlen($ip_n) - 1; $bit >= 0; $bit--) { $bin = sprintf('%08b', ord($ip_n[$bit])) . $bin; } if (function_exists('gmp_init')) { return gmp_strval(gmp_init($bin, 2), 10); } elseif (function_exists('bcadd')) { $dec = '0'; for ($i = 0; $i < strlen($bin); $i++) { $dec = bcmul($dec, '2', 0); $dec = bcadd($dec, $bin[$i], 0); } return $dec; } else { trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); } } function long2ip_v6($dec) { if (function_exists('gmp_init')) { $bin = gmp_strval(gmp_init($dec, 10), 2); } elseif (function_exists('bcadd')) { $bin = ''; do { $bin = bcmod($dec, '2') . $bin; $dec = bcdiv($dec, '2', 0); } while (bccomp($dec, '0')); } else { trigger_error('GMP or BCMATH extension not installed!', E_USER_ERROR); } $bin = str_pad($bin, 128, '0', STR_PAD_LEFT); $ip = array(); for ($bit = 0; $bit <= 7; $bit++) { $bin_part = substr($bin, $bit * 16, 16); $ip[] = dechex(bindec($bin_part)); } $ip = implode(':', $ip); return inet_ntop(inet_pton($ip)); } 

демонстрация

Обратите внимание, что все ответы приведут к неправильным результатам для больших IP-адресов или проходят сложный процесс для получения фактических чисел. Получение фактического целочисленного значения из адреса IPv6 требует двух вещей:

  1. Поддержка IPv6
  2. Расширение GMP ( --with-gmp )

При наличии обоих предварительных условий конверсия проста:

 $ip = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'; $int = gmp_import(inet_pton($ip)); echo $int; // 340282366920938463463374607431768211455 

Бинарное числовое упакованное представление in_addr , возвращаемое inet_pton , уже является целым числом и может быть непосредственно импортировано в GMP, как показано выше. Нет необходимости в специальных конверсиях или что-то еще.

Обратите внимание, что наоборот так же просто:

 $int = '340282366920938463463374607431768211455'; $ip = inet_ntop(str_pad(gmp_export($int), 16, "\0", STR_PAD_LEFT)); echo $ip; // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 

Следовательно, создание двух желаемых функций так же просто, как:

 function ipv6_to_integer($ip) { return (string) gmp_import(inet_pton($ip)); } function ipv6_from_integer($integer) { return inet_ntop(str_pad(gmp_export($integer), 16, "\0", STR_PAD_LEFT)); } 

Хорошо, некоторые откровения из чата с Беном Вонгом … РЕАЛЬНАЯ проблема – это оптимизация поиска в базе данных о службе geoIP.

Макет БД, предлагаемый этой базой данных geoIP, слишком медленный, чтобы просто использовать приложение «BETWEEN» в начале и в конце, хотя хранилище является наиболее экономичным, которое вы можете получить.

Предложение, которое я впервые изложил в чате, заключалось в том, чтобы фрагментировать IP-адрес в 4 типах, которые сравниваются последовательно, но на втором, но этого может быть недостаточно, поскольку вы все еще просматриваете весь БД, который составляет более 1 миллиона строк , Я также имел представление о выполнении масок с масками подсети, но, учитывая, что некоторые диапазоны не находятся в больших масках, сделать это может, опять же, быть недостаточно.

Я посмотрю, что я могу сделать, и я отредактирую этот ответ. Но я отправляю это тем временем для всех, кто хочет помочь в этом.

Попробуй это

 function inet6_to_int64($addr) { /* Expand the address if necessary */ if (strlen($addr) != 39) { $addr = inet6_expand($addr); if ($addr == false) return false; } // if $addr = str_replace(':', '', $addr); $p1 = '0x' . substr($addr, 0, 16); $p2 = '0x' . substr($addr, 16); $p1 = gmp_init($p1); $p2 = gmp_init($p2); $result = array(gmp_strval($p1), gmp_strval($p2)); return $result; } // inet6_to_int64() 

Для получения дополнительных функций или деталей посетите сайт http://www.soucy.org/project/inet6/