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{ 13*2f70db90SWillForan 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 */ 20a060f5a0SWillForan public static function bitmask64On32(string $u64, int $pow) : string { 21*2f70db90SWillForan $upper = bcdiv($u64, Ip32::$b32, 0); 22*2f70db90SWillForan $lower = bcmod($u64, Ip32::$b32); 23*2f70db90SWillForan // str of len 32 all 0s and 1s 24*2f70db90SWillForan $upper_bin = Ip32::decimalToBinary32($upper); 25*2f70db90SWillForan $lower_bin = Ip32::decimalToBinary32($lower); 26*2f70db90SWillForan $bin = $upper_bin . $lower_bin; 2791da8d44SWillForan 28a060f5a0SWillForan $mask = Ip32::makeBitmaskOn32(64-$pow); 2991da8d44SWillForan 3091da8d44SWillForan // most right is lowest bit 3191da8d44SWillForan $res='0'; 3291da8d44SWillForan for ($i=0; $i<64; $i++){ 3391da8d44SWillForan if (bcmul($bin[$i], $mask[$i]) == 1) { 3491da8d44SWillForan $res = bcadd($res, bcpow(2, 63-$i)); 3591da8d44SWillForan } 3691da8d44SWillForan } 3791da8d44SWillForan return $res; 3891da8d44SWillForan } 3991da8d44SWillForan 4091da8d44SWillForan 4191da8d44SWillForan /** 4291da8d44SWillForan * modeling bitshift like ~0 << $pow for 32-bit arch 4391da8d44SWillForan * @param pow power of 2 for mask 4491da8d44SWillForan * @return 64-char string of 1 and 0s 4591da8d44SWillForan * pow=1 4691da8d44SWillForan * 1111111111111111111111111111111111111111111111111111111111111110 4791da8d44SWillForan * pow=63 4891da8d44SWillForan * 1000000000000000000000000000000000000000000000000000000000000000 4991da8d44SWillForan * pow=64 5091da8d44SWillForan * 0000000000000000000000000000000000000000000000000000000000000000 5191da8d44SWillForan */ 52a060f5a0SWillForan private static function makeBitmaskOn32(int $pow) : string { 5391da8d44SWillForan $pow = $pow < 0 ? 64 - $pow : $pow; 5491da8d44SWillForan $mask = sprintf("%064d",0); 5591da8d44SWillForan for ($i=0; $i<64; $i++) { 5691da8d44SWillForan if ($i >= $pow) { 5791da8d44SWillForan $mask[63 - $i] = '1'; 5891da8d44SWillForan } 5991da8d44SWillForan } 6091da8d44SWillForan return $mask; 6191da8d44SWillForan } 6291da8d44SWillForan 6391da8d44SWillForan /** 6491da8d44SWillForan * conversion of inet_pton ipv6 into 64-bit upper and lower 6591da8d44SWillForan * bcmath version for 32-bit architecture 6691da8d44SWillForan * w/o no unpack('J') - unsigned long long (always 64 bit, big endian byte order) 6791da8d44SWillForan * 6891da8d44SWillForan * results match unpack('Jupper/Jlower', $binary) 6991da8d44SWillForan * 7091da8d44SWillForan * @param string $binary inet_pton's ipv6 16 element binary 7191da8d44SWillForan * 72*2f70db90SWillForan * @return string[] upper 64 and lower 64 for ipToNumber 7391da8d44SWillForan */ 74a060f5a0SWillForan public static function ipv6UpperLowerOn32(string $binary) { 7591da8d44SWillForan // unpack into four 32-bit unsigned ints to recombine as 2 64-bit 7691da8d44SWillForan $parts = unpack('N4', $binary); 77*2f70db90SWillForan $upper = Ip32::partsTo64($parts[1], $parts[2]); 78*2f70db90SWillForan $lower = Ip32::partsTo64($parts[3], $parts[4]); 7991da8d44SWillForan return ['upper' => $upper, 'lower' => $lower]; 8091da8d44SWillForan } 81*2f70db90SWillForan 82*2f70db90SWillForan private static function partsTo64(string $high, string $low) : string { 83*2f70db90SWillForan // signed to unsigned 84*2f70db90SWillForan $high = $high<0 ? bcadd($high, Ip32::$b32) : $high; 85*2f70db90SWillForan $low = $low <0 ? bcadd($low , Ip32::$b32) : $low; 86*2f70db90SWillForan 87*2f70db90SWillForan return bcadd(bcmul($high, Ip32::$b32), $low); 88*2f70db90SWillForan } 89*2f70db90SWillForan 90*2f70db90SWillForan /** 91*2f70db90SWillForan * Convert a decimal number to 32-bit binary string using bcmath 92*2f70db90SWillForan * Handles large numbers that exceed PHP_INT_MAX on 32-bit systems 93*2f70db90SWillForan * 94*2f70db90SWillForan * @param string $decimal The decimal number as string 95*2f70db90SWillForan * @return string 32-bit binary representation 96*2f70db90SWillForan */ 97*2f70db90SWillForan private static function decimalToBinary32(string $decimal) : string { 98*2f70db90SWillForan if (bccomp($decimal, '0') == 0) { 99*2f70db90SWillForan return str_repeat('0', 32); 100*2f70db90SWillForan } 101*2f70db90SWillForan $binary = ''; 102*2f70db90SWillForan $num = $decimal; 103*2f70db90SWillForan for ($i = 31; $i >= 0; $i--) { 104*2f70db90SWillForan $power = bcpow('2', (string)$i); 105*2f70db90SWillForan if (bccomp($num, $power) >= 0) { 106*2f70db90SWillForan $binary .= '1'; 107*2f70db90SWillForan $num = bcsub($num, $power); 108*2f70db90SWillForan } else { 109*2f70db90SWillForan $binary .= '0'; 110*2f70db90SWillForan } 111*2f70db90SWillForan } 112*2f70db90SWillForan return $binary; 113*2f70db90SWillForan } 11491da8d44SWillForan } 115