PHP-CLIの「正しい」システム()

注意! すべての考慮事項は、Webサーバーモジュールとしてではなく、CLIモードでのPHPの実行に適用されます!

PHPでsystem()関数を使用したことがある場合、おそらくsystem()がコマンドの最後の行を返し、コマンドの結果をWebページに表示し、自分自身ではなくstdout web -サーバー? そして、なぜsystem()はCのsystem()のように機能しないのですか? 一般的に、答えは見かけよりも簡単です。

実際、PHPのsystem()はexec()と同じ関数を使用します( int php_exec(int type、char * cmd、pval * array、pval * return_value TSRMLS_DC) )、結果を1行ずつ 、累積せずに出力しますexec()のような配列に入れ、文字列のみをバッファとして使用します。 ところで、system()関数のドキュメントはこの動作を示唆しています:
システム()呼び出しは、PHPがサーバーモジュールとして実行されている場合、出力の各行の後にWebサーバーの出力バッファーを自動的にフラッシュしようとします。

また、php_execは基本的にpopen()を使用して対応するコマンドを実行します。つまり、呼び出されたプログラムはSTDINを端末として認識せず、シェルから起動したときとは異なる形式で応答を返す可能性があります。

ラインバッファリングシステムの問題の解決()


行ごとに蓄積せずに、到着時に情報を確実に取得したい場合は、システムの代わりに単純にパススルーを使用できます。 これは、たとえばgit cloneが操作の進行状況を正しく表示するのに十分ですが、同時に、lsは1列に情報を出力します。実際、passthruはphp_execを使用し、したがってpopenを使用するため、結果として生じる結果

proc_open()を使用したソリューション


たとえば、lsでターミナルから実行したときと同じ情報を表示したい場合、および色のサポートが必要な場合は、proc_openを使用できます。
$handle = proc_open("ls", array(0=>STDIN,1=>STDOUT,2=>STDERR), $pipes); $retval = proc_close($handle); 


Unixの方法


原則として、上記の方法ですべてが機能します。
しかし、特別な倒錯が必要な場合、またはプログラムの起動時に何が起こるかを完全に制御したい場合は、古いUNIXの方法でこの問題を解決しようとすることができます:fork-exec(これは* nixおよびpcntl拡張の存在):
 function libcSystem($cmd) { $pid = pcntl_fork(); if($pid < 0) { return -1; } if($pid == 0) { pcntl_exec('/bin/sh', array('-c', $cmd), $_ENV); exit(127); } pcntl_waitpid($pid, $status); return pcntl_wexitstatus($status); } 


CLIのためにPHPでスクリプトを作成し、system()が正常に機能するようにする方法を理解したい人にとって、この記事が役立つことを願っています。

Source: https://habr.com/ru/post/J135200/


All Articles