Matching an IP to a CIDR mask in PHP 5?
If only using IPv4:
- use
ip2long()
to convert the IPs and the subnet range into long integers - convert the /xx into a subnet mask
- do a bitwise 'and' (i.e. ip & mask)' and check that that 'result = subnet'
something like this should work:
function cidr_match($ip, $range)
{
list ($subnet, $bits) = explode('/', $range);
if ($bits === null) {
$bits = 32;
}
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
return ($ip & $mask) == $subnet;
}
In a similar situation, I ended up using symfony/http-foundation.
When using this package, your code would look like:
$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');
foreach($ips as $IP) {
if (\Symfony\Component\HttpFoundation\IpUtils::checkIp($IP, '10.2.0.0/16')) {
print "you're in the 10.2 subnet\n";
}
}
It also handles IPv6.
Link: https://packagist.org/packages/symfony/http-foundation
I found many of these methods breaking after PHP 5.2. However the following solution works on versions 5.2 and above:
function cidr_match($ip, $cidr)
{
list($subnet, $mask) = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet))
{
return true;
}
return false;
}
Example results
cidr_match("1.2.3.4", "0.0.0.0/0"): true cidr_match("127.0.0.1", "127.0.0.1/32"): true cidr_match("127.0.0.1", "127.0.0.2/32"): false
Source http://www.php.net/manual/en/function.ip2long.php#82397.