proc_open
(PHP 4 >= 4.3.0, PHP 5, PHP 7)
proc_open — コマンドを実行し、入出力用にファイルポインタを開く
説明
proc_open
( mixed $cmd
, array $descriptorspec
, array &$pipes
[, string $cwd
[, array $env
[, array $other_options
]]] ) : resource
proc_open() は popen() と よく似ていますが、プログラムの実行をさらに細かく制御できる点で違います。
パラメータ
cmd
実行するコマンドラインを string として渡します。 特殊な文字は適切にエスケープされ、適切にクォートされます。
注意:
Windows では、
other_options
のbypass_shell
をtrue
に設定しないと、 cmd.exe (実際は%ComSpec%
) にcmd
の値を クォートしないまま (つまり、proc_open() に渡されたそのままの値を)/c
と一緒に渡してしまいます。 この振る舞いによって、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) となります。
各要素は、次のようになります。
- プロセスに渡すパイプをあらわす配列。
最初の要素はディスクリプタの型で、2 番目の要素がその型に対応するオプションとなります。
使用できる型は
pipe
(2 番目の要素は、 プロセスにパイプの読み込み側を渡すのならr
、 書き込み側を渡すのならw
) およびfile
(2 番目の要素はファイル名) です。 - 実際のファイルディスクリプタ (オープンしたファイルやソケット、
STDIN
など) をあらわすストリームリソース。
ファイルディスクリプタの番号は、特に 0, 1, 2 に限られているわけでは ありません。有効であるどのようなファイルディスクリプタの番号も指定でき、 それは子プロセスに渡されます。これにより、あるスクリプトと、 子プロセスとして起動している別のスクリプトとの間で通信ができます。 特に、これは PGP や GPG、openssl といったプログラムにパスフレーズを より安全な方法で渡したいとき威力を発揮します。 補助的なファイルディスクリプタを介して、そのようなプログラムの 状態を取得するのにも便利です。
- プロセスに渡すパイプをあらわす配列。
最初の要素はディスクリプタの型で、2 番目の要素がその型に対応するオプションとなります。
使用できる型は
pipes
PHP 側で生成されたパイプの終端にあたる ファイルポインタの配列。
cwd
コマンドの初期作業ディレクトリ。 完全パスである必要があります。 デフォルト値 (現在の PHP プロセスの作業ディレクトリ) を使用したい場合は
null
を指定します。env
実行するコマンドのための環境変数の配列。 現在の PHP プロセスと同じ環境変数を使用する場合は
null
を指定します。other_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 を持ちます。
変更履歴
バージョン | 説明 |
---|---|
7.4.4 | other_options パラメータに
オプション |
7.4.0 | proc_open() 関数は、
|
7.4.0 | other_options パラメータに
オプション |
例
例1 A proc_open() の例
<?php$descriptorspec = array( 0 => 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], '<?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";}?>
上の例の出力は、 たとえば以下のようになります。
Array ( [some_option] => aeiou [PWD] => /tmp [SHLVL] => 1 [_] => /usr/local/bin/php ) command returned 0
例2 proc_open() 関数の癖(Windows限定)
次のプログラムで、ファイル filename.txt
にある
search
というテキストを検索し、結果を出力したいのですが、
実際にはかなり異なる振る舞いをします。
<?php$descriptorspec = [STDIN, STDOUT, STDOUT];$cmd = '"findstr" "search" "filename.txt"';$proc = proc_open($cmd, $descriptorspec, $pipes);proc_close($proc);?>
上の例の出力は以下となります。
'findstr" "search" "filename.txt' is not recognized as an internal or external command, operable program or batch file.
この振る舞いを避けるには、
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 で指定されたタイムアウト時間をもって行う
- バックティック演算子