xts.so - stream
type: channel
link: https://movil.xts.so/tag/stream/
items: 如何用stream filter直接解压gzip格式的压缩流

如何用stream filter直接解压gzip格式的压缩流
type: item
date: 2023-01-15T18:37:00+08:00
description: 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 会给予提示。