Php 如何检查CRC16的有效性

Php 如何检查CRC16的有效性,php,crc,crc16,Php,Crc,Crc16,我正在研究第一次从传感器接收二进制数据。 数据是base64编码的,我应该对数据进行解码和验证,然后将其保存到数据库中。验证过程的一个步骤是检查CRC-16的有效性 我收到的每个有效载荷都有一个CRC码,我有一个函数,应该计算CRC-16码本身,我想知道的是,通过将解码数据传递给CRC-16计算函数,然后将结果与零进行比较,是否足以检查这一点?如果它不是零,则表示数据已损坏 如果一切正常,我需要解包二进制数据并循环结果,以根据特定偏移信息(根据制造商的文档)获取传感器数据,例如电池和空气温度。然

我正在研究第一次从传感器接收二进制数据。 数据是base64编码的,我应该对数据进行解码和验证,然后将其保存到数据库中。验证过程的一个步骤是检查CRC-16的有效性

我收到的每个有效载荷都有一个CRC码,我有一个函数,应该计算CRC-16码本身,我想知道的是,通过将解码数据传递给CRC-16计算函数,然后将结果与零进行比较,是否足以检查这一点?如果它不是零,则表示数据已损坏

如果一切正常,我需要解包二进制数据并循环结果,以根据特定偏移信息(根据制造商的文档)获取传感器数据,例如
电池
空气温度
。然后像我们通常对数据库做的那样保存数据

问题是:当我将
crc16Calc
函数应用于有效的数据集时,会得到非零值

这可能是因为CRC被添加到数据字符串的开头,而不是结尾?我的意思是有效载荷的结构是
,而不是相反

我的代码是:

公共静态$crc16\u tbl=[
0x0000、0xC0C1、0xC181、0x0140、0xC301、0x03C0、0x0280、0xC241、,
0xC601、0x06C0、0x0780、0xC741、0x0500、0xC5C1、0xC481、0x0440、,
0xCC01、0x0CC0、0x0D80、0xCD41、0x0F00、0xCFC1、0xCE81、0x0E40、,
0x0A00、0xCAC1、0xCB81、0x0B40、0xC901、0x09C0、0x0880、0xC841、,
0xD801、0x18C0、0x1980、0xD941、0x1B00、0xDBC1、0xDA81、0x1A40、,
0x1E00、0xDEC1、0xDF81、0x1F40、0xDD01、0x1DC0、0x1C80、0xDC41、,
0x1400、0xD4C1、0xD581、0x1540、0xD701、0x17C0、0x1680、0xD641、,
0xD201、0x12C0、0x1380、0xD341、0x1100、0xD1C1、0xD081、0x1040、,
0xF001、0x30C0、0x3180、0xF141、0x3300、0xF3C1、0xF281、0x3240、,
0x3600、0xF6C1、0xF781、0x3740、0xF501、0x35C0、0x3480、0xF441、,
0x3C00、0xFCC1、0xFD81、0x3D40、0xFF01、0x3FC0、0x3E80、0xFE41、,
0xFA01、0x3AC0、0x3B80、0xFB41、0x3900、0xF9C1、0xF881、0x3840、,
0x2800、0xE8C1、0xE981、0x2940、0xEB01、0x2BC0、0x2A80、0xEA41、,
0xEE01、0x2EC0、0x2F80、0xEF41、0x2D00、0xEDC1、0xEC81、0x2C40、,
0xE401、0x24C0、0x2580、0xE541、0x2700、0xE7C1、0xE681、0x2640、,
0x2200、0xE2C1、0xE381、0x2340、0xE101、0x21C0、0x2080、0xE041、,
0xA001、0x60C0、0x6180、0xA141、0x6300、0xA3C1、0xA281、0x6240、,
0x6600、0xA6C1、0xA781、0x6740、0xA501、0x65C0、0x6480、0xA441、,
0x6C00、0xACC1、0xAD81、0x6D40、0xAF01、0x6FC0、0x6E80、0xAE41、,
0xAA01、0x6AC0、0x6B80、0xAB41、0x6900、0xA9C1、0xA881、0x6840、,
0x7800、0xB8C1、0xB981、0x7940、0xBB01、0x7BC0、0x7A80、0xBA41、,
0xBE01、0x7EC0、0x7F80、0xBF41、0x7D00、0xBDC1、0xBC81、0x7C40、,
0xB401、0x74C0、0x7580、0xB541、0x7700、0xB7C1、0xB681、0x7640、,
0x7200、0xB2C1、0xB381、0x7340、0xB101、0x71C0、0x7080、0xB041、,
0x5000、0x90C1、0x9181、0x5140、0x9301、0x53C0、0x5280、0x9241、,
0x9601、0x56C0、0x5780、0x9741、0x5500、0x95C1、0x9481、0x5440、,
0x9C01、0x5CC0、0x5D80、0x9D41、0x5F00、0x9FC1、0x9E81、0x5E40、,
0x5A00、0x9AC1、0x9B81、0x5B40、0x9901、0x59C0、0x5880、0x9841、,
0x8801、0x48C0、0x4980、0x8941、0x4B00、0x8BC1、0x8A81、0x4A40、,
0x4E00、0x8EC1、0x8F81、0x4F40、0x8D01、0x4DC0、0x4C80、0x8C41、,
0x4400、0x84C1、0x8581、0x4540、0x8701、0x47C0、0x4680、0x8641、,
0x8201、0x42C0、0x4380、0x8341、0x4100、0x81C1、0x8081、0x4040
];
//$crc是介于0和0xFFFF之间的整数
//$dataByte是介于0和0xFF之间的整数
//结果是一个介于0和0xFFFF之间的整数
函数addCRC($crc,$dataByte)
{
$index=($crc&0xFF)^$dataByte;
$crc16int=self::$crc16_tbl[$index];
返回($crc>>8)^$crc16int;
}
//$buffer是包含二进制数据的字符串
//结果是一个介于0和0xFFFF之间的整数
函数crc16Calc($buffer)
{
$crc16=0;
$length=strlen($buffer);
对于($i=0;$i<$length;$i++){
//使用ord()从长度为1的字符串变为介于0和0xFF之间的整数
$dataByte=ord($buffer[$i]);
$crc16=$this->addCRC($crc16,$dataByte);
}
返回$crc16;
}
公共函数存储(请求$Request)
{
//1.解码base64字符串中的数据,并检查CRC有效性。
$content=file($request->file($data));
存储::磁盘('local')->put('examples.bin','';
$file\u handler=fopen('C:\laragon\www\media clone\storage\app\examples.bin','w+');
foreach($行内容){
$decoded_data=base64_decode($line);
//检查CRC验证
打印($this->crc16Calc($decoded_data))。
;//每次都会给出不同的非零数字 如果($this->crc16Calc($decoded_data)!=0) 返回“无效数据”; //否则 fwrite($file\u handler,$decoded\u data); } fclose($file\u handler); }
编辑 下面的数据是用base64编码的,包含20个有效载荷&下图解释了有效载荷的结构,所有多字节二进制字段都是按小端排序的

otykgAFuAGUAAEwBQAMfCqMI6g3zA+UDBQR8AXEBiQEyAiQCPQKh/nb+SwBKAAA=
WVOWgAFuAGUAAEwBQAMOCgAA6g1nAVsBcAEuAi0CMgJLAUgBTgFK/kX+IgAiAAA=
g5v5gAFvAGcAAPAAQAMRCs0IxiWrA54DsgMzAycDQQObAI0ApwCFAnYCFAATAA8=
z/5qgAFvAGcAABkBQAPuCSMJLh+uAqgCtALoA+gD6APY/9j/2P+uAqgCAAAAAA8=
XoVTgAFvAGcAAPgAQAMDCr8JZiq0Aa0BvAGhAkIC3gL+ANAARAGG/7n+GgAWAAA=
SI5CgAFvAGcAAPgAQAPvCQAAWirJAMEA0AD8ALgATwHvAcEBFQKu+U/4NAAvAAU=
RxA9gAFvAGcAAA8BQAMRCrgJUCVbAkwCcgLNAoQCCQPjALIAIAGBAOD/GQAUAAA=
T+s1gAFvAGcAAPgAQAP0CQAATioEAfsADQHgAL4AIgEMAucBIgJe+bL4OAA0AAU=
H+EqgAFvAGcAAPgAQAP8CQAAQip0AXIBdgH0AswB6AOjAND/jgG0/1P9EgAAAAU=
CLUbgAFvAGcAAPgAQAMDCgAAJirIAa8B5AHoA+gD6APT/9L/0//IAa8BAAAAAA8=
3nAQgAFvAGcAAPgAQAMFCq4IHCqtAKUAswAyACoAQgBgAlQCZwKx8gfyQQBAAAA=
fDsKgAFvAGgAADEBQAMvCtYJOfgmAxsDNgM+AzADVwOKAHIAmAAZAgQCEQAPAA8=
YD4pgAFvAGgAADEBQAP2CQAAOfiCAXABlgHbA84D6APf/9D/7f9wAV4BAAAAAA8=
hCW9gAFvAGcAAOkAQAMgCjoAbh6xALEAswC9A7IDxQP7//L/BgB1AGUAAgACAA8=
HRv7gAFvAGcAAL4BQAP5CQAASBPCBbgFzAXoA+gD6APw/+//8P/CBbgFAAAAAA8=
lZPRgAFvAGcAANcAQAMqCnoJTiAoAhwCOALvAuICCAPGALEA0QCTAG4AFQAUAAA=
9AfcgAFvAGcAAE4BQAMdCgAAAMBUCEcIYwi1Aa8BuwHJAr4C1QJQA0oDjgCMAAA=
KHT7gAFuAGUAADwBQAMrCv0ItA9EADQAVADoA+gD6APK/8r/yv9DADQAAAAAAA8=
fcjsgAFvAGcAAK0BQAMdCqMJtg1OA0EDWwOHA3QDpANCACUAVwC6AqcCCgAHAA8=
LHArgAFvAGcAAJwBQAMLCsQJpBXhANAAAgHoA+gD6APO/83/zv/hANAAAAAAAA8=

我还尝试将CRC的前两个字节移到字符串的末尾,然后计算结果,它给出了非零的
0xB9AE
,函数正确地执行了计算,因为我将结果与在线CRC-16计算器进行了比较

  $new_string = mb_strcut($decoded_data,2,46).mb_strcut($decoded_data,0,2);
        print $new_string;
        print 'crc1: '.$this->crc16Calc($new_string).'  ';

只需保存前两个字节,计算剩余的CRC,然后将其与您保存的进行比较。这无疑是最直接、最可验证的方法。更不用说它比你想做的要快一点(即使你可以),因为你避免了在两个字节上计算你不需要的CRC

只有当发送方将CRC字节追加到末尾,并且它们以小的尾端顺序追加它们时,整个事件才会得到零

如果您无法抵抗警报对CRC可爱的代数属性的调用,那么将两个字节按正确的字节顺序移动到末尾,然后