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

PHP 調用 COM 組件執行 DOS 命令:WScript.Shell 與 proc_open

     編輯:PHP 相關知識

兩種實現方式

在 Windows 環境下,PHP 可通過 COM 組件或 proc_open() 執行系統命令。

方式一:WScript.Shell (COM)

if ($execfunc=='wscript' && IS_WIN && IS_COM) {
  $wsh = new COM('WScript.shell');
  $exec = $wsh->exec('cmd.exe /c ' . $command);
  $stdout = $exec->StdOut();
  $stroutput = $stdout->ReadAll();
  echo $stroutput;
}
  • 需啟用 php_com_dotnet.dll 擴展
  • IS_COM 常量需定義為 class_exists('COM')
  • 適合需要捕獲標準輸出的場景
  • 權限:運行 PHP 的用戶需有執行命令權限

方式二:proc_open()

elseif ($execfunc=='proc_open' && IS_WIN && IS_COM) {
  $descriptorspec = [
    0 => ['pipe', 'r'],  // stdin
    1 => ['pipe', 'w'],  // stdout
    2 => ['pipe', 'w']   // stderr
  ];
  $process = proc_open($_SERVER['COMSPEC'], $descriptorspec, $pipes);
  if (is_resource($process)) {
    fwrite($pipes[0], $command . "\r\n");
    fwrite($pipes[0], "exit\r\n");
    fclose($pipes[0]);
    
    while (!feof($pipes[1])) echo fgets($pipes[1], 1024);
    while (!feof($pipes[2])) echo fgets($pipes[2], 1024);
    
    fclose($pipes[1]); fclose($pipes[2]);
    proc_close($process);
  }
}
  • 無需 COM 擴展,跨平台性較好(Linux 也可用)
  • 可分別處理 stdout/stderr
  • 需注意管道阻塞:大量輸出時應非阻塞讀取或用 stream_select()

安全警示 ⚠️

  • 命令注入極高風險:$command 若含用戶輸入必須嚴格過濾(escapeshellcmd()、escapeshellarg())
  • 禁用函數檢查:共享主機常禁用 exec、shell_exec、proc_open、COM
  • 最小權限原則:PHP 進程用戶不應為 Administrator/SYSTEM
  • 審計日誌:記錄執行命令、參數、執行者、時間

現代替代方案

需求推薦方案
執行系統命令Symfony Process Component、proc_open 封裝類
定時任務系統 cron / Windows 任務計劃 + PHP CLI
異步處理隊列系統(Redis/RabbitMQ)+ Worker 進程
文件操作PHP 內置函數(copy、rename、unlink、mkdir 等)
壓縮/解壓ZipArchive、Phar、exec('tar ...') 最後手段

最佳實踐代碼模板

class SafeCommandExecutor {
  private $allowedCommands = ['ping', 'ipconfig', 'dir'];  // 白名單
  
  public function execute(string $cmd, array $args = []): string {
    // 驗證命令在白名單
    $baseCmd = array_shift(explode(' ', $cmd));
    if (!in_array($baseCmd, $this->allowedCommands)) {
      throw new Exception("Command not allowed: $baseCmd");
    }
    // 參數轉義
    $escapedArgs = array_map('escapeshellarg', $args);
    $fullCmd = $baseCmd . ' ' . implode(' ', $escapedArgs);
    
    $descriptorspec = [['pipe','r'], ['pipe','w'], ['pipe','w']];
    $process = proc_open($fullCmd, $descriptorspec, $pipes);
    if (!is_resource($process)) throw new Exception("Process start failed");
    
    $output = '';
    while (!feof($pipes[1])) $output .= fgets($pipes[1], 1024);
    fclose($pipes[1]);
    $exitCode = proc_close($process);
    
    if ($exitCode !== 0) {
      $err = stream_get_contents($pipes[2]);
      fclose($pipes[2]);
      throw new Exception("Command failed ($exitCode): $err");
    }
    return $output;
  }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved