PHP的proc_open手册说明:
文件描述符编号不限于0,1和2 - 您可以指定任何有效的文件描述符编号,并将其传递给子进程。这允许您的脚本与作为“协同进程”运行的其他脚本进行互操作。特别是,这对于以更安全的方式将密码短语传递给PGP,GPG和openssl等程序非常有用。它对于读取这些程序在辅助文件描述符上提供的状态信息也很有用。
发生了什么:我在基于PHP的Web应用程序中调用Perl脚本并在调用中传递参数。我将来不需要将数据发送到脚本。通过stdout [1],我从我在PHP应用程序中使用的Perl脚本json_encoded数据中收到。
我想添加的内容: Perl脚本正在通过网站收集信息,具体取决于初始调用中传递的参数。我想向PHP应用程序发送一个文本字符串,我可以用它来显示为一种进度条。
我认为我应该这样做:我希望(每1-2秒)轮询一次为“升级”更新设置的频道。我会使用Javascript / jQuery写入一个html div容器供用户查看。我不认为我应该将“进度”通道与更关键的“json_encode(数据)”通道混合,因为我需要解密stdout流。 (这是否符合逻辑,实用?)
我的主要问题:如何使用其他“文件描述符?”我会想象其他频道的设置是直截了当的,例如3 => ......在下面:
$tunnels = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
3 => array('pipe', 'w')
);
$io = array();
$resource = proc_open("perl file/tomy/perl/code.pl $param1 $param2 $param3", $tunnels, $io);
if(!is_resource($resource)) {
$error = "No Resource";
}
fclose($io[0]);
$perlOutput = stream_get_contents($io[1]);
$output = json_decode($perlOutput);
$errors = stream_get_contents($io[2]);
print "$errors<p>";
fclose($io[1]);
fclose($io[2]);
$result = proc_close($resource);
if($result != 0) {
echo "you returned a $result result on proc_close";
}
但是,在Perl脚本中,我只需写入stdout,如:
my $json_terms = encode_json(\@terms);
print $json_terms;
如果我对设置其他频道的理解是正确的(上面是3 =&gt; ...),那么我将如何在Perl脚本中写入它?
由于
答案 0 :(得分:2)
您打开一个新的文件句柄并将其复制到文件描述符3:
open STD3, '>&3';
print STDERR "foo\n";
print STD3 "bar\n";
$ perl script.pl 2> file2 3> file3
$ cat file2
foo
$ cat file3
bar
修改:根据Greg Bacon的评论,open STD3, '>&=', 3
或open STD3, '>&=3'
会直接打开文件描述符,例如C fdopen
来电,避免dup
调用并保存文件描述符。
答案 1 :(得分:2)
假设您要监视hello-world程序的进度,其中每个步骤都是写入指定文件描述符的点。
#! /usr/bin/env perl
use warnings;
use strict;
die "Usage: $0 progress-fd\n" unless @ARGV == 1;
my $fd = shift;
open my $progress, ">&=", $fd or die "$0: dup $fd: $!";
# disable buffering on both handles
for ($progress, *STDOUT) {
select $_;
$| = 1;
}
my $output = "Hello, world!\n";
while ($output =~ s/^(.)(.*)\z/$2/s) {
my $next = $1;
print $next;
print $progress ".";
sleep 1;
}
使用bash语法在/tmp/progress
上打开fd 3并将其连接到程序
$ (exec 3>/tmp/progress; ./hello-world 3) Hello, world! $ cat /tmp/progress ..............
(现场观看会更有趣。)
要在终端出现时看到终端上的点,您可以打开进度描述符,并使用bash语法再次有效dup2
到标准错误上,实时更有趣。
$ (exec 17>/dev/null; exec 17>&2; ./hello-world 17) H.e.l.l.o.,. .w.o.r.l.d.!. .
你当然可以跳过
的额外步骤$ (exec 17>&2; ./hello-world 17)
获得相同的效果。
如果您的Perl程序因
之类的错误而死亡$ ./hello-world 333 ./hello-world: dup 333: Bad file descriptor at ./hello-world line 9.
那么PHP端管道的写端可能设置了close-on-exec标志。