gzcompress是如何工作的?

3

我想知道为什么在使用gzcompress()后,需要切掉最后四个字符。

这是我的代码:

header("Content-Encoding: gzip");
echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
$index = $smarty->fetch("design/templates/main.htm") ."\n<!-- Compressed by gzip -->";
$this->content_size = strlen($index);
$this->content_crc = crc32($index);
$index = gzcompress($index, 9);
$index = substr($index, 0, strlen($index) - 4); // Why cut off ??
echo $index;
echo pack('V', $this->content_crc) . pack('V', $this->content_size);

当我不切掉最后4个字符时,源代码会以以下方式结束:
[...]
<!-- Compressed by gzip -->N

当我将它们切断时,读取的内容如下:
[...]
<!-- Compressed by gzip -->

我只在Chrome的代码检查器中看到了额外的N(在Firefox和IE的源代码中没有)。但是似乎在代码末尾有四个额外的字符。

有人能解释一下为什么我需要删掉这四个字符吗?


1
为什么要最后一行?回显不会破坏压缩流吗? - Artefacto
2个回答

8

gzcompress 函数实现了 ZLIB 压缩数据格式,该格式具有 以下结构

     0   1
   +---+---+
   |CMF|FLG|   (more-->)
   +---+---+

(if FLG.FDICT set)

     0   1   2   3
   +---+---+---+---+
   |     DICTID    |   (more-->)
   +---+---+---+---+

   +=====================+---+---+---+---+
   |...compressed data...|    ADLER32    |
   +=====================+---+---+---+---+

在这里,您可以看到最后四个字节是Adler-32校验和

与此相反,GZIP文件格式是一个所谓成员列表,具有以下结构:

   +---+---+---+---+---+---+---+---+---+---+
   |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
   +---+---+---+---+---+---+---+---+---+---+

(if FLG.FEXTRA set)

   +---+---+=================================+
   | XLEN  |...XLEN bytes of "extra field"...| (more-->)
   +---+---+=================================+

(if FLG.FNAME set)

   +=========================================+
   |...original file name, zero-terminated...| (more-->)
   +=========================================+

(if FLG.FCOMMENT set)

   +===================================+
   |...file comment, zero-terminated...| (more-->)
   +===================================+

(if FLG.FHCRC set)

   +---+---+
   | CRC16 |
   +---+---+

   +=======================+
   |...compressed blocks...| (more-->)
   +=======================+

     0   1   2   3   4   5   6   7
   +---+---+---+---+---+---+---+---+
   |     CRC32     |     ISIZE     |
   +---+---+---+---+---+---+---+---+

正如您所看到的,GZIP使用CRC-32校验和进行完整性检查。

因此,要分析您的代码:

  • echo "\x1f\x8b\x08\x00\x00\x00\x00\x00"; – 输出以下标头字段:
    • 0x1f 0x8b - ID1和ID2,用于识别数据格式的标识符(这些是固定值)
    • 0x08 - CM,所使用的压缩方法;8表示使用DEFLATE数据压缩格式(RFC 1951)
    • 0x00 - FLG,标志
    • 0x00000000 - MTIME,修改时间
    • XFL(额外标志)和OS(操作系统)字段由DEFLATE数据压缩格式设置
  • echo $index; - 根据DEFLATE数据压缩格式输出压缩数据
  • echo pack('V',$ this-&gt; content_crc). Pack('V',$ this-&gt; content_size); - 以二进制形式输出未压缩输入数据的CRC-32校验和和大小

2

gzcompress生成的输出遵循RFC1950中描述的格式,你要删除的最后4个字节是adler32校验和。这是“deflate”编码,因此您只需设置“Content-Encoding:deflate”,不需要进行任何操作。

如果您想使用gzip,请使用gzencode(),它使用gzip格式


你能想出最后一个回声是什么吗?他为什么要删除一个校验和并添加另一个(尽管是不同的)?他为什么要添加长度?这是其他格式吗? - Artefacto
似乎他试图通过回显gzip标头并附加crc32和长度(根据gzip规范)来模拟gzip。 - nos
好的观点。 “N”似乎来自最后一行。而不是gzcompress()。如果我注释掉最后一行和4个字符截断行,就没有额外的输出。至于为什么有这些行,我不知道。代码来自在我之前工作在同一项目上的人,所以我也在试图弄清楚为什么有这些行。那么你的意思是这确实产生了一个deflate编码?我想我最好使用gzencode()然后。 - JochenJung
请查看此处的“gzdecode”功能:http://phpxref.com/xref/erfurtwiki/plugins/lib/upgrade.php.source.html。 Gzip头只包含一些标志,并指示以下块是deflate压缩的。Deflate本身会包含压缩数据流的大小长度和压缩数据的adler32 crc校验和。但是gzip将其截掉,并添加了解压缩内容的crc32以及未压缩数据的大小。 - mario

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接