In PHP, how to unzip a file on the fly that has been compressed twice?

I have a bigfile.gz.gz file that is ... big. I would like to unzip it on the fly. Ideally, this is what I mean:

 $in = fopen('compress.zlib://compress.zlib://bigfile.gz.gz', 'rb'); while (!feof($in)) print fread($in, 4096); fclose($in); 

However, compress.zlib:// cannot be bound this way:

 PHP Warning: fopen(): cannot represent a stream of type ZLIB as a File Descriptor in gztest.php on line 1 

So, I thought Id combines gzopen() and compress.zlib:// together:

 $in = gzopen('compress.zlib://bigfile.gz.gz', 'rb'); while (!gzeof($in)) print gzread($in, 4096); gzclose($in); 

However, this only decompresses one gzip level.

I probably tried 10 more other methods, unfortunately gzopen() does not work with php://memory if it was written using fwrite() . And stream_filter_append(… zlib.inflate …) cannot read gzipped files.

This is the best I could come up with, but it spawns two system processes that have unwanted overhead:

 $in = popen('zcat bigfile.gz.gz | gunzip', 'rb'); while (!feof($in)) print fread($in, 4096); fclose($in); 

Can someone suggest something better maybe?

+7
php gzip zlib
source share
1 answer

You can unzip .gz files using the zlib.inflate filter. You just need to cut the gzip header first. To do this, you need to deploy a special filter:

 <?php class gzip_header_filter extends php_user_filter { private $filtered = 0; public function filter($in, $out, &$consumed, $closing) { while ($bucket = stream_bucket_make_writeable($in)) { if($this->filtered == 0) { $header_len = 10; $header = substr($bucket->data, 0, 10); $flags = ord($header[3]); if($flags & 0x08) { // a filename is present $header_len = strpos($bucket->data, "\0", 10) + 1; } $bucket->data = substr($bucket->data, $header_len); $this->filtered = $header_len; } $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); } return PSFS_PASS_ON; } } stream_filter_register('gzip_header_filter', 'gzip_header_filter'); $in = fopen('bigfile.gz.gz', 'rb'); stream_filter_append($in, 'gzip_header_filter', STREAM_FILTER_READ); stream_filter_append($in, 'zlib.inflate', STREAM_FILTER_READ); stream_filter_append($in, 'gzip_header_filter', STREAM_FILTER_READ); stream_filter_append($in, 'zlib.inflate', STREAM_FILTER_READ); while (!feof($in)) print fread($in, 4096); fclose($in); ?> 

Please note that the above code does not process comments and other additional data that can be saved in the gz file.

+2
source share

All Articles