使用stream_filter_append和stream_copy_to_stream解压缩gzip

时间:2012-08-12 19:05:20

标签: php stream zlib

发现这个: https://stackoverflow.com/a/11373078/530599 - 很棒,但

stream_filter_append($fp, 'zlib.inflate', STREAM_FILTER_*

怎么样?

寻找另一种解压缩数据的方法。

$fp = fopen($src, 'rb');
$to = fopen($output, 'wb');

// some filtering here?
stream_copy_to_stream($fp, $to);
fclose($fp);
fclose($to);

其中$srchttp://.../file.gz的某个网址,例如200 + Mb:)

添加了有效的测试代码,但分为两步:

<?php

    $src = 'http://is.auto.ru/catalog/catalog.xml.gz';
    $fp = fopen($src, 'rb');
    $to = fopen(dirname(__FILE__) . '/output.txt.gz', 'wb');
    stream_copy_to_stream($fp, $to);
    fclose($fp);
    fclose($to);

    copy('compress.zlib://' . dirname(__FILE__) . '/output.txt.gz', dirname(__FILE__) . '/output.txt');

2 个答案:

答案 0 :(得分:5)

尝试gzopen打开gzip(.gz)文件进行读取或写入。如果文件不是压缩文件,它会透明地读取它,以便您可以安全地读取非压缩文件。

$fp = gzopen($src, 'rb');
$to = fopen($output, 'w+b');
while (!feof($fp)) {
    fwrite($to, gzread($fp, 2048)); // writes decompressed data from $fp to $to
}

fclose($fp);
fclose($to);

答案 1 :(得分:4)

PHP的流过滤器子系统中令人讨厌的遗漏之一是缺少gzip过滤器。 Gzip本质上是使用deflate方法压缩的内容。但是,它会在缩小的数据之前添加一个2字节的标头,并在最后添加一个Adler-32校验和。如果您只是将一个zlib.inflate过滤器添加到流中,它将不起作用。在附加过滤器之前,您必须跳过前两个字节。

请注意,PHP 5.2.X版中的流过滤器存在严重错误。这是由于流缓冲造成的。基本上PHP将无法通过过滤器传递流的内部缓冲区中的数据。如果你在附加膨胀过滤器之前做了一个fread($ handle,2)来读取gzip标题,那么它很有可能会失败。调用fread()会导致PHP尝试填充其缓冲区。即使对fread()的调用仅要求两个字节,PHP实际上可能会从物理介质中读取更多字节(比如说1024)以尝试提高性能。由于上述错误,额外的1022个字节不会被发送到解压缩例程。