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

发布于 2024-11-14 22:02:45 字数 1764 浏览 2 评论 0原文

根据此处提供的算法,我在尝试在 PHP 中实现 XOR8/LRC 校验和时遇到了真正的问题: http://en.wikipedia.org/wiki/Longitudinal_redundancy_check

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

例如,我确定这个字符串:

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

十六进制校验和为 39(包括最后一个 * 字符)。

对于任何感兴趣该字符串含义的人,它是一条 DART(深海评估和海啸报告)消息 - http://nctr.pmel.noaa.gov/Dart/Pdf/dartMsgManual3.01.pdf

我将字符串转换为包含 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; 
        }

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

        function byteStr2byteArray($s) {
          return array_slice(unpack("C*", "\0".$s), 1);
        }

最后,我使用的带有按位运算符的 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;
        }

然后,我们用 dechex($checksum + 0) 转换 LRC 校验和的最终十进制结果,这样我们就得到了最终的十六进制校验和。

经过所有这些操作后,我没有得到预期的结果,因此任何帮助将不胜感激

提前致谢。


另外,我无法按照 CRC8-Check in PHP 答案使其工作。

I'm having real problems trying to implement a XOR8/LRC checksum in PHP, according to the algorithm present here: http://en.wikipedia.org/wiki/Longitudinal_redundancy_check

What I'm trying to do is, given any string calculate its LRC checksum.

For example, I know for sure this string:

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

Has a hexadecimal checksum of 39 (including the last * char).

For anyone interested what is the meaning of the string, it's is a DART (Deep-ocean Assesment and Reporting of Tsunamis) message - http://nctr.pmel.noaa.gov/Dart/Pdf/dartMsgManual3.01.pdf.

I convert the string to a binary string with 1's and 0's. From there, I try to create a byte array and apply the algorithm to the byte array, but it's not working and I can't figure out why.

The function I'm using for converting to String to Binary String is:

        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; 
        }

The function I'm using for converting from Binary String to Binary Array is:

        function byteStr2byteArray($s) {
          return array_slice(unpack("C*", "\0".$s), 1);
        }

Finally, the LRC implementation I'm using, with bitwise operators, is:

        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;
        }

Then, we convert the final decimal result of the LRC checksum with dechex($checksum + 0), so we have the final hexadecimal checksum.

After all these operations, I'm not getting the expected result, so any help will be highly appreciated.

Thanks in advance.


Also, I can't make it work following the CRC8-Check in PHP answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

-柠檬树下少年和吉他 2024-11-21 22:02:45

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

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

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

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

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

2.1.3 校验和错误,由对应于字符10x31关闭。

2.2.3 六个校验和都是错误的,由对应于字符-0x2D引起。

2.3.1.2 我认为 dev3tries 之间缺少

2.3.1.3 校验和由 0x0D 关闭,并且 dev3tries 之间没有分隔符。如果 dev3 值和 tries 值之间有回车符,则校验和将是正确的。

2.3.2.2-32.3.1.2-3相同。

2.3.3.3 校验和再次错误,并且 tries 之前没有分隔符。

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")
    );
}

I'm afraid that nobody on StackOverflow can help you, and here's why. This question was bugging me so I went to the DART website you mentionned to take a look at their specs. Two problems became apparent:

  • The first one is you have misunderstood part of their specs. Messages start with a Carriage Return (\r or \0x0D) and the asterisk * is not part of the checksum

  • The second, bigger problem is that their specs contain several errors. Some of them may originate from bad copy/paste and/or an incorrect transformation from Microsoft .doc to PDF.

I have taken the time to inspect some of them so that would be nice if you could contact the specs authors or maintainers so they can fix them or clarify them. Here is what I've found.

2.1.2 The message breakdown mentions C/I as message status even though it doesn't appear in the example message.

2.1.3 The checksum is wrong, off by 0x31 which corresponds to the character 1.

2.2.3 The six checksums are wrong, off by 0x2D which corresponds to the character -.

2.3.1.2 I think there's a <cr> missing between dev3 and tries

2.3.1.3 The checksum is off by 0x0D and there's no delimiter between dev3 and tries. The checksum would be correct if there was a carriage return between the dev3 value and the tries value.

2.3.2.2-3 Same as 2.3.1.2-3.

2.3.3.3 Wrong checksum again, and there's no delimiter before tries.

2.4.2 The message breakdown mentions D$2 = message ID which should be D$3 = message ID.

Here's the code I used to verify their checksums:

$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")
    );
}
你爱我像她 2024-11-21 22:02:45

就其价值而言,这是来自维基百科的算法的完全未优化的直接实现:

$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 的算法不一样。

For what it's worth, here's a completely unoptimized, straight-up implementation of the algorithm from 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);

It results in 0x0E for the string from your example, so either I've managed to fudge the implementation or the algorithm that produced 0x39 is not the same.

不必了 2024-11-21 22:02:45

我意识到这个问题很老了,但我很难弄清楚如何做到这一点。它现在可以工作了,所以我想我应该粘贴代码。就我而言,校验和需要以 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;
}

I realize that this question pretty old, but I had trouble figuring out how to do this. It's working now, so I figured I should paste the code. In my case, the checksum needs to return as an ASCII string.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文