【PHP8.x】shell_exec関数の使い方
shell_exec関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
shell_exec関数は、指定されたシェルコマンドを実行し、その実行結果を文字列として取得する関数です。この関数は、PHPスクリプトの中からオペレーティングシステム(OS)のコマンドや外部のプログラムを実行したい場合に利用されます。たとえば、ファイルの情報を一覧表示するlsコマンドや、システムの状態を確認するuptimeコマンドなどをPHPコードから実行し、その標準出力の内容をPHPの変数として受け取ることができます。
コマンドが正常に実行され、何らかの標準出力(STDOUT)があった場合、その出力内容全体が単一の文字列として返されます。もしコマンドが標準出力を行わなかった場合や、実行に失敗して何も出力されなかった場合は、NULLが返されます。標準エラー出力(STDERR)は戻り値には含まれないため、エラーメッセージを捕捉したい場合は、コマンド内で2>&1のようにリダイレクトするなどの工夫が必要です。
特に重要な点として、この関数を使用する際はセキュリティに十分な注意が必要です。ユーザーからの入力値を直接コマンドに含めると、悪意のあるコマンドが実行されてしまう「コマンドインジェクション」という脆弱性を引き起こす可能性があります。そのため、ユーザー入力をコマンドに渡す際には、必ずescapeshellarg()やescapeshellcmd()といった関数を使用して、特殊文字を適切にエスケープすることが強く推奨されます。実行されるコマンドはPHPが動作しているサーバーのOS環境に依存するため、環境間の互換性も考慮する必要があります。
構文(syntax)
1<?php 2$command = 'ls -l'; 3$output = shell_exec($command); 4echo $output; 5?>
引数(parameters)
string $command
- string $command: 実行したいシェルコマンドを文字列で指定します
戻り値(return)
string|null
実行したコマンドの標準出力結果を文字列として返します。コマンドの実行に失敗した場合は null を返します。
サンプルコード
PHPでshell_exec()とexec()の違いを理解する
1<?php 2 3/** 4 * shell_exec() と exec() の違いをデモンストレーションします。 5 * 6 * shell_exec(): コマンドの完全な出力を文字列として返します。 7 * 実行に失敗した場合や機能が無効な場合は null を返します。 8 * exec(): コマンドの出力の最後の行を返します。 9 * オプションで、出力の全行を配列として第2引数に格納します。 10 * オプションで、コマンドの終了ステータスを第3引数に格納します。 11 * 実行に失敗した場合や機能が無効な場合は false を返します。 12 */ 13function demonstrateShellExecAndExecDifference(): void 14{ 15 // 実行するコマンドを定義 16 // 'ls -l' は現在のディレクトリのファイルとディレクトリを詳細表示します。 17 // このコマンドの出力は、PHPが実行される環境 (例: Linux, Windows) や、 18 // 現在のディレクトリの内容によって異なります。 19 $command = 'ls -l'; 20 21 echo "--- shell_exec() の例 ---\n"; 22 // shell_exec() を使用してコマンドを実行 23 // コマンドの標準出力全体を文字列として取得します。 24 $shellExecOutput = shell_exec($command); 25 26 if ($shellExecOutput === null) { 27 echo "shell_exec(): コマンドの実行に失敗したか、PHPのセキュリティ設定 (disable_functions) 等により利用できません。\n"; 28 } else { 29 echo "shell_exec() の出力 (文字列):\n"; 30 echo $shellExecOutput; // 出力全体が単一の文字列として表示される 31 } 32 echo "\n"; 33 34 echo "--- exec() の例 ---\n"; 35 $execOutputLines = []; // 出力の各行を格納する配列 36 $execReturnStatus = -1; // コマンドの終了ステータスを格納する変数 37 38 // exec() を使用してコマンドを実行 39 // 戻り値は出力の最後の行です。 40 // 第2引数 ($execOutputLines) には出力の全行が配列として格納されます。 41 // 第3引数 ($execReturnStatus) にはコマンドの終了ステータスが格納されます。 42 $lastLine = exec($command, $execOutputLines, $execReturnStatus); 43 44 if ($lastLine === false) { 45 echo "exec(): コマンドの実行に失敗したか、PHPのセキュリティ設定 (disable_functions) 等により利用できません。\n"; 46 } else { 47 echo "exec() の戻り値 (最後の行):\n"; 48 echo $lastLine . "\n"; // 最後の行のみが表示される 49 50 echo "\nexec() の第2引数 (全行の配列):\n"; 51 if (empty($execOutputLines)) { 52 echo " 出力がありません。\n"; 53 } else { 54 foreach ($execOutputLines as $line) { 55 echo " " . $line . "\n"; // 配列として格納された全行が表示される 56 } 57 } 58 59 echo "\nexec() の第3引数 (終了ステータス):\n"; 60 echo " " . $execReturnStatus . "\n"; // コマンドの終了ステータス (通常、成功なら0) 61 } 62 echo "\n"; 63} 64 65// 関数を呼び出してデモンストレーションを実行 66demonstrateShellExecAndExecDifference(); 67
PHPのshell_exec関数とexec関数は、PHPスクリプトの中からOSのコマンド(例: ls -lなど)を実行し、その結果を取得するために利用されます。
shell_exec関数は、引数として指定されたコマンドを実行し、その標準出力の「すべて」を単一の文字列として返します。コマンドの実行に失敗したり、PHPのセキュリティ設定(disable_functionsなど)により利用できない場合はnullが戻り値となります。
一方、exec関数は、引数で指定されたコマンドを実行し、その標準出力の「最後の行」を文字列として返します。さらに、第2引数に空の配列を渡すと、コマンドの標準出力の「全行」がその配列の各要素として格納されます。また、第3引数に整数型変数を渡せば、実行されたコマンドの終了ステータス(通常、成功時は0)も取得できます。execがコマンドの実行に失敗したり、利用できない場合はfalseを返します。
このように、両関数は外部コマンドを実行する点で共通していますが、出力の取得形式や追加情報の取得方法、失敗時の戻り値が異なりますので、用途に応じて適切な関数を選択してください。
shell_exec()はコマンドの全出力を文字列で返し、exec()は出力の最後の行を返します。exec()は全出力を配列で、終了ステータスも取得できます。これらの関数はセキュリティリスクが高く、外部からの入力値を使う際は必ずescapeshellcmd()やescapeshellarg()などでエスケープ処理をしてください。サーバーのdisable_functions設定で無効化されている場合もあります。コマンド実行中はPHPの処理が止まるため、長時間かかる処理には注意し、戻り値がnullやfalseの場合のエラー処理を適切に行ってください。
PHP shell_exec 実行されない原因と対処法
1<?php 2 3/** 4 * shell_exec 関数を使用して外部コマンドを実行し、結果を表示するサンプル関数。 5 * コマンドが「実行されない」ケースや、その結果のハンドリングを示します。 6 * 7 * システムエンジニアを目指す初心者向けに、shell_exec が null や空文字列を返す原因と 8 * 考えられる対策をコメントで補足しています。 9 */ 10function demonstrateShellExec(): void 11{ 12 echo "--- shell_exec のデモンストレーション ---" . PHP_EOL . PHP_EOL; 13 14 // 1. 成功する可能性が高いシンプルなコマンドの例 15 echo "--- 1. 成功する可能性が高いコマンドの例 (現在のディレクトリの内容を表示) ---" . PHP_EOL; 16 // OSに応じてコマンドを切り替える (Windows: dir, Linux/macOS: ls -la) 17 $command1 = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'dir' : 'ls -la'; 18 echo "実行コマンド: '{$command1}'" . PHP_EOL; 19 20 // shell_exec を実行 21 $output1 = shell_exec($command1); 22 23 if ($output1 === null) { 24 // null が返された場合、コマンド実行自体に失敗した可能性が高い 25 echo "結果: null が返されました。コマンドの実行に失敗したか、shell_exec が無効化されている可能性があります。" . PHP_EOL; 26 echo "考えられる主な原因:" . PHP_EOL; 27 echo " - PHPの設定 (php.ini) で shell_exec が disable_functions に指定されている。" . PHP_EOL; 28 echo " - コマンド '{$command1}' が見つからない、またはパスが通っていない。" . PHP_EOL; 29 echo " - PHP実行ユーザーにコマンドの実行権限がない。" . PHP_EOL; 30 } else { 31 echo "結果 (成功):" . PHP_EOL; 32 echo $output1 . PHP_EOL; 33 } 34 echo PHP_EOL; 35 36 // 2. 存在しないコマンドの例 (「実行されない」またはエラーになるケース) 37 echo "--- 2. 存在しないコマンドの例 (実行されない、またはエラーになるケース) ---" . PHP_EOL; 38 // 存在しない可能性が高いコマンドを指定 39 $command2 = 'this_nonexistent_command_123456789'; 40 echo "実行コマンド: '{$command2}'" . PHP_EOL; 41 42 $output2 = shell_exec($command2); 43 44 if ($output2 === null) { 45 // null が返された場合、存在しないコマンドのため実行自体がOSレベルで失敗した可能性が高い 46 echo "結果: null が返されました。コマンドの実行に失敗したか、shell_exec が無効化されている可能性があります。" . PHP_EOL; 47 echo "考えられる主な原因:" . PHP_EOL; 48 echo " - コマンド '{$command2}' が見つからない、またはパスが通っていない。(このケースではこれに該当)" . PHP_EOL; 49 echo " - PHPの設定 (php.ini) で shell_exec が disable_functions に指定されている。" . PHP_EOL; 50 echo " - PHP実行ユーザーにコマンドの実行権限がない。" . PHP_EOL; 51 } else if (empty($output2)) { 52 // 空文字列が返された場合、コマンド自体は実行されたものの、標準出力がなかった可能性 53 // エラーメッセージが標準エラー出力に出力され、shell_exec では捕捉できなかったケースが多い 54 echo "結果: 空文字列が返されました。コマンドは実行されたが、標準出力がなかった可能性があります。" . PHP_EOL; 55 echo " (例: コマンドは存在するが引数が不正でエラーメッセージが標準エラー出力に出力された場合)" . PHP_EOL; 56 echo " コマンドが実際に実行されたかどうかは、他の方法で確認する必要があります(例: ファイル作成、ログ出力など)。" . PHP_EOL; 57 } else { 58 // 予想外に何か出力があった場合 59 echo "結果 (予想外の成功):" . PHP_EOL; 60 echo $output2 . PHP_EOL; 61 } 62 echo PHP_EOL; 63 64 // 3. エラーになるコマンドの例(shell_exec は標準エラー出力を捕捉しないため、結果は空になりがち) 65 echo "--- 3. エラーが発生するコマンドの例 (標準エラー出力は取得できないため、結果は空になりがち) ---" . PHP_EOL; 66 // 存在しないファイルを cat/type しようとする例 67 $command3 = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'type non_existent_file_xyz.txt' : 'cat non_existent_file_xyz.txt'; 68 echo "実行コマンド: '{$command3}'" . PHP_EOL; 69 70 $output3 = shell_exec($command3); 71 72 if ($output3 === null) { 73 // null が返された場合、コマンド実行自体に失敗した可能性 74 echo "結果: null が返されました。コマンドの実行に失敗したか、shell_exec が無効化されている可能性があります。" . PHP_EOL; 75 echo "考えられる主な原因:" . PHP_EOL; 76 echo " - コマンド '{$command3}' が見つからない、またはパスが通っていない。" . PHP_EOL; 77 echo " - PHPの設定 (php.ini) で shell_exec が disable_functions に指定されている。" . PHP_EOL; 78 echo " - PHP実行ユーザーにコマンドの実行権限がない。" . PHP_EOL; 79 } else if (empty($output3)) { 80 // 空文字列が返された場合、コマンドは実行されたが、エラーメッセージは標準エラー出力に出力された可能性が高い 81 echo "結果: 空文字列が返されました。コマンドは実行されたが、エラーメッセージは標準エラー出力に出力されたため、" . PHP_EOL; 82 echo " shell_exec では捕捉できませんでした。コマンドが正常終了しなかった可能性が高いです。" . PHP_EOL; 83 } else { 84 // 予想外に何か出力があった場合 (例: エラーメッセージが標準出力に出力されるコマンド) 85 echo "結果 (成功):" . PHP_EOL; 86 echo $output3 . PHP_EOL; 87 } 88 echo PHP_EOL; 89 90 echo "--- shell_exec のデモンストレーション終了 ---" . PHP_EOL; 91 echo "補足: shell_exec はコマンドの標準出力のみを返します。より詳細なエラー情報を取得したい場合(標準エラー出力や終了ステータス)、" . PHP_EOL; 92 echo "passthru(), exec(), proc_open() などの他の関数を検討してください。" . PHP_EOL; 93} 94 95// 関数を実行します 96demonstrateShellExec();
PHP 8のshell_exec関数は、指定された外部コマンドをシステムシェルを通じて実行し、その結果の標準出力を文字列として取得する機能です。引数$commandには、OSのコマンドプロンプトで実行するのと同様のコマンド文字列を渡します。
コマンドが正常に実行され、標準出力がある場合は、その出力内容が文字列で返されます。しかし、shell_execがnullを返した場合、これはコマンドの実行自体がシステムレベルで「実行されない」状態にあることを示します。この主な原因としては、PHPの設定ファイル(php.ini)でshell_execがセキュリティ上の理由から無効化されている、指定したコマンドが見つからない(パスが通っていない)、またはPHPが動作しているユーザーにそのコマンドを実行する権限がない、といった状況が考えられます。
また、コマンドは実行されたものの、標準出力が一切なかった場合は空の文字列が返されます。このケースでは、例えばコマンド自体は存在しても引数が不正でエラーが発生し、そのエラーメッセージが標準エラー出力に出力されたため、shell_execでは捕捉できないという状況がよくあります。
shell_execは標準出力のみを扱うため、コマンドの終了ステータスや標準エラー出力を詳細に確認したい場合は、passthru、exec、proc_openといった別のPHP関数を検討することをお勧めします。
shell_exec関数は、外部コマンドの標準出力のみを文字列として返します。コマンドが全く実行されなかったり、PHPの設定で無効化されていたり、コマンドが見つからない、実行権限がないなどの問題がある場合、戻り値はnullとなります。一方、コマンド自体は実行されたものの、標準出力が何もなかった場合や、エラーメッセージが標準エラー出力に出力された場合は、空文字列が返されます。shell_execは標準エラー出力を捕捉しないため、エラーの詳細は直接取得できません。コマンドの終了ステータスや標準エラー出力も確認したい場合は、passthru()、exec()、proc_open()などの別の関数をご検討ください。