试图理解/ dev / stdin和php:// stdin之间的区别

时间:2014-10-14 14:28:55

标签: php linux node.js

作为一个简单的概念证明,我尝试在节点之间或从节点到php的分叉进程之间共享一个字符串。

根据php docs,使用这个简单的PHP代码来记录stdin的输出:

echo 'test' | php -r 'echo trim(fgets(STDIN));'

工作正常,但是当我从nodejs产生进程时:

spawner.js

var fs = require('fs'); var spawn = require('child_process').spawn;

//dummy stdin file
var stdin = fs.openSync('stdin_file', 'w+');
//write the string
fs.writeSync(stdin, 'test');

spawn('php', ['stdin_test.php'], {
    cwd: __dirname,
    detached: true,
    //to fully detach the process nothing should be piped from or to the parent process 
    stdio: [stdin, fs.openSync('out.log', 'a'), fs.openSync('err.log', 'a')]
})

stdin_test.php

<?php
error_log('php://stdin');
//this should log 'test' but outputs a newline
error_log(trim(fgets(STDIN)));

$t = fopen('/dev/stdin', 'r');
error_log('/dev/stdin:');
//this is working as expected
error_log(trim(fgets($t)));

为什么php://stdin为空?使用/dev/stdin是否安全?无论如何,/dev/stdinphp://stdin之间有什么区别?

请注意,我在两个节点进程之间也有此行为:process.stdin为空,但/dev/stdin具有预期结果。

2 个答案:

答案 0 :(得分:2)

我使用以下脚本(stdin_test.php)进行了测试:

> echo test | php stdin_test.php

stdin_test.php

<?
echo 'STDIN :' ;
echo trim(fgets(STDIN)) ;
echo PHP_EOL;

$stdin_stream = fopen('php://stdin', 'r');
echo 'php://stdin :';
echo trim(fgets($stdin_stream));
echo PHP_EOL;
fclose($stdin_stream);

$stdin_file = fopen('/dev/stdin', 'r');
echo '/dev/stdin :';
echo trim(fgets($stdin_file));
echo PHP_EOL;
fclose($stdin_file);

我回来了:

STDIN :test
php://stdin :
/dev/stdin :

如果我然后注释掉这一行:

//echo trim(fgets(STDIN));

我回来了:

STDIN :
php://stdin :test
/dev/stdin :

如果我注释掉第一个stdin回声(和文件处理程序指针),我得到:

STDIN :
php://stdin :
/dev/stdin : test

查看php://input上的文档以及它是如何一次性可用的,除非(在5.6之后)“保存请求体”这是POST请求的典型情况,但不是PUT请求(显然)。这让我觉得它们被称为“溪流”,因为你可以一次走进它们。

答案 1 :(得分:0)

在生成PHP之前在JS中回放你的stdin流,否则文件指针将位于你刚才写的结尾。