Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to redirect STDOUT to a file in PHP?

Tags:

php

stdout

stdin

The code below almost works, but it's not what I really meant:

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

Is there a more natural way?

like image 673
omg Avatar asked Jun 02 '09 01:06

omg


5 Answers

It is possible to write STDOUT directly to a file in PHP, which is much easier and more straightforward than using output bufferering.

Do this in the very beginning of your script:

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

Why at the very beginning you may ask? No file descriptors should be opened yet, because when you close the standard input, output and error file descriptors, the first three new descriptors will become the NEW standard input, output and error file descriptors.

In my example here I redirected standard input to /dev/null and the output and error file descriptors to log files. This is common practice when making a daemon script in PHP.

To write to the application.log file, this would suffice:

echo "Hello world\n";

To write to the error.log, one would have to do:

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

Please note that when you change the input, output and error descriptors, the build-in PHP constants STDIN, STDOUT and STDERR will be rendered unusable. PHP will not update these constants to the new descriptors and it is not allowed to redefine these constants (they are called constants for a reason after all).

like image 180
Bas Peters Avatar answered Sep 23 '22 13:09

Bas Peters


here's a way to divert OUTPUT which appears to be the original problem

$ob_file = fopen('test.txt','w');

function ob_file_callback($buffer)
{
  global $ob_file;
  fwrite($ob_file,$buffer);
}

ob_start('ob_file_callback');

more info here:

http://my.opera.com/zomg/blog/2007/10/03/how-to-easily-redirect-php-output-to-a-file

like image 22
user340140 Avatar answered Sep 20 '22 13:09

user340140


None of the answers worked for my particular case where I needed a cross platform way of redirecting the output as soon as it was echo'd out so that I could follow the logs with tail -f log.txt or another log viewing app. I came up with the following solution:

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

I haven't noticed any performance issues but if you do, you can change chunk_size to greater values.

Now just tail -f the log file:

tail -f log.txt
like image 39
Danilo Souza Morães Avatar answered Sep 20 '22 13:09

Danilo Souza Morães


No, output buffering is as good as it gets. Though it's slightly nicer to just do

ob_start();
echo 'xxx';
$contents = ob_get_flush();
file_put_contents($file,$contents);
like image 38
chaos Avatar answered Sep 21 '22 13:09

chaos


Using eio pecl module eio is very easy, also you can capture PHP internal errors, var_dump, echo, etc. In this code, you can found some examples of different situations.

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

Call to eio_event_loop is used to be sure that previous eio requests have been processed. If you need append on log, on fopen call, use mode 'ab' instead of 'wb'.

Install eio module is very easy (http://php.net/manual/es/eio.installation.php). I tested this example with version 1.2.6 of eio module.

like image 43
Felicià Barceló Avatar answered Sep 21 '22 13:09

Felicià Barceló