本記事では、PHPから外部コマンドを実行する関数の使い方を紹介する。
PHPから外部コマンドを実行する方法一覧
まずPHPから外部コマンドを実行する関数は以下の6つがある
よく使うのは exec() 、shell_exec(), で、他には
passthru()もバイナリの結果を標準出力(画面)に出力するときに使用する
なので本記事では、exec() 、shell_exec()、passthru()について、
PHPから外部コマンドを実行しその結果を取得する方法を紹介していく。
exec関数の使い方
まずはexec関数から外部コマンドを実行しその結果を取得する方法を紹介していく。
以下の例では、「ls -l」コマンド(指定したディレクトリに存在するファイルやディレクトリを一覧で取得する)を実行してみる。
サンプルとして、以下のような test_dir ディレクトリを作成した
>ls -l test_dir
-rw-r--r-- 1 root staff 0 Nov 20 13:07 example.sh
-rw-r--r-- 1 root staff 0 Nov 20 13:07 sample.php
-rw-r--r-- 1 root staff 0 Nov 20 13:05 test.txt
exec関数の書式
exec(コマンド, アウトプット配列, 実行結果ステータス);
exec関数に指定できる引数は3つあり、使い方が想像しづらいと思うので、一つ一つサンプルプログラムを通して説明していく。
サンプルプログラム①
では実際にexec関数に、「ls -l test_dir」というコマンドを指定して結果を出力してみる。
<?php
$cmd = 'ls -l test_dir';
echo exec($cmd);
?>
実行結果:
-rw-r--r-- 1 root staff 0 Nov 20 13:05 test.txt
まずは引数の一つ目だけを指定した例。
外部コマンドの結果を取得することができたが、最後の一行しか表示されていない。
これはexec関数は第二引数のアウトプットを指定しないと、実行結果の最後の行しか返さないからだ。
サンプルプログラム② 出力結果をすべて取得する
exec関数で外部コマンドの全ての出力結果を取得するには、前述したように第二引数にアウトプット用の配列を指定する必要がある。
以下に第二引数を指定して、出力結果を全て取得する方法を記述する。
<?php
$cmd = 'ls -l test_dir';
exec($cmd, $output);
print_r($output);
?>
実行結果:
Array
(
[0] => total 0
[1] => -rw-r--r-- 1 root staff 0 Nov 20 13:07 example.sh
[2] => -rw-r--r-- 1 root staff 0 Nov 20 13:07 sample.php
[3] => -rw-r--r-- 1 root staff 0 Nov 20 13:05 test.txt
)
第二引数に指定したアウトプット用の配列の結果をprint_r()してみた。
出力結果の行毎に、配列として要素に格納されているのが分かるだろう。
上記のように第二引数を指定すれば、出力結果をすべて1行ごとに配列に格納することが可能だ。
サンプルプログラム③ ステータスを取得する
exec関数によるコマンドが正常に終了したかを確認する場合は、第三引数のステータスを指定する。ステータスはLinuxのコマンド同様に、正常終了の場合0、失敗の場合0以外となる。
以下に第三引数を指定して、実行結果のステータスを取得する方法を記述する。
サンプルプログラム(正常終了):
<?php
$cmd = 'ls -l test_dir';
exec($cmd, $output, $result);
echo '実行結果:'.$result;
?>
実行結果(正常終了):
実行結果:0
コマンドが正常に終了したため、0が出力された。
次に失敗する例を試してみる
サンプルプログラム(失敗):
<?php
$cmd = 'ls -l test_dirrrrrrrrrrrrrrrrr'; 存在しないディレクトリを指定
exec($cmd, $output, $result);
echo '実行結果:'.$result;
?>
実行結果(失敗):
ls: test_dirrrrrrrrrrrrrrrrr: No such file or directory
実行結果:1
存在しないディレクトリを指定したので、実行結果は1(失敗)となった。
このようにexecコマンドは第三引数を指定すれば、コマンドの成功有無をステータスで判断できる。
サンプルプログラム④ 配列に値を追加する
exec関数は、既に値が設定されている配列を第二引数に指定した場合、execコマンドによる実行結果がその配列の要素の最後から追加される。
サンプルプログラム:
<?php
$output = ["test1", "test2", "test3"];
$cmd = 'ls test_dir';
exec($cmd, $output, $result);
print_r($output);
?>
実行結果:
Array
(
[0] => test1
[1] => test2
[2] => test3
[3] => example.sh
[4] => sample.php
[5] => test.txt
)
このように配列の要素の最後に、lsコマンドの結果が追加されていることが分かる。
shell_exec関数の使い方
次にshell_exec関数から外部コマンドを実行しその結果を取得する方法を紹介していく。
shell_exec関数は、exec関数と同じく外部コマンドを実行し、出力結果を返す関数だ。
shell_exec関数の書式。
shell_exec( $コマンド )
引数:
引数は一つとなっており、実行する外部コマンドのみを指定する。
要はexec関数の簡易版とでも言えば良いだろう。
返り値:
実行されたコマンドの出力を返す。
実行時にエラーが発生、または何も出力しなかった場合はNULLを返す。
execコマンドと異なる点は以下となる
- 第二引数に結果を格納するための配列が指定できない。
- 第三引数にステータスを指定できないため、実行に失敗したかどうかを判断することができない。
なので、exec関数とshell_exec関数の使い分けとしては、
- 単純に外部コマンドを実行するだけならshell_exec関数。
- 出力結果を配列で格納したり、実行時のステータスが知りたい場合はexec関数。
と、使い分けると良いだろう。
以下はshell_exec関数の簡単なサンプル。
サンプルプログラム:
<?php
$output = shell_exec('ls -l test_dir');
echo $output;
?>
実行結果:
total 0
-rw-r--r-- 1 root staff 0 Nov 20 13:07 example.sh
-rw-r--r-- 1 root staff 0 Nov 20 13:07 sample.php
-rw-r--r-- 1 root staff 0 Nov 20 13:05 test.txt
標準エラーを取得するには
shell_exec も exec も、結果を取得するのは標準出力(STDOUT)だけだ。
標準エラー(STDERR)を取得するにはコマンドの最後に「2>&1」を追加するとよい。
例:
$command = 'ls -l';
$output = shell_exec("{$command} 2>&1");
print_r($output);
passthru関数の使い方
次にpassthru関数から外部コマンドを実行しその結果を取得する方法を紹介していく。
passthru関数もこれまで同様、外部コマンドを実行し、出力結果を返す関数だ。
<?php
passthru ('ls -l test_dir');
?>
実行結果:
total 0
-rw-r--r-- 1 root staff 0 Nov 20 13:07 example.sh
-rw-r--r-- 1 root staff 0 Nov 20 13:07 sample.php
-rw-r--r-- 1 root staff 0 Nov 20 13:05 test.txt
外部コマンド実行結果をバイナリで受け取る
passthru()関数を使うと、実行結果がバイナリでもそのまま受け取ることが可能だ。
<?php
passthru ('cat img.png');
?>
実行結果:
?PNG
IHDR??/??gAMA??
?a cHRMz&?????u0?`:?p??Q<xeXIfMMJ(?iZ``???tY?* pHYs???+iTXtXML:com.adobe.xmp<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
xmlns:exif="http://ns.adobe.com/exif/1.0/">
<tiff:YResolution>96</tiff:YResolution>
<tiff:ResolutionUnit>2</tiff:ResolutionUnit>
<tiff:XResolution>96</tiff:XResolution>
<tiff:Orientation>1</tiff:Orientation>
<exif:PixelXDimension>1000</exif:PixelXDimension>
<exif:ColorSpace>1</exif:ColorSpace>
<exif:PixelYDimension>641</exif:PixelYDimension>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
??߯???U(??7????oăʪ?~3듕xߧ??7??'Oւ ?]???kg P A ?@H?+??@@@H??G?%QQ???F C??
P?
?6@@@t T@??;?M@@@@?? ? A??N`@@@ A?3 ?@H?+??@@@H??
P?
?6@@@t T@??;?M@@@@?? ? A??N`@@@ A?3 ?@H?+??@@@H??
P?
?6@@@t T@??;?M@@@@?? ? A??N`@@@ A?3 ?@H?+??@@@H??
P?
以下略
上記のように、バイナリの結果を受けとってそのまま出力することが可能だ。
まとめ
今回はPHPで外部コマンドを実行する、PHPをコマンドラインから実行するということについて解説した。
外部コマンドを実行するexec関数、shell_exec関数、passthru関数は、
- コマンドプロンプトやターミナルから実行するコマンドをそのまま使用できる。
- Linuxやコマンドプロンプトなどの外部コマンドや外部プログラムを実行することができる。
① exec()
コマンド実行結果を指定した変数へ返す(配列で取得)
② shell_exec()
コマンド実行結果を全て取得(スカラーで取得)
③ passthru()
コマンド実行結果を直接標準出力へ出力。戻り値はナシ。指定した変数へUnixコマンド実行結果が帰る
passthru()関数はexec()関数と同様にコマンドを実行する。 Unix コマンドからの出力がバイナリデータであり、 ブラウザーへ直接返す必要がある場合 passthru()を 使用する必要がある。
④ system()
コマンド実行結果のうち最後の一行だけ取得
⑤ popen()
プロセスへのファイルポインタをオープンする
⑥ proc_open()
プロセスへの入出力用ファイルポインタを開く