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

Different result in GZIP decompress (PHP / Python)

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

下面2个输出不同结果的例子; 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 成员的预期 return 代码(请务必检查),21722是两个gzip成员的长度,966968是解压数据的累计量,第二个表示er运行t两个字符在已添加结束。

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