[PHP] Error handler sur Max. execution time

yo! les geeks,

Je cherche à intercepter l’erreur “Maximum execution time exceeded” de PHP. Elle arrive, comme l’indique le message, lorsque qu’un script traine trop. Or, mon script va chercher des données RSS à grands coups de fread qui peuvent durer un certain temps. D’ailleurs, on notera que le fread ne retourne pas de code d’erreur en cas de problème
@$fp = @fopen($adresse,“r”);
if ($fp)
{
 $data = fread($fp, 4096);
 while ($data)
 {
if ( !@xml_parse($parser, $data, feof($fp)) )
{
 $err=1;
 break;
}
$data = fread($fp, 4096);
 }
 fclose($fp);
}
Impossible de savoir s’il y a eu erreur quand $data est à FALSE. Ca peut aussi bien signifier la fin du flux.

Mais mon problème n’est pas là… Apparemment set_error_handler refuse de gérer la fatale “Maximum execution…”. Vous connaissez un moyen alternatif ? Et ce, sans toucher à la config de PHP (hébergement mutualisé).

Thx
Antoine

Bon, je sais pas comment regler ton probleme sur max execution time MAIS je peux t’affirmer que c’est une BAD idee de lire un fichier xml comme tu fais: si la fin des 4096 characteres arrivent au milieu d’un tag, tu l’as dans le cul. J’en ai fait l’experience, je connais.
Donc l’exemple de php.net est a chier, et perso, je fais ca:
while ($temp = fread($fp, 4096))
{
  if($temp)
  $datafile=$datafile.$temp;
}
C’est bourrin mais ca fonctionne (Note pour les planques du fond: impossible d’avoir la taille d’un fichier lu via fopen en passant par une URL, d’ou la lecture par bloc)

LoneWolf
Des fois, les exemples de php.net, c’est plus que moyen.

Moui pas faux, mais je pensais que les handlers de parsing XML (xml_set_element_handler et xml_set_character_data_handler) géraient le flux en interne. A priori, je dirais que c’est le cas puisque jusqu’ici je n’ai pas eu à déplorer d’erreur.
Néanmoins ta remarque est tout de même assez juste et, tant qu’à faire, autant aider le parseur en lui passant des données complètes… Donc je prends ton code

EDIT : tographe
EDIT2 :
Apparemment, le parseur XML est prévu pour gérer les flux par morceaux. Cf. la définition de xml_parse où le troisième paramètre indique la fin des données.

  data
Une partie des données à analyser. Un document peut être analysé morceau par morceau, en appelant xml_parse() plusieurs fois, tant que le paramètre is_final est mis à TRUE pour le dernier morceau.
is_final (optional)
S’il vaut TRUE, data est la dernière partie à analyser
 
 
Ce message a été édité par AntoineViau le 29/06/2004

Je t’avouerais que j’ai pas cherche la petite bete, le code repris tel quel de PHP.net ne marchant pas, j’ai fait le mien

Sinon, j’ai fait un parseur XML en PHP qui gere des fichier de +/- 100k (et ca mets 2 ou 3 secondes), il fait quel taille ton fichier pour faire un max execution time out? Ou t’as un traitement hyper complique?

LoneWolf
Ou est la petite bete?

[quote]Je t’avouerais que j’ai pas cherche la petite bete, le code repris tel quel de PHP.net ne marchant pas, j’ai fait le mien

Sinon, j’ai fait un parseur XML en PHP qui gere des fichier de +/- 100k (et ca mets 2 ou 3 secondes), il fait quel taille ton fichier pour faire un max execution time out? Ou t’as un traitement hyper complique?

LoneWolf
Ou est la petite bete?[/quote]
Nanan, pas de traitement complexe… C’est juste un flux RSS qui est attrapé sur un serveur distant avec tout ce que ça implique : si le serveur traine, mon script traine, et le PHP couine. Comme je n’ai aucun contrôle sur le serveur qui héberge le flux PHP, et que j’aimerais avoir un beau message propre (genre “service indisponible”) je cherche désespérément un moyen de hooker le fatal de PHP (max. execution time etc.)
Contrainte supplémentaire : le serveur PHP est mutualisé donc je ne peux pas faire ce que je veux (genre recompiler PHP )

Tu peux utiliser register_shutdown_function pour enregistrer une fonction qui sera executée à la fin de ton script.
Sinon si php est pas en SafeMode, tu peux utiliser set_time_limit pour changer la limite de temps d’execution du script (ou 0 pour pas de limite).

[quote]Tu peux utiliser register_shutdown_function pour enregistrer une fonction qui sera executée à la fin de ton script.
Sinon si php est pas en SafeMode, tu peux utiliser set_time_limit pour changer la limite de temps d’execution du script (ou 0 pour pas de limite).[/quote]Mais comment utiliser register_shutdown_function dans mon cas (détection du maximum execution time) ? Il faut d’abord que j’intercepte l’erreur fatale et ensuite que je puisse agir. Or, d’après la doc :
Les fonctions d’extinction sont appelées après la fin de la requête (notamment les buffers ont été vidés), ce qui fait qu’il est impossible d’afficher du texte depuis cette fonction, avec echo() ou print(), ou encore de lire le contenu des buffers avec ob_get_contents().

Le set_time_limit est effectivement une solution, même si le processus est un peu alambiqué. Il faut d’abord que je fixe un timeout arbitraire pour la lecture du flux RSS que l’on va supposer supérieur au timeout interne de PHP (celui qui provoque le fatal maximum execution etc.). Je check par un timer si je dois ou non réinitialiser le timer interne de PHP par set_time_limit. A côté, un timer perso vérifie si j’ai éclaté ou pas mon timeout arbitraire.
Donc, à la limite, autant faire plus simple : je check par un timer interne le temps que je mets à consulter le flux RSS. En supposant que le timeout interne de PHP est de 30 secondes, je fixe mon seuil à 25 secondes et dès qu’il est dépassé : erreur, on considère que le flux RSS est down.

J’ai cru avoir trouvé une solution pour intercepter les erreurs fatales de PHP (ce qui, officiellement, n’est pas faisable) en utilisant le buffer de sortie et la fonction ob_start(callback). La callback est appelé avec le ob_end ce qui permet d’avoir le contenu de la page générée dans une variable. Ca marche pour l’erreur fatale de parsing mais malheureusement pas sur le max. execution time dont le message n’est pas mis dans le buffer

Antoine