Proc open: примеры (PHP)
proc_open(string $command, array $descriptor_spec, array &$pipes, ?string $cwd = null, ?array $env_vars = null, ?array $options = null): resource|falseФункция proc_open позволяет запускать внешние процессы и организовывать двустороннюю связь с ними через каналы ввода-вывода. Она используется, когда требуется сложное взаимодействие с запущенной программой: передача данных в стандартный ввод, чтение из стандартного вывода и ошибок, а также управление процессом.
command - строка команды для выполнения.
descriptorspec - массив дескрипторов, определяющий каналы связи с процессом. Ключи - номера дескрипторов (0 - stdin, 1 - stdout, 2 - stderr). Значения могут быть: массив с типом канала ('pipe', 'file', 'socket') или ресурсом.
pipes - переменная, в которую будут записаны ресурсы открытых каналов PHP.
cwd - начальная рабочая директория процесса (null - текущая директория PHP).
env - массив переменных окружения для процесса (null - наследуются от PHP).
other_options - дополнительные опции, такие как 'suppress_errors', 'bypass_shell', 'context'.
$descriptors = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"]
];
$process = proc_open('ls -la', $descriptors, $pipes);
if (is_resource($process)) {
fclose($pipes[0]);
echo stream_get_contents($pipes[1]);
fclose($pipes[1]);
proc_close($process);
}total 12 drwxr-xr-x 2 user user 4096 Mar 10 10:00 . drwxr-xr-x 10 user user 4096 Mar 9 09:00 .. -rw-r--r-- 1 user user 56 Mar 10 10:00 test.php
$process = proc_open('wc -w', $descriptors, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], "Hello world from PHP");
fclose($pipes[0]);
echo trim(stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($process);
}4
$options = ['bypass_shell' => true];
$process = proc_open(['echo', 'test'], $descriptors, $pipes, null, null, $options);Возвращает последнюю строку вывода команды. Подходит для простых команд без сложного взаимодействия.
Возвращает весь вывод команды в виде строки. Не поддерживает разделение stdout и stderr.
Выполняет команду и передает сырой вывод напрямую в браузер. Полезно для бинарных данных.
Открывает односторонний канал к процессу. Используется, когда требуется только чтение или только запись.
proc_open предпочтительна для сложных интерактивных сценариев. Для простого выполнения команд достаточно exec или shell_exec. popen подходит для однонаправленного потока данных.
import subprocess
proc = subprocess.Popen(['ls', '-la'], stdout=subprocess.PIPE)
output, error = proc.communicate()
print(output.decode())const { spawn } = require('child_process');
const ls = spawn('ls', ['-la']);
ls.stdout.on('data', (data) => {
console.log(data.toString());
});ls -la 2>&1 | while read line; do
echo "$line"
donePython subprocess предоставляет более высокоуровневый API. Node.js использует событийную модель. PHP proc_open работает с ресурсами и требует ручного управления каналами.
$process = proc_open('sleep 10', $descriptors, $pipes);
echo "Процесс запущен";
// Каналы не закрыты, процесс может остаться зависшим$process = proc_open('cat', $descriptors, $pipes);
fwrite($pipes[0], "data");
// Не закрыт stdin, cat ожидает EOF
$output = stream_get_contents($pipes[1]); // Блокировка// Дескриптор stderr не указан
$descriptors = [
0 => ["pipe", "r"],
1 => ["pipe", "w"]
];
$process = proc_open('command_not_exist', $descriptors, $pipes);
// Ошибки потеряютсяproc_close($process);
$status = proc_get_status($process); // Возвращает устаревшие данные
echo $status['exitcode']; // Может быть невернымДобавлена возможность передавать массив команд вместо строки для безопасного выполнения без оболочки. Улучшена обработка ошибок.
Введены предупреждения при использовании небезопасных конфигураций. Улучшена производительность.
Оптимизировано управление ресурсами процессов. Добавлены новые константы для дескрипторов.
Улучшена совместимость с Windows. Добавлена поддержка дополнительных опций контекста.
$process = proc_open('bc', $descriptors, $pipes);
if (is_resource($process)) {
fwrite($pipes[0], "2 + 2\n");
fflush($pipes[0]);
echo "Результат: " . fgets($pipes[1]);
fwrite($pipes[0], "5 * 3\n");
fflush($pipes[0]);
echo "Результат: " . fgets($pipes[1]);
fwrite($pipes[0], "quit\n");
fclose($pipes[0]);
fclose($pipes[1]);
proc_close($process);
}Результат: 4 Результат: 15
$process = proc_open('command_with_output', $descriptors, $pipes);
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$stdout = '';
$stderr = '';
while (true) {
$read = [$pipes[1], $pipes[2]];
$write = $except = null;
if (stream_select($read, $write, $except, 1) > 0) {
foreach ($read as $stream) {
if ($stream === $pipes[1]) {
$stdout .= fread($stream, 8192);
} else {
$stderr .= fread($stream, 8192);
}
}
}
$status = proc_get_status($process);
if (!$status['running']) break;
}$descriptors = [
1 => ["file", "/tmp/output.log", "w"],
2 => ["pipe", "w"]
];
$process = proc_open('ls -la /', $descriptors, $pipes);
proc_close($process);
// Результат в /tmp/output.log$context = stream_context_create([
'proc' => [
'suppress_errors' => true,
'bypass_shell' => true
]
]);
$process = proc_open(['ls', '-la'], $descriptors, $pipes, null, null, $context);$process = proc_open('sleep 30', $descriptors, $pipes);
$start = time();
while (true) {
$status = proc_get_status($process);
if (!$status['running']) {
break;
}
if (time() - $start > 5) {
proc_terminate($process, SIGKILL);
echo "Процесс завершен по таймауту";
break;
}
usleep(100000);
}