mirror of
https://github.com/php/doc-zh.git
synced 2026-03-24 07:02:15 +01:00
402 lines
14 KiB
XML
402 lines
14 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
<!-- EN-Revision: 6667724b8a42ba501172bc874dd1644a6744be0f Maintainer: yuanyuqiang Status: ready -->
|
||
<!-- CREDITS: mowangjuanzi -->
|
||
<!-- splitted from ./en/functions/exec.xml, last change in rev 1.28 -->
|
||
<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>popen</function> 函数,
|
||
但是 <function>proc_open</function> 提供了更加强大的控制程序执行的能力。
|
||
</para>
|
||
|
||
<!-- ptys are currently disabled in the sources
|
||
<para>
|
||
PHP 5 introduces pty support for systems with Unix98 ptys. This allows
|
||
your script to interact with applications that expect to be talking to a
|
||
terminal. A pty works like a pipe, but is bi-directional, so there is no
|
||
need to specify a read/write mode. The example below shows how to use a
|
||
pty; note that you don't have to have all descriptors talking to a pty.
|
||
Also note that only one pty is created, even though pty is specified 3
|
||
times. In a future version of PHP, it might be possible to do more than
|
||
just read and write to the pty.
|
||
</para>
|
||
-->
|
||
|
||
</refsect1>
|
||
|
||
<refsect1 role="parameters">
|
||
&reftitle.parameters;
|
||
<para>
|
||
<variablelist>
|
||
<varlistentry>
|
||
<term><parameter>command</parameter></term>
|
||
<listitem>
|
||
<para>
|
||
以 &string; 形式执行的命令行。特殊字符必须经过转义,并且使用正确的引号。
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
在 <emphasis>Windows</emphasis> 上, 除非在 <parameter>options</parameter> 中
|
||
把 <literal>bypass_shell</literal> 设置为 &true;
|
||
,否则 <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; 类型传递。
|
||
在这种情况下,进程将直接打开(不通过 shell )。
|
||
而 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>
|
||
包含了要传送至进程的管道的描述信息的数组。第一个元素为描述符类型,第二个元素是针对该描述符的选项。有效的类型有:<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> shell。
|
||
</member>
|
||
<member>
|
||
<literal>blocking_pipes</literal> (仅用于 Windows 平台):
|
||
设置为 &true; 表示强制堵塞管道。
|
||
</member>
|
||
<member>
|
||
<literal>create_process_group</literal> (仅用于 Windows 平台):
|
||
设置为 &true; 表示允许子进程处理 <literal>CTRL</literal> 事件。
|
||
</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 起,如果 <parameter>command</parameter> 是没有元素的空数组,则会抛出 <exceptionname>ValueError</exceptionname>。
|
||
</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>
|
||
如果 <parameter>command</parameter> 是没有元素的空数组,将会抛出 <exceptionname>ValueError</exceptionname>。
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>7.4.4</entry>
|
||
<entry>
|
||
为 <parameter>options</parameter> 参数增加 <literal>create_new_console</literal> 选项。
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>7.4.0</entry>
|
||
<entry>
|
||
<function>proc_open</function> 的 <parameter>command</parameter> 参数现在也允许数组类型。
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>7.4.0</entry>
|
||
<entry>
|
||
为 <parameter>options</parameter> 参数增加 <literal>create_process_group</literal> 选项。
|
||
</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"), // 标准输入,子进程从此管道中读取数据
|
||
1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据
|
||
2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件
|
||
);
|
||
|
||
$cwd = '/tmp';
|
||
$env = array('some_option' => 'aeiou');
|
||
|
||
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
|
||
|
||
if (is_resource($process)) {
|
||
// $pipes 现在看起来是这样的:
|
||
// 0 => 可以向子进程标准输入写入的句柄
|
||
// 1 => 可以从子进程标准输出读取的句柄
|
||
// 错误输出将被追加到文件 /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 "command returned $return_value\n";
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
Array
|
||
(
|
||
[some_option] => aeiou
|
||
[PWD] => /tmp
|
||
[SHLVL] => 1
|
||
[_] => /usr/local/bin/php
|
||
)
|
||
command returned 0
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
<example>
|
||
<title><function>proc_open</function> 在 Windows 上的怪异行为</title>
|
||
<simpara>
|
||
虽然人们可能期望下面的程序能够搜索文件
|
||
<filename>filename.txt</filename> 进行文本搜索,
|
||
并打印结果,但它的行为相当不同。
|
||
</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' is not recognized as an internal or external command,
|
||
operable program or batch file.
|
||
]]>
|
||
</screen>
|
||
<simpara>
|
||
要解决该行为,通常只需将 <parameter>command</parameter> 加上引号:
|
||
</simpara>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
$cmd = '""findstr" "search" "filename.txt""';
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<!-- ptys are currently disabled
|
||
<para>
|
||
<example>
|
||
<title>ptys usage</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
// Create a pseudo terminal for the child process
|
||
$descriptorspec = array(
|
||
0 => array("pty"),
|
||
1 => array("pty"),
|
||
2 => array("pty")
|
||
);
|
||
$process = proc_open("cvs -d:pserver:cvsread@cvs.php.net:/repository login", $descriptorspec, $pipes);
|
||
if (is_resource($process)) {
|
||
// work with it here
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
-->
|
||
|
||
</refsect1>
|
||
|
||
<refsect1 role="notes">
|
||
&reftitle.notes;
|
||
<note>
|
||
<para>
|
||
Windows 兼容性:超过 2 的描述符也可以作为可继承的句柄传送到子进程。
|
||
但是,由于 Windows 的架构并不将文件描述符和底层句柄进行关联,
|
||
所以,子进程无法访问这样的句柄。
|
||
标准输入,标准输出和标注错误会按照预期工作。
|
||
</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>The <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
|
||
-->
|