
PHP8 上級/準上級試験の認定模擬問題として、プライム・ストラテジー様のPRIME STUDYが認定されているようです。ただ、この模擬問題には解説がありませんので解説をまとめていこうと思います。シリーズ第24回目です。

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。

今回は外部プログラムの実行やシェル操作に関連する関数に関する問題です。exec()、shell_exec()、system() などの関数や、escapeshellarg()、escapeshellcmd() などのエスケープ関数の挙動について理解を深めることができます。これらはシステムコマンドの実行や引数のエスケープ処理など、セキュリティ上も重要な役割を果たします。しっかりと押さえておきましょう!
PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/
問題文
関数 に関する説明の中で、誤っているものを1つ選びなさい。
なお「\」はバックスラッシュに読み替えること。
また、すべてのコードには下記のコードが適切な箇所に書かれているものとする。
declare(strict_types=1);
error_reporting(-1);
下記はマニュアルから一部引用した内容である。
exec ( string $command , array &$output = null , int &$result_code = null ) : string|false
shell_exec ( string $cmd ) : string
system ( string $command , int &$result_code = null ) : string|false
escapeshellarg ( string $arg ) : string
escapeshellarg() は、文字列をシングルクオート で括り、既存のシングルクオートを全てクオート/エスケープします。これにより、文字列を直接シェル関数に渡し、単一の安全な引数として処理することを可能にします
escapeshellcmd ( string $command ) : string
escapeshellcmd() は、文字列中においてシェルコマンドを だまして勝手なコマンドを実行する可能性がある文字をエスケープします。
(中略)
&#;`|*?~^()[]{}$\、\x0A および \xFF については、その文字の前に \ (バックスラッシュ) が追加されます。’ および ” は、対になっていない場合にのみエスケープされます。
proc_nice ( int $increment ) : bool
posix_kill ( int $pid , int $sig ) : bool
”’
(1)
PHP で外部プログラムを動かすためには、 exec() 関数、passthru() 関数、shell_exec() 関数、system() 関数、バックティック演算子 ` などを使う。
これらのうち、shell_exec() 関数とバックティック演算子は「同じもの」である。
また、exec() 関数と system() 関数は返り値として「コマンド結果の最後の行を返す」、passthru() 関数は「未整形の出力を表示(stdout に出力)する」ところに差異がある。
そのため、以下のコード
$cmd = 'vmstat 1 1';
echo "exec()\n";
$s = exec($cmd, $output, $return_var);
echo $s, PHP_EOL;
echo PHP_EOL;
echo "shell_exec()\n";
$s = shell_exec($cmd);
echo $s, PHP_EOL;
echo PHP_EOL;
echo "system()\n";
ob_start();
$s = system($cmd, $return_var);
ob_end_clean();
echo $s, PHP_EOL;
を実行すると、結果は次のような表記となる。
exec()
1 0 67236 87052 0 606796 0 0 0 1 1 1 0 0 100 0 0
shell_exec()
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 67236 86728 0 606796 0 0 0 1 1 1 0 0 100 0 0
system()
1 0 67236 86564 0 606796 0 0 0 1 1 1 0 0 100 0 0
(2)
シェル引数として使われる文字列をエスケープするための関数として、escapeshellarg() 関数と escapeshellcmd() 関数がある。
どちらも「エスケープをする」処理を行うため、どちらを使っても意味合いは同じなので、どちらを使ってもよい。
しかし、外部入力をシェル引数に使う場合は、必ずどちらかの関数でエスケープをする必要がある。
そのため、以下のコード
$arguments = 'ab&c "d ef" > \'gh\'';
$e = escapeshellarg($arguments);
echo $e, PHP_EOL;
$e = escapeshellcmd($arguments);
echo $e, PHP_EOL;
を実行すると、結果は次のとおりとなる。
'ab&c "d ef" > '\''gh'\'''
'ab&c "d ef" > '\''gh'\'''
(3)
「システムコールとライブラリ関数を規定した POSIX.1 (IEEE Std 1003.1)」標準ドキュメントで 定義された関数へのインターフェイスが提供されている、POSIX 関数がある。
デフォルトで有効になっているが、Windows 環境では利用できないので注意が必要である。
現在のプロセスのグループ ID を返す posix_getpgrp()、 現在のプロセス ID を返す posix_getpid()、 親プロセスの ID を返す posix_getppid()、 プロセス時間を得る posix_times() などがある。
そのため、以下のコード
var_dump( posix_getpgrp() );
var_dump( posix_getpid() );
var_dump( posix_getppid() );
var_dump( posix_times() );
を実行すると、結果は次のとおりとなる。(プロセスID、時間のため、値は実行毎に変わる)
int(694)
int(694)
int(523)
array(5) {
["ticks"]=>
int(1358853909)
["utime"]=>
int(0)
["stime"]=>
int(0)
["cutime"]=>
int(0)
["cstime"]=>
int(0)
}
(4)
”’
プロセスに働きかける関数として、proc_nice() 関数や posix_kill() 関数がある。
proc_nice() は自プロセスの優先度を変更し、posix_kill() は指定したプロセスにシグナルを送信する。
シグナル SIGKILL は「プロセスの強制終了」なので、SIGKILL を送信されたプログラムはそこで実行を停止する。
そのため、以下のコード
var_dump( trim(nice) );
proc_nice(10);
var_dump( trim(nice) );
posix_kill(posix_getpid(), SIGKILL);
echo 'test', PHP_EOL;
を実行すると、結果は次のとおりとなる。
string(1) "0"
string(2) "10"
Killed
解説
選択肢1の解説
正しいです。
exec()、shell_exec()、system() などの関数は外部プログラムを実行するために使用されます。それぞれの動作についても説明通りです。exec() は結果を配列で返す、shell_exec() は標準出力を文字列で返す、system() は結果を標準出力に表示し、コマンドの結果を返します。
選択肢2の解説
誤りです。
escapeshellarg() と escapeshellcmd() は異なる用途を持つ関数であり、「どちらを使っても意味合いは同じ」という説明は誤りです。
選択肢3の解説
正しいです。
POSIX 関数(posix_getpgrp(), posix_getpid(), posix_getppid(), posix_times())は、POSIX標準に準拠した関数であり、主にUNIX系システムで使用されます。Windows環境では利用できない点も正しいです。
選択肢4の解説
正しいです。
proc_nice() は自プロセスの優先度を変更し、posix_kill() は指定したプロセスにシグナルを送信します。シグナル SIGKILL はプロセスを強制終了させるため、実行後に「Killed」と表示される動作は正しいです。
正解選択肢
以上より選択肢2が正解となります。
他の問題へ
模擬問題(1)インストール
模擬問題(2)変数の型
模擬問題(3)クラス
模擬問題(4)メソッドその1
模擬問題(5)メソッドその2
模擬問題(6)リファレンス
模擬問題(7)名前空間
模擬問題(8)エラー
模擬問題(9)定義済みのインターフェイスとクラスおよび SPL インターフェイス
模擬問題(10)SPL
模擬問題(11)定義済の変数
模擬問題(12)PHP7.0.xからPHP7.1.xへの移行
模擬問題(13)可変変数
模擬問題(14)PHP7.3.xからPHP7.4.xへの移行
模擬問題(15)PHP7.4.xからPHP8.0.xへの移行
模擬問題(16)制御構造
模擬問題(17)XSS(クロスサイトスクリプティング)
模擬問題(18)ファイルアップロード
模擬問題(19)推測困難なトークン
模擬問題(20)セッション
模擬問題(21)PHP のメモリ消費
模擬問題(22)関数その1
模擬問題(23)関数その2
模擬問題(24)関数その3
模擬問題(25)関数その4
模擬問題(26)関数その5
模擬問題(27)関数その6
模擬問題(28)関数その7
模擬問題(29)関数その8
模擬問題(30)関数その9
コメント