../libraries/bcbitwise.php


<?php
/**
 * EngineAPI Helper Functions - bcBitwise
 */

/**
 * Utility Class - bcmath bitwise implementation
 * 
 * This library provides arbitrary precision AND, OR, XOR, leftshift and rightshift for use with
 * PHP with the bcmath extension enabled.
 * 
 * @see http://www.nirvani.net/software/bc_bitwise/bc_bitwise-0.9.0.inc.php.asc
 * @package Helper Functions\bcBitwise
 */
class bcBitwise
{
    /**
     * MAX_BASE is the maximum base that can be represented in one byte on the host machine.
     * On most modern systems, this value can be 256, but if there are still any systems
     * with 7-bit bytes out there, you should use 128 for maximum portability.
     * @see self::bc2bin()
     * @see self::bin2bc()
     * @const
     */
    const MAX_BASE=128;

    /**
     * Class flag showing the existence of the bcmath PHP Extension
     * @see self::bcExists()
     * @var bool
     */
    public static $bcExists;

    // ============================================================================================

    /**
     * BCMath implementation of PHP's Bitwise AND
     * @param string $x
     * @param string $y
     * @return string
     * @static
     */
    public static function bcAND($x, $y)
    {
        self::bcExists();
        return self::__bitwise($x, $y, 'and');
    }

    /**
     * BCMath implementation of PHP's Bitwise OR
     * @param string $x
     * @param string $y
     * @return string
     * @static
     */
    public static function bcOR($x, $y)
    {
        self::bcExists();
        return self::__bitwise($x, $y, 'or');
    }

    /**
     * BCMath implementation of PHP's Bitwise XOR
     * @param string $x
     * @param string $y
     * @return string
     * @static
     */
    public static function bcXOR($x, $y)
    {
        self::bcExists();
        return self::__bitwise($x, $y, 'xor');
    }

    /**
     * BCMath implementation of PHP's Bitwise Left Shift (<<)
     * @param string $num
     * @param string $shift
     * @return string
     * @static
     */
    public static function bcLeftShift($num, $shift)
    {
        self::bcExists();
        bcscale(0);
        return bcmul($num, bcpow(2, $shift));
    }

    /**
     * BCMath implementation of PHP's Bitwise Right Shift (>>)
     * @param string $num
     * @param string $shift
     * @return string
     * @static
     */
    public static function bcRightShift($num, $shift)
    {
        self::bcExists();
        bcscale(0);
        return bcdiv($num, bcpow(2, $shift));
    }

    /**
     * Internal implementation of the bitwise operations.
     * (This is the guts of this utility class)
     *
     * @param string $x
     * @param string $y
     * @param string $op
     * @return string
     * @static
     */
    private static function __bitwise($x, $y, $op)
    {
        self::bcExists();

        $bx = self::bc2bin($x);
        $by = self::bc2bin($y);

        // Pad $bx and $by so that both are the same length.
        list($bx, $by) = self::equalBinPad($bx, $by);

        $ret = '';
        for($ix = 0; $ix < strlen($bx); $ix++){
            $xd = substr($bx, $ix, 1);
            $yd = substr($by, $ix, 1);
            switch($op){
                case 'and':
                    $ret .= $xd & $yd;
                    break;

                case 'or':
                    $ret .= $xd | $yd;
                    break;

                case 'xor':
                    $ret .= $xd ^ $yd;
                    break;
            }
        }

        return self::bin2bc($ret);
    }

    /**
     * Pad the operands on the most-significant end so they have the same number of bytes.
     *
     * @param string $x
     *        binary-format number as converted from decimal format with bc2bin()
     * @param string $y
     *        binary-format number as converted from decimal format with bc2bin()
     * @return array
     * @static
     */
    private static function equalBinPad($x, $y)
    {
        self::bcExists();

        $length = max(strlen($x), strlen($y));
        return array(self::fixedBinPad($x, $length), self::fixedBinPad($y, $length));
    }

    /**
     * Pad a binary number up to a certain length
     *
     * @param string $num
     *        The operand to be padded.
     * @param int $length
     *        The desired minimum length for $num
     * @return string
     * @static
     */
    private static function fixedBinPad($num, $length)
    {
        self::bcExists();

        $pad = '';
        for($ii = 0; $ii < $length - strlen($num); $ii++){
            $pad .= self::bc2bin('0');
        }
        return $pad.$num;
    }

    /**
     * Convert a decimal number to the internal binary format used by this library.
     * @param string $num
     * @return string
     * @static
     */
    private static function bc2bin($num)
    {
        self::bcExists();
        return self::dec2base($num, self::MAX_BASE);
    }

    /**
     * The reverse of self::bc2bin()
     * @param string $num
     * @return string
     * @static
     */
    private static function bin2bc($num)
    {
        self::bcExists();
        return self::base2dec($num, self::MAX_BASE);
    }

    /**
     * Convert a decimal value to any other base value
     * @param string $dec
     * @param string $base
     * @param bool $digits
     * @return string
     * @static
     */
    public static function dec2base($dec, $base, $digits = FALSE)
    {
        self::bcExists();

        if($base < 2 or $base > 256) die("Invalid Base: " . $base);
        bcscale(0);
        $value = "";
        if(!$digits) $digits = self::digits($base);
        while($dec > $base - 1){
            $rest = bcmod($dec, $base);
            $dec = bcdiv($dec, $base);
            $value = $digits[$rest] . $value;
        }
        $value = $digits[intval($dec)] . $value;
        return (string)$value;
    }

    /**
     * Convert another base value to its decimal value
     * @param string $value
     * @param string $base
     * @param bool $digits
     * @return string
     * @static
     */
    public static function base2dec($value, $base, $digits = FALSE)
    {
        self::bcExists();

        if($base < 2 or $base > 256) die("Invalid Base: " . $base);
        bcscale(0);
        if($base < 37) $value = strtolower($value);
        if(!$digits) $digits = self::digits($base);
        $size = strlen($value);
        $dec = "0";
        for($loop = 0; $loop < $size; $loop++){
            $element = strpos($digits, $value[$loop]);
            $power = bcpow($base, $size - $loop - 1);
            $dec = bcadd($dec, bcmul($element, $power));
        }
        return (string)$dec;
    }

    /**
     * The purpose of digits() function is to supply the characters that will be used as digits for the base you want.
     *
     * NOTE:
     * You can use any characters for that when you convert
     * to another base, but when you convert again to the decimal base, you need to use the
     * same characters or you will get another unexpected result.
     *
     * @param string $base
     * @return string
     * @static
     */
    public static function digits($base)
    {
        self::bcExists();

        if($base > 64){
            $digits = "";
            for($loop = 0; $loop < 256; $loop++){
                $digits .= chr($loop);
            }
        } else {
            $digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
        }
        $digits = substr($digits, 0, $base);
        return (string)$digits;
    }

    /**
     * Internal check for the existence of the bcmath extension
     * @static
     * @return bool
     */
    private static function bcExists()
    {
        if(self::$bcExists) return self::$bcExists;

        if(!extension_loaded('bcmath')){
            self::$bcExists = FALSE;
            exit("bcmath extention required\nFile: " . basename(__FILE__) . "\nLine: " . __LINE__ . "\n");
        } else {
            self::$bcExists = TRUE;
        }
        return self::$bcExists;
    }
}








Tutorials
About Us
Contents have been open source in GITHUB. Please give me a ⭐ if you found this helpful :)
Community
Problem? Raise me a new issue.
Support Us
Buy me a coffee. so i can spend more nights for this :)

BTCSCHOOLS would like to present you with more pratical but little theory throughout our tutorials. Pages' content are constantly keep reviewed to avoid mistakes, but we cannot warrant correctness of all contents. While using this site, you agree to accept our terms of use, cookie & privacy policy. Copyright 2019 by BTCSCHOOLS. All Rights Reserved.