proc_open
(PHP 4 >= 4.3.0, PHP 5, PHP 7)
proc_open — Выполнить команду и открыть указатель на файл для ввода/вывода
Описание
$cmd
, array $descriptorspec
, array &$pipes
, string $cwd
= null
, array $env
= null
, array $other_options
= null
) : resourceproc_open() аналогична popen(), но предоставляет намного больше контроля над выполнением программы.
Список параметров
-
cmd
-
Командная для выполнения, указанная как строка (string). Специальные символы должны быть должным образом экранированы, и должны применяться правильные кавычки.
Замечание: В Windows, если для
bypass_shell
не установлено значениеtrue
вother_options
,cmd
передается в cmd.exe (точнее,%ComSpec%
) с флагом/c
в виде строки без кавычек (т.е. точно так, как было задано в proc_open()). Это может привести к тому, что cmd.exe удалит заключающие изcmd
(подробности смотрите в документации cmd.exe), приводя к неожиданному и потенциально даже опасному поведению, потому что сообщения об ошибках cmd.exe могут содержать (частично) переданный параметрcmd
(смотрите пример ниже).Начиная с PHP 7.4.0,
cmd
может передаваться как массив (array) параметров команды. В этом случае процесс будет открыт напрямую (не проходя через оболочку) и PHP позаботится о экранировании любого необходимого аргумента.Замечание:
В Windows экранирование аргумента массива (array) элементов предполагает, что синтаксический анализ выполненной команды совместим с синтаксическим анализом аргументов командной строки, выполняемых средой выполнения VC.
-
descriptorspec
-
Массив, ключи которого представляют собой номер дескриптора, а значение описывает, как PHP должен передать этот дескриптор дочернему процессу. 0 - stdin, 1 - stdout и 2 - stderr.
Каждый элемент может быть:
-
Массивом, описывающим канал (pipe) для передачи процессу. Первый
элемент - это дескриптор типа, второй - настройка для выбранного типа.
Возможные типы:
pipe
(второй элемент либоr
для передачи процессу стороны канала для чтения, либоw
для передачи стороны записи) иfile
(второй элемент - имя файла). -
Ресурсом потока, представляющим дескриптор файла (например, открытый
файл, сокет,
STDIN
).
Номера дескрипторов не ограничены только 0, 1 и 2 - вы можете назначить любой действительный номер дескриптора и он будет передан дочернему процессу. Это позволяет скрипту взаимодействовать с другими скриптами, работающими, как параллельные процессы. В частности, таким образом можно передавать данные, требующие защиты, в программы вроде PGP, GPG и openssl более безопасно. Также это может оказаться полезным для чтения статусной информации, предоставляемой этими программами на вспомогательных файловых дескрипторах.
-
Массивом, описывающим канал (pipe) для передачи процессу. Первый
элемент - это дескриптор типа, второй - настройка для выбранного типа.
Возможные типы:
-
pipes
-
Будет задан массивом указателей на файлы, соответствующие созданным каналам передачи данных PHP.
-
cwd
-
Рабочая директория команды. Это должен быть абсолютный путь к директории или
null
, если требуется использовать директорию по умолчанию (рабочая директория текущего процесса PHP). -
env
-
Массив переменных окружения для запускаемой команды или
null
, если требуется использовать то же самое окружение, что и у текущего PHP-процесса. -
other_options
-
Позволяет задать дополнительные настройки. На данный момент поддерживаются следующие настройки:
-
suppress_errors
(только для Windows): при установке вtrue
не будут показываться ошибки, возникающие в ходе работы функции -
bypass_shell
(только для Windows): при установке вtrue
процесс будет запущен в обход оболочкиcmd.exe
-
blocking_pipes
(только для Windows): принудительно блокировать поток при значенииtrue
-
create_process_group
(только для Windows): разрешить дочернему процессу обрабатыватьCTRL
события, если установлено значениеtrue
-
create_new_console
(только для Windows): новый процесс использует новую консоль, а не наследует консоль своего родителя
-
Возвращаемые значения
Возвращает ресурс, представляющий процесс. Этот ресурс необходимо освобождать
функцией proc_close() по завершении работы с ним.
В случае ошибки возвращает false
.
Список изменений
Версия | Описание |
---|---|
7.4.4 |
Добавлена опция create_new_console oв
параметр other_options .
|
7.4.0 |
proc_open() теперь также принимает массив (array)
в cmd .
|
7.4.0 |
Добавлена опция create_process_group в
параметр other_options .
|
Примеры
Пример #1 Пример использования proc_open()
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // stdin - канал, из которого дочерний процесс будет читать
1 => array("pipe", "w"), // stdout - канал, в который дочерний процесс будет записывать
2 => array("file", "/tmp/error-output.txt", "a") // stderr - файл для записи
);
$cwd = '/tmp';
$env = array('some_option' => 'aeiou');
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
// $pipes теперь выглядит так:
// 0 => записывающий обработчик, подключенный к дочернему stdin
// 1 => читающий обработчик, подключенный к дочернему stdout
// Вывод сообщений об ошибках будет добавляться в /tmp/error-output.txt
fwrite($pipes[0], '<?php print_r($_ENV); ?>');
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
// Важно закрывать все каналы перед вызовом
// proc_close во избежание мертвой блокировки
$return_value = proc_close($process);
echo "команда вернула $return_value\n";
}
?>
Результатом выполнения данного примера будет что-то подобное:
Array ( [some_option] => aeiou [PWD] => /tmp [SHLVL] => 1 [_] => /usr/local/bin/php ) команда вернула 0
Пример #2 proc_open() причуда в Windows
Хотя можно ожидать, что следующая программа будет искать в файле
filename.txt текст search
и выводить результаты, она ведет себя несколько иначе.
<?php
$descriptorspec = [STDIN, STDOUT, STDOUT];
$cmd = '"findstr" "search" "filename.txt"';
$proc = proc_open($cmd, $descriptorspec, $pipes);
proc_close($proc);
?>
Результат выполнения данного примера:
'findstr" "search" "filename.txt' не распознается как внутренняя или внешняя команда, работающая программа или пакетный файл.
Чтобы обойти это поведение, обычно достаточно
передать cmd
в дополнительных кавычках:
$cmd = '""findstr" "search" "filename.txt""';
Примечания
Замечание:
Совместимость с Windows: Дескрипторы дальше 2 (stderr) наследуются дочерними процессам, однако с тех пор как Windows не ассоциирует номера файловых дескрипторов с низкоуровневыми обработчиками, дочерние процессы не имеют (пока) к ним доступа. Это не относится к stdin, stdout и stderr.
Замечание:
Если нужен однонаправленный канал процесса, используйте функцию popen(), так как она значительно проще в использовании.
Смотрите также
- popen() - Открывает файловый указатель процесса
- exec() - Выполнить внешнюю программу
- system() - Выполнить внешнюю программу и отобразить вывод
- passthru() - Выполнить внешнюю программу и отобразить необработанный вывод
- stream_select() - Запускает эквивалент системного вызова select() на заданных массивах потоков с таймаутом, указанным параметрами tv_sec и tv_usec
- Оператор обратный апостроф