Подтвердить что ты не робот

Как перенаправить STDOUT на файл в PHP?

Код ниже почти работает, но это не то, что я действительно имел в виду:

ob_start();
echo 'xxx';
$contents = ob_get_contents();
ob_end_clean();
file_put_contents($file,$contents);

Есть ли более естественный способ?

4b9b3361

Ответ 1

Можно писать STDOUT непосредственно в файл на PHP, что намного проще и проще, чем использование буферизации вывода.

Сделайте это в самом начале вашего script:

fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('application.log', 'wb');
$STDERR = fopen('error.log', 'wb');

Почему в самом начале вы можете спросить? Никаких дескрипторов файлов не нужно открывать, потому что когда вы закрываете дескрипторы стандартного ввода, вывода и файла ошибки, первые три новых дескриптора станут НОВЫМИ стандартными дескрипторами ввода, вывода и файла ошибок.

В моем примере здесь я перенаправил стандартный ввод в /dev/null и дескрипторы файла вывода и файла ошибок в файлы журнала. Это обычная практика при создании демона script в PHP.

Чтобы записать файл application.log, это будет достаточно:

echo "Hello world\n";

Чтобы записать в error.log, нужно было бы:

fwrite($STDERR, "Something went wrong\n"); 

Обратите внимание, что при изменении ввода, вывода и дескрипторов ошибок встроенные PHP-константы STDIN, STDOUT и STDERR будут недоступны. PHP не будет обновлять эти константы для новых дескрипторов, и им не разрешено переопределять эти константы (они называются константами по какой-то причине).

Ответ 3

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

ob_start();
echo 'xxx';
$contents = ob_get_flush();
file_put_contents($file,$contents);

Ответ 4

Вот уродливое решение, которое было полезно для проблемы, которую я имел (нужно отлаживать).

if(file_get_contents("out.txt") != "in progress")
{
    file_put_contents("out.txt","in progress");
    $content = file_get_contents('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
    file_put_contents("out.txt",$content);
}

Основной недостаток заключается в том, что вам лучше не использовать переменные $_POST. Но вы не должны ставить его в самом начале.

Ответ 5

Вы можете установить расширение Eio

pecl install eio

и дублировать файловый дескриптор

$temp=fopen('/tmp/my_stdout','a');
$my_data='my something';
$foo=eio_dup2($temp,STDOUT,EIO_PRI_MAX,function($data,$esult,$request){
    var_dump($data,$esult,$request);
    var_dump(eio_get_last_error($request));
},$my_data);
eio_event_loop();
echo "something to stdout\n";
fclose($temp);

это создает новый файловый дескриптор и перезаписывает целевой поток STDOUT

это также можно сделать с помощью STDERR

и константы STD [OUT | ERR] по-прежнему доступны

Ответ 6

Использование eio pecl module eio очень просто, также вы можете записывать внутренние ошибки PHP, var_dump, echo и т.д. В этом коде вы можете найти несколько примеров различных ситуаций.

$fdout = fopen('/tmp/stdout.log', 'wb');
$fderr = fopen('/tmp/stderr.log', 'wb');

eio_dup2($fdout, STDOUT);
eio_dup2($fderr, STDERR);
eio_event_loop();

fclose($fdout);
fclose($fderr);

// output examples
echo "message to stdout\n";

$v2dump = array(10, "graphinux");
var_dump($v2dump);

// php internal error/warning
$div0 = 10/0;

// user errors messages
fwrite(STDERR, "user controlled error\n");

Вызов eio_event_loop используется, чтобы быть уверенным, что предыдущие запросы eio были обработаны. Если вам нужно добавить в журнал, по вызову fopen, используйте режим 'ab' вместо 'wb'.

Установить eio-модуль очень просто (http://php.net/manual/es/eio.installation.php). Я проверил этот пример с версией 1.2.6 модуля eio.

Ответ 7

Ни один из ответов не работал для моего конкретного случая, когда мне нужен был кросс-платформенный способ перенаправления вывода, как только он был эхо-сигнал, чтобы я мог следить за журналами с помощью tail -f log.txt или другого просмотра журнала приложение. Я придумал следующее решение:

$logFp = fopen('log.txt', 'w');

ob_start(function($buffer) use($logFp){
    fwrite($logFp, $buffer);
}, 1); //notice the use of chunk_size == 1

echo "first output\n";
sleep(10)
echo "second output\n";

ob_end_clean();

Я не заметил никаких проблем с производительностью, но если вы это сделаете, вы можете изменить chunk_size на большие значения.

Теперь просто хвост - файл журнала:

tail -f log.txt