xref: /dokuwiki/inc/Ip32.php (revision 91da8d440c37d90167dc8ee25e6de7f854a11f1e)
1*91da8d44SWillForan<?php
2*91da8d44SWillForan
3*91da8d44SWillForan/**
4*91da8d44SWillForan * DokuWiki 32bit shims for IP address functions.
5*91da8d44SWillForan *
6*91da8d44SWillForan * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7*91da8d44SWillForan */
8*91da8d44SWillForan
9*91da8d44SWillForannamespace dokuwiki;
10*91da8d44SWillForan
11*91da8d44SWillForanclass Ip32
12*91da8d44SWillForan{
13*91da8d44SWillForan    /**
14*91da8d44SWillForan     * slow and ugly bitwise_and for 32bit arch
15*91da8d44SWillForan     * @param $u64 unsigned 64bit integer as string
16*91da8d44SWillForan     *            likely from ipv6_upper_lower_32
17*91da8d44SWillForan     * @param $pow 0-64 power of 2 for bitmask
18*91da8d44SWillForan     */
19*91da8d44SWillForan    public static function bitmask64_32(string $u64, int $pow) : string {
20*91da8d44SWillForan        //$u64 = sprintf("%.0f", $u65);
21*91da8d44SWillForan        $b32 = '4294967296';
22*91da8d44SWillForan        $bin = sprintf("%032b%032b",
23*91da8d44SWillForan                bcdiv($u64, $b32, 0),
24*91da8d44SWillForan                bcmod($u64, $b32));
25*91da8d44SWillForan
26*91da8d44SWillForan        $mask = Ip32::make_bitmask_32(64-$pow);
27*91da8d44SWillForan
28*91da8d44SWillForan        // most right is lowest bit
29*91da8d44SWillForan        $res='0';
30*91da8d44SWillForan        for ($i=0; $i<64; $i++){
31*91da8d44SWillForan            if (bcmul($bin[$i], $mask[$i]) == 1) {
32*91da8d44SWillForan                $res = bcadd($res, bcpow(2, 63-$i));
33*91da8d44SWillForan            }
34*91da8d44SWillForan        }
35*91da8d44SWillForan        return $res;
36*91da8d44SWillForan    }
37*91da8d44SWillForan
38*91da8d44SWillForan
39*91da8d44SWillForan    /**
40*91da8d44SWillForan     * modeling bitshift like  ~0 << $pow for 32-bit arch
41*91da8d44SWillForan     * @param pow power of 2 for mask
42*91da8d44SWillForan     * @return 64-char string of 1 and 0s
43*91da8d44SWillForan     * pow=1
44*91da8d44SWillForan     * 1111111111111111111111111111111111111111111111111111111111111110
45*91da8d44SWillForan     * pow=63
46*91da8d44SWillForan     * 1000000000000000000000000000000000000000000000000000000000000000
47*91da8d44SWillForan     * pow=64
48*91da8d44SWillForan     * 0000000000000000000000000000000000000000000000000000000000000000
49*91da8d44SWillForan     */
50*91da8d44SWillForan    private static function make_bitmask_32(int $pow) : string {
51*91da8d44SWillForan        $pow = $pow < 0 ? 64 - $pow : $pow;
52*91da8d44SWillForan        $mask = sprintf("%064d",0);
53*91da8d44SWillForan        for ($i=0; $i<64; $i++) {
54*91da8d44SWillForan            if ($i >= $pow) {
55*91da8d44SWillForan                $mask[63 - $i] = '1';
56*91da8d44SWillForan            }
57*91da8d44SWillForan        }
58*91da8d44SWillForan        return $mask;
59*91da8d44SWillForan    }
60*91da8d44SWillForan
61*91da8d44SWillForan    /**
62*91da8d44SWillForan     * conversion of inet_pton ipv6 into 64-bit upper and lower
63*91da8d44SWillForan     * bcmath version for 32-bit architecture
64*91da8d44SWillForan     * w/o no unpack('J') - unsigned long long (always 64 bit, big endian byte order)
65*91da8d44SWillForan     *
66*91da8d44SWillForan     * results match unpack('Jupper/Jlower', $binary)
67*91da8d44SWillForan     *
68*91da8d44SWillForan     * @param string $binary inet_pton's ipv6 16 element binary
69*91da8d44SWillForan     *
70*91da8d44SWillForan     * @return int[] upper 64 and lower 64 for ipToNumber
71*91da8d44SWillForan     */
72*91da8d44SWillForan    public static function ipv6_upper_lower_32(string $binary) {
73*91da8d44SWillForan       // unpack into four 32-bit unsigned ints to recombine as 2 64-bit
74*91da8d44SWillForan       $b32 = 4294967296; // bcpow(2, 32)
75*91da8d44SWillForan       $parts = unpack('N4', $binary);
76*91da8d44SWillForan       $upper = bcadd(bcmul($parts[1], $b32),
77*91da8d44SWillForan                      $parts[2]);
78*91da8d44SWillForan       $lower = bcadd(bcmul($parts[3], $b32),
79*91da8d44SWillForan                      $parts[4]);
80*91da8d44SWillForan       return ['upper' => $upper, 'lower' => $lower];
81*91da8d44SWillForan    }
82*91da8d44SWillForan }
83