Если PHP shell_exec () работает слишком долго или исполняемая программа зависает ... как отловить ошибку? - PullRequest
0 голосов
/ 05 августа 2010

Если я выполняю с shell_exec() внешнюю программу (unix) и она работает более 30 секунд, PHP умирает с фатальной ошибкой.Это потому, что внешняя программа зависла / потерпела крах или я не знаю.

Я хочу отловить эту ошибку.try{}..catch{} здесь не работает.Как я могу определить, зависла ли внешняя программа?Обычно моя внешняя программа запускается менее чем за 2 секунды.

1 Ответ

0 голосов
/ 05 августа 2010

Вы можете использовать эту функцию system_with_timeout, определенную в скрипте run-tests.php, включенном в исходный дистрибутив:

(ключ - последний параметр, переданный stream_select)

function system_with_timeout($commandline, $env = null, $stdin = null)
{
    global $leak_check, $cwd;

    $data = b'';

    $bin_env = array();
    foreach((array)$env as $key => $value) {
        $bin_env[(binary)$key] = (binary)$value;
    }

    $proc = proc_open($commandline, array(
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w'),
        2 => array('pipe', 'w')
        ), $pipes, $cwd, $bin_env, array('suppress_errors' => true, 'binary_pipes' => true));

    if (!$proc) {
        return false;
    }

    if (!is_null($stdin)) {
        fwrite($pipes[0], (binary) $stdin);
    }
    fclose($pipes[0]);

    $timeout = $leak_check ? 300 : (isset($env['TEST_TIMEOUT']) ? $env['TEST_TIMEOUT'] : 60);

    while (true) {
        /* hide errors from interrupted syscalls */
        $r = $pipes;
        $w = null;
        $e = null;

        $n = @stream_select($r, $w, $e, $timeout);

        if ($n === false) {
            break;
        } else if ($n === 0) {
            /* timed out */
            $data .= b"\n ** ERROR: process timed out **\n";
            proc_terminate($proc);
            return $data;
        } else if ($n > 0) {
            $line = (binary) fread($pipes[1], 8192);
            if (strlen($line) == 0) {
                /* EOF */
                break;
            }
            $data .= $line;
        }
    }

    $stat = proc_get_status($proc);

    if ($stat['signaled']) {
        $data .= b"\nTermsig=" . $stat['stopsig'];
    }

    $code = proc_close($proc);
    return $data;
}

Время ожидания определяется передачей массива, подобного следующему: array('TEST_TIMEOUT' => 200) в качестве второго параметра.

...