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是世界上最好的语言'));