GZIP解压(PHP / Python)结果不同



当我在PHP中解压缩数据时,我有一个gzip文件似乎缺少字符。然而,当我这样做时,例如在Python中,字符是存在的。在这种情况下,最后两个字符(']}')丢失,这使得数据成为无效的JSON。

下面两个例子都输出不同的结果;PHP怎么可能不输出完整的数据?我也检查了GZIP内容,看起来长度和CRC是无效的;至少当我将结构与本网站的数据进行比较时:https://docs.fileformat.com/compression/gz/

<?php
$base64gzip = 'H4sIAAAAAAAAA7XSO04DQAwE0J5jbE3h8d9cJUoRiSPQcXmEFKR4KFKlfdr12Lv+Pp+3r9v5uFwORnTSACTO9f3tUcKfiLbOsFQsEVMxEkwtMRNROtO9b4V0yT5TAcoq5O5QBtkssSeV6LxnSUXWVEKDp5jmDocmNa3e6ZapYJE9OypCWXxXDo0BC2VJKr+qT3AdTXsialw5BHb/5ZBwbRNHWm2C51/aA3n/IwNX9+RJaveE369mcdrOmNFXScdLxKUg64GgkkqLFrz4JjJ+rj/Cx4XMxgMAAB+LCAAAAAAAAAOLrQUAZzx4YAIAAAA=';
echo gzdecode(base64_decode($base64gzip));
#!/usr/bin/python
import gzip
import base64
base64gzip = '''H4sIAAAAAAAAA7XSO04DQAwE0J5jbE3h8d9cJUoRiSPQcXmEFKR4KFKlfdr12Lv+Pp+3r9v5uFwORnTSACTO9f3tUcKfiLbOsFQsEVMxEkwtMRNROtO9b4V0yT5TAcoq5O5QBtkssSeV6LxnSUXWVEKDp5jmDocmNa3e6ZapYJE9OypCWXxXDo0BC2VJKr+qT3AdTXsialw5BHb/5ZBwbRNHWm2C51/aA3n/IwNX9+RJaveE369mcdrOmNFXScdLxKUg64GgkkqLFrz4JjJ+rj/Cx4XMxgMAAB+LCAAAAAAAAAOLrQUAZzx4YAIAAAA='''
print(gzip.decompress(base64.b64decode(base64gzip)))

^^ Python输出该数据,包括最后的']}'字符。

b'{"data":[["190296311161"],n["190296311154"],n["190296311154"],n["190296328299"],n["190296328275"],n["190296303203"],n["190296303197"],n["190296333002"],n["190296303883"],n["190296350870"],n["190296307515"],n["190296307164"],n["190296309168"],n["190296309151"],n["190296305863"],n["075679761255"],n["190296303982"],n["190296303975"],n["190296332784"],n["190296336621"],n["190296336607"],n["190296317552"],n["190296317545"],n["190296352591"],n["190296352584"],n["190296306297"],n["190296334955"],n["190296352263"],n["190296352263"],n["190296323584"],n["190296350139"],n["5054283041637"],n["5054283014655"],n["5054283014648"],n["5054283014631"],n["190296350146"],n["190296306273"],n["190296310751"],n["190296310744"],n["190296315992"],n["190296315992"],n["190296315992"],n["190296315992"],n["190296315992"],n["190296315985"],n["190296315985"],n["190296315985"],n["190296315985"],n["190296315985"],n["190296340710"],n["5054283120622"],n["190296305870"],n["190296330094"]]}'

可以有人指出我在正确的方向,为什么这在PHP失败,我如何仍然可以确保我得到相同的内容,例如在Python?

您的gzip流有效且正确。它由两个gzip成员组成,每个成员都是一个有效的gzip流,其中第二个成员仅包含字符]}。Python正确地解码了两个gzip成员,而PHP似乎只解码了第一个gzip成员,忽略并静默地丢弃了第二个。

这是PHP的gzdecode()中的一个错误,并且似乎在最新的PHP中仍然存在。

另一种选择是在循环中使用inflate_init(),inflate_add()inflate_get_read_len()来读取所有成员。关键是inflate_get_read_len()是到目前为止已经消耗的gzip流的字节数,使您能够找到下一个gzip成员的开始。下面是我在PHP操场上运行的一个示例,其中包含您的数据来展示这个想法:

$b64 = 'H4sIAAAAAAAAA7XSO04DQAwE0J5jbE3h8d9cJUoRiSPQcXmEFKR4KFKlfdr12Lv+Pp+3r9v5uFwORnTSACTO9f3tUcKfiLbOsFQsEVMxEkwtMRNROtO9b4V0yT5TAcoq5O5QBtkssSeV6LxnSUXWVEKDp5jmDocmNa3e6ZapYJE9OypCWXxXDo0BC2VJKr+qT3AdTXsialw5BHb/5ZBwbRNHWm2C51/aA3n/IwNX9+RJaveE369mcdrOmNFXScdLxKUg64GgkkqLFrz4JjJ+rj/Cx4XMxgMAAB+LCAAAAAAAAAOLrQUAZzx4YAIAAAA=';
$bin = base64_decode($b64);
$gz = inflate_init(ZLIB_ENCODING_GZIP);
$dec = inflate_add($gz, $bin);
echo inflate_get_status($gz), "n";
echo inflate_get_read_len($gz), "n";
echo strlen($dec), "n";
$used = inflate_get_read_len($gz);
$gz = inflate_init(ZLIB_ENCODING_GZIP);
$dec .= inflate_add($gz, substr($bin, $used));
echo inflate_get_status($gz), "n";
echo inflate_get_read_len($gz), "n";
echo strlen($dec), "n";

这个输出:

1
217
966
1
22
968

其中1是一个完整和正确的gzip成员的预期返回代码(一定要检查),21722是两个gzip成员的长度,966968是解压数据的累积量,第二个显示末尾添加了错误的两个字符。

你可以使用那些没有错误的函数来编写你自己的gzdecode_complete()

最新更新