Comparing an IP Address against a given range
I was recently asked how one might compare a given IP address against a range of IP addresses (assumedly in an elegant manner). I can’t really see why one would ever really need to do this kind of thing in php, but the chap in question explained that it was for the management of an IP address block-list.
anyway, here’s the code I wrote for it. After having done so, I wonder whether a natural text based comparison would have done the trick just as well (you’d still need the validation of course). It seems to work ok but i have not thought it through fully…
–edit–
my tek-tips colleague feherke, pointed out to me that there’s an even easier way of converting ip addresses to decimal notation. the script is accordingly edited
–/edit–
The code : …
<?php /** * class to compare an ip address against a given range of IPs * * sample usage * <code> $ipRangeCompare = new IPRangeCompare; $result = $ipRangeCompare->compare('212.143.142.1', '212.142.142.1', '212.143.140.255'); if ($ipRangeCompare->isError){ echo $ipRangeCompare->getErrorMessages(); exit; } else { if ($result){ echo "Confirmed that $ipRangeCompare->ip is within the range $ipRangeCompare->startIP - $ipRangeCompare->endIP"; } else { echo "Confirmed that $ipRangeCompare->ip is NOT within the range $ipRangeCompare->startIP - $ipRangeCompare->endIP"; } } * </code> */ class IPRangeCompare{ public $endIP; public $startIP; public $ip; public $errors; public $isError; /** * constructor method * @return */ public function __construct(){ $this->flush(); } /** * public method that kick starts the engine. * * @return bool - true if the IP is in the provided range, false otherwise * * @param object $startIP * @param object $endIP * @param object $ip */ public function compare ($startIP, $endIP, $ip){ $this->flush(); $this->startIP = $startIP; $this->endIP = $endIP; $this->ip = $ip; if (!$this->isValidIP($this->startIP) || !$this->isValidIP($this->endIP) || !$this->isValidIP($this->ip)){ $this->setError('IP address provided is not valid'); return false; } $this->startIPDecimal = $this->getDecimalIP($this->startIP); $this->endIPDecimal = $this->getDecimalIP($this->endIP); $this->ipDecimal = $this->getDecimalIP($this->ip); $this->checkIPDirection(); $match = ($this->ipDecimal >= $this->startIPDecimal) && ($this->ipDecimal <= $this->endIPDecimal); return $match; } /** * public function to return the error messages * * @return string */ public function getErrorMessage(){ $return = ''; if ($this->isError){ foreach ($this->errors as $e){ $return .= "\r\n<div class=\"errorMessage\">$e</div>\r\n"; } } return $return; } /** * method to invert start and end ip addresses if they have been entered the wrong way around * * @return void */ private function checkIPDirection(){ if ($this->startIPDecimal > $this->endIPDecimal){ $temp = $this->endIPDecimal; $this->endIPDecimal = $this->startIPDecimal; $this->startIPDecimal = $temp; $temp = $this->endIP; $this->endIP = $this->startIP; $this->startIP = $temp; } } /** * private method to convert an octet based IP address to a decimal * * @return decimal IP address * @param string $ip */ private function getDecimalIP($ip){ return ip2long($ip); /* left in for historic reasons only $bits = explode ('.', $ip); //convert the octets to binary foreach ($bits as $bit){ $_bits[] = str_pad(decbin($bit), 8, '0', STR_PAD_LEFT); } //now implode the _bits $bin = implode('', $_bits); //convert to decimal $dec = bindec($bin); return $dec; */ } /** * private method for determining whether the ip address provided is in the right format * * @return bool: true for the right format, false otherwise * @param object $ip */ private function isValidIP($ip){ $pattern = '/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/ims'; $result = preg_match($pattern, $ip, $matches); if (!$result){ return false; } for($i=1; $i<=4; $i++){ if ($matches[$i] < 0 || $matches[$i] > 255){ return false; } } return true; } /** * private helper method to set error messages * * @return void * @param object $error */ private function setError($error){ $this->errors[] = $error; $this->isError = true; } /** * private method for zeroing the variables * @return */ private function flush(){ $this->errors = array(); $this->startIP = $this->endIP = $this->ip = null; $this->isError= false; } } ?>