proc_open

(PHP 4 >= 4.3.0, PHP 5, PHP 7)

proc_open Выполнить команду и открыть указатель на файл для ввода/вывода

Описание

proc_open ( mixed $cmd , array $descriptorspec , array &$pipes , string $cwd = null , array $env = null , array $other_options = null ) : resource

proc_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 более безопасно. Также это может оказаться полезным для чтения статусной информации, предоставляемой этими программами на вспомогательных файловых дескрипторах.

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(
   
=> array("pipe""r"),  // stdin - канал, из которого дочерний процесс будет читать
   
=> array("pipe""w"),  // stdout - канал, в который дочерний процесс будет записывать
   
=> 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 
= [STDINSTDOUTSTDOUT];
$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
  • Оператор обратный апостроф