如何将标准输出重定向到 PHP 中的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/937627/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 00:23:28  来源:igfitidea点击:

how to redirect STDOUT to a file in PHP?

phpstdoutstdin

提问by omg

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?

有没有更自然的方法?

回答by Bas Peters

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

可以将 STDOUT 直接写入 PHP 中的文件,这比使用输出缓冲更容易和直接。

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.

在我的示例中,我将标准输入重定向到 /dev/null 并将输出和错误文件描述符重定向到日志文件。这是在 PHP 中制作守护程序脚本时的常见做法。

To write to the application.logfile, this would suffice:

要写入application.log文件,这就足够了:

echo "Hello world\n";

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

要写入error.log,必须执行以下操作:

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).

请注意,当您更改输入、输出和错误描述符时,内置的 PHP 常量 STDIN、STDOUT 和 STDERR 将无法使用。PHP 不会将这些常量更新为新的描述符,并且不允许重新定义这些常量(毕竟它们被称为常量是有原因的)。

回答by user340140

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

这是一种转移 OUTPUT 的方法,这似乎是原始问题

$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

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

回答by chaos

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

回答by Felicià Barceló

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.

使用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");

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'.

调用 eio_event_loop 用于确保先前的 eio 请求已被处理。如果您需要在日志上附加,在 fopen 调用时,请使用模式 'ab' 而不是 '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.

安装 eio 模块非常简单(http://php.net/manual/es/eio.installation.php)。我用 1.2.6 版的 eio 模块测试了这个例子。

回答by Danilo Souza Mor?es

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:

没有一个答案适用于我的特定情况,我需要一种跨平台的方式在输出后立即重定向输出,以便我可以使用 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();

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

我没有注意到任何性能问题,但如果你注意到了,你可以将 chunk_size 更改为更大的值。

Now just tail -f the log file:

现在只需 tail -f 日志文件:

tail -f log.txt

回答by buburs

Here is an ugly solution that was useful for a problem I had (need to debug).

这是一个丑陋的解决方案,对我遇到的问题(需要调试)很有用。

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

The main drawback of that is that you'd better not to use the $_POST variables. But you dont have to put it in the very beggining.

这样做的主要缺点是您最好不要使用 $_POST 变量。但你不必把它放在最开始的地方。

回答by Vaclav Krauz

You can install Eio extension

您可以安装 Eio 扩展

pecl install eio

pecl 安装 eio

and duplicate a file descriptor

并复制文件描述符

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

this creates new file descriptor and rewrites target stream of STDOUT

这将创建新的文件描述符并重写 STDOUT 的目标流

this can be done with STDERR as well

这也可以用 STDERR 来完成

and constants STD[OUT|ERR] are still usable

和常量 STD[OUT|ERR] 仍然可用