| 函數 | 回傳值 | 輸出處理 | 適用場景 | 安全性 |
|---|---|---|---|---|
system() | 最後一行輸出 | 直接輸出到瀏覽器 | 簡單指令、即時顯示結果 | 需 escapeshellarg() |
exec() | 最後一行輸出 | 可選陣列參數接收所有行 | 需捕獲輸出、取得狀態碼 | 需 escapeshellarg() |
passthru() | 狀態碼 | 直接輸出二進位資料 | 圖片、PDF、二進位串流 | 需 escapeshellarg() |
proc_open() | 資源處理序 | 完全控制 stdin/stdout/stderr | 雙向通訊、長時間程序、管道 | 最高 (陣列參數自動跳脫) |
<?php
// 列出目錄
$lastLine = system('ls -la', $returnVar);
echo "返回碼: $returnVar\n";
echo "最後一行: $lastLine\n";
// 即時輸出長時間程序進度
system('tar czf backup.tar.gz /var/www 2>&1'); // 直接顯示進度
?>
<?php
$output = [];
$returnVar = 0;
exec('whoami', $output, $returnVar);
echo "使用者: " . implode("\n", $output) . "\n";
echo "狀態碼: $returnVar\n";
// 取得程式路徑
exec('which php', $output);
echo "PHP 路徑: $output[0]\n";
?>
<?php
// 直接輸出圖片
header('Content-Type: image/png');
passthru('cat /path/to/image.png');
// 影片串流轉碼
passthru('ffmpeg -i input.mp4 -f mp4 - 2>/dev/null');
?>
<?php
$descriptors = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'] // stderr
];
$proc = proc_open('php -r "echo fgets(STDIN);"', $descriptors, $pipes);
if (is_resource($proc)) {
// 寫入 stdin
fwrite($pipes[0], "Hello from PHP!\n");
fclose($pipes[0]);
// 讀取 stdout
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
// 讀取 stderr
$error = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return = proc_close($proc);
echo "輸出: $output\n錯誤: $error\n返回碼: $return\n";
}
?>
<?php
// 危險!使用者輸入: "; rm -rf / ; #
$filename = $_GET['file'] ?? '';
system("ls $filename"); // 命令注入!
// 安全:escapeshellarg
$safeArg = escapeshellarg($filename);
system("ls $safeArg");
// 最佳:proc_open 陣列模式 (無 Shell 解析)
$proc = proc_open(['ls', $filename], $descriptors, $pipes);
// 或 PHP 7.4+ fnmatch 白名單驗證
if (preg_match('/^[a-zA-Z0-9_\-\.]+$/', $filename)) {
system("ls " . escapeshellarg($filename));
}
?>
能用 PHP 內建函數完成的,盡量不用系統指令: