Last active
June 4, 2016 23:26
-
-
Save Tar-Minyatur/4915cbcb7ad3034949da42ae154de0d5 to your computer and use it in GitHub Desktop.
This is not necessarily the best implementation to achieve the goal. Using CIDR masks and working with those would probably be more sensible. This code mostly came to life as an example for good code structure.
This file contains hidden or 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 | |
/** | |
* Model of an IPv4 network address. | |
* Use {@link IPv4Address#fromString} to create an instance. | |
* Use {@link IPv4Address#isReserved} to check if the address has been reserved | |
* by IETF or IANA for special purposes and thus is most likely invalid for a | |
* client connected from outside the local network. | |
*/ | |
class IPv4Address { | |
/** | |
* @var array | |
*/ | |
private $octets; | |
/** | |
* Use {@link IPv4Address#fromString} to create a safe instance. | |
*/ | |
private function __construct(array $octets) { | |
$this->octets = $octets; | |
} | |
/** | |
* Creates an instance from a given string. | |
* @param string $ip IP address in format x.x.x.x where x in range(0,255) | |
* @throws Exception if the IP address looks invalid | |
* @return IPv4Address | |
*/ | |
public static function fromString($ip) { | |
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { | |
throw new Exception("IP address is invalid"); | |
} | |
$tokens = explode('.', $ip); | |
$octets = array_map($tokens, function ($item) { return intval($item); }}); | |
return new IPv4Address($octets); | |
} | |
/** | |
* Checks if the IP address is reserved for special purposes by IETF or IANA. | |
* @return bool | |
*/ | |
public function isReserved() { | |
return $this->hasReservedFirstOctet() || | |
$this->hasReservedFirstAndSecondOctet() || | |
$this->hasOnlyReservedOctets(); | |
} | |
private function hasReservedFirstOctet() { | |
return $this->octetsMatch(array(0, 10, 127)) || // 0.*, 10.*, 127.* | |
$this->octetsMatch(range(224, 239)) || // 224.* - 239.* | |
$this->octetsMatch(range(240, 255)); // 250.* - 255.* | |
} | |
private function hasReservedFirstAndSecondOctet() { | |
return $this->octetsMatch(100, range( 64, 127)) || // 100.64.* - 100.127.* | |
$this->octetsMatch(172, range( 16, 31)) || // 172.16.* - 172.31.* | |
$this->octetsMatch(198, range( 18, 19)) || // 198.18.* - 198.19.* | |
$this->octetsMatch(169, 168) || // 169.168.* | |
$this->octetsMatch(192, 168); // 192.168.* | |
} | |
private function hasOnlyReservedOctets() { | |
return $this->octetsMatch(192, 0, 0) || // 192.0.0.* | |
$this->octetsMatch(192, 0, 2) || // 192.0.2.* | |
$this->octetsMatch(192, 51, 100) || // 192.51.100.* | |
$this->octetsMatch(192, 88, 99) || // 192.88.99.* | |
$this->octetsMatch(203, 0, 113) || // 203.0.113.* | |
$this->octetsMatch(255, 255, 255, 255); // 255.255.255.255 | |
private function octetsMatch($v1, $v2 = null, $v3 = null, $v4 = null) { | |
list($o1, $o2, $o3, $o4) = $this->octets; | |
return (is_null($v1) || (is_array($v1) && in_array($o1, $v1)) || ($o1 === $v1)) && | |
(is_null($v2) || (is_array($v2) && in_array($o2, $v2)) || ($o2 === $v2)) && | |
(is_null($v3) || (is_array($v3) && in_array($o3, $v3)) || ($o3 === $v3)) && | |
(is_null($v4) || (is_array($v4) && in_array($o4, $v4)) || ($o4 === $v4)); | |
} | |
public function toString() { | |
return implode('.', $this->octets); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment