在PHP中应该使用哪种压缩方法?

79

我有大量数据需要使用两个PHP脚本进行移动:一个在客户端使用命令行PHP脚本,另一个则在Apache背后。我将数据POST到服务器端,并使用php://input流将其保存在Web服务器端。为防止达到任何内存限制,数据被分成每个POST请求的500kB块。所有这些都有效。

现在,为了节省带宽并加快速度,我想在发送数据之前压缩数据,在接收端解压数据。我找到了3对可以完成该任务的函数,但我无法决定使用哪一个:

您会推荐哪一对函数?为什么?

更新:我刚刚阅读了zlib FAQ:

gzip格式(gzencode)旨在保留有关单个文件的目录信息,例如名称和最后修改日期。另一方面,zlib格式(gzcompress)旨在用于内存和通信渠道应用程序,并具有比gzip更紧凑的头部和尾部,并使用比gzip更快的完整性检查。


1
php中似乎还没有可用的gzdecode()函数,因此请避免使用它。 - user137621
1
gzdecode() 仅适用于 PHP 5.4.0 或更新版本:http://php.net/manual/en/function.gzdecode.php - Mikko Rantalainen
4个回答

110

这些都可以使用。三者之间存在微妙的差别:

  • gzencode() 使用 GZIP 文件格式,与命令行工具 gzip 相同。该文件格式包含可选元数据的头部、DEFLATE 压缩数据以及包含 CRC32 校验和长度检查的尾部。
  • gzcompress() 使用 ZLIB 格式。它有一个较短的头部,仅用于标识压缩格式,DEFLATE 压缩数据和包含 ADLER32 校验和的尾部。
  • gzdeflate() 仅使用原始 DEFLATE 算法,这是其他两种格式的基础。

这三种方法在底层使用相同的算法,因此它们在速度和效率上不会有区别。 gzencode()gzcompress() 都添加了一个校验和,因此可以验证存档的完整性,这在不可靠的传输和存储方法中非常有用。如果所有内容都存储在本地且不需要任何其他元数据,则 gzdeflate() 就足够了。为了实现可移植性,我建议使用 gzencode()(GZIP 格式),它可能比其他工具更好地支持 gzcompress()(ZLIB 格式)。

当压缩非常短的字符串时,每种方法的开销变得相关,因为对于非常短的输入,开销可能占输出的重要部分。通过压缩空字符串来测量每种方法的开销如下:

  • gzencode('') - 20 字节
  • gzcompress('') - 8 字节
  • gzdeflate('') - 2 字节

3
几乎正确。我进行了一些调查,似乎 gzencode 并不是没有任何标头数据 - 它只是具有不同的标头数据。 - Milan Babuškov
3
@Milan 我想你的意思是“gzcompress并不是没有任何头数据 - 它只是有不同的头数据”。 - thomasrutter

50

我不是PHP专家,无法回答提出的问题,但似乎这里有很多猜测和模糊的信息。

DEFLATE是ZLIB、GZIP等使用的压缩算法的名称。理论上,GZIP支持替代压缩算法,但实际上并没有。

“GZIP算法”并不存在。GZIP使用DEFLATE算法,并在压缩数据周围添加框架数据。使用GZIP时,您可以添加文件名、文件时间、CRC甚至注释等内容。这些元数据是可选的,许多GZIP程序会省略它们。

ZLIB类似,只是具有不同、更有限的元数据集合和特定的2字节头。

这都写在IETF RFC 195019511952中。

说“GZIP算法比DEFLATE更好地压缩”就是胡说八道。 "GZIP算法"不存在。而GZIP格式中使用的算法是DEFLATE


8

所有方法本质上都是相同的,它们之间的区别主要在于头信息。我个人会使用gzencode,这将产生与gzip实用程序的命令行调用相等的输出。


-1
100倍放大镜
   <?php
        function tenc1($x,$s){
            do{$s=gzencode($s,9);}while(--$x);
            return chunk_split(base64_encode($s));
        }
        function tenc2($x,$s){
            do{$s=gzcompress($s,9);}while(--$x);
            return chunk_split(base64_encode($s));
        }
        function tenc3($x,$s){
            do{$s=gzdeflate($s,9);}while(--$x);
            return chunk_split(base64_encode($s));
        }
    
    $string=str_repeat(str_shuffle(implode('',array_merge(range('0','9'),range('a','z'),range('A','Z')))),200000);
    echo'gzencode '.strlen(tenc1(100,$string)).PHP_EOL;
    echo'gzcompress '.strlen(tenc2(100,$string)).PHP_EOL;
    echo'gzdeflate '.strlen(tenc3(100,$string)).PHP_EOL;

PHP 7.4.33 的结果
gzencode 3204
gzcompress 1712
gzdeflate 904

https://onlinephp.io/c/674e5


这个测试并没有测试任何相关的东西。一旦你压缩了某个东西,用相同算法多次重新压缩输出是没有任何收益的。每次迭代,gzencode和gzcompress都会添加自己的头部和尾部,这就解释了为什么这些大小会随着重复迭代而增加。在现实世界中,没有人会这样做。 - thomasrutter

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