I'm trying to stream a tar.gz
without buffering anything in memory or saving data do disk. I need to gzip a bunch of PDF files (~100kb per file).
Everything seems to work fine if small 10-20 bytes text files are sent through the script and the user downloads a readable tar.gz
file, but when sending real data (run-time generated PDF files) the script blocks and stops
Below is a snippet of the code. Why is the script blocking when writing to stdin
after a couple of iterations of the loop? It stops at this point waiting for something
Every step is logged to a file to see the message before writing to stdin
is the last logged message
$proc = proc_open('gzip - -c', [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
], $pipes);
stream_set_read_buffer($pipes[1], 0);
stream_set_read_buffer($pipes[2], 0);
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
while(true){
log_step('file stream');
// fetching data from database and generating PDF file as tar stream (string)
log_step('stdin: '.strlen($tar_string));
fwrite($pipes[0], $tar_string); // <--- in the second iteration the script blocks/stops here!
log_step('stdin done!');
if($output = stream_get_contents($pipes[1])){
log_step('output: '.strlen($output));
echo $output;
}
}
Output log file
2021-01-26 10:28:29 file stream
2021-01-26 10:28:29 stdin: 116224
2021-01-26 10:28:29 stdin done!
2021-01-26 10:28:29 output: 32768
2021-01-26 10:28:29 file stream
2021-01-26 10:28:29 stdin: 116736
full code
$proc = proc_open('gzip - -c', [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
], $pipes);
stream_set_read_buffer($pipes[1], 0);
stream_set_read_buffer($pipes[2], 0);
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
// get data from database
while($row = $result->fetch()){
// generate PDF
$filename = $pdf['name'];
$filesize = strlen($pdf['data']);
$header = pack(
'a100a8a8a8a12A12a8a1a100a255',
$filename,
sprintf('%6s ', ''),
sprintf('%6s ', ''),
sprintf('%6s ', ''),
sprintf('%11s ', $filesize),
sprintf('%11s', ''),
sprintf('%8s ', ' '),
0,
'',
''
);
$checksum = 0;
for($i=0; $i<512; $i++){
$checksum += ord($header{$i});
}
$checksum_data = pack(
'a8',
sprintf('%6s ', decoct($checksum))
);
for($i=0, $j=148; $i<8; $i++, $j++){
$header{$j} = $checksum_data{$i};
}
fwrite($pipes[0], $header.$pdf['data'].pack(
'a'.(512 * ceil($filesize / 512) - $filesize),
''
));
if($output = stream_get_contents($pipes[1])){
echo $output;
}
}
fwrite($pipes[0], pack('a512', ''));
fclose($pipes[0]);
while(true){
if($output = stream_get_contents($pipes[1])){
echo $output;
}
if(!proc_get_status($proc)['running']){
foreach($pipes as $pipe){
if(is_resource($pipe)){
fclose($pipe);
}
}
proc_close($proc);
break;
}
}
question from:
https://stackoverflow.com/questions/65883806/stream-run-time-generated-gzip-file-with-proc-open