1: <?php
2: // declare(encoding='UTF-8');
3: /**
4: * Classe de gestion des exceptions.
5: * C'est un Singleton.
6: *
7: * @category PHP 5.2
8: * @package Framework
9: * @author Aurélien PERONNET <aurelien@tela-botanica.org>
10: * @author Jean-Pascal MILCENT <jmp@tela-botanica.org>
11: * @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
12: * @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
13: * @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
14: * @version $Id: GestionnaireException.php 367 2011-10-03 12:40:48Z jpm $$
15: * @link /doc/framework/
16: *
17: */
18: class GestionnaireException {
19:
20: const MODE_CLI = 'cli';
21:
22: /** Liste des exceptions enregistrées */
23: private static $exceptions = array();
24:
25: /** Détermine si l'on affiche ou non le contexte */
26: private static $contexte = false;
27:
28: /** Détermine si l'on loggue ou non les erreurs */
29: private static $logger = false;
30:
31: /** Détermine si l'affichage des erreurs est forcé (true) ou pas (false) à la destruction de la classe */
32: private static $afficher = false;
33:
34: /** Definit si php est lancé en ligne de commande ou en mode serveur */
35: private static $mode = null ;
36:
37: /** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
38: private static $parametres_obligatoires = array('debogage', 'debogage_contexte', 'log_debogage');
39:
40: /** Initialise le Gestionnaire d'exceptions et d'erreur sans tenir comptes des paramêtres de config. */
41: public static function initialiser() {
42: self::$mode = php_sapi_name();
43: // Désactivation des balises HTML dans les messages d'erreur de PHP en mode ligne de commande
44: if (self::$mode == self::MODE_CLI) {
45: ini_set('html_errors', 0);
46: }
47:
48: set_exception_handler(array(get_class(),'gererException'));
49: set_error_handler(array(get_class(),'gererErreur'));
50: }
51:
52: /** Configure le Gestionnaire d'exceptions et d'erreur à partir des paramêtres de config. */
53: public static function configurer() {
54: Config::verifierPresenceParametres(self::$parametres_obligatoires);
55: self::$contexte = Config::get('debogage_contexte');
56: self::$logger = Config::get('log_debogage');
57: self::$afficher = Config::get('debogage');
58: }
59:
60: /**
61: * Renvoie le nombre d'exceptions et d'erreurs levées.
62: * @see getExceptions() pour obtenir les exceptions formatées.
63: * @since 0.3
64: * @return int le nombre d'exception actuellement levées
65: */
66: public static function getExceptionsNbre() {
67: return count(self::$exceptions);
68: }
69:
70: /**
71: * Renvoie le booleen définissant si l'on affiche le contexte ou non
72: * @return bool true si on affiche le contexte sinon false.
73: */
74: public static function getContexte() {
75: return self::$contexte;
76: }
77:
78: /**
79: * Definit si l'on veut afficher le contexte ou non
80: * @param bool true si on veut afficher le contexte, false sinon, par défaut vaut false
81: */
82: public static function setContexte($contexte) {
83: self::$contexte = $contexte;
84: }
85:
86: /**
87: * Fonction de gestion des exceptions, remplace le handler par défaut.
88: * Si une boucle génère de multiple exception (ou erreur) identique une seule sera stockée.
89: * @param Exception $e l'exception à traiter
90: */
91: public static function gererException(Exception $e) {
92: $cle = hash('md5', $e->getMessage().'-'.$e->getFile().'-'.$e->getLine());
93: if (!isset(self::$exceptions[$cle])) {
94: self::$exceptions[$cle] = $e;
95: self::loggerException($e);
96: }
97: }
98:
99: /**
100: * Gère les erreurs en les convertissant en exceptions (remplace la fonction gestion d'erreurs native de php)
101: * @param int $niveau le niveau de l'erreur
102: * @param string $message le message associé à l'erreur
103: * @param string $fichier le nom du fichier où l'erreur s'est produite
104: * @param int $ligne la ligne où l'erreur s'est produite
105: * @param string $contexte le contexte associé à l'erreur
106: */
107: public static function gererErreur($niveau, $message, $fichier, $ligne, $contexte){
108: // Si un rapport d'erreur existe, création d'une exception
109: if (error_reporting() != 0) {
110: $e = new ErrorException($message, 0, $niveau, $fichier, $ligne);
111: self::gererException($e);
112: }
113: return null;
114: }
115:
116: /**
117: * Renvoie les exceptions au format (X)HTML ou bien au format texte suivant le mode d'utilisation de PHP.
118: * @since 0.3
119: * @deprecated
120: * @see getExceptionsFormatees()
121: * @return string les exceptions formatées en texte ou (X)HTML.
122: */
123: public static function getExceptions() {
124: return self::getExceptionsFormatees();
125: }
126:
127: /**
128: * Renvoie les exceptions au format (X)HTML ou bien au format texte suivant le mode d'utilisation de PHP.
129: * @since 0.3
130: * @return string les exceptions formatées en texte ou (X)HTML.
131: */
132: public static function getExceptionsFormatees() {
133: $retour = '';
134: if (self::getExceptionsNbre() > 0) {
135: foreach (self::$exceptions as $cle => $e) {
136: switch (self::$mode) {
137: case self::MODE_CLI :
138: $retour .= self::formaterExceptionTxt($e);
139: break;
140: default:
141: $retour .= self::formaterExceptionXhtml($e);
142: }
143: // Nous vidons le tableau des exceptions au fur et à mesure pour éviter le réaffichage avec le destructeur.
144: unset(self::$exceptions[$cle]);
145: }
146: }
147: return $retour;
148: }
149:
150: /**
151: * Renvoie le tableau d'objets Exception générées par le script PHP triées du niveau de sévérité le plus élevé au moins élevé.
152: * Format du tableau :
153: * array{sévérité_1 = array{Exception1, Exception2, Exception3,...}, sévérité_1 = array{Exception1, Exception2, ...}, ...};
154: * ATTENTION : si vous utilisez cette méthode, c'est à vous de gérer l'affichage des Exceptions. Le gestionnaire d'exception
155: * n'enverra plus rien au navigateur ou à la console.
156: * @since 0.3
157: * @return array le tableau trié d'objet Exception.
158: */
159: public static function getExceptionsTriees() {
160: $retour = array();
161: if (self::getExceptionsNbre() > 0) {
162: foreach (self::$exceptions as $cle => $e) {
163: $retour[$e->getSeverity()][] = $e;
164: // Nous vidons le tableau des exceptions au fur et à mesure pour éviter le réaffichage avec le destructeur.
165: unset(self::$exceptions[$cle]);
166: }
167: ksort($retour);
168: }
169: return $retour;
170: }
171:
172: /**
173: * Logue une exception donnée sous une forme lisible si self::logger vaut true.
174: * @param Exception $e l'exception à logger
175: */
176: private static function loggerException(Exception $e) {
177: if (self::$logger) {
178: $message = self::formaterExceptionTxt($e);
179: Log::ajouterEntree('erreurs', $message);
180: }
181: }
182:
183: /**
184: * Formate en texte une exception passée en paramètre.
185: * @since 0.3
186: * @param Exception l'exception à formater.
187: */
188: public static function formaterExceptionDebug(Exception $e) {
189: $txt = '';
190: if ($e->getSeverity() == E_USER_NOTICE) {
191: $txt = $e->getMessage();
192: } else {
193: $txt = self::formaterExceptionTxt($e);
194: }
195: return $txt;
196: }
197:
198: /**
199: * Formate en texte une exception passée en paramètre.
200: * @since 0.3
201: * @param Exception l'exception à formater.
202: */
203: public static function formaterExceptionTxt(Exception $e) {
204: $message = '';
205: $message .= $e->getMessage()."\n";
206: $message .= 'Fichier : '.$e->getFile()."\n";
207: $message .= 'Ligne : '.$e->getLine()."\n";
208: if (self::getContexte()) {
209: $message .= 'Contexte : '."\n".print_r($e->getTraceAsString(), true)."\n";
210: }
211: $message .= "\n";
212: return $message;
213: }
214:
215: /**
216: * Formate en (X)HTML une exception passée en paramètre.
217: * @since 0.3
218: * @param Exception l'exception à formater.
219: */
220: public static function formaterExceptionXhtml(Exception $e) {
221: $message = '';
222: $message .= '<div class="debogage">'."\n";
223: $message .= $e->getMessage()."\n";
224: $message .= '<span class="debogage_fichier">'.'Fichier : '.$e->getFile().'</span>'."\n";
225: $message .= '<span class="debogage_ligne">'.'Ligne : '.$e->getLine().'</span>'."\n";
226: if (self::getContexte()) {
227: $message .= '<pre>'."\n";
228: $message .= '<strong>Contexte : </strong>'."\n".print_r($e->getTraceAsString(), true)."\n";
229: $message .= '</pre>'."\n";
230: }
231: $message .= '</div>'."\n";
232: return $message;
233: }
234:
235: /**
236: * Lors de la destruction de la classe si des exceptions n'ont pas été affichées, et si le débogage est à true, elles sont
237: * affichées.
238: */
239: public function __destruct() {
240: // Si des erreurs n'ont pas été affichée nous forçons leur affichage
241: if (self::$afficher && self::getExceptionsNbre() > 0) {
242: echo self::getExceptionsFormatees();
243: }
244: }
245:
246: }
247: ?>