191da8d44SWillForan<?php 291da8d44SWillForan 391da8d44SWillForan/** 491da8d44SWillForan * DokuWiki 32bit shims for IP address functions. 591da8d44SWillForan * 691da8d44SWillForan * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 791da8d44SWillForan */ 891da8d44SWillForan 991da8d44SWillForannamespace dokuwiki; 1091da8d44SWillForan 1191da8d44SWillForanclass Ip32 1291da8d44SWillForan{ 132f70db90SWillForan public static $b32 = '4294967296'; 1491da8d44SWillForan /** 1591da8d44SWillForan * slow and ugly bitwise_and for 32bit arch 1691da8d44SWillForan * @param $u64 unsigned 64bit integer as string 17a060f5a0SWillForan * likely from ipv6UpperLowerOn32 1891da8d44SWillForan * @param $pow 0-64 power of 2 for bitmask 1991da8d44SWillForan */ 20*ba6d945fSWillForan public static function bitmask64On32(string $u64, int $pow): string 21*ba6d945fSWillForan { 222f70db90SWillForan $upper = bcdiv($u64, Ip32::$b32, 0); 232f70db90SWillForan $lower = bcmod($u64, Ip32::$b32); 242f70db90SWillForan // str of len 32 all 0s and 1s 252f70db90SWillForan $upper_bin = Ip32::decimalToBinary32($upper); 262f70db90SWillForan $lower_bin = Ip32::decimalToBinary32($lower); 272f70db90SWillForan $bin = $upper_bin . $lower_bin; 2891da8d44SWillForan 29a060f5a0SWillForan $mask = Ip32::makeBitmaskOn32(64 - $pow); 3091da8d44SWillForan 3191da8d44SWillForan // most right is lowest bit 3291da8d44SWillForan $res = '0'; 3391da8d44SWillForan for ($i = 0; $i < 64; $i++) { 3491da8d44SWillForan if (bcmul($bin[$i], $mask[$i]) == 1) { 3591da8d44SWillForan $res = bcadd($res, bcpow(2, 63 - $i)); 3691da8d44SWillForan } 3791da8d44SWillForan } 3891da8d44SWillForan return $res; 3991da8d44SWillForan } 4091da8d44SWillForan 4191da8d44SWillForan 4291da8d44SWillForan /** 4391da8d44SWillForan * modeling bitshift like ~0 << $pow for 32-bit arch 4491da8d44SWillForan * @param pow power of 2 for mask 4591da8d44SWillForan * @return 64-char string of 1 and 0s 4691da8d44SWillForan * pow=1 4791da8d44SWillForan * 1111111111111111111111111111111111111111111111111111111111111110 4891da8d44SWillForan * pow=63 4991da8d44SWillForan * 1000000000000000000000000000000000000000000000000000000000000000 5091da8d44SWillForan * pow=64 5191da8d44SWillForan * 0000000000000000000000000000000000000000000000000000000000000000 5291da8d44SWillForan */ 53*ba6d945fSWillForan private static function makeBitmaskOn32(int $pow): string 54*ba6d945fSWillForan { 5591da8d44SWillForan $pow = $pow < 0 ? 64 - $pow : $pow; 5691da8d44SWillForan $mask = sprintf("%064d", 0); 5791da8d44SWillForan for ($i = 0; $i < 64; $i++) { 5891da8d44SWillForan if ($i >= $pow) { 5991da8d44SWillForan $mask[63 - $i] = '1'; 6091da8d44SWillForan } 6191da8d44SWillForan } 6291da8d44SWillForan return $mask; 6391da8d44SWillForan } 6491da8d44SWillForan 6591da8d44SWillForan /** 6691da8d44SWillForan * conversion of inet_pton ipv6 into 64-bit upper and lower 6791da8d44SWillForan * bcmath version for 32-bit architecture 6891da8d44SWillForan * w/o no unpack('J') - unsigned long long (always 64 bit, big endian byte order) 6991da8d44SWillForan * 7091da8d44SWillForan * results match unpack('Jupper/Jlower', $binary) 7191da8d44SWillForan * 7291da8d44SWillForan * @param string $binary inet_pton's ipv6 16 element binary 7391da8d44SWillForan * 742f70db90SWillForan * @return string[] upper 64 and lower 64 for ipToNumber 7591da8d44SWillForan */ 76*ba6d945fSWillForan public static function ipv6UpperLowerOn32(string $binary) 77*ba6d945fSWillForan { 7891da8d44SWillForan // unpack into four 32-bit unsigned ints to recombine as 2 64-bit 7991da8d44SWillForan $parts = unpack('N4', $binary); 802f70db90SWillForan $upper = Ip32::partsTo64($parts[1], $parts[2]); 812f70db90SWillForan $lower = Ip32::partsTo64($parts[3], $parts[4]); 8291da8d44SWillForan return ['upper' => $upper, 'lower' => $lower]; 8391da8d44SWillForan } 842f70db90SWillForan 85*ba6d945fSWillForan private static function partsTo64(string $high, string $low): string 86*ba6d945fSWillForan { 872f70db90SWillForan // signed to unsigned 882f70db90SWillForan $high = $high < 0 ? bcadd($high, Ip32::$b32) : $high; 892f70db90SWillForan $low = $low < 0 ? bcadd($low, Ip32::$b32) : $low; 902f70db90SWillForan 912f70db90SWillForan return bcadd(bcmul($high, Ip32::$b32), $low); 922f70db90SWillForan } 932f70db90SWillForan 942f70db90SWillForan /** 952f70db90SWillForan * Convert a decimal number to 32-bit binary string using bcmath 962f70db90SWillForan * Handles large numbers that exceed PHP_INT_MAX on 32-bit systems 972f70db90SWillForan * 982f70db90SWillForan * @param string $decimal The decimal number as string 992f70db90SWillForan * @return string 32-bit binary representation 1002f70db90SWillForan */ 101*ba6d945fSWillForan private static function decimalToBinary32(string $decimal): string 102*ba6d945fSWillForan { 1032f70db90SWillForan if (bccomp($decimal, '0') == 0) { 1042f70db90SWillForan return str_repeat('0', 32); 1052f70db90SWillForan } 1062f70db90SWillForan $binary = ''; 1072f70db90SWillForan $num = $decimal; 1082f70db90SWillForan for ($i = 31; $i >= 0; $i--) { 1092f70db90SWillForan $power = bcpow('2', (string)$i); 1102f70db90SWillForan if (bccomp($num, $power) >= 0) { 1112f70db90SWillForan $binary .= '1'; 1122f70db90SWillForan $num = bcsub($num, $power); 1132f70db90SWillForan } else { 1142f70db90SWillForan $binary .= '0'; 1152f70db90SWillForan } 1162f70db90SWillForan } 1172f70db90SWillForan return $binary; 1182f70db90SWillForan } 11991da8d44SWillForan} 120