web-dev-qa-db-fra.com

PHP: gestionnaire d'erreurs personnalisé - gestion des erreurs d'analyse et fatales

Comment gérer les erreurs parse & fatal en utilisant un gestionnaire d'erreur personnalisé?

54
A.N.M. Saiful Islam

Réponse simple: vous ne pouvez pas. Voir le manuel :

Les types d'erreur suivants ne peuvent pas être traités avec une fonction définie par l'utilisateur: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING et la plupart des E_STRICT générés dans le fichier où set_error_handler () est appelé.

Pour toute autre erreur, vous pouvez utiliser set_error_handler()

ÉDITER:

Puisqu'il semble qu'il y ait des discussions sur ce sujet, en ce qui concerne l'utilisation de register_shutdown_function, nous devrions jeter un oeil à la définition de la gestion: Pour moi, gérer une erreur signifie attraper l'erreur et réagir de manière "agréable" pour l'utilisateur et les données sous-jacentes (bases de données, fichiers, services Web, etc.).

En utilisant register_shutdown_function vous ne pouvez pas gérer une erreur à partir du code où elle a été appelée, ce qui signifie que le code cesserait de fonctionner au point où l'erreur se produit. Vous pouvez cependant présenter à l'utilisateur un message d'erreur au lieu d'une page blanche, mais vous ne pouvez pas, par exemple, annuler tout ce que votre code a fait avant d'échouer.

27
Dan Soap

En fait, vous pouvez gérer les erreurs d'analyse et fatales. Il est vrai que la fonction de gestionnaire d'erreurs que vous avez définie avec set_error_handler () ne sera pas appelée. Pour ce faire, définissez une fonction d'arrêt avec register_shutdown_function (). Voici ce que je travaille sur mon site Web:

Fichier prepend.php (ce fichier sera ajouté automatiquement à tous les scripts php). Voir ci-dessous pour des conseils sur l'ajout préalable de fichiers à PHP.

set_error_handler("errorHandler");
register_shutdown_function("shutdownHandler");

function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context)
{
$error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line;
switch ($error_level) {
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_PARSE:
        mylog($error, "fatal");
        break;
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
        mylog($error, "error");
        break;
    case E_WARNING:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_USER_WARNING:
        mylog($error, "warn");
        break;
    case E_NOTICE:
    case E_USER_NOTICE:
        mylog($error, "info");
        break;
    case E_STRICT:
        mylog($error, "debug");
        break;
    default:
        mylog($error, "warn");
}
}

function shutdownHandler() //will be called when php script ends.
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_PARSE:
        $error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
        mylog($error, "fatal");
}
}

function mylog($error, $errlvl)
{
...do whatever you want...
}

PHP appellera la fonction errorHandler () s'il détecte une erreur dans l'un des scripts. Si l'erreur force le script à s'arrêter immédiatement, l'erreur est gérée par la fonction shutdownHandler ().

Cela fonctionne sur le site que j'ai en cours de développement. Je ne l'ai pas encore testé en production. Mais il détecte actuellement toutes les erreurs que je trouve lors de son développement.

Je crois qu'il y a un risque d'attraper deux fois la même erreur, une fois par chaque fonction. Cela peut se produire si une erreur que je gère dans la fonction shutdownHandler () a également été détectée par la fonction errorHandler ().

TODO:

1 - J'ai besoin de travailler sur une meilleure fonction log () pour gérer les erreurs avec élégance. Étant donné que je suis encore en développement, j'enregistre essentiellement l'erreur dans une base de données et je la répercute sur l'écran.

2 - Implémentez la gestion des erreurs pour tous les appels MySQL.

3 - Implémenter la gestion des erreurs pour mon code javascript.

NOTES IMPORTANTES:

1 - J'utilise la ligne suivante dans mon php.ini pour ajouter automatiquement le script ci-dessus à tous les scripts php:

auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"

ça marche bien.

2 - J'enregistre et résout toutes les erreurs, y compris les erreurs E_STRICT. Je crois au développement d'un code propre. Pendant le développement, mon fichier php.ini a les lignes suivantes:

track_errors = 1
display_errors = 1
error_reporting = 2147483647
html_errors = 0

Lorsque je serai en ligne, je changerai display_errors à 0 pour réduire le risque que mes utilisateurs voient des messages d'erreur PHP PHP).

J'espère que ça aidera quelqu'un.

69
jdias

Vous pouvez suivre ces erreurs en utilisant un code comme celui-ci:

(Les erreurs d'analyse ne peuvent être détectées que si elles se produisent dans les fichiers de script other via include() ou require(), ou en mettant ce code dans un auto_prepend_file comme d'autres réponses l'ont mentionné.)

function shutdown() {
    $isError = false;

    if ($error = error_get_last()){
    switch($error['type']){
        case E_ERROR:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
            $isError = true;
            break;
        }
    }

    if ($isError){
        var_dump ($error);//do whatever you need with it
    }
}

register_shutdown_function('shutdown');
30
Deniss Kozlovs

D'après les commentaires PHP.net sur la page http://www.php.net/manual/en/function.set-error-handler.php

J'ai réalisé que quelques personnes ici ont mentionné que vous ne pouvez pas capturer les erreurs d'analyse (type 4, E_PARSE). Ce n'est pas vrai. Voici comment je fais. J'espère que ça aidera quelqu'un.

1) Créez un fichier "auto_prepend.php" dans la racine Web et ajoutez ceci:

<?php 
register_shutdown_function('error_alert'); 

function error_alert() 
{ 
        if(is_null($e = error_get_last()) === false) 
        { 
                mail('[email protected]', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 

2) Ajoutez ensuite ce "php_value auto_prepend_file /www/auto_prepend.php" à votre fichier .htaccess dans la racine Web.

  • assurez-vous de modifier l'adresse e-mail et le chemin d'accès au fichier.
11
Creativehavoc

D'après mon expérience, vous pouvez détecter tout type d'erreurs, masquer le message d'erreur par défaut et afficher un message d'erreur de votre choix (si vous le souhaitez). Vous trouverez ci-dessous les éléments dont vous avez besoin.

1) Un script de niveau initial/supérieur, appelons-le index.php Où vous stockez vos fonctions de gestion d'erreurs personnalisées. Les gestionnaires de fonctions d'erreur personnalisées doivent rester au sommet afin de détecter les erreurs en dessous, par "ci-dessous", je veux dire dans les fichiers inclus.

2) L'hypothèse que ce premier script est exempt d'erreur doit être vraie! ceci est très important, vous ne pouvez pas intercepter les erreurs fatales dans index.php lorsque votre fonction de gestion des erreurs personnalisée se trouve dans index.php.

3) Directives Php (doivent également être trouvées dans index.php) set_error_handler("myNonFatalErrorHandler"); # pour détecter les erreurs non fatales register_shutdown_function('myShutdown'); # pour détecter les erreurs fatales ini_set('display_errors', false); #afin de masquer les erreurs montrées à l'utilisateur par php ini_set('log_errors',FALSE); # en supposant que nous enregistrons nous-mêmes les erreurs ini_set('error_reporting', E_ALL); #Nous aimons signaler toutes les erreurs

pendant la production (si je ne me trompe pas) nous pouvons laisser ini_set('error_reporting', E_ALL); tel quel afin de pouvoir enregistrer les erreurs, en même temps ini_set('display_errors', false); s'assurera qu'aucune erreur ne sera affichée à l'utilisateur.

En ce qui concerne le contenu réel des deux fonctions dont je parle, myNonFatalErrorHandler et myShutdown, je ne mets pas de contenu détaillé ici afin de garder les choses simples. De plus, les autres visiteurs ont donné beaucoup d'exemples. Je montre juste une idée très simple.

function myNonFatalErrorHandler($v, $m, $f, $l, $c){
 $some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like";
 //You can display the content of $some_logging_var_arr1 at the end of execution too.
}

function myShutdown()
{
  if( ($e=error_get_last())!==null ){
      $some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line'];
  }
//display $some_logging_var_arr2 now or later, e.g. from a custom session close function
}

quant à $ err_lvl cela peut être:

$err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING',
E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');
5
Melsi

Le script avec erreur d'analyse est toujours interrompu et ne peut pas être géré. Donc, si le script est appelé directement ou par include/require, vous ne pouvez rien faire. Mais s'il est appelé par AJAX, flash ou de toute autre manière, il existe une solution de contournement pour détecter les erreurs d'analyse.

J'en avais besoin pour gérer le script swfupload . Swfupload est un flash qui gère les téléchargements de fichiers et chaque fois que le fichier est téléchargé, il appelle PHP script de gestion pour gérer les données de fichier - mais il n'y a pas de sortie de navigateur, donc le PHP = la gestion du script nécessite ces paramètres à des fins de débogage:

  • avertissements et notifications ob_start (); au début et stocker le contenu dans la session par ob_get_contents (); à la fin du script de gestion: il peut être affiché dans le navigateur par un autre script
  • erreurs fatales register_shutdown_function () pour définir la session avec la même astuce que ci-dessus
  • erreurs d'analyse si l'ob_get_contents () se trouve à la fin du script de gestion et qu'une erreur d'analyse s'est produite avant, la session n'est pas remplie (elle est nulle) . Le script de débogage peut le gérer de cette façon: if(!isset($_SESSION["swfupload"])) echo "parse error";

Remarque 1 null signifie is not set À isset()

4
Jan Turoň