Потоковая передача вывода с помощью PHP ob_start и ob_get_clean

У меня есть скрипт, который echo выводит содержимое в php-скрипт и приводит к очень большому файлу, например. 100 МБ

В настоящее время я использую следующий способ для захвата вывода и записи в другой файл.

ob_start();
require_once 'dynamic_data.php'; // echo 100MB data
$data = ob_get_clean();
file_put_contents($path, $data);

Есть ли простой способ переписать вышеприведенную программу (лучше не трогать dynamic_data.php, так как ее сложно реорганизовать), чтобы она могла напрямую передавать вывод в файл, не сохраняя содержимое в памяти?


person Ryan    schedule 08.06.2014    source источник
comment
Разве вы не можете добавить файловые операции непосредственно в dymanic_data.php вместо эха и повторного захвата вывода без эха? Любые ограничения в этом?   -  person shatheesh    schedule 08.06.2014
comment
Потому что проще зациклить/эхо, используя PHP в качестве языка шаблона, чем напрямую печатать в файл. Кроме того, я могу повторно использовать тот же сценарий для веб-вывода.   -  person Ryan    schedule 08.06.2014


Ответы (2)


ob_start документация предлагает решение этой проблемы. Вам нужно передать $output_callback и $chunk_size.

Допустим, вы установили $chunk_size на 1 МБ. Затем каждый 1 МБ буферизованных выходных данных ваш $output_callback будет вызываться с этими данными, и вы можете сбросить его на диск (при этом выходной буфер неявно сбрасывается).

$output_callback = function($data) {
   //$buffer contains our 1MB of output

   file_put_contents($path, $data);

   //return new string buffer
   return "";
}

//call $output_callback every 1MB of output buffered.
ob_start($output_callback, 1048576);

require_once 'dynamic_data.php';

//call ob_clean at the end to get any remaining bytes 
//(implicitly calls $output_callback final time)
ob_clean();
person Martin Konecny    schedule 08.06.2014

Вы можете использовать proc_open и вызвать интерпретатор PHP с помощью этого файла как аргумент. Это не сохранит данные в памяти, но создаст другой процесс.

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("file", $path, "w"),  // stdout is a pipe that the child will write to
   2 => array("file", $path, "a") // stderr is a file to write to
);

$process = proc_open('php dynamic_data.php', $descriptorspec, $pipes);

if (is_resource($process)) {
    // $pipes now looks like this:
    // 0 => writeable handle connected to child stdin
    // 1 => readable handle connected to child stdout
    // Any error output will be appended to /tmp/error-output.txt

    fclose($pipes[0]);
    fclose($pipes[1]);
    $return_value = proc_close($process);
}
?>
person Shiplu Mokaddim    schedule 08.06.2014