首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 執行 Linux 系統指令完整指南:system、exec、passthru、proc_open 比較

     編輯:PHP 相關知識

四大核心函數比較

函數回傳值輸出處理適用場景安全性
system()最後一行輸出直接輸出到瀏覽器簡單指令、即時顯示結果需 escapeshellarg()
exec()最後一行輸出可選陣列參數接收所有行需捕獲輸出、取得狀態碼需 escapeshellarg()
passthru()狀態碼直接輸出二進位資料圖片、PDF、二進位串流需 escapeshellarg()
proc_open()資源處理序完全控制 stdin/stdout/stderr雙向通訊、長時間程序、管道最高 (陣列參數自動跳脫)

1. system() - 簡單直接

<?php
// 列出目錄
$lastLine = system('ls -la', $returnVar);
echo "返回碼: $returnVar\n";
echo "最後一行: $lastLine\n";

// 即時輸出長時間程序進度
system('tar czf backup.tar.gz /var/www 2>&1'); // 直接顯示進度
?>

2. exec() - 捕獲完整輸出

<?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";
?>

3. passthru() - 二進位輸出

<?php
// 直接輸出圖片
header('Content-Type: image/png');
passthru('cat /path/to/image.png');

// 影片串流轉碼
passthru('ffmpeg -i input.mp4 -f mp4 - 2>/dev/null');
?>

4. proc_open() - 進階雙向控制 (推薦)

<?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";
}
?>

安全性鐵律

  1. 絕不直接使用使用者輸入:必須經過 `escapeshellarg()` 或 `escapeshellcmd()`
  2. 優先使用 `proc_open` 陣列參數模式:自動處理跳脫,無 Shell 注入風險
  3. 限制執行權限:Web 使用者 (www-data) 不應有 root 權限
  4. 停用危險函數:`php.ini` 設定 `disable_functions = exec,system,passthru,shell_exec,proc_open,popen` (視需求保留)
  5. 使用絕對路徑:避免 PATH 劫持攻擊

安全範例:使用者輸入檔名列出檔案

<?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));
}
?>

常見應用場景

  • 系統監控:`df -h`, `free -m`, `uptime`
  • 媒體處理:`ffmpeg`, `imagemagick (convert)`, `ghostscript`
  • 備份腳本:`tar`, `mysqldump`, `rsync`
  • 憑證管理:`openssl`, `certbot`
  • 程式碼部署:`git pull`, `composer install`, `npm run build`

替代方案:PHP 原生函數優先

能用 PHP 內建函數完成的,盡量不用系統指令:

  • 檔案操作:`glob()`, `scandir()`, `copy()`, `unlink()`, `mkdir()`, `rename()`
  • 壓縮:`ZipArchive`, `PharData`, `gzcompress()`
  • 圖片:`GD`, `Imagick` 擴展
  • 網路:`cURL`, `stream_context_create()`
  • 程序管理:`pcntl_fork()`, `pcntl_exec()` (CLI 限定)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved