2010-08-05 16 views
0

Si j'exécute avec shell_exec() un programme externe (unix) et cela fonctionne pendant plus de 30 secondes, PHP meurt avec une erreur fatale. C'est parce que le programme externe a pendu/s'est écrasé ou je ne sais pas.Si PHP shell_exec() fonctionne trop longtemps ou un programme exécuté se bloque ... comment attraper l'erreur?

Je veux attraper cette erreur. try{}..catch{} ne fonctionne pas ici. Comment puis-je savoir si un programme externe a été suspendu? Habituellement, mon programme externe s'exécute moins de 2 secondes.

Répondre

0

Vous pouvez utiliser cette fonction system_with_timeout définie dans le script "run-tests.php", inclus dans la distribution source:

(la clé est le dernier paramètre passé à 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; 
} 

Le délai d'attente est donné en passant un tableau comme celui-ci: array('TEST_TIMEOUT' => 200) comme deuxième paramètre.

+0

Cette fonction ne tue pas le processus .. Si elle a expiré. – user338418

+0

Semble que: \t $ arr = proc_get_status ($ proc); \t posix_kill ($ arr ['pid'], 9); A fait le travail. – user338418

+0

@user Cela ressemble à un problème connu: http://php.net/manual/fr/function.proc-terminate.php#81353 – Artefacto