Files
php-doc-ru/reference/exec/functions/proc-open.xml
2024-12-05 23:06:24 +03:00

382 lines
17 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 6667724b8a42ba501172bc874dd1644a6744be0f Maintainer: tmn Status: ready -->
<!-- Reviewed: no -->
<refentry xml:id="function.proc-open" xmlns="http://docbook.org/ns/docbook">
<refnamediv>
<refname>proc_open</refname>
<refpurpose>
Выполняет команду и открывает указатель на файл для ввода или вывода
</refpurpose>
</refnamediv>
<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<type class="union"><type>resource</type><type>false</type></type><methodname>proc_open</methodname>
<methodparam><type class="union"><type>array</type><type>string</type></type><parameter>command</parameter></methodparam>
<methodparam><type>array</type><parameter>descriptor_spec</parameter></methodparam>
<methodparam><type>array</type><parameter role="reference">pipes</parameter></methodparam>
<methodparam choice="opt"><type class="union"><type>string</type><type>null</type></type><parameter>cwd</parameter><initializer>&null;</initializer></methodparam>
<methodparam choice="opt"><type class="union"><type>array</type><type>null</type></type><parameter>env_vars</parameter><initializer>&null;</initializer></methodparam>
<methodparam choice="opt"><type class="union"><type>array</type><type>null</type></type><parameter>options</parameter><initializer>&null;</initializer></methodparam>
</methodsynopsis>
<para>
Функция <function>proc_open</function> аналогична функции <function>popen</function>,
но предоставляет значительно больше контроля над выполнением программы.
</para>
</refsect1>
<refsect1 role="parameters">
&reftitle.parameters;
<para>
<variablelist>
<varlistentry>
<term><parameter>command</parameter></term>
<listitem>
<para>
Команда для выполнения, указанная как строка (&string;).
Специальные символы должны быть должным образом экранированы,
и должны применяться правильные кавычки.
</para>
<note>
<simpara>
В <emphasis>Windows</emphasis>, если для <literal>bypass_shell</literal> не установлено значение &true; в
<parameter>options</parameter>, <parameter>command</parameter>
передаётся в <command>cmd.exe</command> (точнее, <literal>%ComSpec%</literal>)
с флагом <literal>/c</literal> в виде строки <emphasis>без кавычек</emphasis>
(т.е. точно так, как было задано в <function>proc_open</function>).
Это может привести к тому, что <command>cmd.exe</command> удалит заключающие из
<parameter>command</parameter> (подробности смотрите в документации <command>cmd.exe</command>),
приводя к неожиданному и потенциально даже опасному поведению, потому что сообщения об ошибках <command>cmd.exe</command> могут содержать (частично) переданный параметр
<parameter>command</parameter> (смотрите пример ниже).
</simpara>
</note>
<para>
Начиная с PHP 7.4.0 параметр <parameter>command</parameter> разрешается передавать
как массив (&array;) параметров команды.
Тогда функция откроет процесс напрямую (не проходя через оболочку)
и PHP позаботится об экранировании любого необходимого аргумента.
</para>
<note>
<para>
В ОС Windows экранирование аргумента массива (&array;) элементов предполагает,
что синтаксический анализ выполненной команды совместим с синтаксическим анализом аргументов
командной строки, выполняемых средой выполнения VC.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>descriptor_spec</parameter></term>
<listitem>
<para>
Массив, ключи которого представляют собой номер дескриптора, а значение
описывает, как PHP должен передать этот дескриптор дочернему процессу.
0 — stdin, 1 — stdout и 2 — stderr.
</para>
<para>
Каждый элемент может быть:
<simplelist>
<member>
Массивом, описывающим канал (pipe) для передачи процессу. Первый
элемент — это дескриптор типа, второй - настройка для выбранного типа.
Возможные типы: <literal>pipe</literal> (второй элемент либо
<literal>r</literal> для передачи процессу стороны канала для
чтения, либо <literal>w</literal> для передачи стороны записи)
и <literal>file</literal> (второй элемент - имя файла).
Обратите внимание, что всё, кроме <literal>w</literal>, обрабатывается как <literal>r</literal>.
</member>
<member>
Ресурсом потока, представляющим дескриптор файла (например, открытый
файл, сокет, <constant>STDIN</constant>).
</member>
</simplelist>
</para>
<para>
Номера дескрипторов не ограничены только 0, 1 и 2 - вы можете назначить
любой действительный номер дескриптора и он будет передан дочернему
процессу. Это позволяет скрипту взаимодействовать с другими скриптами,
работающими, как параллельные процессы. В частности, таким образом можно
передавать данные, требующие защиты, в программы вроде PGP, GPG и
openssl более безопасно. Также это может оказаться полезным для чтения
статусной информации, предоставляемой этими программами на
вспомогательных файловых дескрипторах.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>pipes</parameter></term>
<listitem>
<para>
Будет задан массивом указателей на файлы, соответствующие созданным
каналам передачи данных PHP.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>cwd</parameter></term>
<listitem>
<para>
Рабочая директория команды. Это должен быть
<emphasis role="strong">абсолютный</emphasis> путь к директории или
&null;, если требуется использовать директорию по умолчанию (рабочая
директория текущего процесса PHP).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>env_vars</parameter></term>
<listitem>
<para>
Массив переменных окружения для запускаемой команды или &null;, если
требуется использовать то же самое окружение, что и у текущего PHP-процесса.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>options</parameter></term>
<listitem>
<para>
Позволяет задать дополнительные настройки. На данный момент
поддерживаются следующие настройки:
<simplelist>
<member>
<literal>suppress_errors</literal> (только для Windows): при установке
в &true; не будут показываться ошибки, возникающие в ходе работы
функции
</member>
<member>
<literal>bypass_shell</literal> (только для Windows): при установке в
&true; процесс будет запущен в обход оболочки
<literal>cmd.exe</literal>
</member>
<member>
<literal>blocking_pipes</literal> (только для Windows): принудительно
блокировать поток при значении &true;
</member>
<member>
<literal>create_process_group</literal> (только для Windows): разрешить
дочернему процессу обрабатывать <literal>CTRL</literal> события, если установлено значение &true;
</member>
<member>
<literal>create_new_console</literal> (только для Windows): новый процесс использует новую консоль, а не наследует консоль своего родителя
</member>
</simplelist>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
Функция возвращает ресурс, который представляет процесс. Этот ресурс требуется освобождать
функцией <function>proc_close</function> по завершении работы с ним.
Функция возвращает &false;, если возникла ошибка.
</para>
</refsect1>
<refsect1 role="errors">
&reftitle.errors;
<simpara>
Начиная с версии PHP 8.3.0, функция выбрасывает ошибку <exceptionname>ValueError</exceptionname>,
если значение параметра <parameter>command</parameter> представляет собой массив,
в котором нет хотя бы одного непустого элемента.
</simpara>
</refsect1>
<refsect1 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>8.3.0</entry>
<entry>
Теперь функция выбрасывает ошибку <exceptionname>ValueError</exceptionname>,
если значение параметра <parameter>command</parameter> представляет собой массив,
в котором нет хотя бы одного непустого элемента.
</entry>
</row>
<row>
<entry>7.4.4</entry>
<entry>
Добавлена опция <literal>create_new_console</literal> в
параметр <parameter>options</parameter>.
</entry>
</row>
<row>
<entry>7.4.0</entry>
<entry>
<function>proc_open</function> теперь также принимает массив (&array;)
в <parameter>command</parameter>.
</entry>
</row>
<row>
<entry>7.4.0</entry>
<entry>
Добавлена опция <literal>create_process_group</literal> в
параметр <parameter>options</parameter>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</refsect1>
<refsect1 role="examples">
&reftitle.examples;
<para>
<example>
<title>Пример использования <function>proc_open</function></title>
<programlisting role="php">
<![CDATA[
<?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";
}
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
Array
(
[some_option] => aeiou
[PWD] => /tmp
[SHLVL] => 1
[_] => /usr/local/bin/php
)
команда вернула 0
]]>
</screen>
</example>
</para>
<para>
<example>
<title><function>proc_open</function> причуда в Windows</title>
<simpara>
Хотя можно ожидать, что следующая программа будет искать в файле
<filename>filename.txt</filename> текст <literal>search</literal>
и выводить результаты, она ведёт себя несколько иначе.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$descriptorspec = [STDIN, STDOUT, STDOUT];
$cmd = '"findstr" "search" "filename.txt"';
$proc = proc_open($cmd, $descriptorspec, $pipes);
proc_close($proc);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
'findstr" "search" "filename.txt' не распознается как внутренняя или внешняя команда,
работающая программа или пакетный файл.
]]>
</screen>
<simpara>
Чтобы обойти это поведение, обычно достаточно передать <parameter>command</parameter> в дополнительных кавычках:
</simpara>
<programlisting role="php">
<![CDATA[
$cmd = '""findstr" "search" "filename.txt""';
]]>
</programlisting>
</example>
</para>
</refsect1>
<refsect1 role="notes">
&reftitle.notes;
<note>
<para>
Совместимость с Windows: Дескрипторы дальше 2 (stderr) наследуются
дочерними процессам, однако с тех пор как Windows не ассоциирует номера
файловых дескрипторов с низкоуровневыми обработчиками, дочерние процессы
не имеют (пока) к ним доступа. Это не относится к stdin, stdout и stderr.
</para>
</note>
<note>
<para>
Если нужен однонаправленный канал процесса, используйте функцию
<function>popen</function>, так как она значительно проще в использовании.
</para>
</note>
</refsect1>
<refsect1 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>popen</function></member>
<member><function>exec</function></member>
<member><function>system</function></member>
<member><function>passthru</function></member>
<member><function>stream_select</function></member>
<member><link linkend="language.operators.execution">Оператор обратный апостроф</link></member>
</simplelist>
</para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->