如何将 STDOUT 重定向到 PHP 中的文件?

发布于 2024-07-23 02:10:00 字数 181 浏览 10 评论 0原文

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

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

有更自然的方法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

傲性难收 2024-07-30 02:10:00

您可以安装 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);

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

这也可以使用 STDERR 完成

,并且常量 STD[OUT|ERR] 仍然可用

You can install Eio extension

pecl install 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

this can be done with STDERR as well

and constants STD[OUT|ERR] are still usable

梦旅人picnic 2024-07-30 02:10:00

可以将 STDOUT 直接写入 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 不会将这些常量更新为新的描述符,并且不允许重新定义这些常量(毕竟它们被称为常量是有原因的)。

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

挽容 2024-07-30 02:10:00

这些答案都不适用于我的特定情况,在这种情况下,我需要一种跨平台方式在回显输出后立即重定向输出,以便我可以使用 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

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
各自安好 2024-07-30 02:10:00

不,输出缓冲已经是最好的了。 虽然这样做稍微好一些

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

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);
猥琐帝 2024-07-30 02:10:00

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

$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-一个文件

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

痴情换悲伤 2024-07-30 02:10:00

使用 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 调用时附加到日志上,请使用模式“ab”而不是“wb”。

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

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.

给妤﹃绝世温柔 2024-07-30 02:10:00

我知道这个问题很古老,但是尝试做这个问题所要求的事情的人很可能最终会来到这里......你们俩。

如果您在特定环境下运行...

  • 在 Linux 下运行(可能是大多数其他 Unix 类操作系统,未经测试)
  • 通过 CLI 运行(在 Web 服务器上未经测试)

您实际上可以关闭所有文件描述符 (是的,这意味着最好在执行一开始就执行此操作...例如,在调用 pcntl_fork() 调用后台守护进程中的进程之后(这似乎是最常见的)常见的需要是这样的)

fclose( STDIN );  // fd 3
fclose( STDERR);  // fd 2
fclose( STDOUT ); // fd 1

然后重新打开文件描述符,将它们分配给一个不会超出范围并因此被垃圾收集的变量,因为 Linux 可以预见地会在正确的位置打开它们。 您可以使用任何您想要的文件或设备,我给出了 /dev/null 作为 STDIN (fd3)的

$kept_in_scope_variable_fd1 = fopen(...); // fd 1
$kept_in_scope_variable_fd2 = fopen(...); // fd 2
$kept_in_scope_variable_fd3 = fopen( '/dev/null', ... ); // fd 3

示例,因为这可能是此类代码的最常见情况

。执行诸如 echoprint_rvar_dump 等正常操作,无需专门使用函数写入文件。 当您尝试将您不想或无法重写的后台代码改写为文件指针输出友好时,这非常有用。

YMMV 适用于其他环境以及诸如打开其他 FD 之类的事情。我的建议是从一个小型测试脚本开始,以证明它在您的环境中是否有效,然后从那里开始进行集成。

祝你好运。

I understand that this question is ancient, but people trying to do what this question asks will likely end up here... Both of you.

If you are running under a particular environment...

  • Running under Linux (probably most other Unix like operating systems, untested)
  • Running via CLI (Untested on web servers)

You can actually close all of your file descriptors (yes all, which means it's probably best to do this at the very beginning of execution... for example just after a pcntl_fork() call to background the process in a daemon (which seems like the most common need for something like this)

fclose( STDIN );  // fd 3
fclose( STDERR);  // fd 2
fclose( STDOUT ); // fd 1

And then re-open the file descriptors, assigning them to a variable that will not fall out of scope and thus be garbage collected. Because Linux will predictably open them in the proper order.

$kept_in_scope_variable_fd1 = fopen(...); // fd 1
$kept_in_scope_variable_fd2 = fopen(...); // fd 2
$kept_in_scope_variable_fd3 = fopen( '/dev/null', ... ); // fd 3

You can use whatever files or devices you want for this. I gave /dev/null as the example for STDIN (fd3) because that's probably the most common case for this kind of code.

Once this is done you should be able to do normal things like echo, print_r, var_dump, etc without specifically needing to write to a file with a function. Which is useful when you're trying to background code that you do not want to, or aren't able to, rewrite to be file-pointer-output-friendly.

YMMV for other environments and things like having other FD's open, etc. My advice is to start with a small test script to prove that it works, or doesn't, in your environment and then move on to integration from there.

Good luck.

黎歌 2024-07-30 02:10:00

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

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 变量。
但你不必一开始就把它放在一起。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文