Skip to content

Instantly share code, notes, and snippets.

@wuhei
Created July 25, 2024 08:43
Show Gist options
  • Save wuhei/3a62cf28e57be3c124db8f2ad62b7f57 to your computer and use it in GitHub Desktop.
Save wuhei/3a62cf28e57be3c124db8f2ad62b7f57 to your computer and use it in GitHub Desktop.
check if ip (ipv4 or ipv6) is within a certain CIDR subnet
<?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