PHP CRC16(CRC32)

PHP CRC16(CRC32)

PHP CRC16(CRC32)


資料來源: https://github.com/zgldh/crc16-php/blob/master/src/Crc16.php

https://blog.csdn.net/zhang197093/article/details/89061957


關鍵字: 

字串轉位元陣列(byte Array)

ord(): 將字元變成0~255的數字
char():將0~255的數字變成字元


GITHUB:

<?php

//Crc16.php

namespace Crc16;


class Crc16
{
    /**
     * CRC-16/IBM
     * @param $str
     * @return mixed
     */
    public static function IBM($str)
    {
        return self::hash($str, 0x8005, 0, 0, true, true);
    }

    /**
     * CRC-16/MAXIM
     * @param $str
     * @return mixed
     */
    public static function MAXIM($str)
    {
        return self::hash($str, 0x8005, 0, 0xffff, true, true);
    }

    /**
     * CRC-16/USB
     * @param $str
     * @return mixed
     */
    public static function USB($str)
    {
        return self::hash($str, 0x8005, 0xffff, 0xffff, true, true);
    }

    /**
     * CRC-16/MODBUS
     * @param $str
     * @return mixed
     */
    public static function MODBUS($str)
    {
        return self::hash($str, 0x8005, 0xffff, 0, true, true);
    }

    /**
     * CRC-16/CCITT
     * @param $str
     * @return mixed
     */
    public static function CCITT($str)
    {
        return self::hash($str, 0x1021, 0, 0, true, true);
    }

    /**
     * CRC-16/CCITT-FALSE
     * @param $str
     * @return mixed
     */
    public static function CCITT_FALSE($str)
    {
        return self::hash($str, 0x1021, 0xffff, 0, false, false);
    }

    /**
     * CRC-16/X25
     * @param $str
     * @return mixed
     */
    public static function X25($str)
    {
        return self::hash($str, 0x1021, 0xffff, 0xffff, true, true);
    }

    /**
     * CRC-16/XMODEM
     * @param $str
     * @return mixed
     */
    public static function XMODEM($str)
    {
        return self::hash($str, 0x1021, 0, 0, false, false);
    }

    /**
     * CRC-16/DNP
     * @param $str
     * @return mixed
     */
    public static function DNP($str)
    {
        return self::hash($str, 0x3d65, 0, 0xffff, true, true);
    }

    /**
     * 将一个字符按比特位进行反转 eg: 65 (01000001) --> 130(10000010)
     * @param $char
     * @return string $char
     */
    private static function reverseChar($char)
    {
        $byte = ord($char);
        $tmp = 0;
        for ($i = 0; $i < 8; ++$i) {
            if ($byte & (1 << $i)) {
                $tmp |= (1 << (7 - $i));
            }
        }
        return chr($tmp);
    }

    /**
     * 将一个字节流按比特位反转 eg: 'AB'(01000001 01000010)  --> '\x42\x82'(01000010 10000010)
     * @param $str
     * @return mixed
     */
    private static function reverseString($str)
    {
        $m = 0;
        $n = strlen($str) - 1;
        while ($m <= $n) {
            if ($m == $n) {
                $str[$m] = self::reverseChar($str[$m]);
                break;
            }
            $ord1 = self::reverseChar($str[$m]);
            $ord2 = self::reverseChar($str[$n]);
            $str[$m] = $ord2;
            $str[$n] = $ord1;
            $m++;
            $n--;
        }
        return $str;
    }

    /**
     * @param string $str         待校验字符串
     * @param int $polynomial     二项式
     * @param int $initValue      初始值
     * @param int $xOrValue       输出结果前异或的值
     * @param bool $inputReverse  输入字符串是否每个字节按比特位反转
     * @param bool $outputReverse 输出是否整体按比特位反转
     * @return int
     */
    public static function hash($str, $polynomial, $initValue, $xOrValue, $inputReverse = false, $outputReverse = false)
    {
        $crc = $initValue;

        for ($i = 0; $i < strlen($str); $i++) {
            if ($inputReverse) {
                // 输入数据每个字节按比特位逆转
                $c = ord(self::reverseChar($str[$i]));
            } else {
                $c = ord($str[$i]);
            }
            $crc ^= ($c << 8);
            for ($j = 0; $j < 8; ++$j) {
                if ($crc & 0x8000) {
                    $crc = (($crc << 1) & 0xffff) ^ $polynomial;
                } else {
                    $crc = ($crc << 1) & 0xffff;
                }
            }
        }
        if ($outputReverse) {
            // 把低地址存低位,即采用小端法将整数转换为字符串
            $ret = pack('cc', $crc & 0xff, ($crc >> 8) & 0xff);
            // 输出结果按比特位逆转整个字符串
            $ret = self::reverseString($ret);
            // 再把结果按小端法重新转换成整数
            $arr = unpack('vshort', $ret);
            $crc = $arr['short'];
        }
        return $crc ^ $xOrValue;
    }
}
<?php
//Test.php
use Crc16\Crc16;
use PHPUnit\Framework\TestCase;

final class EmailTest extends TestCase
{
    public function testIBM()
    {
        $rawString = '1234567890';
        $hashAnswer = 'c57a';
        $hashResult = dechex(Crc16::IBM($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testMAXIM()
    {
        $rawString = '1234567890';
        $hashAnswer = '3a85';
        $hashResult = dechex(Crc16::MAXIM($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testUSB()
    {
        $rawString = '1234567890';
        $hashAnswer = '3df5';
        $hashResult = dechex(Crc16::USB($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testMODBUS()
    {
        $rawString = '1234567890';
        $hashAnswer = 'c20a';
        $hashResult = dechex(Crc16::MODBUS($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testCCITT()
    {
        $rawString = '1234567890';
        $hashAnswer = '286b';
        $hashResult = dechex(Crc16::CCITT($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testCCITT_FALSE()
    {
        $rawString = '1234567890';
        $hashAnswer = '3218';
        $hashResult = dechex(Crc16::CCITT_FALSE($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testX25()
    {
        $rawString = '1234567890';
        $hashAnswer = '4b13';
        $hashResult = dechex(Crc16::X25($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testXMODEM()
    {
        $rawString = '1234567890';
        $hashAnswer = 'd321';
        $hashResult = dechex(Crc16::XMODEM($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }

    public function testDNP()
    {
        $rawString = '1234567890';
        $hashAnswer = 'bc1b';
        $hashResult = dechex(Crc16::DNP($rawString));
        $this->assertEquals($hashAnswer, $hashResult);
    }
}


zhang197093:

/**
 * 将一个字符按比特位进行反转 eg: 65 (01000001) --> 130(10000010)
 * @param $char
 * @return $char
 */
function reverseChar($char) {
    $byte = ord($char);
    $tmp = 0;
    for ($i = 0; $i < 8; ++$i) {
        if ($byte & (1 << $i)) {
            $tmp |= (1 << (7 - $i));
        }
    }
    return chr($tmp);
}
 
/**
 * 将一个字节流按比特位反转 eg: 'AB'(01000001 01000010)  --> '\x42\x82'(01000010 10000010)
 * @param $str
 */
function reverseString($str) {
    $m = 0;
    $n = strlen($str) - 1;
    while ($m <= $n) {
        if ($m == $n) {
            $str{$m} = reverseChar($str{$m});
            break;
        }
        $ord1 = reverseChar($str{$m});
        $ord2 = reverseChar($str{$n});
        $str{$m} = $ord2;
        $str{$n} = $ord1;
        $m++;
        $n--;
    }
    return $str;
}
 
/**
 * @param string $str 待校验字符串
 * @param int $polynomial 二项式
 * @param int $initValue 初始值
 * @param int $xOrValue 输出结果前异或的值
 * @param bool $inputReverse 输入字符串是否每个字节按比特位反转
 * @param bool $outputReverse 输出是否整体按比特位反转
 * @return int
 */
function crc16($str, $polynomial, $initValue, $xOrValue, $inputReverse = false, $outputReverse = false) {
    $crc = $initValue;
 
    for ($i = 0; $i < strlen($str); $i++) {
        if ($inputReverse) {
            // 输入数据每个字节按比特位逆转
            $c = ord(reverseChar($str{$i}));
        } else {
            $c = ord($str{$i});
        }
        $crc ^= ($c << 8);
        for ($j = 0; $j < 8; ++$j) {
            if ($crc & 0x8000) {
                $crc = (($crc << 1) & 0xffff) ^ $polynomial;
            } else {
                $crc = ($crc << 1) & 0xffff;
            }
        }
    }
    if ($outputReverse) {
        // 把低地址存低位,即采用小端法将整数转换为字符串
        $ret = pack('cc', $crc & 0xff, ($crc >> 8) & 0xff);
        // 输出结果按比特位逆转整个字符串
        $ret = reverseString($ret);
        // 再把结果按小端法重新转换成整数
        $arr = unpack('vshort', $ret);
        $crc = $arr['short'];
    }
    return $crc ^ $xOrValue;
}
/* 列举一些常用的crc16算法 */
 
// CRC-16/IBM
printf("%x\n", crc16('1234567890', 0x8005, 0, 0, true, true));
 
// CRC-16/MAXIM
printf("%x\n", crc16('1234567890', 0x8005, 0, 0xffff, true, true));
 
// CRC-16/USB
printf("%x\n", crc16('1234567890', 0x8005, 0xffff, 0xffff, true, true));
 
// CRC-16/MODBUS
printf("%x\n", crc16('1234567890', 0x8005, 0xffff, 0, true, true));
 
// CRC-16/CCITT
printf("%x\n", crc16('1234567890', 0x1021, 0, 0, true, true));
 
// CRC-16/CCITT-FALSE
printf("%x\n", crc16('1234567890', 0x1021, 0xffff, 0, false, false));
 
// CRC-16/X25
printf("%x\n", crc16('1234567890', 0x1021, 0xffff, 0xffff, true, true));
 
// CRC-16/XMODEM
printf("%x\n", crc16('1234567890', 0x1021, 0, 0, false, false));
 
// CRC-16/DNP
printf("%x\n", crc16('1234567890', 0x3d65, 0, 0xffff, true, true));


—-


CRC32:

function php_crc32($str) {
    $polynomial = 0x04c11db7;
    $crc = 0xffffffff;
    for ($i = 0; $i < strlen($str); $i++) {
        $c = ord(reverseChar($str{$i}));
        $crc ^= ($c << 24);
        for ($j = 0; $j < 8; $j++) {
            if ($crc & 0x80000000) {
                $crc = (($crc << 1) & 0xffffffff) ^ $polynomial;
            } else {
                $crc = ($crc << 1) & 0xffffffff;
            }
        }
    }
    $ret = pack('cccc', $crc & 0xff, ($crc >> 8) & 0xff, ($crc >> 16) & 0xff, ($crc >> 24) & 0xff);
    $ret = reverseString($ret);
    $arr = unpack('Vret', $ret);
    $ret = $arr['ret'] ^ 0xffffffff;
    return $ret;
}
 
var_dump(php_crc32('1234567890') === crc32('1234567890'));
var_dump(php_crc32('php是世界上最好的语言') === crc32('php是世界上最好的语言'));

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *