php执行程序可设置超时时间,linux下可用

来源:赵克立博客 分类: PHP 标签:PHP发布时间:2021-01-13 23:24:32最后更新:2021-01-15 20:02:47浏览:320
版权声明:
本文为博主原创文章,转载请声明原文链接...谢谢。o_0。
更新时间:
2021-01-15 20:02:47
温馨提示:
技术类文章有它的时效性,请留意文章更新时间,如发现内容有误请留言指出,防止别人"踩坑",我会及时更新文章

使用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    = <<<eot
\$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秒后进程退出

2101141610600897947425.png


微信号:kelicom QQ群:215861553 紧急求助须知
点击更换验证码
Win32/PHP/JS/Android/Python