Streaming output to a file and the browser
Asked Answered
B

4

15

So, I'm looking for something more efficient than this:

<?php
ob_start();
include 'test.php';
$content = ob_get_contents();

file_put_contents('test.html', $content);

echo $content;
?>

The problems with the above:

  • Client doesn't receive anything until the entire page is rendered
  • File might be enormous, so I'd rather not have the whole thing in memory

Any suggestions?

Belshazzar answered 6/3, 2009 at 16:49 Comment(2)
you mean test.php (or the result of evaluation thereof) may be huge?Gimpel
Result of evaluating it might be huge.Belshazzar
S
6

Interesting problem; don't think I've tried to solve this before.

I'm thinking you'll need to have a second request going from your front-facing PHP script to your server. This could be a simple call to http://localhost/test.php. If you use fopen-wrappers, you could use fread() to pull the output of test.php as it is rendered, and after each chunk is received, output it to the screen and append it to your test.html file.

Here's how that might look (untested!):

<?php
$remote_fp = fopen("http://localhost/test.php", "r");
$local_fp = fopen("test.html", "w");
while ($buf = fread($remote_fp, 1024)) {
    echo $buf;
    fwrite($local_fp, $buf);
}
fclose($remote_fp);
fclose($local_fp);
?>
Siam answered 6/3, 2009 at 17:14 Comment(1)
Interesting. Adding this one to my toolbelt.Belshazzar
C
3

A better way to do this is to use the first two parameters accepted by ob_start: output_callback and chunk_size. The former specifies a callback to handle output as it's buffered, and the latter specifies the size of the chunks of output to handle.

Here's an example:

$output_file = fopen('test.html', 'w');
if ($output_file === false) {
    // Handle error
}

$write_ob_to_file = function($buffer) use ($output_file) {
    fwrite($output_file, $buffer);

    // Output string as-is
    return false;
};

ob_start($write_ob_to_file, 4096);
include 'test.php';
ob_end_flush();

fclose($output_file);

In this example, the output buffer will be flushed (sent) for every 4096 bytes of output (and once more at the end by the ob_end_flush call). Each time the buffer is flushed, the callback $write_ob_to_file will be called and passed the latest chunk. This gets written to test.html. The callback then returns false, meaning "output this chunk as is". If you wanted to only write the output to file and not to PHP's output stream, you could return an empty string instead.

Costumer answered 7/5, 2016 at 15:41 Comment(0)
D
0

Pix0r's answer is what you want unless you actually need it "included" rather than just executed. For example, if you have login information before the test.php, it will not get passed into the file if you call it with fopen.

If you need it genuinely included, then what you have is the simplest method, but if you want constant output, you'll need to actually write test.php in a manner that outputs as well as stores the information as it goes. As far as I know there's no way to both collect buffer and output it as you go.

Denmark answered 6/3, 2009 at 18:0 Comment(0)
F
-2

Here you go x-send-file, use mod_xsendfile to send file efficiently, really easy.

Feller answered 6/3, 2009 at 18:12 Comment(1)
I'll look into it, but it doesn't address my problem exactly. I want to generate and stream large files from PHP without having to generate the static file first. I'd like to do them in parallel.Belshazzar

© 2022 - 2024 — McMap. All rights reserved.