John Davidson

zlib - Writing a chunked gzip file to an arbitrary output stream in PHP

0 comments
Message:


My original code does this:


    $data = file_get_contents($source);
$compressed_data = gzencode($data);
file_put_contents($destination, $compressed_data);

This works fine, and it seemingly supports a lot of different values for $source and $destination - including in-memory file systems, stdin/stdout streams, etc.


However, large files have to be fully loaded into memory, so I'd like to switch this over to a chunked approach.


I've tried the following:


    $in = fopen($source, 'rb');
$out = gzopen($destination, 'wb');
while (!feof($in)) {
gzwrite($out, fread($in, 4096));
}

But this gives me an error with stream wrappers (such as https://packagist.org/packages/mikey179/vfsstream): gzopen(): cannot represent a stream of type user-space as a File Descriptor.


Also tried the following:


    $in = fopen($source, 'rb');
$out = fopen($destination, 'wb');
stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, -1);
while (!feof($in)) {
fwrite($out, fread($in, 4096));
}

But the resulting output doesn't appear to be valid GZIP (missing header maybe?)


Finally I tried this:


    $in = fopen($source, 'rb');
$out = fopen('compress.zlib://' . $destination, 'wb');
while (!feof($in)) {
fwrite($out, fread($in, 4096));
}

But (unsurprisingly) this failed if $destination already had a wrapper (such as php://stdin or the vfs:// mentioned above).


There has to be a way to do this, but searching hasn't turned up any examples for it.



My Answer:
One way to achieve writing a chunked gzip file to an arbitrary output stream in PHP is to use the `Zlib` extension. Here's an example code snippet that demonstrates how to do this:

php
$source = 'path/to/source/file';
$destination = 'path/to/destination/file';

$in = fopen($source, 'rb');
$out = fopen($destination, 'wb');

stream_filter_append($out, 'zlib.deflate', STREAM_FILTER_WRITE, ['window' => 15]);

while (!feof($in)) {
$chunk = fread($in, 4096);
fwrite($out, $chunk);
}

fclose($in);
fclose($out);


In this code snippet:
- We open the source file in read mode and the destination file in write mode.
- We append the `zlib.deflate` filter to the output stream, which will compress the data using gzip compression.
- We read the source file in chunks of 4096 bytes and write each chunk to the output stream.
- Finally, we close both input and output streams.

This approach should work for writing chunked gzip files to various types of output streams, including file streams, memory streams, and others.

Rate this post

5 of 5 based on 6514 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us