Php将ipv6转换为数字

Ben*_*Ben 15 php

在Ipv4中,我们可以使用ip2long它将其转换为数字,

如何在PHP中将ipv6压缩为数字转换?

我试过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
Run Code Online (Sandbox Code Playgroud)

Gla*_*vić 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
Run Code Online (Sandbox Code Playgroud)

功能:

启用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));
}
Run Code Online (Sandbox Code Playgroud)

demo


boe*_*bot 8

$ ip_2不是有效的IPv6地址.你需要在那里的"::"表示零遗漏点.

如果你有一个

$ip_2='2001::11ff:ffff:f';
$ip_2='2001:11ff::ffff:f';
$ip_2='2001:11ff:ffff::f';
Run Code Online (Sandbox Code Playgroud)

那么inet_pton()应该可以正常工作.

正如已经暗示的那样,PHP没有128整数类型,所以你能得到的最好的是二进制字符串中的数字字符串 inet_pton()给你...是的,就是这样,这就是为什么它看起来很奇怪.如果你看一下这些字符串的位,你会发现它们正是你所期望的.

以下是如何将二进制字符串扩展为数字字符串(str_pad()中缺少参数"0"):

/**
 * @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);
}
Run Code Online (Sandbox Code Playgroud)

  • @boen_robot:函数`ipv6_numeric`无法正常工作。对于`2001:11ff:ffff :: f`,它输出无效的'425408532453474964660062882882822604240',应该是'42540853245347499499564798372846648688655',例如[here](http://www.v6decode.com/#address=2001%3A11ff%3Affff% 3A%3Af)。 (2认同)
  • 这是因为`base_convert`遭受溢出的困扰,PHP手册上还有一个巨大的红色框,警告该错误。看我的答案。 (2认同)

Fle*_*der 8

请注意,所有答案都会导致大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
Run Code Online (Sandbox Code Playgroud)

返回的二进制数字打包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
Run Code Online (Sandbox Code Playgroud)

因此,构建两个所需的函数非常简单:

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));
}
Run Code Online (Sandbox Code Playgroud)