如何在PHP中实现纵向冗余校验(LRC/CRC8/XOR8)校验和?

如何在PHP中实现纵向冗余校验(LRC/CRC8/XOR8)校验和?,php,checksum,Php,Checksum,根据这里的算法,我在尝试用PHP实现XOR8/LRC校验和时遇到了实际问题: 我想做的是,给定任何字符串,计算其LRC校验和 例如,我肯定知道这个字符串: D$1I 11/14/2006 18:15:00 1634146 3772376 3772344 3772312 3772294 1* 十六进制校验和为39(包括最后一个字符) 对任何感兴趣的人来说,这条线的意义是什么,它是一条DART(深海海啸评估和报告)信息- 我将该字符串转换为具有1和0的二进制字符串。从那里,我尝试创建一个字节数组,

根据这里的算法,我在尝试用PHP实现XOR8/LRC校验和时遇到了实际问题:

我想做的是,给定任何字符串,计算其LRC校验和

例如,我肯定知道这个字符串:

D$1I 11/14/2006 18:15:00 1634146 3772376 3772344 3772312 3772294 1*
十六进制校验和为39(包括最后一个字符)

对任何感兴趣的人来说,这条线的意义是什么,它是一条DART(深海海啸评估和报告)信息-

我将该字符串转换为具有1和0的二进制字符串。从那里,我尝试创建一个字节数组,并将算法应用到字节数组,但它不起作用,我也不知道为什么

我用于将字符串转换为二进制字符串的函数是:

        function str2binStr($str) { 
         $ret = '';
         for ($i = 0, $n = strlen($str); $i < $n; ++$i) 
           $ret .= str_pad(decbin(ord($str[$i])), 8, 0, STR_PAD_LEFT); 
         return $ret; 
        }
最后,我正在使用的LRC实现(使用位运算符)是:

        function lrc($byteArr) {
           $lrc = 0;
           $byteArrLen = count($byteArr);
           for ($i = 0; $i < $byteArrLen; $i++) {
             $lrc = ($lrc + $byteArr[$i]) & 0xFF;
           }
           $lrc = (($lrc ^ 0xFF) + 1) & 0xFF;
           return $lrc;
        }
功能lrc($byteArr){
$lrc=0;
$byteArrLen=计数($byteArr);
对于($i=0;$i<$byteArrLen;$i++){
$lrc=($lrc+$byteArr[$i])&0xFF;
}
$lrc=($lrc^0xFF)+1)和0xFF;
返回$lrc;
}
然后,我们将LRC校验和的最终十进制结果转换为dechex($checksum+0),从而得到最终的十六进制校验和

在所有这些操作之后,我没有得到预期的结果,因此非常感谢您的帮助

提前谢谢



另外,我也无法按照答案进行操作。

值得一提的是,这里有一个完全未优化的、直接实现的Wikipedia算法:

$buffer = 'D$1I 11/14/2006 18:15:00 1634146 3772376 3772344 3772312 3772294 1*';

$LRC = 0;
foreach (str_split($buffer, 1) as $b)
{
    $LRC = ($LRC + ord($b)) & 0xFF;
}
$LRC = (($LRC ^ 0xFF) + 1) & 0xFF;

echo dechex($LRC);

它会导致您示例中的字符串出现
0x0E
,因此,要么我设法伪造了实现,要么生成0x39的算法不一样。

我担心StackOverflow上没有人可以帮助您,原因如下。这个问题困扰着我,所以我去了你提到的DART网站看看他们的规格。两个问题变得显而易见:

  • 第一个是您误解了他们的部分规格。消息以回车(
    \r
    \0x0D
    )开头,星号
    *
    不是校验和的一部分

  • 第二个更大的问题是他们的规范包含几个错误。其中一些可能源于错误的复制/粘贴和/或从Microsoft.doc到PDF的不正确转换

我已经花了时间检查了其中的一些,如果你能联系规范的作者或维护者,以便他们能够修复或澄清它们,那就太好了。这是我发现的

2.1.2消息细分将
C/I
作为消息状态,即使它没有出现在示例消息中

2.1.3校验和错误,通过与字符
1
对应的
0x31
关闭

2.2.3六个校验和错误,通过与字符
-
对应的
0x2D
关闭

2.3.1.2我认为
dev3
尝试之间缺少

2.3.1.3校验和被
0x0D
关闭,并且
dev3
尝试之间没有分隔符。如果
dev3
值和
trys
值之间存在回车符,则校验和是正确的

2.3.2.2-32.3.1.2-3相同

2.3.3.3再次出现错误的校验和,并且在
尝试之前没有分隔符

2.4.2消息细分提到
D$2=消息ID
,应该是
D$3=消息ID

下面是我用来验证其校验和的代码:

$messages = array(
    "\rD\$0 11/15/2006 13:05:28 3214.2972 N 12041.3991 W* 46",
    "\rD\$1I 11/14/2006 18:15:00 1634146 3772376 3772344 3772313 3772294 1* 39",
    "\rD\$1I 11/14/2006 19:15:00 1634146 3772275 3772262 3772251 3772249 1* 38",
    "\rD\$1I 11/14/2006 20:15:00 1634146 3772249 3772257 3772271 3772293 1* 3E",
    "\rD\$1I 11/14/2006 21:15:00 1634146 3772315 3772341 3772373 3772407 1* 39",
    "\rD\$1I 11/14/2006 22:15:00 1634146 3772440 3772472 3772506 3772540 1* 3C",
    "\rD\$1I 11/14/2006 23:15:00 1634146 3772572 3772603 3772631 3772657 1* 3B",
    "\rD\$2I 00 tt 18:32:45 ts 18:32:00 3772311\r00000063006201* 22",
    "\rD\$2I 01 tt 18:32:45 ts 18:32:00 3772311\r000000630062706900600061005f005ffffafff9fff8fff8fff7fff6fff401* 21",
    "\rD\$2I 02 tt 18:32:45 ts 18:32:00 3772335\rfffdfffafff7fff5fff1ffeeffea00190048ffe1ffddffdaffd8ffd5ffd101* 21"
);

foreach ($messages as $k => $message)
{
    $pos = strpos($message, '*');

    $payload = substr($message, 0, $pos);
    $crc = trim(substr($message, $pos + 1));

    $checksum = 0;

    foreach (str_split($payload, 1) as $c)
    {
        $checksum ^= ord($c);
    }

    $crc = hexdec($crc);

    printf(
        "Expected: %02X - Computed: %02X - Difference: %02X - Possibly missing: %s\n",
        $crc, $checksum, $crc ^ $checksum, addcslashes(chr($crc ^ $checksum), "\r")
    );
}

我意识到这个问题很老了,但我很难弄明白怎么做。它正在工作,所以我想我应该粘贴代码。在我的例子中,校验和需要作为ASCII字符串返回

public function getLrc($string)
{
    $LRC = 0;
    // Get hex checksum.
    foreach (str_split($string, 1) as $char) {
        $LRC ^= ord($char);
    }
    $hex = dechex($LRC);
    // convert hex to string
    $str = '';
    for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
    return $str;
}
公共函数getLrc($string)
{
$LRC=0;
//获取十六进制校验和。
foreach(str_split($string,1)作为$char){
$LRC^=作战需求文件($char);
}
$hex=dechex($LRC);
//将十六进制转换为字符串
$str='';

对于($i=0;$iHi-Josh),非常感谢您的时间。实施说明:"所有字符的异或,包括“*”,所以我假设它是一个XOR8校验和。另外,为什么要将字符串拆分为一个数组,然后将每个字符处理为它的ASCII值?你确定这就是wikipedia算法中一个字节的意思吗?在PHP中,字符串是一个字节数组。事实上,你可以根据接下来,例如,
ord(“a^b”)
ord(“a”)^ord(“b”)
相同。感谢您的澄清。将此与您的其他答案结合起来,一切似乎都更加清晰。噢,哇,令人惊讶的答案,我将其分成几个部分。关于是否包含*char,文档中规定您不能包含它(前面的所有字符都是*),但在回答了他们关于校验和的问题后,他们告诉我校验和中应该包含*,所以我采用了最后一种方法。我完全没有看到示例的回车,谢谢你指出。我知道2.1.2消息细分缺少C/I,这是因为状态可以是C/I/NS(NS=未设置);这是他们通过电子邮件发送给我的一份附带文档。请确保此修复说明将送达…他们,我将直接链接到他的stackoverflow问题。再次感谢您提供的难以置信的帮助。
public function getLrc($string)
{
    $LRC = 0;
    // Get hex checksum.
    foreach (str_split($string, 1) as $char) {
        $LRC ^= ord($char);
    }
    $hex = dechex($LRC);
    // convert hex to string
    $str = '';
    for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
    return $str;
}