proc_open
コマンドを実行し、入出力用にファイルポインタを開く
&reftitle.description;
resourcefalseproc_open
arraystringcommand
arraydescriptor_spec
arraypipes
stringnullcwd&null;
arraynullenv_vars&null;
arraynulloptions&null;
proc_open は popen と
よく似ていますが、プログラムの実行をさらに細かく制御できる点で違います。
&reftitle.parameters;
command
実行するコマンドラインを &string; として渡します。
特殊な文字は適切にエスケープされ、適切にクォートされます。
Windows では、
options の bypass_shell を &true; に設定しないと、
cmd.exe (実際は%ComSpec%) に
command の値を クォートしないまま
(つまり、proc_open に渡されたそのままの値を)
/c と一緒に渡してしまいます。
この振る舞いによって、cmd.exe が
command からクォートを削除してしまうため、
(詳細は cmd.exe のドキュメントを参照ください)
予期しない、潜在的に危険とさえ言える結果になります。なぜなら、
cmd.exe のエラーメッセージには、
渡された command (の一部) が含まれる可能性があるからです(下の例を見てください)。
PHP 7.4.0 以降、command にはコマンドの引数も含めた &array; を渡せるようになりました。
この場合、プロセスは直接(シェルを介さずに)オープンされ、PHP が必要な引数のエスケープを全て行います。
Windows では、&array; で渡されるコマンドライン引数のエスケープは、
コマンドライン引数の解釈が
VCランタイムによって行われるものと互換性があることを前提にして行われます。
descriptor_spec
数値添字の配列で、ディスクリプタ番号をキーとし、PHP がその
ディスクリプタをどのように子プロセスに渡すかを表すのが
対応する値となります。
0 が標準入力 (stdin)、1 が標準出力 (stdout) で、
2 が標準エラー出力 (stderr) となります。
各要素は、次のようになります。
プロセスに渡すパイプをあらわす配列。
最初の要素はディスクリプタの型で、2 番目の要素がその型に対応するオプションとなります。
使用できる型は pipe (2 番目の要素は、
プロセスにパイプの読み込み側を渡すのなら r、
書き込み側を渡すのなら w)
および file (2 番目の要素はファイル名)
です。
w 以外に何を指定しても、
r のように扱われるので注意して下さい。
実際のファイルディスクリプタ (オープンしたファイルやソケット、
STDIN など) をあらわすストリームリソース。
ファイルディスクリプタの番号は、特に 0, 1, 2 に限られているわけでは
ありません。有効であるどのようなファイルディスクリプタの番号も指定でき、
それは子プロセスに渡されます。これにより、あるスクリプトと、
子プロセスとして起動している別のスクリプトとの間で通信ができます。
特に、これは PGP や GPG、openssl といったプログラムにパスフレーズを
より安全な方法で渡したいとき威力を発揮します。
補助的なファイルディスクリプタを介して、そのようなプログラムの
状態を取得するのにも便利です。
pipes
PHP 側で生成されたパイプの終端にあたる
ファイルポインタの配列。
cwd
コマンドの初期作業ディレクトリ。
完全パスである必要があります。
デフォルト値 (現在の PHP プロセスの作業ディレクトリ) を使用したい場合は
&null; を指定します。
env_vars
実行するコマンドのための環境変数の配列。
現在の PHP プロセスと同じ環境変数を使用する場合は
&null; を指定します。
options
その他の追加オプションを指定することが可能です。
現在サポートされているオプションは次の通りです。
suppress_errors (windows のみ):
&true; にすると、この関数が出力するエラーを抑制します。
bypass_shell (windows のみ):
&true; にすると、cmd.exe シェルをバイパスします。
blocking_pipes (windows のみ):
&true; に設定すると、パイプを強制的に切断します。
create_process_group (Windows のみ):
&true; に設定すると、
子プロセスが CTRL イベントを
ハンドルすることを許可します。
create_new_console (windows のみ):
新しいプロセスは親の console を継承せず、新しい console を持ちます。
&reftitle.returnvalues;
プロセスを表すリソースを返します。このリソースは、使用し終えた際に
proc_close を使用して開放する必要があります。
失敗した場合は &false; を返します。
&reftitle.errors;
PHP 8.3.0 以降では、
command
に配列を指定したのに、空でない要素を最低一つ含んでいない場合
ValueError
をスローするようになりました。
&reftitle.changelog;
&Version;
&Description;
8.3.0
command
に配列を指定したのに、空でない要素を最低一つ含んでいない場合
ValueError
をスローするようになりました。
7.4.4
options パラメータに
オプション create_new_console が追加されました。
7.4.0
proc_open 関数は、
command に &array; を渡せるようになりました。
7.4.0
options パラメータに
オプション create_process_group が追加されました。
&reftitle.examples;
proc_open の例
array("pipe", "r"), // stdin は、子プロセスが読み込むパイプです。
1 => array("pipe", "w"), // stdout は、子プロセスが書き込むパイプです。
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 => 子プロセスの stdin に繋がれた書き込み可能なハンドル
// 1 => 子プロセスの stdout に繋がれた読み込み可能なハンドル
// すべてのエラー出力は /tmp/error-output.txt に書き込みされます。
fwrite($pipes[0], '');
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";
}
?>
]]>
&example.outputs.similar;
aeiou
[PWD] => /tmp
[SHLVL] => 1
[_] => /usr/local/bin/php
)
command returned 0
]]>
proc_open 関数の癖(Windows限定)
次のプログラムで、ファイル filename.txt にある
search というテキストを検索し、結果を出力したいのですが、
実際にはかなり異なる振る舞いをします。
]]>
&example.outputs;
この振る舞いを避けるには、
command を追加のクォートで囲めば通常は十分です:
&reftitle.notes;
Windows における互換性: 2 (stderr) よりも大きな番号のディスクリプタは
子プロセスに継承可能なハンドルとして渡されますが、
Windows のアーキテクチャは、ファイルディスクリプタの番号と
より低レベルなハンドルを関連付けないので、子プロセスは、
それらのハンドルにアクセスする術を持ちません。stdin, stdout, stderr
は期待通り動きます。
もし単方向(一方向)のパイプを利用したいだけでしたら、
popen を使うほうがより簡単です。
&reftitle.seealso;
popen
exec
system
passthru
stream_select
バッククォート演算子