外部コマンドを実行する関数「system」と「exec」の比較
PHPでバッチやコマンドラインプログラムを作る時は手軽に外部コマンドをコールするのもありだと思う。
その際、「system」と「exec」どちらを使うべきか迷ったので両者の挙動を検証してみた。
string system ( string command [, int &return_var] )
pwd コマンドを呼び出す
% php -r '$cmd = "pwd"; system($cmd, $arr); var_dump($arr);' /path/to/current int(0)
存在しない badcommand を呼び出す
% php -r '$cmd = "badcommand"; system($cmd, $arr); var_dump($arr);' sh: badcommand: command not found int(127)
結果は標準出力に吐かれ、終了ステータスコードが第二引数の参照に渡される
結果を受け取りたい時は $res = system($cmd, $arr); とする(後述)
string exec ( string command [, array &output [, int &return_var]] )
pwd コマンドを呼び出す
% php -r '$cmd = "pwd"; exec($cmd, $arr, $res); var_dump($arr); var_dump($res);' array(1) { [0]=> string(16) "/path/to/current" } int(0)
存在しない badcommand を呼び出す
% php -r '$cmd = "badcommand"; exec($cmd, $arr, $res); var_dump($arr); var_dump($res);' sh: badcommand: command not found array(0) { } int(127)
結果は第二引数の参照に渡され、終了ステータスコードが第三引数の参照に渡される
system は結果を標準出力に吐くところがちょっと嫌。(使いどころによっては便利だが)
また、下記のように結果を受けるようにした場合、最後の1行しか取得できない。
この仕様を知らないと思わぬところでハマリそう。
% php -r '$cmd = "ls -l"; $res = system($cmd, $arr); var_dump($res); var_dump($arr);' total 0 -rw-rw-r-- 1 hogeho fugafu 0 Sep 28 16:32 aaa -rw-rw-r-- 1 hogeho fugafu 0 Sep 28 16:34 bbb -rw-r--r-- 1 hogeho fugafu 0 Sep 28 16:36 ccc string(47) "-rw-r--r-- 1 hogeho fugafu 0 Sep 28 16:36 ccc" int(0)
上記の理由から、外部コマンドを呼ぶときは「exec」に決定。
バッチでは終了ステータスだけ見て、結果が必要ない場合が多いので以下のようなコードが現実的。
function removeTempFiles() { $cmd = 'rm -f /path/to/tmp/*'; exec($cmd, $arr, $res); if ($res === 0) { return true; } else { return false; } }
もし、$cmd 変数に信頼できない値が混入する可能性がある時は「escapeshellcmd」や「escapeshellarg」をかましてセキュリティー対策も忘れずに。
ちなみに、結果だけ必要で終了ステータスコードが不要な場合は shell_exec を使ってもよい
% php -r '$cmd = "ls -l"; $res = shell_exec($cmd); var_dump($res);' string(152) "total 0 -rw-rw-r-- 1 hogeho fugafu 0 Sep 28 16:32 aaa -rw-rw-r-- 1 hogeho fugafu 0 Sep 28 16:34 bbb -rw-r--r-- 1 hogeho fugafu 0 Sep 28 16:36 ccc "
なお、shell_exec は実行演算子 バッククォート (``) のエイリアスでもある。
$res = `ls -l`;
と書いてもOK。