public function testIsInNetwork() { $ip = new Ip('2001:304:234a::1'); $this->assertEquals(true, $ip->isInNetwork(new Ip('2001:304:234a::'), 48)); $ip = new Ip('2001:304:234b::1'); $this->assertEquals(false, $ip->isInNetwork(new Ip('2001:304:234a::'), 48)); $ip = new Ip('127.2.4.5'); $this->assertEquals(true, $ip->isInNetwork(new Ip('127.2.3.4'), 16)); $ip = new Ip('127.2.127.9'); $this->assertEquals(false, $ip->isInNetwork(new Ip('127.2.128.0'), 17)); }
/** * Tests if an IP address belongs to a specific network * * Accepts a network base address and a prefix length. * * @param Ip $base Base address for the network to test * @param int $prefixlen Prefix length to test * @return bool */ public function isInNetwork(Ip $base, $prefixlen) { $baseVersion = $base->getVersion(); $thisVersion = $this->getVersion(); if ($prefixlen < 0) { throw new InvalidArgumentException('Prefix length cannot be negative'); } if ($baseVersion !== $thisVersion) { throw new InvalidArgumentException('Address version does not match supplied network base version'); } if ($thisVersion === 4 && $prefixlen > 32) { throw new InvalidArgumentException('Address version (4) was not supplied a correct prefix length'); } if ($thisVersion === 6 && $prefixlen > 128) { throw new InvalidArgumentException('Address version (6) was not supplied a correct prefix length'); } // First create a 128-bit long binary string regardless of IP version. // IPv4 addresses are left-padded with zeroes so that the algorithm // can be used generically. // // Next, split the 128-bit string into 32-bit chunks, and convert them // to unsigned integers. We can then use this to perform the bitwise // comparisons that we need later. $prefixIntegerArray = array_map('bindec', str_split(str_pad(str_pad(str_repeat('1', $prefixlen), $thisVersion === 4 ? 32 : 128, '0'), 128, '0', STR_PAD_LEFT), 32)); $baseIntegerArray = $base->toIntegerArray(); $thisIntegerArray = $this->toIntegerArray(); // If it's version 4, we just want to compare final array position $start = $thisVersion === 4 ? 3 : 0; for ($i = $start; $i < 4; $i++) { $a = $thisIntegerArray[$i]; $b = $baseIntegerArray[$i]; $p = $prefixIntegerArray[$i]; // If the address ANDed with the prefix mask is not equal to the // base address ANDed with the prefix mask, we can bail. if (($a & $p) !== ($b & $p)) { return false; } } return true; }