使用php执行外部命令并且取返回值,可设置超时时间,如果超时则中止进程/**
* 执行命令行程序,直到超时退出,只支持linux
* @param string $cmd 命令行程序
* @param string $stdin 标准输入
* @param int $timeout 时间时间秒
* @return array 输出命令结果和错误内容
* @throws Exception
*/
function exec_timeout(string $cmd, string $stdin, int $timeout): array
{
// 传递给进程的标准描述符
$descriptors = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout
2 => array('pipe', 'w') // stderr
);
// 启动进程
$process = proc_open($cmd, $descriptors, $pipes);
if (!is_resource($process)) {
throw new \Exception('Could not execute process');
}
//如果有标准输入内容的话就写入
if ($stdin) {
fwrite($pipes[0], $stdin);
}
fclose($pipes[0]);
// 设置标准输出异步不阻塞
stream_set_blocking($pipes[1], 0);
// 设置标准错误输出异步不阻塞
stream_set_blocking($pipes[2], 0);
// 时间时间转为微妙
$timeout = $timeout * 1000000;
// 标准输出内容
$buffer = '';
// 一直等待到超时退出或执行完自动退出
while ($timeout > 0) {
$start = microtime(true);
// Wait until we have output or the timer expired.
$read = array($pipes[1]);
$other = array();
stream_select($read, $other, $other, 0, $timeout);
// Get the status of the process.
// Do this before we read from the stream,
// this way we can't lose the last bit of output if the process dies between these functions.
$status = proc_get_status($process);
// Read the contents from the buffer.
// This function will always return immediately as the stream is non-blocking.
$buffer .= stream_get_contents($pipes[1]);
if (!$status['running']) {
// Break from this loop if the process exited before the timeout.
break;
}
// Subtract the number of microseconds that we waited.
$timeout -= (microtime(true) - $start) * 1000000;
}
// Check if there were any errors.
$errors = stream_get_contents($pipes[2]);
// if (!empty($errors)) {
// throw new \Exception($errors);
// }
// Kill the process in case the timeout expired and it's still running.
// If the process already exited this won't do anything.
proc_terminate($process, 9);
// Close all streams.
// fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
return [
'error' => $errors,
'result' => $buffer
];
}
调用执行一个php的死循环$code = <<
\$i=0;
while(true){
echo \$i++,PHP_EOL;
sleep(1);
}
eot;
$res = exec_timeout('php -a ', $code, 5);
//替换掉开头的输出和空行
$res['result'] = preg_replace('@Interactive shell\s*\n\s*\n@', '', $res['result']);
print_r($res);
5秒后进程退出