Created
July 25, 2024 08:43
-
-
Save wuhei/3a62cf28e57be3c124db8f2ad62b7f57 to your computer and use it in GitHub Desktop.
check if ip (ipv4 or ipv6) is within a certain CIDR subnet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function ip_in_cidr($ip, $cidr) { | |
// Determine IP version with FILTER_VALIDATE_IP | |
$ip_version = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? 4 : | |
(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? 6 : false); | |
if (!$ip_version) { | |
throw new InvalidArgumentException("{$ip} is not a valid IP address"); | |
} | |
// Split CIDR into network and mask | |
list($network, $mask) = explode('/', $cidr); | |
// Validate network address | |
if (!filter_var($network, $ip_version == 4 ? FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 : FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | |
throw new InvalidArgumentException("Network address {$network} in CIDR is invalid"); | |
} | |
if ($ip_version == 4) { | |
return ipv4_in_cidr($ip, $network, $mask); | |
} else { | |
return ipv6_in_cidr($ip, $network, $mask); | |
} | |
} | |
function ipv4_in_cidr($ip, $network, $mask) { | |
$ip_long = ip2long($ip); | |
$network_long = ip2long($network); | |
$mask_long = -1 << (32 - $mask); | |
$network_long &= $mask_long; | |
return ($ip_long & $mask_long) === $network_long; | |
} | |
function ipv6_in_cidr($ip, $network, $mask) { | |
$ip_binary = inet_pton($ip); | |
$network_binary = inet_pton($network); | |
$mask_binary = str_repeat("\xFF", $mask / 8) . str_repeat("\x00", 16 - $mask / 8); | |
if ($mask % 8) { | |
$mask_binary[floor($mask / 8)] = chr(0xFF << (8 - ($mask % 8))); | |
} | |
return ($ip_binary & $mask_binary) === ($network_binary & $mask_binary); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment