在 Windows 環境下,PHP 可通過 COM 組件或 proc_open() 執行系統命令。
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')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);
}
}
stream_select()$command 若含用戶輸入必須嚴格過濾(escapeshellcmd()、escapeshellarg())exec、shell_exec、proc_open、COM| 需求 | 推薦方案 |
|---|---|
| 執行系統命令 | 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;
}
}