32) { throw new Exception("CIDR must be between 0 and 32."); } if ($cidr === 32) { return [ 'network' => $ip, 'first' => $ip, 'last' => $ip, 'hosts' => 1, ]; } if ($cidr === 31) { $ipLong = ip2long($ip); $network = $ipLong & (-1 << (32 - $cidr)); return [ 'network' => long2ip($network), 'first' => long2ip($network), 'last' => long2ip($network + 1), 'hosts' => 2, ]; } $hosts = (1 << (32 - $cidr)) - 2; $ipLong = ip2long($ip); $mask = -1 << (32 - $cidr); $network = $ipLong & $mask; $firstIP = $network + 1; $lastIP = $network + $hosts; return [ 'network' => long2ip($network), 'first' => long2ip($firstIP), 'last' => long2ip($lastIP), 'hosts' => $hosts, ]; } /** * Calculate IPv6 * * @param string $ip * @param int $cidr * @return array * @throws \Exception */ private static function calculateIPv6(string $ip, int $cidr): array { if ($cidr < 0 || $cidr > 128) { throw new Exception("CIDR must be between 0 and 128."); } if ($cidr === 128) { return [ 'network' => $ip, 'first' => $ip, 'last' => $ip, 'hosts' => 1, ]; } if ($cidr === 127) { $binaryIP = inet_pton($ip); $network = substr($binaryIP, 0, intval($cidr / 8)); $firstHost = inet_ntop($network); $lastHost = inet_ntop($binaryIP); return [ 'network' => $firstHost, 'first' => $firstHost, 'last' => $lastHost, 'hosts' => 2, ]; } // General case for other IPv6 subnets $totalHosts = bcpow(2, 128 - $cidr); // Number of total IPs $binaryIP = inet_pton($ip); // Calculate the network address $network = substr($binaryIP, 0, intval($cidr / 8)); $remainder = $cidr % 8; if ($remainder > 0) { $lastByte = ord($binaryIP[intval($cidr / 8)]) & (0xFF << (8 - $remainder)); $network .= chr($lastByte); } $network = str_pad($network, 16, "\0"); $networkAddress = inet_ntop($network); return [ 'network' => $networkAddress, 'first' => $cidr == 128 ? $networkAddress : inet_ntop($network), 'last' => $cidr == 128 ? $networkAddress : inet_ntop($network), // Adjusted for simplicity 'hosts' => $totalHosts, ]; } }