web-dev-qa-db-ja.com

PHPでSTDOUTをファイルにリダイレクトする方法は?

以下のコードはほとんど機能しますが、私が本当に意図したものではありません:

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

もっと自然な方法はありますか?

52
omg

PHPでSTDOUTをファイルに直接書き込むことができます。これは、出力バッファリングを使用するよりもはるかに簡単で簡単です。

スクリプトの冒頭でこれを実行します。

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

なぜ最初に尋ねるかもしれませんか?標準入力、出力、およびエラーファイル記述子を閉じると、最初の3つの新しい記述子が新しい標準入力、出力、およびエラーファイル記述子になるため、ファイル記述子をまだ開いてはなりません。

この例では、標準入力を/ dev/nullにリダイレクトし、出力およびエラーファイル記述子をログファイルにリダイレクトしました。これは、PHPでデーモンスクリプトを作成する際の一般的な方法です。

application.logファイルに書き込むには、これで十分です。

echo "Hello world\n";

error.logに書き込むには、次の手順を実行する必要があります。

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

入力、出力、およびエラー記述子を変更すると、ビルドインPHP定数STDIN、STDOUT、およびSTDERRが使用不可になります。PHPこれらの定数を新しい記述子に更新しないでください。また、これらの定数を再定義することはできません(それらは結局、定数と呼ばれます)。

119
Bas Peters

ここに元の問題のように見えるOUTPUTを迂回する方法があります

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

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

ob_start('ob_file_callback');

詳細はこちら:

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

16
user340140

いいえ、出力バッファリングは得られるのと同じくらい良いです。ただやるほうが少しいいけど

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

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します。

tail -f log.txt

Eio peclモジュール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呼び出しで、「wb」ではなく「ab」モードを使用します。

Eioモジュールのインストールは非常に簡単です( http://php.net/manual/es/eio.installation.php )。この例は、バージョン1.2.6のeioモジュールでテストしました。

2

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]はまだ使用可能です

1
Vaclav Krauz

これは、私が抱えていた問題(デバッグが必要)に役立つwasい解決策です。

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変数を使用しないほうが良いということです。しかし、あなたはそれを非常に始めに入れる必要はありません。

1
buburs