https://github.com/sjzzhanglu/crc16
PHP CRC-16/IBM,CRC-16/MAXIM,CRC-16/USB,CRC-16/MODBUS,CRC-16/CCITT,CRC-16/CCITT-FALSE,CRC-16/X25,CRC-16/XMODEM,CRC-16/DNP
模式多项式初始值结果异或值输入数据翻转输出数据翻转
CRC-16/IBM0x800500truetrue
CRC-16/MAXIM0x800500xfffftruetrue
CRC-16/USB0x80050xffff0xfffftruetrue
CRC-16/MODBUS0x80050xffff0truetrue
CRC-16/CCITT0x102100truetrue
CRC-16/CCITT-FALSE0x10210xffff0falsefalse
CRC-16/X250x10210xffff0xfffftruetrue
CRC-16/XMODEM0x102100falsefalse
CRC-16/DNP0x3d6500xfffftruetrue
$crc = new Sjzzhanglu\Crc16();
$hexString = ''; // 十六进制字符串
$poly = 0x8005; // 多项式
$initValue = 0xffff; // 初始值
$xOrValue = 0x0000; // 结果异或值
$inputReverse = true; // 输入数据翻转
$outputReverse = true; // 输出数据翻转
$checkValue = $crc->crc16($hexString, 'hex', $poly, $initValue, $xOrValue, $inputReverse, $outputReverse);
源码:
<?php
namespace Sjzzhanglu;
class Crc16{
/**
* @param string $str 待校验字符串
* @param string $strType hex:16进制;ascii:ascii码
* @param int $polynomial 二项式
* @param int $initValue 初始值
* @param int $xOrValue 输出结果前异或的值
* @param bool $inputReverse 输入字符串是否每个字节按比特位反转
* @param bool $outputReverse 输出是否整体按比特位反转
* @return int
*/
public function crc16($str,$strType="hex", $polynomial, $initValue, $xOrValue, $inputReverse = false, $outputReverse = false) {
$crc = $initValue;
if($strType == "hex"){
$str = pack('H*', $str);
}
for ($i = 0; $i < strlen($str); $i++) {
if ($inputReverse) {
// 输入数据每个字节按比特位逆转
$c = ord($this->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 = $this->reverseString($ret);
// 再把结果按小端法重新转换成整数
$arr = unpack('vshort', $ret);
$crc = $arr['short'];
}
return base_convert($crc ^ $xOrValue, 10, 16);
}
/**
* 将一个字节流按比特位反转 eg: 'AB'(01000001 01000010) --> '\x42\x82'(01000010 10000010)
* @param $str
*/
public function reverseString($str) {
$m = 0;
$n = strlen($str) - 1;
while ($m <= $n) {
if ($m == $n) {
$str{$m} = $this->reverseChar($str{$m});
break;
}
$ord1 = $this->reverseChar($str{$m});
$ord2 = $this->reverseChar($str{$n});
$str{$m} = $ord2;
$str{$n} = $ord1;
$m++;
$n--;
}
return $str;
}
/**
* 将一个字符按比特位进行反转 eg: 65 (01000001) --> 130(10000010)
* @param $char
* @return $char
*/
public 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);
}
}