PHPでsystem()を走らせたときに、エラーメッセージも取得する方法
システムコマンドを使ったときに、エラーメッセージってどうやって取得するんだろう??
・・・と、PHPのシステムコマンドのマニュアルを見ても出ない。
そういう時は、プロセスをちゃんとみるproc_openを使う。
http://jp.php.net/manual/ja/function.proc-open.php
で作った関数。
<?php function system_ex($cmd, $stdin = "") { $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w") ); $process = proc_open($cmd, $descriptorspec, $pipes); $result_message = ""; $error_message = ""; $return = null; if (is_resource($process)) { fputs($pipes[0], $stdin); fclose($pipes[0]); while ($error = fgets($pipes[2])){ $error_message .= $error; } while ($result = fgets($pipes[1])){ $result_message .= $result; } foreach ($pipes as $k=>$_rs){ if (is_resource($_rs)){ fclose($_rs); } } $return = proc_close($process); } return array( 'return' => $return, 'stdout' => $result_message, 'stderr' => $error_message, ); }
コマンド$cmdを走らせて、その結果を
<?php array( 'stdout' => $result_message, 'stderr' => $error_message, );
で所得してくれる。エラーメッセージをログに入れておきたい時とか便利。
サンプル
<?php $cmd = "ls hogehoge"; // こんなファイル・ディレクトリは存在しない $ret = system_ex($cmd, $input); var_dump($ret); /* array(2) { ["stdout"]=> string(0) "" ["stderr"]=> string(81) "ls: hogehoge: そのようなファイルやディレクトリはありません " */ }
入力をしたい場合
<?php $cmd = "grep hogehoge "; $input=<<<EOF hogehoge aaahogeaaahoge bbbhogehogeccc aaaaaaa bbbbbbbbbb EOF; $ret = system_ex($cmd, $input); var_dump($ret); /* array(2) { ["stdout"]=> string(24) "hogehoge bbbhogehogeccc " ["stderr"]=> string(0) "" } */
追記:10年振りに改良
実は、STDOUTが64Kを越えるとデッドロックが掛かるので、修正した。
ポイントは、tmpfile()を使ってファイルポインタを渡したところ。
<?php function system_ex($cmd, $stdin = "") { $descriptorspec = array( 0 => array("pipe", "r"), 1 => tmpfile(), 2 => array("pipe", "w") ); $process = proc_open($cmd, $descriptorspec, $pipes); $result_message = ""; $error_message = ""; $return = null; if (is_resource($process)) { fputs($pipes[0], $stdin); fclose($pipes[0]); while ($error = fgets($pipes[2])){ $error_message .= $error; } fseek($descriptorspec[1], 0); while ($result = fgets($descriptorspec[1])){ $result_message .= $result; } foreach ($pipes as $k=>$_rs){ if (is_resource($_rs)){ fclose($_rs); } } $return = proc_close($process); } if ($return !== 0){ throw new \Exception("Error in system command.\n => $cmd \n" . $error_message); } return array( 'return' => $return, 'stdout' => $result_message, 'stderr' => $error_message, ); }