Потоковая передача в файл и браузер

Итак, я ищу что-то более эффективное, чем это:

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

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

echo $content;
?>

Проблемы с вышесказанным:

  • Клиент ничего не получает, пока вся страница не будет отображаться
  • Файл может быть огромным, поэтому я бы предпочел не хранить все это в памяти

Любые предложения?

Ответ 1

Интересная проблема; не думаю, что я пытался решить это раньше.

Я думаю, вам понадобится второй запрос, идущий от вашего PHP-интерфейса script на ваш сервер. Это может быть простой вызов http://localhost/test.php. Если вы используете fopen-wrappers, вы можете использовать fread(), чтобы вывести результат test.php по мере его рендеринга и после получения каждого фрагмента вывести его на экран и добавить его в файл test.html.

Вот как это может выглядеть (непроверено!):

<?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);
?>

Ответ 2

Лучший способ сделать это - использовать первые два параметра, принятые ob_start: output_callback и chunk_size. Первая специфицирует обратный вызов для обработки вывода по мере его буферизации, а последний определяет размер кусков вывода для обработки.

Вот пример:

$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);

В этом примере выходной буфер будет очищен (отправлен) для каждых 4096 байтов вывода (и еще раз в конце вызовом ob_end_flush). Каждый раз, когда буфер сбрасывается, обратный вызов $write_ob_to_file вызывается и передается последним фрагментом. Это записывается в test.html. Затем обратный вызов возвращает false, что означает "вывести этот кусок как есть". Если вы хотите только написать вывод в файл, а не в выходной поток PHP, вы можете вернуть пустую строку.

Ответ 3

Ответ Pix0r - это то, что вам нужно, если вы действительно не нуждаетесь в нем "включено", а не просто выполняете. Например, если у вас есть информация для входа перед test.php, он не будет передаваться в файл, если вы вызываете его с помощью fopen.

Если вам это действительно нужно включить, то то, что у вас есть, является самым простым методом, но если вы хотите иметь постоянный вывод, вам нужно будет фактически написать test.php таким образом, чтобы он выводил, а также сохранял информацию по мере ее поступления, Насколько я знаю, нет никакого способа как собирать буфер, так и выводить его, когда вы идете.

Ответ 4

Здесь вы идете x-send-file, используйте mod_xsendfile, чтобы отправить файл эффективно, очень просто.