Parallels Desktop 25% OFF クーポンあります

【PHP入門】外部コマンドを実行する5つの方法を比較

PHPで外部コマンドを実行する方法

PHPでUNIXコマンドを実行する方法っていろいろあって迷っちゃう♪と困り果てているあなたに朗報です。この記事では、以下の5つの方法を比較して解説します。

  • exec()
  • passthru()
  • system()
  • shell_exec()
  • 実行演算子 `…`

それぞれの使い方と特徴を解説し、どんな時にどれを使うべきかをズバリ教えちゃいます。

目次

PHPで外部コマンドを実行する方法の比較表

最初に結論を言いますね(親切設計)。コマンドの実行結果が文字列ならばexec()関数、バイナリならばpassthru()関数を使いましょう。他の関数は使いません。

方法コール時の出力実行結果の取得終了ステータスの取得出力の種類説明
exec()なし可能可能テキストテキストを扱うならこれ
passthru()あり不可可能バイナリバイナリを扱うならこれ
system()あり最後の行のみ可能テキストC言語のsystem関数に似ている
shell_exec()なし可能不可テキスト実行演算子と同じ
実行演算子可能不可テキストshell_exec()関数と同じ

ご覧のとおり、実行結果終了ステータスの両方を完全に取得できるのは、exec()関数だけです。そしてバイナリセーフなのはpassthuru()関数だけです。

system()関数は、コールするとすぐに実行結果を表示してしまうので、あまり使い勝手が良くないと私は思います。一旦変数に入れたいですよね。

shell_exec()関数と実行演算子は、まったく同じように動作します。終了ステータス(コマンドの実行が成功したか失敗したかの情報)を取得できないので、あまりおすすめできません。

上記の他に、PHPでコマンドを実行する関数としてpopen, proc_open, pcntl_execなどがあります。これらは、PHPスクリプトとは別のプロセスでコマンドを実行するための関数です。使い方がちょいと複雑なので、ここでは扱いません。初心者向けの記事なので。

exec()

exec()関数の書式

exec($command, $output, $result_code)
  • 第一引数$commandは、実行するコマンドを指定します。
  • 第二引数$outputを指定すると、コマンドの実行結果が格納されます。実行結果の各行が配列の要素として格納されます。行末のホワイトスペース(改行など)は取り除かれます。配列にすでに要素が入っている場合は、その後ろに追記されます。
  • 第三引数$result_codeを指定すると、コマンドの終了ステータスが格納されます。終了ステータスは、正常終了ならば0、異常終了ならば0以外になります。
  • 戻り値は、コマンドの実行結果の最後の行です。失敗時はfalseを返します。

exec()関数の使い方

まずls -l sample_dirというコマンドを実行して、戻り値を出力してみます。これはsample_dir内のファイル一覧を表示するコマンドです。

$command = 'ls -l sample_dir';
echo exec($command);

/*実行結果
drwxr-xr-x 2 masawo staff 64 6 14 01:04 sample3
*/

これでは、実行結果の最後の1行しか表示できません。

次は、第二引数を指定してすべての結果を取得する例です。

$command = 'ls -l sample_dir';
exec($command, $output);
print_r($output);

/*実行結果
Array
(
    [0] => total 16
    [1] => -rw-r--r--  1 masawo  staff   209  6 14 01:05 sample1.php
    [2] => -rw-r--r--  1 masawo  staff  1367  6 14 01:10 sample2.txt
    [3] => drwxr-xr-x  2 masawo  staff    64  6 14 01:04 sample3
)
*/

実行結果の各行が$outputの要素として格納されました。いえーい。

さらに、終了ステータスを取得してみましょう。

$command = 'ls -l sample_dir';
exec($command, $output, $result_code);
echo $result_code;

/*実行結果
0
*/
$command = 'ls -l nonexistent_dir'; //存在しないディレクトリを参照
exec($command, $output, $result_code);
echo $result_code;

/*実行結果
1
*/

コマンドの実行に成功した場合は0、失敗した場合は1が出力されました。いえーい。

終了ステータスで条件分岐をして、エラーメッセージを表示したりできますね。

$command = 'ls -l sample_dir';
exec($command, $output, $result_code);

//終了ステータスが0以外ならばエラー
if ($result_code) {
  echo 'コマンドの実行に失敗しました';
//終了ステータスが0ならば成功
} else {
  print_r($output);
}
プログラミング学習、お疲れさまです

プログラミングの独学に行き詰まっていませんか?誰かに相談したい、もっと効率よく学びたいなら、プログラミングスクールを検討してみてください。

passthru()

passthru()関数の書式

passthru($command, $result_code)
  • 第一引数$commandは、実行するコマンドを指定します。
  • 第二引数$result_codeを指定すると、コマンドの終了ステータスが格納されます。終了ステータスは、正常終了ならば0、異常終了ならば0以外になります。
  • 戻り値は、成功時にnull、失敗時にfalseを返します。
  • コールすると実行結果をそのまま出力します。

passthru()関数の使い方

まずはls -l sample_dirを実行してみましょう。

$command = 'ls -l sample_dir';
passthru($command);

/*実行結果
total 16
-rw-r--r--  1 masawo  staff   209  6 14 01:05 sample1.php
-rw-r--r--  1 masawo  staff  1367  6 14 01:10 sample2.txt
drwxr-xr-x  2 masawo  staff    64  6 14 01:04 sample3
*/

コマンドの実行結果が、何も加工されずにそのまま表示されました。exec()関数より簡単じゃんと思ったかもしれませんが、このpassthru()関数は実行結果をただ出力するだけです。変数に入れておいてゴニョゴニョするということはできませんのでご注意ください。

passthru()関数が実力を発揮するのは、バイナリデータを扱うときです。PNG画像を表示する例を見てみましょう。

header('Content-Type: image/png');
$command = 'cat image.png';
passthru($command);

/*実行結果
(画像が表示されます)
*/

最初にheader()関数を使ってHTTPヘッダを送信します。ブラウザに画像を表示するには、画像データを出力する前にContent-Typeを送信しておく必要があります。次にcat image.pngコマンドを実行して画像ファイルのデータをそのまま出力しています。

passthru()の出力を変数に入れたい

passthru()は実行結果をブラウザなどに直接出力する関数です。そうではなく、変数に格納したいというワガママなあなたにPHPの出力制御関数を使う方法を伝授します。

//出力のバッファリングを開始する
ob_start();

//コマンドの実行
$command = 'cat image.png';
passthru($command);

//バッファの内容を変数に格納
$output = ob_get_contents();

//バッファをクリアしバッファリングを終了する
ob_end_clean();

バッファリングとは、出力を一旦バッファに溜めておくことです。頭痛薬ではありません(つまらない)。この例ではpassthru()関数の出力をすぐに表示せずにバッファリングして、そのデータをob_get_contents()関数を使って変数$outputに格納しています。

system()

system()関数の書式

system($command, $result_code)
  • 第一引数$commandは、実行するコマンドを指定します。
  • 第二引数$result_codeを指定すると、コマンドの終了ステータスが格納されます。終了ステータスは、正常終了ならば0、異常終了ならば0以外になります。
  • 戻り値は、コマンドの実行結果の最後の行です。失敗時はfalseを返します。
  • コールすると実行結果をそのまま出力します。

system()関数の使い方

いつものls -l sample_dirコマンドを実行してみます。

$command = 'ls -l sample_dir';
system($command);

/*実行結果
total 16
-rw-r--r--  1 masawo  staff   209  6 14 01:05 sample1.php
-rw-r--r--  1 masawo  staff  1367  6 14 01:10 sample2.txt
drwxr-xr-x  2 masawo  staff    64  6 14 01:04 sample3
*/

実行結果がすべて表示されました。

exec()関数と比較すると、実行結果をただ表示するだけならばsystem()関数のほうが簡単なんですけど、それだけなんですよね。ケースバイケースで使い分けるほどの魅力を感じないです(辛口)。

shell_exec()

shell_exec()関数の書式

shell_exec($command)
  • 引数$commandは、実行するコマンドを指定します。
  • 戻り値は、コマンドの実行結果です。失敗時はnullを返します。コマンドが何も出力しなかった場合もnullを返します。

shell_exec()関数の使い方

いつものls -l sample_dirコマンドを実行してみましょう。

$command = 'ls -l sample_dir';
$output = shell_exec($command);
echo $output;

/*実行結果
total 16
-rw-r--r--  1 masawo  staff   209  6 14 01:05 sample1.php
-rw-r--r--  1 masawo  staff  1367  6 14 01:10 sample2.txt
drwxr-xr-x  2 masawo  staff    64  6 14 01:04 sample3
*/

複数行の実行結果を取得して変数に入れることができます。終了ステータスの取得ができないのが欠点です。shell_exec()関数は、次に解説する実行演算子のエイリアスです。だから関数としてはとてもシンプルだけど機能面で物足りないんですね。

実行演算子

実行演算子の書式

$output = `$command`;

コマンドをバッククォート`...`で括ると、その実行結果を返します。

実行演算子の使い方

例のls -l sample_dirコマンドを実行してみましょう。

$output = `ls -l sample_dir`;
echo $output;

/*実行結果
total 16
-rw-r--r--  1 masawo  staff   209  6 14 01:05 sample1.php
-rw-r--r--  1 masawo  staff  1367  6 14 01:10 sample2.txt
drwxr-xr-x  2 masawo  staff    64  6 14 01:04 sample3
*/

とてもシンプルに書くことができます。シンプルすぎてコードを読む時にわかりにくいので、私は使いません。老眼だと、バッククォートとシングルクォートの区別がつかないのよね。

標準エラー出力を取得したい

例えば、ターミナルで次のようなコマンドを実行するとエラーメッセージが表示されます。

% ls -l nonexistent_dir #存在しないディレクトリを参照
ls: nonexistent_dir: No such file or directory

これまで紹介した5つの方法では、このエラーメッセージを取得することができません。これは、これらの関数が取得する実行結果は標準出力(stdout)のみだからです。

コマンドの実行に成功したときの出力を標準出力(stdout)、失敗したときの出力を標準エラー出力(stderr)といいます。標準エラー出力を取得するには、コマンドの最後に2>&1という呪文を追加します。

$command = 'ls -l nonexistent_dir 2>&1';
exec($command, $output);
print_r($output);

/*実行結果
Array
(
    [0] => ls: nonexistent_dir: No such file or directory
)
*/

2>&1は、標準出力と標準エラー出力をまとめて出力するための呪文です。なので、成功すれば実行結果が出力されるし、失敗すればエラーメッセージが出力されます。

さいごに

というわけで、PHPで外部コマンドを実行する方法を比較しました。もう一度いいますが、

  • コマンドの出力がテキストならばexec()関数
  • コマンドの出力がバイナリならばpassthru()関数

です。他の方法は使いません。覚えなくていいです。私を信じてください。

でわでわ

プログラミング学習、お疲れさまです

プログラミングの独学に行き詰まっていませんか?誰かに相談したい、もっと効率よく学びたいなら、プログラミングスクールを検討してみてください。

PHPで外部コマンドを実行する方法

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次