= $pow) { $mask[63 - $i] = '1'; } } return $mask; } /** * conversion of inet_pton ipv6 into 64-bit upper and lower * bcmath version for 32-bit architecture * w/o no unpack('J') - unsigned long long (always 64 bit, big endian byte order) * * results match unpack('Jupper/Jlower', $binary) * * @param string $binary inet_pton's ipv6 16 element binary * * @return string[] upper 64 and lower 64 for ipToNumber */ public static function ipv6UpperLowerOn32(string $binary) { // unpack into four 32-bit unsigned ints to recombine as 2 64-bit $parts = unpack('N4', $binary); $upper = Ip32::partsTo64($parts[1], $parts[2]); $lower = Ip32::partsTo64($parts[3], $parts[4]); return ['upper' => $upper, 'lower' => $lower]; } private static function partsTo64(string $high, string $low) : string { // signed to unsigned $high = $high<0 ? bcadd($high, Ip32::$b32) : $high; $low = $low <0 ? bcadd($low , Ip32::$b32) : $low; return bcadd(bcmul($high, Ip32::$b32), $low); } /** * Convert a decimal number to 32-bit binary string using bcmath * Handles large numbers that exceed PHP_INT_MAX on 32-bit systems * * @param string $decimal The decimal number as string * @return string 32-bit binary representation */ private static function decimalToBinary32(string $decimal) : string { if (bccomp($decimal, '0') == 0) { return str_repeat('0', 32); } $binary = ''; $num = $decimal; for ($i = 31; $i >= 0; $i--) { $power = bcpow('2', (string)$i); if (bccomp($num, $power) >= 0) { $binary .= '1'; $num = bcsub($num, $power); } else { $binary .= '0'; } } return $binary; } }