PHP:管道和直通,以混合和匹配外部linux程序(带有STDIN和STDOUT)作为组件


PHP: pipe and passthru to mix and match external linux program (with STDIN and STDOUT) as components

我是PHP初学者。我想调用一个外部Unix命令,通过管道将一些内容(例如字符串和文件)导入其中,并将结果显示在我的输出缓冲区(浏览器)中。

考虑以下内容:

echo '<h1>stuff for my browser output window</h1>';
$fnmphp= '/tmp/someinputfile';
$sendtoprogram = "myheader: $fnmphp'n'n".get_file_contents($fnmphp);
popen2outputbuf("unixprogram < $sendtoprogram");
echo '<p>done</p>';

一个更好的解决方案是让PHP将myheader(写入Unix程序),然后通过管道将文件$fnmphp(导入Unix程序);unixprogram的输出会立即进入我的浏览器输出缓冲区。

我不认为PHP使用stdout,所以我的Unix程序STDOUT的输出会进入浏览器。否则,如果我使用system(),这将成为默认情况。我只能想到需要编写临时文件的解决方案。

我想我站在了这条线上(德语成语;电线交叉)——这可能有一个明显的解决方案。

更新:

这是一个完全不雅但相当精确的解决方案,我想取代:

function pipe2eqb( $text ) {
        $whatever= '/tmp/whatever-'.time().'-'.$_SESSION['uid'];
        $inf = "$whatever.in";
        $outf= "$whatever.out";
        assert(!file_exists($inf));
        assert(!file_exists($outf));    
        file_put_contents($inf, $text);
        assert(file_exists($inf));
        system("unixprog < $inf > $outf");
        $fo= file_get_contents($outf);
        unlink($infilename);
        unlink($outfilename);
        return $fo;
}

替换输入或输出很容易,但我想同时替换两者。当我找到解决方案时,我会发布它。

最好的方法是proc_open函数族

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin 
   1 => array("pipe", "w"),  // stdout 
   2 => array("pipe", "w") // stderr
);
$cwd = NULL;//'/tmp';
$env = NULL;//array();
$cmd='unixprog ';
$process = proc_open($cmd, $descriptorspec, $pipes, $cwd, $env);
assert(false!==$process);

现在,为了给unixprog提供论据,请像一样

$cmd='unixprog --arg1='.escapeshellarg($arg1).' --arg2='.escapeshellarg($arg2);

要与程序的stdin对话,请执行

assert(strlen($stdinmessage)===fwrite($pipes[0],$stdinmessage));

要从进程的stdout读取,请执行

$stdout=file_get_contents($pipes[$1])

要从进程的stderr读取,请执行

$stderr=file_get_contents($pipes[$2])

要检查程序是否已完成,请执行

$status=proc_get_status($process);
if($status['running']){echo 'child process is still running.';}

当流程结束时,要检查流程的返回代码,

echo 'return code from child process: '.$status['exitcode'];

要等待子进程完成,可以执行

while(proc_get_status($process)['running']){sleep(1);}

这是一种快速而简单的方法,但它不是最佳的。tl;dr:可能是速度慢或者浪费cpu。长版本:有一些近乎最佳的事件驱动方式可以做到这一点,但我不确定如何做到。想象一下,必须运行一个程序10次,但程序在100毫秒内执行。这个代码需要10秒!而最佳代码将仅使用1秒。你可以使用usleep()微秒,但它仍然不是最佳的,想象一下,如果你每100微秒检查一次,但程序执行需要10秒:你会浪费cpu,检查状态100000次,而最佳代码只检查一次。。我确信有一种奇特的方法可以让php休眠,直到进程通过一些回调/信号结束,也许是通过stream_select,但我还没有解决它。(如果有人有解决方案,请告诉我!)

--阅读更多http://php.net/manual/en/book.exec.php