-
-
Save pavinjosdev/cb1d636ea9dc2bd201d54107d10650c5 to your computer and use it in GitHub Desktop.
<?php | |
/** | |
* Validates the format of a CIDR notation string | |
* | |
* @param string $cidr | |
* @return bool | |
*/ | |
function validateCidr($cidr) | |
{ | |
$parts = explode('/', $cidr); | |
if(count($parts) != 2) { | |
return false; | |
} | |
$ip = $parts[0]; | |
$netmask = $parts[1]; | |
if (!preg_match("/^\d+$/", $netmask)){ | |
return false; | |
} | |
$netmask = intval($parts[1]); | |
if($netmask < 0) { | |
return false; | |
} | |
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { | |
return $netmask <= 32; | |
} | |
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | |
return $netmask <= 128; | |
} | |
return false; | |
} | |
?> |
This validation unexpectedly let through '2403:7000:8000:900::3a/56'
The essential difference between inet and cidr data types is that inet accepts values with 'nonzero' bits to the right of the netmask, whereas cidr does NOT.
Say, if you have a /8 netmask, the 'cidr' type requires that all the 24 rightmost bits are ZERO.
Note: inet does not have this requirement.
Can you factor in the Zeroes requirement into your method?
This validation unexpectedly let through '2403:7000:8000:900::3a/56'
@chrisharrisonkiwi The function checks for valid CIDR notations of IPv4 and IPv6 addresses (not PostgreSQL data types). 2403:7000:8000:900::3a/56
is a valid CIDR notation of an IPv6 address.
From reading the RFC on IPv6 addressing, relevant page: https://tools.ietf.org/html/rfc4291#page5
it mentions this:
When writing both a node address and a prefix of that node address
(e.g., the node's subnet prefix), the two can be combined as follows:
the node address 2001:0DB8:0:CD30:123:4567:89AB:CDEF
and its subnet number 2001:0DB8:0:CD30::/60
can be abbreviated as 2001:0DB8:0:CD30:123:4567:89AB:CDEF/60
Good gist, but why the double checking?
$netmask = $parts[1];
if (!preg_match("/^\d+$/", $netmask)){
return false;
}
$netmask = intval($parts[1]);
if ($netmask < 0) {
return false;
}
preg_match() will return false if there's anything but digits in $netmask, no? So how are you going to end up with a negative number? Also, would it not be a good idea to include a minimum/maximum length in the regexp for preg_match() 🤔
Just my two cents, as I'm unsure of the intent. I don't know if intval() is an actual function or a language construct, but casting using (int) may be faster.
Also, I think the preg_match regex could be changed to '/^\d{1,3}$/' for further validation.
@joho1968 The integer conversion does appear to be redundant, I believe the check for less than zero was to prevent negative integers from being passed through. Regex can't be good for speed, perhaps you could use some built-ins to check if the netmask is a positive integer?
Improved netmask validation.