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

如何在PHP中将标准输出重定向到文件?,php,stdout,stdin,Php,Stdout,Stdin,下面的代码几乎可以工作,但这不是我真正的意思: ob_start(); echo 'xxx'; $contents = ob_get_contents(); ob_end_clean(); file_put_contents($file,$contents); 有更自然的方法吗?没有,输出缓冲是最好的。尽管这样做稍微好一点 ob_start(); echo 'xxx'; $contents = ob_get_flush(); file_put_contents($file,$contents)

下面的代码几乎可以工作,但这不是我真正的意思:

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

有更自然的方法吗?

没有,输出缓冲是最好的。尽管这样做稍微好一点

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

可以用PHP将标准输出直接写入文件,这比使用输出缓冲更简单、更直接

在脚本开始时执行以下操作:

fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('application.log', 'wb');
$STDERR = fopen('error.log', 'wb');
为什么一开始你会问?不应打开任何文件描述符,因为当您关闭标准输入、输出和错误文件描述符时,前三个新描述符将成为新的标准输入、输出和错误文件描述符

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

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

echo "Hello world\n";
要写入error.log,必须执行以下操作:

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

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

以下是一种转移输出的方法,这似乎是原始问题

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

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

ob_start('ob_file_callback');
更多信息请点击此处:


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

这样做的主要缺点是最好不要使用$\u POST变量。
但是您不必把它放在最底层。

您可以安装Eio扩展

pecl安装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);
这将创建新的文件描述符并重写标准输出的目标流

这也可以通过STDERR实现


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

使用eio pecl模块eio非常简单,您还可以捕获PHP内部错误、var|u dump、echo等。在这段代码中,您可以找到一些不同情况的示例

$fdout=fopen('/tmp/stdout.log','wb');
$fderr=fopen('/tmp/stderr.log','wb');
eio_dup2($fdout,标准输出);
eio_dup2($fderr,STDERR);
eio_事件_循环();
fclose($fdout);
fclose($fderr);
//输出示例
回显“发送到标准输出的消息\n”;
$v2dump=array(10,“graphinux”);
var_转储($v2dump);
//php内部错误/警告
$div0=10/0;
//用户错误消息
fwrite(STDERR,“用户控制的错误”);
调用eio_事件_循环用于确保已处理以前的eio请求。如果需要在日志上追加,在fopen调用时,使用模式“ab”而不是“wb”


安装eio模块非常简单()。我用eio模块的1.2.6版测试了这个示例

没有一个答案适用于我的特殊情况,在这种情况下,我需要一种跨平台的方式,在输出被回显后立即重定向,以便我可以使用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_大小更改为更大的值

现在只需跟踪日志文件:

tail -f log.txt

ob_get_flush()是否也会将缓冲区内容发送到浏览器?也许ob_get_clean()会更好。有没有一种方法也可以获取STDERR?这个特性在它的基本Unix行为中有记录(这也是它不能移植到windows的原因)。Unix提供了文件可用的最小文件描述符。如果FCO关闭0、1和2,则它们将可用于下一个3打开。Unix的简单性也很好。如果它与cron脚本一起使用,您可能希望将
fopen
与模式
a
一起使用,这样就不会覆盖以前的日志。祝您好运。这完全是出于运气。这不是解决办法。@Pacerier,没错。如何命名变量并不重要。为了便于阅读,我只是将它们保持不变。唯一真正重要的是关闭默认描述符和打开新描述符的顺序。你真的应该在这里接受答案。Bas Peters为您提供了完美的解决方案。示例代码是将输出重定向到文件,而不是标准输出,Bas的解决方案似乎只起作用,因为CLI(以及较小程度的CGI)环境可交换地使用这些流。apache模块PHP没有。如果您使用的是PHP5.3或更高版本,我建议您使用闭包函数,而无需将
$ob_file
设置为全局:
$ob_file_callback=function($buffer)use($ob_file){fwrite($ob_file,$buffer);};ob_start($ob_file_callback)
这对我来说很有用,应该是我生活中可以接受的答案view@user340140如果你知道如何重定向stdin,请分享。
tail -f log.txt