diff --git a/Tests/ipaddressesTest.php b/Tests/ipaddressesTest.php new file mode 100644 index 0000000..7d3c428 --- /dev/null +++ b/Tests/ipaddressesTest.php @@ -0,0 +1,255 @@ + */ + +/** Test the ipaddresses.php file */ +class test_ipaddresses extends PHPUnit_Framework_TestCase +{ + + public function test_validIPAddress1 () + { + $i = new ipaddresses (); + $res = $i->validIPAddress ("::"); + $this->assertSame (true, $res); + } + public function test_validIPAddress2 () + { + $i = new ipaddresses (); + $res = $i->validIPAddress ("1::"); + $this->assertSame (true, $res); + } + public function test_validIPAddress3 () + { + $i = new ipaddresses (); + $res = $i->validIPAddress ("::1"); + $this->assertSame (true, $res); + } + public function test_validIPAddress4 () + { + $i = new ipaddresses (); + $res = $i->validIPAddress ("2001::1"); + $this->assertSame (true, $res); + } + public function test_validIPAddress5 () + { + $i = new ipaddresses (); + $res = $i->validIPAddress ("1.2.3.4"); + $this->assertSame (true, $res); + } + public function test_validIPAddress6 () + { + $this->setExpectedException ("Exception"); + $i = new ipaddresses (); + $res = $i->validIPAddress (""); + } + public function test_validIPAddress7 () + { + $this->setExpectedException ("Exception"); + $i = new ipaddresses (); + $res = $i->validIPAddress (array ()); + } + + public function test_validIPv4Address1 () + { + $i = new ipaddresses (); + $res = $i->validIPv4Address ("::"); + $this->assertSame (false, $res); + } + public function test_validIPv4Address2 () + { + $i = new ipaddresses (); + $res = $i->validIPv4Address ("1.2.3.4"); + $this->assertSame (true, $res); + } + + public function test_validIPv6Address1 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("1.2.3.4"); + $this->assertSame (false, $res); + } + public function test_validIPv6Address2 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("::"); + $this->assertSame (true, $res); + } + public function test_validIPv6Address3 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("1::"); + $this->assertSame (true, $res); + } + public function test_validIPv6Address4 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("::1"); + $this->assertSame (true, $res); + } + public function test_validIPv6Address5 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("1::1"); + $this->assertSame (true, $res); + } + public function test_validIPv6Address6 () + { + $i = new ipaddresses (); + $res = $i->validIPv6Address ("1:1:1"); + $this->assertSame (false, $res); + } + + public function test_uncompressIPv6a () + { + $i = new ipaddresses (); + $res = $i->uncompressIPv6 ("1::1"); + $this->assertSame ("1:0:0:0:0:0:0:1", $res); + } + public function test_uncompressIPv6b () + { + $i = new ipaddresses (); + $res = $i->uncompressIPv6 ("1::"); + $this->assertSame ("1:0:0:0:0:0:0:0", $res); + } + public function test_uncompressIPv6c () + { + $i = new ipaddresses (); + $res = $i->uncompressIPv6 ("::"); + $this->assertSame ("0:0:0:0:0:0:0:0", $res); + } + public function test_uncompressIPv6d () + { + $i = new ipaddresses (); + $res = $i->uncompressIPv6 ("1.2.3.4"); + $this->assertSame ("1.2.3.4", $res); + } + + public function test_groupIPv6a () + { + $this->setExpectedException ("Exception"); + $i = new ipaddresses (); + $res = $i->groupIPv6 ("1.2.3.4"); + } + public function test_groupIPv6b () + { + $i = new ipaddresses (); + $res = $i->groupIPv6 ("0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.". + "0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f"); + $this->assertSame ("0123:4567:89ab:cdef:0123:4567:89ab:cdef", $res); + } + + public function test_completeAddressWithZero1 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("::"); + $this->assertSame ("0000:0000:0000:0000:0000:0000:0000:0000", $res); + } + public function test_completeAddressWithZero2 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("::1"); + $this->assertSame ("0000:0000:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero3 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("1::"); + $this->assertSame ("0001:0000:0000:0000:0000:0000:0000:0000", $res); + } + public function test_completeAddressWithZero4 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("1::1"); + $this->assertSame ("0001:0000:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero5 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("1:222::1"); + $this->assertSame ("0001:0222:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero6 () + { + $i = new ipaddresses (); + $res = $i->completeAddressWithZero ("1.2.3.4"); + $this->assertSame ("1.2.3.4", $res); + } + + // TODO : cidrToBin + // TODO : str_base_convert + + public function test_reverseIPAddress1 () + { + $i = new ipaddresses (); + $res = $i->reverseIPAddress ("1.2.3.4"); + $this->assertSame ("4.3.2.1", $res); + } + public function test_reverseIPAddress2 () + { + $i = new ipaddresses (); + $res = $i->reverseIPAddress ("::"); + $this->assertSame ("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); + } + public function test_reverseIPAddress3 () + { + $i = new ipaddresses (); + $res = $i->reverseIPAddress ("::1"); + $this->assertSame ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); + } + public function test_reverseIPAddress4 () + { + $i = new ipaddresses (); + $res = $i->reverseIPAddress ("2::1"); + $this->assertSame ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); + } + public function test_reverseIPAddress5 () + { + $i = new ipaddresses (); + $res = $i->reverseIPAddress ("2::abcd:1"); + $this->assertSame ("1.0.0.0.d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); + } + + public function test_netmask2cidr1 () + { + $this->setExpectedException ("Exception"); + $i = new ipaddresses (); + $res = $i->netmask2cidr (0); + } + public function test_netmask2cidr2 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("255.255.255.0"); + $this->assertSame (24, $res); + } + public function test_netmask2cidr3 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("255.255.255.255"); + $this->assertSame (32, $res); + } + public function test_netmask2cidr4 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("255.255.255.255"); + $this->assertSame (32, $res); + } + public function test_netmask2cidr5 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("255.0.0.0"); + $this->assertSame (8, $res); + } + public function test_netmask2cidr6 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("127.0.0.0"); + $this->assertSame (7, $res); + } + public function test_netmask2cidr7 () + { + $i = new ipaddresses (); + $res = $i->netmask2cidr ("63.0.0.0"); + $this->assertSame (6, $res); + } +} diff --git a/ipaddresses.php b/ipaddresses.php new file mode 100644 index 0000000..2df9730 --- /dev/null +++ b/ipaddresses.php @@ -0,0 +1,237 @@ + */ + +/** Manage the IP addresses conversions */ +class ipaddresses +{ + /** Return true if the provided IP address is valid (IPv4 or IPv6) */ + public function validIPAddress ($ip) + { + if (!is_string ($ip) || $ip === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + $rc = $this->validIPv4Address ($ip); + if ($rc === TRUE) + return TRUE; + $rc = $this->validIPv6Address ($ip); + return $rc; + } + + /** Return true if the provided IP address is valid and is IPv4 */ + public function validIPv4Address ($ip) + { + if (!is_string ($ip) || $ip === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + if ($rc ===FALSE) + return FALSE; + return TRUE; + } + + /** Return true if the provided IP address is valid and is IPv6 */ + public function validIPv6Address ($ip) + { + if (!is_string ($ip) || $ip === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + if ($rc ===FALSE) + return FALSE; + return TRUE; + } + + /** Return the IPv6 uncompressed (all the fields exists). They are not filled by + zeros + If the provided IP is IPv4, there is no change applied + Return False if the parameter is invalid + Based on http://www.weberdev.com/get_example.php3?ExampleID=3921 */ + public function uncompressIPv6 ($ip) + { + if (! is_string ($ip) || $ip === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + if (strstr ($ip,"::")) + { + $e = explode (":", $ip); + // Case where :: is in start + if ($e[0] === "") + $e[0] = "0"; + // Case where :: is in end + if ($e[count ($e)-1] === "") + $e[count ($e)-1] = "0"; + $s = 8 - count ($e); + foreach ($e as $key=>$val) + { + if ($val === "") + { + for ($i=0 ; $i<=$s ; $i++) + $newipv6[] = 0; + } + else + { + $newipv6[] = $val; + } + } + $ip = implode (":", $newipv6); + } + return $ip; + } + + /* Get an IPv6 address with the format + x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x + and return it with format + xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx + Return false if the IP provided is not complete */ + public function groupIPv6 ($ipv6) + { + if (! is_string ($ipv6) || $ipv6 === "") + throw new \Exception (dgettext("domframework", "Invalid IPv6 address"), 500); + if (substr_count ($ipv6, ".") !== 31) + throw new \Exception (dgettext("domframework", "Invalid IPv6 address"), 500); + $ipv6 = str_replace (".", "", $ipv6); + $new = ""; + for ($i = 0 ; $i < 32 ; $i++) + { + if ($i % 4 === 0 && $i !== 0) + { + $new .= ":"; + } + $new .= $ipv6[$i]; + } + return $new; + } + + /* Return the IP adddress with filling the fields with the missing zeros. + Valid only on IPv6 (but don't change anything if the provided address is IPv4) */ + public function completeAddressWithZero ($ip) + { + if (! is_string ($ip) || $ip === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + $ip = $this->uncompressIPv6 ($ip); + if (substr_count ($ip, ":") === 7) + { + // IPv6 + $ips = explode (":", $ip); + $ipnew = array(); + foreach ($ips as $iptmp) + { + $ipnew[] = sprintf ("%04x", hexdec ($iptmp)); + } + return implode (":", $ipnew); + } + elseif (substr_count ($ip, ".") === 3) + { + // IPv4 + return $ip; + } + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + } + + /* Return the provided CIDR in binary. Length must be in bytes. + Return FALSE if the parameters are invalid */ + public function cidrToBin ($cidr, $length) + { + if (! is_numeric ($cidr) || $cidr < 0 || $cidr > 128) + throw new \Exception (dgettext("domframework", "Invalid CIDR"), 500); + if (! is_numeric ($length) || $length < 1 || $length > 16) + throw new \Exception (dgettext("domframework", "Invalid length"), 500); + $val=""; + for ( $i=0 ; $i<$length*8 ; $i++ ) + { + if ($i < $cidr) $val.="1"; + else $val.="0"; + } + return pack ('H*', $this->str_base_convert ($val, 2, 16)); + } + + /* Base conversion with 128 bits support for IPv6 + Based on http://fr2.php.net/manual/en/function.base-convert.php#109660 */ + public function str_base_convert($str, $frombase=10, $tobase=36) + { + $str = trim ($str); + if (intval ($frombase) != 10) + { + $len = strlen ($str); + $q = 0; + for ($i=0; $i<$len; $i++) + { + $r = base_convert ($str[$i], $frombase, 10); + $q = bcadd (bcmul ($q, $frombase), $r); + } + } + else + { + $q = $str; + } + + if (intval ($tobase) != 10) + { + $s = ''; + while (bccomp ($q, '0', 0) > 0) + { + $r = intval (bcmod($q, $tobase)); + $s = base_convert ($r, 10, $tobase) . $s; + $q = bcdiv ($q, $tobase, 0); + } + } + else + { + $s = $q; + } + + return $s; + } + + /* Reverse the provided IP address + The IPv6 are returned in format : + x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x */ + function reverseIPAddress ($ipReverse) + { + if (!is_string ($ipReverse) || $ipReverse === "") + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + $ipReverse = $this->completeAddressWithZero ($ipReverse); + if (substr_count ($ipReverse, ":") === 7 && strlen ($ipReverse) == 39) + { + // Complete IPv6 with quadruplets and colon + $ip = str_replace (":", "", $ipReverse); + $tmp2 = array_reverse (str_split ($ip)); + return implode (".", $tmp2); + } + elseif (substr_count ($ipReverse, ".") === 31) + { + // IPv6 with dots + $tmp2 = explode (".", $ipReverse); + $tmp2 = array_reverse ($tmp2); + $ipnew = implode (".", $tmp2); + return $ipnew; + } + elseif (substr_count ($ipReverse, ".") === 3) + { + // IPv4 + $tmp2 = explode (".", $ipReverse); + $tmp2 = array_reverse ($tmp2); + $ipnew = implode (".", $tmp2); + return $ipnew; + } + throw new \Exception (dgettext("domframework", "Invalid IP address"), 500); + } + + /* This function return the CIDR associated to the provided netmask + Ex. Return 24 for a mask 255.255.255.0 + Work only in IPv4 + Return FALSE if the provided IP is invalid */ + public function netmask2cidr ($netmask) + { + $netmask = ip2long ($netmask); + if ($netmask === FALSE) + throw new \Exception (dgettext("domframework", "Invalid netmask"), 500); + $netmask = decbin ($netmask); + for ($i=0 ; $i<32 ; $i++) + { + if ($netmask{$i} == 0) + { + break; + } + } + return $i; + } +}