压缩过滤器

虽然 压缩包装器 提供了一种在本地文件系统上创建 gzip 和 bz2 兼容文件的方法,但它们不提供对网络流进行通用压缩的方法,也不提供从非压缩流开始并转换为压缩流的方法。为此,可以随时将压缩过滤器应用于任何流资源。

注意: 压缩过滤器不会生成命令行实用程序(如 gzip)使用的标头和尾部。它们只压缩和解压缩压缩数据流的有效负载部分。

zlib.deflate 和 zlib.inflate

zlib.deflate(压缩)和 zlib.inflate(解压缩)是 » RFC 1951 中描述的压缩方法的实现。 deflate 过滤器最多接受三个作为关联数组传递的参数。 level 描述要使用的压缩强度(1-9)。更高的数字通常会产生更小的有效负载,但会以额外的处理时间为代价。还存在两个特殊的压缩级别:0(用于完全不压缩),以及 -1(zlib 内部默认值——当前为 6)。 window 是压缩循环回滚窗口大小的以 2 为底的对数。更高的值(最高 15——32768 字节)会产生更好的压缩,但会以内存为代价,而更低的值(最低 9——512 字节)会产生更差的压缩,但内存占用更小。默认的 window 大小当前为 15memory 是一个表示应分配多少工作内存的比例。有效值范围从 1(最小分配)到 9(最大分配)。此内存分配仅影响速度,不会影响生成的有效负载的大小。

注意: 由于压缩级别是最常用的参数,因此它可以作为简单的整数值(而不是数组元素)来提供。

如果启用了 zlib 支持,则可以使用 zlib.* 压缩过滤器。

示例 #1 zlib.deflatezlib.inflate

<?php
$params
= array('level' => 6, 'window' => 15, 'memory' => 9);

$original_text = "This is a test.\nThis is only a test.\nThis is not an important string.\n";
echo
"The original text is " . strlen($original_text) . " characters long.\n";

$fp = fopen('test.deflated', 'w');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, $params);
fwrite($fp, $original_text);
fclose($fp);

echo
"The compressed file is " . filesize('test.deflated') . " bytes long.\n";
echo
"The original text was:\n";
/* Use readfile and zlib.inflate to decompress on the fly */
readfile('php://filter/zlib.inflate/resource=test.deflated');

/* Generates output:

The original text is 70 characters long.
The compressed file is 56 bytes long.
The original text was:
This is a test.
This is only a test.
This is not an important string.

*/
?>

示例 #2 zlib.deflate 简单

<?php
$original_text
= "This is a test.\nThis is only a test.\nThis is not an important string.\n";
echo
"The original text is " . strlen($original_text) . " characters long.\n";

$fp = fopen('test.deflated', 'w');
/* Here "6" indicates compression level 6 */
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, 6);
fwrite($fp, $original_text);
fclose($fp);

echo
"The compressed file is " . filesize('test.deflated') . " bytes long.\n";

/* Generates output:

The original text is 70 characters long.
The compressed file is 56 bytes long.

*/
?>

bzip2.compress 和 bzip2.decompress

bzip2.compressbzip2.decompress 的工作方式与上面描述的 zlib 过滤器相同。 bzip2.compress 过滤器接受最多两个作为关联数组元素给出的参数:blocks 是一个从 1 到 9 的整数值,指定为工作区分配的 100kbyte 块的数量。 work 也是一个从 0 到 250 的整数值,表示在回退到更慢但更可靠的方法之前,使用正常压缩方法要付出多少努力。调整此参数仅影响压缩速度。此设置不会更改压缩输出的大小或内存使用情况。工作因子为 0 指示 bzip 库使用内部默认值。 bzip2.decompress 过滤器只接受一个参数,该参数可以作为普通布尔值传递,也可以作为关联数组的 small 元素传递。 small 设置为 **true** 值时,指示 bzip 库以最小内存占用量执行解压缩,但会以速度为代价。

如果启用了 bz2 支持,则可以使用 bzip2.* 压缩过滤器。

示例 #3 bzip2.compressbzip2.decompress

<?php
$param
= array('blocks' => 9, 'work' => 0);

echo
"原始文件大小为 " . filesize('LICENSE') . " 字节。\n";

$fp = fopen('LICENSE.compressed', 'w');
stream_filter_append($fp, 'bzip2.compress', STREAM_FILTER_WRITE, $param);
fwrite($fp, file_get_contents('LICENSE'));
fclose($fp);

echo
"压缩后的文件大小为 " . filesize('LICENSE.compressed') . " 字节。\n";

/* 输出结果如下:

原始文件大小为 3288 字节。
压缩后的文件大小为 1488 字节。

*/
?>
添加备注

用户贡献的备注 4 个备注

匿名
8 年前
要读取来自 http 的 gzip 编码流
<?php
$opts
= [
"http" => [
"method" => "GET",
"header" => [ "Accept-Encoding: gzip" ],
]
];
$ctx = stream_context_create($opts);
$f = fopen("https://php.net", "r", false, $ctx);
// 检查 stream_get_meta_data($f)["wrapper_data"] 是否包含 "Content-Encoding: gzip"
stream_filter_append($f, "zlib.inflate", STREAM_FILTER_READ, ["window" => 30]);
echo
stream_get_contents($f); // 任何流处理
fclose($f);
匿名
3 年前
要使用 zlib.inflate 过滤器处理最初使用 gzcompress() 或 zlib.deflate 写入的数据,请将 window 选项设置为 15,如这里所述:https://bugs.php.net/bug.php?id=68556

<?php
$fh
= fopen(file_name, 'rb');
stream_filter_append($fh, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15]);
$contents = stream_get_contents($fh);
fclose($fh);
bohwaz
6 年前
请注意,此功能目前存在一个 bug。ftell()、fseek() 和 fstat() 函数无法使用。在使用此函数后写入流不会像预期那样更改流位置。

参见 bug:https://bugs.php.net/bug.php?id=49874

此外,zlib 过滤器不适用于 php://temp、php://memory 和 php://input 流,不会输出任何内容到这些流。
TingSong
1 年前
要解压缩 gzip 压缩流

<?php
$stream
= fopen('https://example.com/some/file.txt.gz', 'rb');
stream_filter_append($stream, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15+16]);

// 直接读取解压缩的行
$line = fgets($stream);

// 处理这些行
?>

如 zlib 文档所述 https://www.zlib.net/manual.html#Advanced

“window” 参数介于 8 到 15 之间,指定了窗口大小,从 2⁸ 到 2¹⁵ 字节。它可以添加 16 来使用 gzip 头部和尾部包装而不是 zlib 包装。

此外,window 可以是 -8..-15 用于解压缩原始 deflate 数据。
To Top