同 exec(),Linux 下第三參數 $return_var 無法接收負數,始終為 0-255 無符號值。
exit(251)。echo $? 顯示 251。$code = 251。ext/standard/exec.c → php_exec() → waitpid() → WEXITSTATUS(status) 宏提取低 8 位 → 無符號化。<?php
function executeCommand($cmd, $cwd = null, $timeout = 30) {
$spec = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];
$proc = proc_open($cmd, $spec, $pipes, $cwd);
if (!is_resource($proc)) {
throw new RuntimeException("Failed to start process: $cmd");
}
// 非阻塞讀取避免死鎖
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$stdout = '';
$stderr = '';
$start = time();
while (true) {
$status = proc_get_status($proc);
if (!$status['running']) break;
if (time() - $start > $timeout) {
proc_terminate($proc, SIGKILL);
throw new RuntimeException("Command timeout: $cmd");
}
$stdout .= stream_get_contents($pipes[1]);
$stderr .= stream_get_contents($pipes[2]);
usleep(10000); // 10ms
}
// 讀取剩餘輸出
$stdout .= stream_get_contents($pipes[1]);
$stderr .= stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) { fclose($pipe); }
$exitCode = proc_close($proc); // 0-255
return [
'exit_code' => $exitCode,
'stdout' => $stdout,
'stderr' => $stderr,
'success' => $exitCode === 0,
];
}
// 使用
$result = executeCommand('/home/wwwroot/test/rtest.out');
if (!$result['success']) {
// 解析 stderr/stdout 獲取真實錯誤
echo "Exit: {$result['exit_code']}\n";
echo "Err: {$result['stderr']}\n";
}
?>
cwd)、環境變量、超時控制、信號發送。<?php
// composer require symfony/process
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
$process = new Process(['/home/wwwroot/test/rtest.out']);
$process->setTimeout(30);
$process->setWorkingDirectory('/home/wwwroot/test');
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
echo $process->getOutput();
// $process->getExitCode() 仍為 0-255
?>