【PHP入門】外部コマンドの実行(exec)とコマンドライン実行の方法

PHPではプログラムの中からLinuxやコマンドプロンプトで使用するコマンドを実行したり、シェルスクリプトなどの外部プログラムを実行するための関数が用意されています。

この記事ではexec関数で外部コマンドを実行する基本的な方法から、

  • 外部コマンドによる出力結果を全て取得する方法
  • 外部コマンドによる実行結果のステータスを取得する方法
  • pingによるネットワーク機器の疎通確認をする方法
  • sshによるリモートコマンドを実行する方法
  • shell_exec関数を使用した外部コマンドの実行方法

などのexec関数の応用的な使い方についても解説します。

さらに、

  • PHPをコマンドラインから実行する方法
  • PHPをコマンドラインから実行する時に便利なオプション

についても解説していきます!

目次

exec関数とは

PHPのプログラムから、外部コマンドやプログラムを実行するにはexec関数を使用します。

外部コマンドとは、Windowsのコマンドプロンプトで実行するコマンドや、MacやLinuxのターミナルからのコマンドによる命令文のことを指します。

exec関数では、そんな外部コマンドを指定して実行することが可能です。exec関数は以下のように記述します。

書き方:

string exec(string $コマンド [, array &$アウトプット [, int &$ステータス ]] )

引数:
第一引数には実行するコマンドやプログラム名を指定します。第二引数を指定した場合は、コマンドの出力結果を各行ごとに配列に格納されます。第三引数を指定した場合は実行したコマンドのステータスを取得できます。

返り値:
コマンドの出力の最後の行を文字列で返します。

exec関数の使い方

ここでは実際にexec関数を使用して、外部コマンドを実行してみましょう。

以下の例では指定したディレクトリに存在するファイルやディレクトリを一覧で取得するコマンド「ls -l」を実行してみます。

Windowsの場合は同様のコマンドである「dir」を指定すると良いでしょう。

サンプルプログラム:

<?php
 
$cmd = 'ls -l /opt';
echo exec($cmd);
 
?>

実行結果:

drwxr-xr-x     5 root  wheel    170 Jun 10 16:14 standalone

外部コマンドの結果を取得することができましたが、一行でしか表示されていませんね……。

これはexec関数は第二引数のアウトプットを指定しないと、実行結果の最後の行しか返さないからです。

出力結果をすべて取得する

exec関数で外部コマンドの全ての出力結果を取得するには、前述したように第二引数にアウトプット用の配列を指定する必要があります。

以下に第二引数を指定して、出力結果を全て取得する方法を記述します。

サンプルプログラム:

<?php
 
$cmd = 'ls -l /usr';
exec($cmd, $opt);
print_r($opt);
 
?>

実行結果:

Array
(
    [0] => total 8
    [1] => lrwxr-xr-x     1 root  wheel      8 Aug 30  2014 X11 -> /opt/X11
    [2] => drwxr-xr-x  1066 root  wheel  36244 Jun 10 16:15 bin
    ・・・省略・・・
)

このように第二引数を指定すれば、出力結果がすべて1行ごとに配列に格納されていますね!

ステータスを取得する

exec関数によるコマンドが正常に終了したかを確認する場合は、第三引数のステータスを指定します。ステータスはLinuxのコマンド同様に0(正常終了)、0以外(失敗)となります。

以下に第三引数を指定して、実行結果のステータスを取得する方法を記述します。

サンプルプログラム(正常終了):

<?php
 
$cmd = 'ls -l /usr';
exec($cmd, $opt, $return_ver);
echo '実行結果:'.$return_ver;
 
?>

実行結果(正常終了):

実行結果:0

サンプルでは、コマンドが正常に終了したため、0が出力されました。

以下は、存在しないディレクトリに対して「ls -l」コマンドを実行した結果です。

サンプルプログラム(失敗):

<?php
 
$cmd = 'ls -l /user';
exec($cmd, $opt, $return_ver);
echo '実行結果:'.$return_ver;
 
?>

実行結果(失敗):

実行結果:1

存在しないディレクトリを指定したので、実行結果は1(失敗)となりました。

このようにexecコマンドは第三引数を指定すれば、コマンドの成功有無をステータスで判断できることがわかりますね!

また、はじめに紹介したようにexecコマンドは、コマンド以外にも外部プログラムも同様に指定することが可能です。

配列に値を追加する

exec関数は、既に値が設定されている配列を第二引数に指定した場合、execコマンドによる実行結果がその配列の要素の最後から追加されます。

サンプルプログラム:

<?php
 
$opt = ['apple', 'orange', 'melon'];
 
$cmd = 'ls';
exec($cmd, $opt, $return_ver);
print_r($opt);
 
?>

実行結果:

Array
(
    [0] => apple
    [1] => orange
    [2] => melon
    [3] => php1.txt
    [4] => php2.txt
    [5] => php3.txt
)

このように配列の要素の最後に、lsコマンドの結果が追加されていることがわかります。

exec関数が失敗する原因

前述したように、exec関数の第三引数を使用して、コマンドが正常に終了したかどうかのステータスを取得することができます。

ここでは0以外の失敗のステータスが返される例をあげ、どのように対応したらよいかを解説していきます。

コマンドが見つからない

存在しないコマンドをexec関数で実行すると、失敗のステータスが返されます。

以下は間違ったコマンドを実行した例です。

サンプルプログラム:

<?php

$cmd = 'l /usr';
exec($cmd, $opt, $return_ver);
echo '実行結果:'.$return_ver;

?>

実行結果:

sh: l: コマンドが見つかりません
実行結果:127

「l」というコマンドは存在しないため、127という失敗のステータスが返ってきています。

この場合は、コマンドに入力ミスがないか、コマンドにパスが通っているか、を確認する必要があります。

コマンドに実行権限がない

実行権限がないコマンドをexec関数で実行した場合も、失敗のステータスが返されます。

以下は、rootユーザ以外のユーザで「/root」の一覧を取得しようとした例です。

サンプルプログラム:

<?php

$cmd = 'ls /root';
exec($cmd, $opt, $return_ver);
echo '実行結果:'.$return_ver;

?>

実行結果:

ls: cannot open directory /root: 許可がありません
実行結果:2

このような場合は、コマンドをsudoで実行することで解決することができます

sudoはroot権限でコマンドを実行することのできるコマンドです。sudoでコマンドを実行するには実行ユーザのパスワード入力が必要になります。

通常は端末からパスワードを入力するよう促されますが、sudoコマンドの「-S」オプションを使用することで、パスワードを端末入力ではなく標準入力から読み込むことができます。

sudoでコマンド実行するサンプルです。

サンプルプログラム:

<?php

$cmd = "echo 'pass' | sudo -S ls /root";
exec($cmd, $opt, $return_ver);
echo '実行結果:'.$return_ver;

?>

実行結果:

実行結果:0

‘pass’には実行するユーザのパスワードを記述してください。

$cmdの中の「|」はパイプといい、複数のコマンドを組み合わせる役割を持ちます。ここでは、「echo ‘pass’」の出力を「sudo -S ls /root」に渡すことができます。

これで、途中でパスワード入力を行うことなく実行できます。

pingによる導通確認

pingとは、主にネットワークの疎通を確認するために使用されるコマンドです。

特に大規模なシステムでは、たくさんのネットワークマシンを使用するため、事前にネットワークが正常に疎通するか、確認するためによく使用されます。

pingはネットワークに繋がっていて、IPアドレスを保持している機器であれば、疎通確認ができます。

exec関数は外部コマンドが使用できるため、以下のようにpingによる疎通確認ができます。

サンプルプログラム:

<?php
 
$ipaddr = 'xxx.xxx.xx.x';
$r = exec(sprintf('ping -c 1 -W 1 %s',
          escapeshellarg($ipaddr)),
          $opt, $return_ver);
 
if($return_ver == 0){
  echo '疎通成功';
}else{
  echo '疎通失敗';
}
 
?>

実行結果:

疎通成功

このようにpingコマンドを実行すれば、通信先の機器がネットワークに接続されているか、第三引数のステータスを取得することにより疎通確認をすることができます。

$ipaddrの’xxx.xxx.xx.x’;の箇所は、ご自身のPCやネットワークサーバのIPアドレスに置き換えて確認してみてください。

ssh(セキュアシェル)を実行する

sshとはSecure Shell(セキュアシェル)の略称で、ネットワーク上のリモートコンピュータと通信して命令を実行したり、データをやりとりするときに使用します。

sshは認証やネットワーク上のやりとりが全て暗号化されるため、安全に通信をすることができます。

PHPでsshによるコマンドを実行する場合は、ssh2_exec関数を使用します。

ssh2_exec関数でsshの通信を行うは、事前に公開鍵と秘密鍵の設定をしておく必要があります。

ssh設定の詳細については、以下のページを参照してください。
https://www.adminweb.jp/web-service/ssh/index8.html
http://www14.plala.or.jp/campus-note/vine_linux/server_ssh/sshd_config.html

以下はsshによるリモートコマンドを実行する一般的な方法となります。

サンプルプログラム:

<?php
 
//リモートコンピュータに接続する
$con = ssh2_connect('xxx.xxx.xx.x', 22);
 
//ユーザー名とパスワードを指定する
ssh2_auth_password($con, 'user', 'password');
 
//ファイルをコピーする
ssh2_exec($con, 'cp -p /Users/Shared/PHP/php1.txt .');
 
?>

ssh2_connectではリモートコンピュータのIPアドレスと、ポート番号の22番を指定します。

ポート番号22は、sshでログインするときに使用する番号となります。

ssh2_auth_passwordではリモートコンピュータのユーザ名とパスワードを指定します。

ログインが成功したらssh2_exec関数により、外部コマンドを実行します。

shell_exec関数とは

shell_exec関数はexec関数と同じく外部コマンドを実行し、出力結果を返します。

shell_exec関数は以下のように記述します。

書き方:

string shell_exec( string $コマンド )

引数:
実行するコマンドやプログラム名を指定します。

execコマンドと異なる点は、

  • 第二引数に結果を格納するための配列が指定できない。
  • 第三引数にステータスを指定できないため、実行に失敗したかどうかを判断することができない。

などが挙げられます。そのため、

単純に外部コマンドを実行するだけならshell_exec関数。出力結果を配列で格納したり、実行時のステータスが知りたい場合はexec関数。

と、使い分けると良いでしょう。

返り値:
実行されたコマンドの出力を返します。

実行時にエラーが発生、または何も出力しなかった場合はNULLを返します。

以下はshell_exec関数の簡単なサンプルです。

サンプルプログラム:

<?php
 
$out = shell_exec('ls -l');
echo $out;
 
?>

実行結果:

-rw-r--r-- 1 samurai wheel    99 10月 15 21:15 2017 exec.php
-rw-r--r-- 1 samurai wheel    99 10月 15 21:17 2017 shell_exec.php

コマンドラインでPHPを実行する

PHPはWebアプリケーション開発によく使われるので、ブラウザから実行する場合が多いのですが、コマンドラインから実行することもできます。

コマンドラインとは、Windowsのコマンドプロンプト、MacやLinuxのターミナルのようにキーボードからコマンドを打ち込むツールです。

ここでは、PHPをコマンドラインで実行する方法と便利なオプションについて解説していきます。

PHPファイルを実行する(-fオプション)

PHPファイルをコマンドラインから実行するには以下のように指定します。

コマンドラインからの実行方法:

> php -f PHPファイル名

「-f」オプションはなくても動作します。

対話的に実行する(-aオプション)

「-a」オプションを使用すると、PHPファイルを作成することなく、対話的に実行することができます。

ちょっと関数の動作を確認したい、といった場合に便利です。

実行サンプル:

> php -a
Interactive shell

php > $array = [
php > 0,
php > 1,
php > 2,
php > ];
php > print_r($array);
Array
(
    [0] => 0
    [1] => 1
    [2] => 2
)
php > quit

「php -a」を入力してから、「quit」または「exit」が入力されるまで実行されます。

1行のコードを実行する(-rオプション)

「-r」オプションを使用すると、1行のコードを簡単に実行することができます。

実行サンプル:

> php -r 'echo "Samurai Engineern";'
Samurai Engineer

「-a」オプションより簡単な処理を試すのに適しています。

コマンドラインでPHPを実行する時のオプションには様々なものがあります。以下のページを参照してください。
http://php.net/manual/ja/features.commandline.options.php

コマンドラインでの実行については、以下の記事でも解説しています!

まとめ

今回はPHPで外部コマンドを実行する、PHPをコマンドラインから実行するということについて解説しました。

外部コマンドを実行するexec関数は、

  • コマンドプロンプトやターミナルから実行するコマンドをそのまま使用できる。
  • Linuxやコマンドプロンプトなどの外部コマンドや外部プログラムを実行することができる。
  • pingによる導通確認ができる。
  • ssh2_execではsshによるリモートコマンドが実行できる。
  • よく似た関数としてshell_exec関数がある

コマンドライン実行時のオプションには、

  • 「-f」オプションで実行するPHPファイルを指定できる
  • 「-a」オプションでPHPのコードを対話的に実行できる
  • 「-r」オプションでPHPの1行コードを実行できる

などがわかりましたね!

もしexec関数の使い方やコマンドライン実行について忘れてしまったら、この記事を思い出してくださいね!

この記事を書いた人

侍エンジニア塾は「人生を変えるプログラミング学習」をコンセンプトに、過去多くのフリーランスエンジニアを輩出したプログラミングスクールです。侍テック編集部では技術系コンテンツを中心に有用な情報を発信していきます。

目次