Skip to content

Instantly share code, notes, and snippets.

@Tar-Minyatur
Last active June 4, 2016 23:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tar-Minyatur/4915cbcb7ad3034949da42ae154de0d5 to your computer and use it in GitHub Desktop.
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.
<?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