Руководство 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
вызова и сохраняя дескриптор файла.