生成Luhn校验和

Ali*_*xel 12 php algorithm checksum check-digit luhn

验证Luhn校验和有很多实现,但很少用于生成它们.我遇到过这个,但是在我的测试中它发现它是错误的,我不理解delta变量背后的逻辑.

我已经创建了这个应该生成Luhn校验和的函数,但由于某些原因我还没有理解生成的校验和在一半时间内是无效的.

function Luhn($number, $iterations = 1)
{
    while ($iterations-- >= 1)
    {
        $stack = 0;
        $parity = strlen($number) % 2;
        $number = str_split($number, 1);

        foreach ($number as $key => $value)
        {
            if ($key % 2 == $parity)
            {
                $value *= 2;

                if ($value > 9)
                {
                    $value -= 9;
                }
            }

            $stack += $value;
        }

        $stack = 10 - $stack % 10;

        if ($stack == 10)
        {
            $stack = 0;
        }

        $number[] = $stack;
    }

    return implode('', $number);
}
Run Code Online (Sandbox Code Playgroud)

一些例子:

Luhn(3); // 37, invalid
Luhn(37); // 372, valid
Luhn(372); // 3728, invalid
Luhn(3728); // 37283, valid
Luhn(37283); // 372837, invalid
Luhn(372837); // 3728375, valid
Run Code Online (Sandbox Code Playgroud)

我正在验证针对此页面生成的校验和,我在这里做错了什么?


为了将来参考,这是工作功能.

function Luhn($number, $iterations = 1)
{
    while ($iterations-- >= 1)
    {
        $stack = 0;
        $number = str_split(strrev($number), 1);

        foreach ($number as $key => $value)
        {
            if ($key % 2 == 0)
            {
                $value = array_sum(str_split($value * 2, 1));
            }

            $stack += $value;
        }

        $stack %= 10;

        if ($stack != 0)
        {
            $stack -= 10;
        }

        $number = implode('', array_reverse($number)) . abs($stack);
    }

    return $number;
}
Run Code Online (Sandbox Code Playgroud)

我删除了$ parity变量,因为我们不需要它用于此目的,并验证:

function Luhn_Verify($number, $iterations = 1)
{
    $result = substr($number, 0, - $iterations);

    if (Luhn($result, $iterations) == $number)
    {
        return $result;
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

ang*_*son 9

编辑:对不起,我现在意识到你已经有了我几乎所有的答案,你只是错误地确定了哪个因素用于哪个数字.

我的整个答案现在可以用这句话总结:

您将因子反转,您将错误的数字乘以2,具体取决于数字的长度.


看看关于Luhn算法维基百科文章.

你的校验和一半时间无效的原因是你的支票是你的号码有一个奇数位数的一半,然后你把错误的数字加倍.

对于37283,当从右边开始计算时,您会得到以下数字序列:

  3 * 1 =  3             3
  8 * 2 = 16 --> 1 + 6 = 7
  2 * 1 =  2             2
  7 * 2 = 14 --> 1 + 4 = 5
+ 3 * 1 =  3             3
=                       20
Run Code Online (Sandbox Code Playgroud)

该算法要求您将原始数字中的各个数字与"右起每两个数字"的乘积的各个数字相加.

所以从右边开始,你总计3 +(1 + 6)+ 2 +(1 + 4)+ 3,这样就可以得到20.

如果您最终得到的数字以零结尾,即20,则该数字有效.

现在,您的问题暗示您想知道如何生成校验和,嗯,这很容易,请执行以下操作:

  1. 加上额外的零,所以你的数字从xyxyxyxy到xyxyxyxy0
  2. 计算新数字的luhn校验和
  3. 取总和,模数10,这样你就得到一个从0到10的单个数字
  4. 如果数字为0,那么祝贺你的校验和数字为零
  5. 否则,计算10位数以获得最后一位数而不是零所需的数字

示例:Number为12345

  1. 坚持零:123450
  2. 计算123450的luhn校验和,得到

    0   5    4    3    2    1
    1   2    1    2    1    2  <-- factor
    0   10   4    6    2    2  <-- product
    0  1 0   4    6    2    2  <-- sum these to: 0+1+0+4+6+2+2=15
    
    Run Code Online (Sandbox Code Playgroud)
  3. 取总和(15),模数10,它给你5

  4. 数字(5),不是零
  5. 计算10-5,它给你5,最后一位数应该是5.

结果是123455.