PHP中的crc32b输出不等于Python [英] Output of crc32b in PHP is not equal to Python

查看:83
本文介绍了PHP中的crc32b输出不等于Python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 PHP 代码段转换为 Python3 代码,但输出的 print echo 不同。



您可以在步骤1中看到它。



您知道问题出在哪里吗?我也附加了输入数组,但我认为它们是相等的。

  .W2 + vs ee7523b2 

编辑



当我从TRUE切换为raw时到FALSE,第一步的输出是相同的。 $ d = strrev(hash( crc32b,$ d,FALSE))。 $ d



但是问题是我必须将PHP转换为Python,而不是相反,因为那样我会在步骤中使用2,我需要具有相等的输出。



PHP输出(CMD)

  0-> 1 1 100 EUR 20190101 11111111Faktúra1 SK6807200002891987426353 0 0 
1-> W2 + 1 1 100 EUR 20190101 11111111Faktúra1 SK6807200002891987426353 0 0
2-> 00004e00007715c242b04d5014490af1445dd61c1527ddc5f4461ca5886caf63fd8fbcf7df69c2035760ecb28d8171efdb409c0206996498ea7921e715172e60c210f923f070079ffba40000
$$$> $$$> b

  ------- 
0-> 1 1 100 EUR 20190101 11111111Faktúra1 SK6807200002891987426353 0 0
1-> ee7523b2 1 1100 EUR 20190101 11111111Faktúra1 SK6807200002891987426353 0 0
2-> b'00006227515c7830302762275c783030325c7865305c7864386a34585c7862346d5c7838665c7865625c7863315c786266625c7839625c786339675c786332785c7831645c7862392c415c7862625c7831645c78663770365c786463735c786236572d606c225c7865355c7865635c7831345c7863655c786331205c7830635c7831315c7861375c7839345c7864665c7865635c7830365c7831652c22265c7866355c7862335c7866345c78616145585c7861625c7866395c7839615c7839645c7865645c7864625c7830305c7864355c7861643b5c7865365f5c7866645c786533405c78303027'



<强> PHP

 <?php 
$ suma = 100;
$ datum = 20190101;
$ varsym = 11111111;
$ konsym =;
$ specsym =;
$ poznamka =Faktúra;
$ iban = SK6807200002891987426353;
$ swift =;

$ d =爆破( \t,array(
0 =>'',
1 =>'1',
2 = > implode( \t,array(
true,
$ suma,// SUMA
'EUR',// JEDNOTKA
$ datum,// DATUM
$ varsym,// VARIABILNY SYMBOL
$ konsym,// KONSTANTNY SYMBOL
$ specsym,// SPECIFICKY SYMBOL
'',
$ poznamka,// POZNAMKA
'1',
$ iban,// IBAN
$ swift,// SWIFT
'0',
'0'
))
));
// 0
echo 0->。$ d。 \n;
$ d = strrev(hash( crc32b,$ d,TRUE))。 $ d;
// 1
echo 1->。$ d。 \n;
$ x = proc_open( / usr / bin / xz'--format = raw''--lzma1 = lc = 3,lp = 0,pb = 2,dict = 128KiB''-c''- ',[0 => [ pipe, r],1 => [ pipe, w]],$ p);
fwrite($ p [0],$ d);
fclose($ p [0]);
$ o = stream_get_contents($ p [1]);
fclose($ p [1]);
proc_close($ x);

$ d = bin2hex( \x00\x00。pack( v,strlen($ d))。$ o);
// 2
echo 2->。$ d。 \n;
?>

PYTHON

  def crc32b(x):
h = zlib.crc32(x)
x ='%08X'%(h& 0xffffffff,)
返回x.lower()

t = \t
gen = t.join([ 1,
100,#相同的变量
EUR,
20190101,
11111111,



Faktúra,
1,
SK6807200002891987426353,

0,
0]


d = t.join([[
, 1,gen])
#0
print(f 0-> {d})
hashD = crc32b (d.encode())#OK

hashD = hashD [::-1]
#hashD = str(binascii.unhexlify(hashD))
d = hashD + d
#1
print(f 1-> {d})
args = shlex.split( xz'--format = raw''--lzma1 = lc = 3,lp = 0,pb = 2,dict = 128KiB'-c-)
进程= subprocess.Popen(args,shell = False,stdin = subprocess.PIPE,stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
输出= process.communicate(d。 encode())

pack = \x00\x00 + str(struct.pack( H,len(d)))str(输出[0])

d = binascii.hexlify(pack.encode())
#2
print(f 2-> {d})


解决方案

不适用于 PHP
根据 [Python 3 ]:zlib。 crc32 数据[,值] 强调是我的):


计算数据的CRC(循环冗余校验)校验和,结果为无符号32位整数


您正在混淆:




  • 它的值-也可以看作长度为4的 ASCII 字符串

  • 其值的文本表示形式(在 base 16 )-长度为8的字符串






 >>> crc = 0x2B3257EE#zlib.crc32为您的文本
>>返回的值;> type(crc),crc
(< class'int'> ,, 724719598)
>>
>> [对于[0、8、16、24]中的shift_bits,为[chr((crc> shift_bits)& 0xFF)]
['î','W','2','+']


注释




  • 一种方法是将数字的4个字节中的每一个转换为 char

  • 要从 uint32 值获取字节,必须将 uint32 移至右侧( [Python.Wiki]:BitwiseOperators ),按值( [3,2,1 ,0] )乘以 8 (字节数)


    • 此外,要除去不需要的字节(除最右边的字节以外的任何字节),结果值也将用 0xFF 进行 255


  • 由于小端顺序,字节被转换为 char 的顺序相反(从右到l eft)

  • 1 st char 'î')看起来不同,但这只是表示形式的问题(在我的控制台 vs 您的控制台中)



将其集成到您的代码,您需要将 crc32b 函数修改(并删除对 hashD 的任何进一步处理)为:

  def crc32b(x):
crc = zlib.crc32(x)
返回 .join([chr((crc> ;> shift_bits)& [x,0,8,16,24]中的shift_bits为0xFF)))

有关此详细信息一般主题,请检查 [SO]:Python struct.pack()行为(@CristiFati的回答)



@ EDIT0



添加以 hex 表示形式开头的版本:


 >> crc = 0x2B3257EE 
>> crc_hex = {:08X}。format(crc)
>>> crc_hex
‘2B3257EE’
>>>
>> list(reversed([chr(int(crc_hex [2 * i] + crc_hex [2 * i + 1],16))for range(len(crc_hex)// 2)]))
[' î,'W','2','+']





  • 从我的 PoV 中看,这很丑陋,而且效率不高(许多来回转换),但由于某些人在进行位操作时遇到了麻烦,所以仍然发布了

  • 关键点是一次处理2个 hex char ,并且仅在转换后反转


I'm trying to convert PHP snippet into Python3 code but outputs of print and echo are different.

You can see it in the step 1.

Do you know where is the problem? I'm attaching input arrays too but I think they are equal.

�W2+ vs ee7523b2

EDIT

When I switch raw from TRUE to FALSE, outputs of 1st step are the same. $d = strrev(hash("crc32b", $d, FALSE)) . $d

But the problem is that I have to convert PHP to Python, not the opposite because, then I'm usit in the step 2 which I need to have equal output.

PHP OUTPUT (CMD)

0 ->    1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
1 -> �W2+   1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
2 -> 00004e00007715c242b04d5014490af1445dd61c1527ddc5f4461ca5886caf63fd8fbcf7df69c2035760ecb28d8171efdb409c0206996498ea7921e715172e60c210f923f070079ffba40000

PYTHON OUTPUT

-------
0 ->    1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
1 -> ee7523b2   1   1   100 EUR 20190101    11111111                Faktúra 1   SK6807200002891987426353        0   0
2 -> b'00006227515c7830302762275c783030325c7865305c7864386a34585c7862346d5c7838665c7865625c7863315c786266625c7839625c786339675c786332785c7831645c7862392c415c7862625c7831645c78663770365c786463735c786236572d606c225c7865355c7865635c7831345c7863655c786331205c7830635c7831315c7861375c7839345c7864665c7865635c7830365c7831652c22265c7866355c7862335c7866345c78616145585c7861625c7866395c7839615c7839645c7865645c7864625c7830305c7864355c7861643b5c7865365f5c7866645c786533405c78303027'

PHP

<?php
$suma = "100";
$datum = "20190101";
$varsym = "11111111";
$konsym = "";
$specsym = "";
$poznamka = "Faktúra";
$iban = "SK6807200002891987426353";
$swift = "";

$d = implode("\t", array(
    0 => '',
    1 => '1',
    2 => implode("\t", array(
        true,
        $suma,                      // SUMA
        'EUR',                      // JEDNOTKA
        $datum,                 // DATUM
        $varsym,                    // VARIABILNY SYMBOL
        $konsym,                        // KONSTANTNY SYMBOL
        $specsym,                       // SPECIFICKY SYMBOL
        '',
        $poznamka,                  // POZNAMKA
        '1',
        $iban,  // IBAN
        $swift,                 // SWIFT
        '0',
        '0'
    ))
));
// 0
echo "0 -> ".$d."\n";
$d = strrev(hash("crc32b", $d, TRUE)) . $d;
// 1
echo "1 -> ".$d."\n";
$x = proc_open("/usr/bin/xz '--format=raw' '--lzma1=lc=3,lp=0,pb=2,dict=128KiB' '-c' '-'", [0 => ["pipe", "r"], 1 => ["pipe", "w"]], $p);
fwrite($p[0], $d);
fclose($p[0]);
$o = stream_get_contents($p[1]);
fclose($p[1]);
proc_close($x);

$d = bin2hex("\x00\x00" . pack("v", strlen($d)) . $o);
// 2
echo "2 -> ".$d."\n";
?>

PYTHON

    def crc32b(x):
        h = zlib.crc32(x)
        x='%08X' % (h & 0xffffffff,)
        return x.lower()

    t = "\t"
    gen = t.join(["1",
                  "100", # SAME VARIABLES 
                  "EUR",
                  "20190101",
                  "11111111",
                  "",
                  "",
                  "",
                  "Faktúra",
                  "1",
                  "SK6807200002891987426353",
                  "",
                  "0",
                  "0"]
                 )

    d = t.join([
        "", "1", gen])
    # 0
    print(f"0 -> {d}")
    hashD = crc32b(d.encode()) # OK

    hashD = hashD[::-1]
    # hashD = str(binascii.unhexlify(hashD))
    d = hashD + d
    # 1
    print(f"1 -> {d}")
    args = shlex.split("xz '--format=raw' '--lzma1=lc=3,lp=0,pb=2,dict=128KiB' -c -")
    process = subprocess.Popen(args, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    output = process.communicate(d.encode())

    pack = "\x00\x00" + str(struct.pack("H", len(d))) + str(output[0])

    d = binascii.hexlify(pack.encode())
    # 2
    print(f"2 -> {d}")

解决方案

Didn't work with PHP.
According to [Python 3]: zlib.crc32(data[, value]) (emphasis is mine):

Computes a CRC (Cyclic Redundancy Check) checksum of data. The result is an unsigned 32-bit integer.

You are making a confusion between:

  • Its value - which can also be seen as an ASCII string of length 4
  • The textual representation of its value (in base 16) - which is a string of length 8

>>> crc = 0x2B3257EE  # The value returned by zlib.crc32 for your text
>>> type(crc), crc
(<class 'int'>, 724719598)
>>>
>>> [chr((crc >> shift_bits) & 0xFF) for shift_bits in [0, 8, 16, 24]]
['î', 'W', '2', '+']

Notes:

  • One way to do it is converting each of the number's 4 bytes into a char
  • To get a byte from the uint32 value, the uint32 must be shifted to the right ([Python.Wiki]: BitwiseOperators) by the order of that byte in the value ([3, 2, 1, 0]) multiplied by 8 (number of bits in a byte)
    • Also, to get rid of the unwanted bytes (any of them except the right-most one), the resulting value is also anded with 0xFF (255)
  • Due to little endianness, the bytes are converted to chars in reversed order (from right to left)
  • The 1st char ('î') looks different, but it's just a matter of representation (in my console vs yours)

Integrating it into your code, you need to modify your crc32b function (and also remove any further processing on hashD) to:

def crc32b(x):
    crc = zlib.crc32(x)
    return "".join([chr((crc >> shift_bits) & 0xFF) for shift_bits in [0, 8, 16, 24]])

For more details on this general topic, check [SO]: Python struct.pack() behavior (@CristiFati's answer).

@EDIT0:

Adding the version that starts from the hex representation:

>>> crc = 0x2B3257EE
>>> crc_hex = "{:08X}".format(crc)
>>> crc_hex
'2B3257EE'
>>>
>>> list(reversed([chr(int(crc_hex[2 * i] + crc_hex[2 * i + 1], 16)) for i in range(len(crc_hex) // 2)]))
['î', 'W', '2', '+']

  • From my PoV, this is uglier, also it's inefficient (many back and forth conversions), but posting anyway as some folks have trouble working on bit operations
  • The key point is to handle 2 hex chars at a time, and only reverse after conversion

这篇关于PHP中的crc32b输出不等于Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆