proc_open:扩展文件描述符编号以启用Perl脚本的"状态"反馈

Ric*_*sin 6 php perl proc-open

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";
}
Run Code Online (Sandbox Code Playgroud)

但是,在Perl脚本中,我只需写入stdout,如:

my $json_terms = encode_json(\@terms);
print $json_terms;
Run Code Online (Sandbox Code Playgroud)

如果我对设置附加通道的理解是正确的(上面,3 => ...),那么我将如何在Perl脚本中写入它?

谢谢

Gre*_*con 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;
}
Run Code Online (Sandbox Code Playgroud)

使用bash语法打开fd 3/tmp/progress并将其连接到程序是

$ (exec 3>/tmp/progress; ./hello-world 3)
你好世界!

$猫/tmp/进度
............

(看直播更有趣。)

为了在终端上出现的点也能看到,您可以打开进度描述符并有效地将dup2其显示在标准错误上 - 再次使用 bash 语法,实时获得更多乐趣。

$ (执行 17>/dev/null; 执行 17>&2; ./hello-world 17)
你好,。。世界!。
。

你当然可以跳过额外的步骤

$ (执行 17>&2; ./hello-world 17)

以获得相同的效果。

如果您的 Perl 程序因以下错误而终止

$ ./hello-world 333
./hello-world: dup 333: ./hello-world 第 9 行有错误的文件描述符。

那么 PHP 端管道的写入端可能设置了 close-on-exec 标志。