83 votes

Comment attraper l'erreur fatale : Le temps d'exécution maximal de 30 secondes a été dépassé en PHP

Je me suis amusé avec un système que je développe et j'ai réussi à provoquer ça :

Erreur fatale : Le temps d'exécution maximum de 30 secondes a été dépassé

Cela s'est produit lorsque je faisais quelque chose d'irréaliste, mais néanmoins cela pourrait se produire avec un utilisateur.

Quelqu'un sait-il s'il existe un moyen d'attraper cette exception ? Je me suis renseigné, mais tout le monde semble suggérer d'augmenter le temps imparti.

1 votes

Je crois qu'une fois le temps d'exécution dépassé, le script est terminé. Dans ce cas, le script qui aurait pu attraper l'exception a déjà été tué.

0 votes

Les erreurs fatales ne peuvent pas être attrapées (ce ne sont pas des exceptions) ou traitées. Vous pouvez seulement gérer la fin de script de manière gracieuse en enregistrement d'une fonction d'arrêt mais le script se terminera après.

0 votes

99voto

TheJanOnline Points 171

Que diriez-vous d'essayer comme le dit la documentation PHP (enfin... au moins un de ses lecteurs) :

<?php
function shutdown()
{
 $a = error_get_last();

 if ($a == null) {echo "No errors";}
 else {print_r($a);}
}

register_shutdown_function('shutdown');
ini_set('max_execution_time', 1);
sleep(3);
?>

Jetez un coup d'œil aux liens suivants :

  1. http://www.php.net/manual/en/function.set-error-handler.php#106061
  2. http://www.php.net/manual/en/function.register-shutdown-function.php

36voto

cwallenpoole Points 34940

Vos seules options sont d'augmenter le temps d'exécution autorisé (le mettre à 0 le rend infini, mais ce n'est pas recommandé) du script ou de créer un nouveau fil de discussion et d'espérer le meilleur.

La raison pour laquelle elle n'est pas rattrapable est qu'elle n'est pas vraiment lancée. Aucune ligne de code n'a déclenché l'erreur, PHP a plutôt dit : "Non, désolé, c'est trop long. Il est temps de s'arrêter". Et cela a du sens. Imaginez qu'un script avec un temps d'exécution maximum de 30 secondes attrape cette erreur et prenne encore 30 secondes... dans un programme mal conçu, cela ouvre des opportunités d'exploitation plutôt méchantes. Au minimum, cela crée des opportunités pour DOS attaques.

22voto

GordonM Points 14008

Ce n'est pas une exception, c'est une erreur. Il existe des différences importantes entre les exceptions et les erreurs. Tout d'abord, les erreurs ne peuvent pas être attrapées avec la sémantique try/catch.

Les scripts de PHP sont construits autour d'un paradigme de temps d'exécution courts, donc PHP est configuré par défaut pour supposer que si un scripts a été exécuté pendant plus de 30 secondes, il doit être pris dans une boucle infinie et doit donc être terminé. Ceci afin d'éviter qu'un scripts PHP errant ne provoque un déni de service, que ce soit par accident ou par intention malveillante.

Cependant, les scripts ont parfois besoin de plus de temps d'exécution que celui qui leur est alloué par défaut.

Vous pouvez essayer de modifier le temps d'exécution maximal, soit en utilisant le bouton set_time_limit() ou en modifiant la valeur de max_execution_time dans le php.ini pour augmenter la limite. Vous pouvez également supprimer complètement la limite en fixant le temps d'exécution à 0, bien que cela ne soit pas recommandé.

set_time_limit() peuvent être désactivés par des mécanismes tels que disable_functions donc il pourrait ne pas être disponible pour vous, de même vous pourriez ne pas avoir accès à php.ini . Si c'est le cas, vous devez contacter votre hôte pour obtenir de l'aide.

Une exception : les scripts PHP exécutés à partir de l'interface de l'utilisateur. ligne de commande . Dans ces conditions d'exécution, les scripts de PHP peuvent être interactifs et doivent passer un long moment à traiter des données ou à attendre des entrées. Pour cette raison, il n'y a pas de max_execution_time limite sur les scripts exécutés à partir de la ligne de commande par défaut.


ED EDIT TO ADD : La gestion des erreurs de PHP 7 a été profondément remaniée. Je crois que les erreurs et les exceptions sont maintenant toutes deux des sous-classes de Throwable. Cela peut rendre ce qui précède non pertinent pour PHP7+, bien que je doive regarder de plus près les spécificités de la gestion des erreurs pour en être sûr.

9voto

Pyzozord Points 143

Oui, j'ai testé la solution de TheJanOnline. sleep() ne compte pas dans le temps d'exécution du php donc voici une version qui fonctionne avec une boucle indéfinie :

<?php 
function shutdown() 
 { 
     $a=error_get_last(); 
     if($a==null)   
         echo "No errors"; 
     else 
          print_r($a); 

 } 
register_shutdown_function('shutdown'); 
ini_set('max_execution_time',1 ); 
while(1) {/*nothing*/}
// will die after 1 sec and print error
?>

8voto

p.vansia Points 335

Il n'y a rien que vous puissiez faire à ce sujet. Mais vous pouvez avoir un arrêt en douceur en utilisant la fonction register_shutdown_function.

<?php 

ini_set('display_errors', '0');         
ini_set("max_execution_time",15 ); //you can use this if you know your script should not take longer than 15 seconds to finish

register_shutdown_function('shutdown');

function shutdown() 
{ 
       $error = error_get_last();

       if ($error['type'] === E_ERROR) {

      //do your shutdown stuff here
      //be care full do not call any other function from within shutdown function
      //as php may not wait until that function finishes
      //its a strange behavior. During testing I realized that if function is called 
      //from here that function may or may not finish and code below that function
      //call may or may not get executed. every time I had a different result. 

      // e.g.

      other_function();

      //code below this function may not get executed

       } 

} 

while(true)
{

}

function other_function()
{
  //code in this function may not get executed if this function
  //called from shutdown function
} 

?>

0 votes

Serait other_function() sera-t-il appelé pendant l'arrêt s'il a été déclaré avant la boucle infinie ?

0 votes

@Douglas.Sesar other_function() sera appelée de toute façon. Mais il n'y a aucune garantie qu'elle se termine et que tout code situé en dessous de l'appel de fonction. Si l'autre_fonction() prend très peu de temps pour faire très peu de choses, elle peut finir et tout code en dessous de l'appel de fonction. Mais si elle prend trop de temps pour accomplir une tâche, il n'y a aucune garantie qu'elle se termine entièrement !

0 votes

Dans le sens le plus strict de la question du PO, cette solution fonctionne. Je tiens à reconnaître que ma réponse légèrement élaborée a été inspirée par votre réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X