proc_open: расширение номеров дескрипторов файлов для включения «статуса» обратной связи из сценария Perl

Руководство proc_open PHP гласит:

Номера дескрипторов файлов не ограничены 0, 1 и 2 – вы можете указать любой допустимый номер дескриптора файла, и он будет передан дочернему процессу. Это позволяет вашему сценарию взаимодействовать с другими сценариями, которые запускаются как «совместные процессы». В частности, это полезно для передачи парольных фраз в такие программы, как PGP, GPG и openssl более безопасным образом. Он также полезен для чтения информации о статусе, предоставляемой этими программами в дополнительных дескрипторах файлов.

Что происходит: я вызываю Perl-скрипт в веб-приложении на основе PHP и передаю параметры в вызове. У меня нет необходимости отправлять данные в сценарий. Через stdout [1] я получаю из Perl-скрипта json_encoded данные, которые я использую в своем приложении PHP.

Что я хотел бы добавить: Perl-скрипт развивается через веб-сайт, собирающий информацию в зависимости от параметров, переданных в его первоначальном вызове. Я хотел бы отправить обратно в PHP-приложение текстовую строку, которую я мог бы использовать, чтобы отображать как своего рода индикатор выполнения.

Как я думаю, я должен это сделать: я ожидал бы опроса (каждые 1-2 секунды) канала, который был настроен для обновления «прогрессии». Я бы использовал Javascript / jQuery для записи в контейнер html div для просмотра пользователем. Я не думаю, что я должен смешивать канал «прогресс» с более критическим каналом «json_encode (data)», как тогда мне нужно было бы расшифровать поток 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 => …), то как я буду писать в него в Perl-скрипте?

благодаря

Предположим, вы хотите следить за ходом программы 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 для открытия fd 3 on /tmp/progress и подключения его к программе

  $ (exec 3> / tmp / progress; ./hello-world 3)
 Привет мир!

 $ cat / tmp / progress
 .............. 

(Это забавно смотреть вживую.)

Чтобы также увидеть точки на вашем терминале по мере их появления, вы можете открыть свой дескриптор прогресса и эффективно dup2 его на стандартную ошибку, снова используя синтаксис bash и больше удовольствия в режиме реального времени.

  $ (exec 17> / dev / null; exec 17> & 2; ./hello-world 17)
 Здравствуйте,.  .Мир!.
 , 

Конечно, вы можете пропустить дополнительный шаг с помощью

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

чтобы получить тот же эффект.

Если ваша программа Perl умирает с ошибкой, такой как

  $ ./hello-world 333
 ./hello-world: dup 333: Плохой дескриптор файла на ./hello-world line 9. 

то конец записи вашего канала на стороне PHP, вероятно, имеет установленный флаг close-on-exec.

Вы открываете новый дескриптор файла и дублируете его в дескриптор файла 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 

Редактируйте: за комментарий Грега Бэкона, open STD3, '>&=', 3 или open STD3, '>&=3' открыть дескриптор файла напрямую, например, вызов fdopen C, избегая dup вызова и сохраняя дескриптор файла.