PHP 提供了流过滤器功能，可以直接在流的读写过程中透明地进行加密、压缩、计算校验和等操作。然而压缩过滤器的官方文档上只介绍了 zlib.deflate 和 zlib.inflate 两个过滤器可以处理 zlib 压缩的数据流，没有提供直接处理 gzip 格式压缩流的方法。 在上一篇文章中我分享了使用 DEFLATE 算法的三种压缩格式，可以知道 zlib 和 gzip 使用的都是 DEFLATE 数据压缩算法，只是头尾长度和内容不同而已。这里我再分享一下直接用 zlib 过滤器处理 gzip 压缩流的方法，毕竟流过滤器有着不必接触原始文件，直接进行数据处理的优势。 方法非常简单，只要在挂载 zlib 流过滤器时，提供参数 window=31 即可。以下是范例代码，我们从 S3 中读取 gzip 压缩过的 CSV 文件流： $stream = $s3_client->getReadStream('somefile.csv.gz'); stream_filter_append($stream, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 31]); $line = fgets($stream); if (trim($line) !== '') { $fields = str_getcsv($line); // ... } 根据 PHP 的官方文档，这个 window 参数的值应该在 8 到 15 之间才对，表示压缩时的窗口大小为 28 到 215 之间，为什么可以指定为 31 呢？这可以算是 zlib 库的一种高级用法。根据 zlib 库的文档，windowBit 可以介于 8..15，意思是窗口大小在28 到 215 之间，也可以指定 -8..-15 表示要输出没有 zlib 封装的 DEFLATE 原始数据，或者还可以加上 16 来改用 gzip 封装格式。zlib 库中的 windowBit 正好对应了 PHP stream_filter_append 中 $params 参数里的 window 项目。 可能是因为 zlib 文档中声明这些高级用法是只针对当前版本有效，所以 PHP 官方文档没有将这些特殊值收录进来。不过至少当前版本我们可以放心使用，可以在 composer.json 中的 platform 部分声明一下兼容的 ext-zlib 版本为 ^1.0，这样版本有变化的时候，composer 会给予提示。
Gzip 是一种非常常见的压缩格式，PHP 也有一系列 gz 开头的函数用于操作 gzip 格式的压缩文件。然而令人困惑的是，同样是做压缩处理，却有着 gzdeflate、gzcompress、gzencode 三个函数可用。那么它们都有着什么区别，平时又究竟应该用哪个呢？ 这三个函数使用的压缩算法是一样的，都是 DEFLATE 压缩算法，三者的区别仅在于数据的封装格式不同。 gzdeflate 函数输出的是 DEFLATE 算法生成的原始数据，也被称作 RAW 格式的数据。由 RFC1951 定义 gzcompress 函数输出的是 zlib 格式的数据，它在 DEFLATE 生成的原始数据开头增加了两个字节的 header，末尾增加了四个字节的 ADLER-32 校验和。由 RFC1950 定义 gzencode 函数输出的是 gzip 格式，它是 gzip 工具定义的文件存储格式，理论上讲允许使用不同的压缩算法，但实际上目前只有 DEFLATE 一种实现。gzip 格式在 DEFLATE 生成的原始数据开头加入了一个至少10字节的变长header，末尾加入了固定8个字节的 tailer。由 RFC1952 定义 了解了三个函数的区别，就可以根据需要选择具体用哪个函数了。 gzdeflate 适用于可靠数据传输和存储环境下，需要减少数据量的情况。比如把数据压缩后存入 redis 或者 MySQL 的 blob 字段。 gzcompress 适用于需要处理 zlib 格式数据的场景。比如向 Accept-Encoding: deflate 的浏览器输出压缩的数据流。 gzencode 适用于需要被 gzip 工具解压的情况。比如把数据压缩并保存到 OSS 上，命名为 xxx.gz 的文件，允许用户下载后自行解压。 对了，PHP 还有一个 zlib_encode 函数，允许开发人员指定 $encoding 参数，它可以是 ZLIB_ENCODING_RAW、 ZLIB_ENCODING_DEFLATE 或者 ZLIB_ENCODING_GZIP 三者之一，正好对应了 gzdeflate、gzcompress 和 gzencode 三个函数的效果。如果读代码的人怕搞混，不妨考虑直接使用这个函数。