<?php
function ipv6_addr_in_subnet($addr, $subnet, $mask = null)
{
$addrBin = @inet_pton($addr);
if (!$addrBin) {
throw new \InvalidArgumentException('Invalid IPv6 address: ' . $addr);
}
$cidr = 0;
if (isset($mask)) {
if (is_int($mask)) {
$cidr = (int)$mask;
if ($cidr < 0 || $cidr > 128) {
throw new \InvalidArgumentException('Invalid IPv6 CIDR mask: ' . $mask);
}
} else {
$maskBin = @inet_pton($mask);
if (!$maskBin) {
throw new \InvalidArgumentException('Invalid IPv6 mask: ' . $mask);
}
}
$subnetAddr = $subnet;
} else {
$parts = explode('/', $subnet);
$numParts = count($parts);
if ($numParts === 1) {
$maskBin = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
} else if ($numParts === 2) {
$cidr = (int)$parts[1];
} else {
throw new \InvalidArgumentException('Invalid IPv6 subnet');
}
$subnetAddr = $parts[0];
}
if (!isset($maskBin)) {
$blocks = (int)($cidr / 16);
$maskBin = pack(
'n*',
...array_fill(0, $blocks, 0xffff),
...array_pad([((2 ** (16 - ($cidr % 16))) - 1) ^ 0xffff], 8 - $blocks, 0)
);
}
$subnetAddrBin = @inet_pton($subnetAddr);
if (!$subnetAddrBin) {
throw new \InvalidArgumentException('Invalid IPv6 address: ' . $subnetAddr);
}
return ($addrBin & $maskBin) === ($subnetAddrBin & $maskBin);
}
var_dump(ipv6_addr_in_subnet('2001::1', '2001::/16'));
var_dump(ipv6_addr_in_subnet('2001::1', '2000::/17'));
var_dump(ipv6_addr_in_subnet('2001::1', '2001::/15'));
var_dump(ipv6_addr_in_subnet('2001::1', '2001::/120'));
preferences:
35.67 ms | 402 KiB | 5 Q