在php中将IPv6 cidr拆分为/64块

在php中将IPv6 cidr拆分为/64块,php,ipv6,cidr,Php,Ipv6,Cidr,我希望创建一个脚本,将ipv6范围或cidr作为输入,并输出/64块的列表(或每个/64块中的第一个IP) 我有一个类似于IPv4 IP的函数,但我不了解如何将其重新用于ipv6 Function BreakTo30($CIDR) { $CIDR = explode("/", $CIDR); // this breaks the CIDR block into octlets and /notation $octet = ip2long($CIDR[0]); //turn the

我希望创建一个脚本,将ipv6范围或cidr作为输入,并输出/64块的列表(或每个/64块中的第一个IP)

我有一个类似于IPv4 IP的函数,但我不了解如何将其重新用于ipv6

Function BreakTo30($CIDR)
{
    $CIDR = explode("/", $CIDR); // this breaks the CIDR block into octlets and /notation
    $octet = ip2long($CIDR[0]); //turn the first 3 octets into a long for calculating later
    $NumberOf30s = pow(2,(30-$CIDR[1]))-1; //calculate the number of /30s in the CIDR block
    $OutputArray = array();
    for ($i=-4; $i<4 * $NumberOf30s; $OutputArray[] = (long2ip($octet + ($i += 4)))); //fancy math to output each /30
    return $OutputArray; //returns an array of ranges

}
功能中断30($CIDR)
{
$CIDR=explode(“/”,$CIDR);//这将CIDR块分解为八位字节和/表示法
$octet=ip2long($CIDR[0]);//将前3个八位字节转换为long,以便以后计算
$NumberOf30s=pow(2,(30-$CIDR[1])-1;//计算CIDR块中/30s的数量
$OutputArray=array();

对于($i=-4;$i有一个解决方案可以满足您的需求,并且需要您匹配它的:D

它的要求是安装GMP或BCMATH扩展,因为在这种情况下,您将处理非常大的小数

<?php
$cidr ="2001:adb8:85a3:1111:1111:8a2e:3270:7334/120";
$all = listIPv6InBlock($cidr);

echo "CIDR is $cidr<br/>\r\n";
echo "Count is ". count($all)."<br/>\r\n";

printAddresses($all);

function listIPv6InBlock($CIDR)
{
    $CIDR = explode("/", $CIDR); // this breaks the CIDR block into octlets and /notation
    $octet = ip2long_v6($CIDR[0]); //turn the first 3 octets into a long for calculating later
    $NumberOfIPs = pow(2,(128-$CIDR[1]))-1; //calculate the number of /30s in the CIDR block
    $OutputArray = array();
    for ($i=0; $i< $NumberOfIPs; $i++){
        $OutputArray[] = long2ip_v6(bcadd($octet,"$i"));
    }
    return $OutputArray; //returns an array of ranges
}

function printAddresses($arr){
    foreach($arr as $ip){
        echo "$ip <br/>\r\n";       
    }
}

/*
 *The following two functions are credited to (https://stackoverflow.com/users/67332/glavi%C4%87) 
 * who gave this answer :https://stackoverflow.com/a/19497446/896244
 */
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));
}
?>

如您所见,此解决方案对小数(作为字符串)执行计算

注1

作为IPv4示例,您提供的解决方案列出了块中的每四个IP地址,我提供的解决方案列出了块中的所有IP地址,您可以通过使用
$I+=4
而不是
$I++
来进行调整

注2

为什么我们要使用GMP/BCMATH?答案是,在某一点上,大小数将被转换成浮点数,这将导致数字失去精度,这对这种计算是不好的

学分


多亏发布了关于如何将IPv6转换为小数以及如何将IPv6转换为小数的帖子

我又看了一遍,可接受的答案并不完全是我想要的,因为它列出了/128个块,而不是/64。listIPv6InBlock需要更改为:

function listIPv6InBlock($CIDR)
{
    $CIDR = explode("/", $CIDR); // this breaks the CIDR block into octlets and /notation
    $octet = ip2long_v6($CIDR[0]); 
    $NumberOfIPs = pow(2,(64-$CIDR[1])); //calculate the number of /64s in the CIDR block
    $OutputArray = array();
    $a = gmp_init($octet);
    $b = gmp_init('18446744073709551616'); // long /64

    for ($i=0; $i< $NumberOfIPs; $i++){
        $c = gmp_mul($b,$i);
        $d = gmp_add($a,$c);

        $OutputArray[] = long2ip_v6(gmp_strval($d));
    }
    return $OutputArray; //returns an array of ranges
}
函数列表IPV6InBlock($CIDR)
{
$CIDR=explode(“/”,$CIDR);//这将CIDR块分解为八位字节和/表示法
$octet=ip2long_v6($CIDR[0]);
$NumberOfIPs=pow(2,(64-$CIDR[1]);//计算CIDR块中/64的数量
$OutputArray=array();
$a=gmp_init($octet);
$b=gmp_init('18446744073709551616');//长/64
对于($i=0;$i<$NumberOfIPs;$i++){
$c=gmp_mul($b$i);
$d=gmp_加上($a,$c);
$OutputArray[]=long2ip_v6(gmp_strval($d));
}
return$OutputArray;//返回范围数组
}

@weath_沙鼠那么我什么时候能拿到赏金?现在应该已经拿到了。