将IPv6地址与CIDR子网匹配

MW.*_*MW. 7 php ip ipv6 cidr

有没有一种方法可以使用CIDR表示法将IPv6地址与IPv6子网匹配?我正在寻找的是与此等价的IPv6: 在PHP 5中将IP匹配到CIDR掩码?

由于IPv6地址长度为128位,因此无法使用上面给出的示例,从而防止按位左移正常工作.你能想到其他任何方式吗?

编辑:在答案列表中添加了我自己的解决方案.

Sni*_*fff 13

由于您无法将IPv6地址转换为整数,因此您应该操作位,如下所示:

$ip='21DA:00D3:0000:2F3B:02AC:00FF:FE28:9C5A';
$cidrnet='21DA:00D3:0000:2F3B::/64';

// converts inet_pton output to string with bits
function inet_to_bits($inet) 
{
   $unpacked = unpack('A16', $inet);
   $unpacked = str_split($unpacked[1]);
   $binaryip = '';
   foreach ($unpacked as $char) {
             $binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
   }
   return $binaryip;
}    

$ip = inet_pton($ip);
$binaryip=inet_to_bits($ip);

list($net,$maskbits)=explode('/',$cidrnet);
$net=inet_pton($net);
$binarynet=inet_to_bits($net);

$ip_net_bits=substr($binaryip,0,$maskbits);
$net_bits   =substr($binarynet,0,$maskbits);

if($ip_net_bits!==$net_bits) echo 'Not in subnet';
else echo 'In subnet';
Run Code Online (Sandbox Code Playgroud)

此外,如果您使用某个数据库来存储IP,它可能已经具有比较它们的所有功能.例如,Postgres有一个inet类型,可以确定IP是否包含在子网中,如下所示:

SELECT 
   '21DA:00D3:0000:2F3B:02AC:00FF:FE28:9C5A'::inet << 
   '21DA:00D3:0000:2F3B::/64'::inet;
Run Code Online (Sandbox Code Playgroud)

9.11.PostgreSQL中的网络地址函数和操作符

  • 很好-由于某种原因,我从未考虑过二进制字符串。 (2认同)

Sou*_*euh 6

您也可以使用IpUtils从类的symfony/HTTP的基础包:

IpUtils::checkIp6('2a01:8760:2:3001::1', '2a01:8760:2:3001::1/64')
Run Code Online (Sandbox Code Playgroud)

这将检查IPv6有效性和范围匹配.false如果不是这样的话会返回.


jch*_*ook 5

PHP可以对字符串进行按位运算!

  • IPv4 或 IPv6
  • 无基数转换
  • 无 ASCII 位串
  • 相当快
<?php

/**
 * Does the given IP match the CIDR prefix?
 */
function matchIp(string $ip, string $cidr): bool
{
  // Get mask bits
  list($net, $maskBits) = explode('/', $cidr);

  // Size
  $size = (strpos($ip, ':') === false) ? 4 : 16;

  // Convert to binary
  $ip = inet_pton($ip);
  $net = inet_pton($net);
  if (!$ip || !$net) {
    throw new InvalidArgumentException('Invalid IP address');
  }

  // Build mask
  $solid = floor($maskBits / 8);
  $solidBits = $solid * 8;
  $mask = str_repeat(chr(255), $solid);
  for ($i = $solidBits; $i < $maskBits; $i += 8) {
    $bits = max(0, min(8, $maskBits - $i));
    $mask .= chr((pow(2, $bits) - 1) << (8 - $bits));
  }
  $mask = str_pad($mask, $size, chr(0));

  // Compare the mask
  return ($ip & $mask) === ($net & $mask);
}

Run Code Online (Sandbox Code Playgroud)