Precision about error_log when configured with syslog: the syslog() call is done with severity NOTICE.
XXXIII. Gestion des erreurs
Introduction
Ces fonctions permettent de gérer les erreurs et de les enregistrer. Vous pouvez définir les règles de traitement des erreurs et choisir la manière de les enregistrer : vous pouvez adapter le rapport d'erreurs à vos besoins.
Avec les fonctions d'enregistrements, vous pouvez envoyer directement les rapports à d'autres machines (ou même les envoyer par email à un pager), à l'historique système, ou encore sélectionner les erreurs les plus importantes et ne pas enregistrer les autres.
La fonction de niveau d'erreur vous permet de personnaliser le niveau et le type d'erreur noté : depuis les inoffensives alertes jusqu'aux erreurs personnalisées retournées par les fonctions.
Pré-requis
Ces fonctions sont disponibles dans le module PHP standard, qui est toujours accessible.
Installation
Il n'y pas d'installation nécessaire pour utiliser ces fonctions, elles font parties du coeur de PHP.
Configuration à l'exécution
Le comportement de ces fonctions est affecté par la configuration dans le fichier php.ini.
Tableau 1. Options de configuration
| Nom | Par défaut | Modifiable | Historique |
|---|---|---|---|
| error_reporting | NULL | PHP_INI_ALL | |
| display_errors | "1" | PHP_INI_ALL | |
| display_startup_errors | "0" | PHP_INI_ALL | Disponible depuis PHP 4.0.3. |
| log_errors | "0" | PHP_INI_ALL | |
| log_errors_max_len | "1024" | PHP_INI_ALL | Disponible depuis PHP 4.3.0. |
| ignore_repeated_errors | "0" | PHP_INI_ALL | Disponible depuis PHP 4.3.0. |
| ignore_repeated_source | "0" | PHP_INI_ALL | Disponible depuis PHP 4.3.0. |
| report_memleaks | "1" | PHP_INI_ALL | Disponible depuis PHP 4.3.0. |
| track_errors | "0" | PHP_INI_ALL | |
| html_errors | "1" | PHP_INI_ALL | PHP_INI_SYSTEM en PHP <=4.2.3. Disponible depuis PHP 4.0.2. |
| docref_root | "" | PHP_INI_ALL | Disponible depuis PHP 4.3.0. |
| docref_ext | "" | PHP_INI_ALL | Disponible depuis PHP 4.3.2. |
| error_prepend_string | NULL | PHP_INI_ALL | |
| error_append_string | NULL | PHP_INI_ALL | |
| error_log | NULL | PHP_INI_ALL | |
| warn_plus_overloading | NULL | PHP_INI?? |
Voici un éclaircissement sur l'utilisation des directives de configuration.
- error_reporting entier
Fixe le niveau d'erreur. Ce paramètre est un entier, représentant un champ de bits. Ajoutez les valeurs suivantes pour choisir le niveau que vous désirez, telles que décrites dans la section Constantes pré-définies, et dans le fichier php.ini. Pour modifier cette configuration durant l'exécution du script, utilisez la fonction error_reporting(). Voyez aussi la directive display_errors.
En PHP 4 et PHP 5, la configuration par défaut est E_ALL & ~E_NOTICE. Elle montre toutes les erreurs, sauf les E_NOTICE. Il est recommandé de les afficher durant le développement.
Note : Activer le rapport d'erreur de niveau E_NOTICE durant le développement a des avantages. En terme de débogage, les message d'alertes vous signalent des bogues potentiels dans votre code. Par exemple, l'utilisation de valeurs non initialisées est signalée. Il est aussi plus pratique pour trouver des coquilles, et, ainsi, gagner du temps. Les messages NOTICE vous signaleront aussi les mauvaises pratiques de codage. Par exemple $arr[item] doit toujours être écrit $arr['item'] car PHP va considérer "item" comme une constante, au premier abord. Si cette constante n'est pas définie, alors il va l'utiliser comme une chaîne.
Note : En PHP 5, un nouveau niveau d'erreur nommé E_STRICT est disponible. Comme E_STRICT n'est pas inclus sans E_ALL, vous devez explicitement activer ce niveau d'erreur. Activer E_STRICT pendant le développement peut être bénéfique. Les messages STRICT vous aideront à utiliser la dernière et meilleure suggestion de méthode de codage, par exemple, vous alertera de l'utilisation de fonctions non recommandées.
En PHP 3, la configuration par défaut est (E_ERROR | E_WARNING | E_PARSE), ce qui correspond à la même configuration qu'en PHP 4. Notez toutefois que les constantes ne sont pas supportées dans le php3.ini de PHP 3, et que le niveau d'erreur doit être spécifié numériquement, c'est à dire 7.
- display_errors boolean
Cette directive détermine si les erreurs doivent être affichées à l'écran ou non.
Note : C'est une directive nécessaire en développement mais qui ne doit jamais être utilisée sur un système en production. (e.g. systèmes connectés à Internet).
Note : Bien que display_errors peut être défini en cours d'exécution (avec la fonction ini_set()), il n'aura aucun effet si le script a des erreurs fatales, car l'action désirée au moment de l'exécution ne sera pas exécutée.
- display_startup_errors boolean
Même si display_errors est activé, des erreurs peuvent survenir lors de la séquence de démarrage de PHP, et ces erreurs sont cachées. Avec cette option, vous pouvez les afficher, ce qui est recommandé pour le débogage. En dehors de ce cas, il est fortement recommandé de laisser display_startup_errors à off.
- log_errors boolean
Indique où les messages d'erreur générés doivent être écrits : dans l'historique du serveur ou dans error_log. Cette fonction est spécifique aux serveurs.
Note : Il est recommandé d'utiliser l'historique d'erreur, plutôt que d'afficher les erreurs sur les sites de production.
- log_errors_max_len entier
Configure la taille maximale des erreurs qui seront enregistrées dans l'historique, en kilo octets. Dans les informations de error_log, l'origine est ajoutée. La valeur par défaut est de 1024. 0 signifie qu'il n'y a pas de limite de taille. Cette longueur est appliqué pour enregistrer dans l'historique les erreurs, afficher les erreurs et également à $php_errormsg.
Lorsqu'un entier est utilisé, sa valeur est mesuré en octets. Vous pouvez également utiliser la notation sténographique comme décrit dans cette entrée de la FAQ..
- ignore_repeated_errors boolean
Ne pas enregistrer des messages répétitifs. Les erreurs répétées doivent survenir au même moment, à la même ligne et depuis le même fichier de script, jusqu'à ce que ignore_repeated_source soit mis à TRUE.
- ignore_repeated_source boolean
Ignore la source du message lors des messages répétés. Lorsque vous avez configuré cette option à On, vous n'enregistrerez pas les erreurs répétées provenant de fichiers et lignes de code différents.
- report_memleaks boolean
Si ce paramètre est mis à Off, alors les fuites de mémoires ne seront pas affichées (sur la sortie standard, stdout ou dans les logs). Cette option n'a d'effet que si PHP a été compilé avec l'option de débogage, et si error_reporting inclut E_WARNING dans sa liste.
- track_errors boolean
Si cette option est activée, le dernier message d'erreur sera placé dans la variable globale $php_errormsg.
- html_errors boolean
Désactive les balises HTML dans les messages d'erreurs. Le nouveau format d'erreurs HTML fournit des messages cliquables, qui redirige l'utilisateur vers la documentation de l'erreur ou de la fonction. Ces références sont affectées par docref_root et docref_ext.
- docref_root string
Le nouveau format d'erreur contient une référence à une page décrivant l'erreur, ou la fonction ayant causé l'erreur. Pour le manuel, vous pouvez télécharger ce dernier dans votre langue, et configurer cette option pour qu'elle pointe sur lui. Si votre copie du manuel est accessible à '/manual/', vous pouvez simplement utiliser docref_root=/manual/. De plus, vous devez configurer docref_ext pour qu'elle corresponde aux extensions de votre manuel. docref_ext=.html. Il est possible d'utiliser des références externes. Par exemple, vous pouvez utiliser docref_root=http://manual/en/ ou docref_root="http://landonize.it/?how=url&theme=classic&filter=Landon&url=http%3A%2F%2Fwww.php.net%2F"
La plupart du temps, vous utilisez l'option docref_root avec un slash a la fin ('/'). Mais ce n'est pas obligatoire, comme le montre le second exemple ci-dessus.
Note : Cette directive est destiné à vous aider dans votre développement en rendant facile la consultation de la description d'une fonction. Ne jamais l'utiliser sur un système de production (e.g. système connecté à Internet).
- docref_ext string
Voir aussi docref_root.
Note : La valeur de docref_ext doit commencer par un point '.'.
- error_prepend_string string
La chaîne à placer avant les messages d'erreur.
- error_append_string string
La chaîne à placer après les messages d'erreur.
- error_log string
Nom du fichier où seront enregistrées les erreurs. Le fichier doit être accessible en écriture par l'utilisateur exécutant le serveur web. Si la valeur spéciale syslog est utilisée, les erreurs seront envoyées au système d'historique du serveur. Sous Unix, cela correspond à syslog(3) et sous Windows NT, à l'historique d'événement. L'historique n'est pas supporté sous Windows 95. Voir aussi : syslog(). Si cette directive n'est pas fixée, les erreurs sont envoyées au journal d'erreurs SAPI. Par exemple, s'il s'agit d'une erreur de journal dans Apache ou stderr dans CLI.
- warn_plus_overloading boolean
Si cette option est activée, PHP va afficher une alerte lorsque l'opérateur d'addition (+) est utilisé avec des chaînes de caractères. Cela peut aider à trouver les erreurs où le plus est utilisé comme opérateur de concaténation au lieu de point (.). Cette option n'existe pas en PHP 4.
Constantes pré-définies
Les constantes listées ici sont toujours disponibles dans PHP.
Note : Vous pouvez utiliser ces constantes dans le fichier php.ini mais pas hors de PHP, comme dans le fichier httpd.conf, où vous devez utiliser les valeurs de champs de bits.
Tableau 2. Erreurs et historique
| Valeur | Constante | Description | Note |
|---|---|---|---|
| 1 | E_ERROR (entier) | Les erreurs sont aussi affichées par défaut, et l'exécution du script est interrompue. Elles indiquent des erreurs qui ne peuvent pas être ignorées, comme des problèmes d'allocation de mémoire, par exemple. | |
| 2 | E_WARNING (entier) | Les alertes sont affichées par défaut, mais n'interrompent pas l'exécution du script. Elles indiquent un problème qui doit être intercepté par le script durant l'exécution du script. Par exemple, appeler ereg() avec une regex invalide. | |
| 4 | E_PARSE (entier) | Les erreurs d'analyse ne doivent être générées que par l'analyseur. Elles ne sont citées ici que dans le but d'être exhaustif. | |
| 8 | E_NOTICE (entier) | Les notices ne sont pas affichées par défaut, et indiquent que le script a rencontré quelque chose qui peut être une erreur, mais peut aussi être un événement normal dans la vie du script. Par exemple, essayer d'accéder à une valeur qui n'a pas été déclarée, ou appeler stat() sur un fichier qui n'existe pas. | |
| 16 | E_CORE_ERROR (entier) | Elles sont similaires aux erreurs E_ERROR, mais elles sont générées par le code de PHP. Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 32 | E_CORE_WARNING (entier) | Elles sont similaires à E_WARNING, mais elles sont générées par le code de PHP. Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 64 | E_COMPILE_ERROR (entier) | Elles sont similaires à E_ERROR, mais elles sont générées par Zend Scripting Engine. Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 128 | E_COMPILE_WARNING (entier) | Elles sont similaires à E_WARNING, mais elles sont générées par Zend Scripting Engine. Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 256 | E_USER_ERROR (entier) | E_USER_ERROR est comparable à E_ERROR. Elle est générée en PHP par l'utilisation de la fonction trigger_error(). Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 512 | E_USER_WARNING (entier) | E_USER_WARNING est comparable à E_WARNING. Elle est générée en PHP par l'utilisation de la fonction trigger_error(). Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 1024 | E_USER_NOTICE (entier) | E_USER_NOTICE est comparable à E_NOTICE. Elle est générée en PHP parl'utilisation de la fonction trigger_error(). Les fonctions ne doivent pas générer ce genre d'erreur. | depuis PHP 4 seulement |
| 2048 | E_STRICT (entier) | Notices au moment de l'exécution. Permet d'obtenir des suggestions de PHP pour modifier votre code, assurant ainsi une meilleure interopérabilité et compatibilité de celui-ci. | PHP 5 seulement. |
| 4096 | E_RECOVERABLE_ERROR (entier) | Erreur fatale qui peut être captée. Ceci indique qu'une erreur probablement dangereuse s'est produite, mais n'a pas laissé l'engin Zend dans un état instable. Si l'erreur n'est pas attrapée par un gestionnaire d'erreur défini par l'utilisateur (voyez aussi set_error_handler(), l'application arrête prématurément comme si cela était une E_ERROR. | Depuis PHP 5.2 |
| 8191 | E_ALL (entier) | Toutes les erreurs et alertes supportées sauf le niveau E_STRICT dans PHP < 6. | 6143 dans PHP 5.2 et 2047 auparavant |
Les valeurs ci-dessus (numérique ou symbolique) sont utilisées pour constituer des champs de bits, qui spécifient le niveau de rapport d'erreur. Vous pouvez utiliser les opérateurs de bits pour combiner ces valeurs pour en faire des masques qui filtrent certaines erreurs. Notez bien que seuls '|', '~', '!', '^' et '&' seront compris dans le fichier php.ini, et que aucun opérateur logique ne sera compris en php3.ini.
Exemples
Ci-dessous, vous trouverez un exemple de gestion des erreurs par PHP. Il y est défini un gestionnaire d'erreur, qui enregistre les informations dans un fichier (au format XML), et envoie un courriel au développeur si l'erreur est critique.
Voir aussi
Voir aussi syslog().
- Table des matières
- debug_backtrace -- Génère le contexte de débogage
- debug_print_backtrace -- Affiche une backtrace
- error_log -- Stocke un message d'erreur
- error_reporting -- Fixe le niveau de rapport d'erreurs PHP
- restore_error_handler -- Réactive l'ancienne fonction de gestion des erreurs
- restore_exception_handler -- Réactive l'ancienne fonction de gestion d'exceptions
- set_error_handler -- Spécifie une fonction utilisateur comme gestionnaire d'erreurs
- set_exception_handler -- Définit une fonction utilisateur de gestion d'exceptions
- trigger_error -- Déclenche une erreur utilisateur
- user_error -- Alias de trigger_error()
If you are using PHP as an Apache module, your default behavior may be to write PHP error messages to Apache's error log. This is because the error_log .ini directive may be set equal to "error_log" which is also the name of Apache's error log. I think this is intentional.
However, you can separate Apache errors from PHP errors if you wish by simply setting a different value for error_log. I write mine in the /var/log folder.
I have found that on servers that enforce display_errors to be off it is very inconvenient to debug syntax errors since they cause fatal startup errors. I have used the following method to bypass this limitation:
The syntax error is inside the file "syntax.php", therefore I create a file "syntax.debug.php" with the following code:
<?php
error_reporting(E_ALL);
ini_set('display_errors','On');
include('syntax.php');
?>
The 5 line file is guaranteed to be free of errors, allowing PHP to execute the directives within it before including the file which previously caused fatal startup errors. Now those fatal startup errors become run time fatal errors.
Note the example code listed here calls date() every time this is called. If you have a complex source base which calls the custom error handler often, it can end up taking quite a bit of time. I ran a profiler on som code and discovered that 50% of the time was spent in the date function in this error handler.
It is totally possible to use debug_backtrace() inside an error handling function. Here, take a look:
<?php
set_error_handler('errorHandler');
function errorHandler( $errno, $errstr, $errfile, $errline, $errcontext)
{
echo 'Into '.__FUNCTION__.'() at line '.__LINE__.
"\n\n---ERRNO---\n". print_r( $errno, true).
"\n\n---ERRSTR---\n". print_r( $errstr, true).
"\n\n---ERRFILE---\n". print_r( $errfile, true).
"\n\n---ERRLINE---\n". print_r( $errline, true).
"\n\n---ERRCONTEXT---\n".print_r( $errcontext, true).
"\n\nBacktrace of errorHandler()\n".
print_r( debug_backtrace(), true);
}
function a( )
{
//echo "a()'s backtrace\n".print_r( debug_backtrace(), true);
asdfasdf; // oops
}
function b()
{
//echo "b()'s backtrace\n".print_r( debug_backtrace(), true);
a();
}
b();
?>
Outputs:
<raw>
Into errorhandler() at line 9
---ERRNO---
8
---ERRSTR---
Use of undefined constant asdfasdf - assumed 'asdfasdf'
---ERRFILE---
/home/theotek/test-1.php
---ERRLINE---
23
---ERRCONTEXT---
Array
(
)
Backtrace of errorHandler()
Array
(
[0] => Array
(
[function] => errorhandler
[args] => Array
(
[0] => 8
[1] => Use of undefined constant asdfasdf - assumed 'asdfasdf'
[2] => /home/theotek/test-1.php
[3] => 23
[4] => Array
(
)
)
)
[1] => Array
(
[file] => /home/theotek/test-1.php
[line] => 23
[function] => a
)
[2] => Array
(
[file] => /home/theotek/test-1.php
[line] => 30
[function] => a
[args] => Array
(
)
)
[3] => Array
(
[file] => /home/theotek/test-1.php
[line] => 33
[function] => b
[args] => Array
(
)
)
)
</raw>
So, the first member of the backtrace's array is not really surprising, except from the missing "file" and "line" members.
The second member of the backtrace seem the be a hook inside the zend engine that is used to trigger the error.
Other members are the normal backtrace.
if you cannot use php 5+ and if you do not know, when your administrator/provider will update to a newer php-version, this could be interesting. otherwise it surely is not. ;-)
if you use the example above "example 1: using error handling in a script" with a php version prior to php 5, the part
<?php
$errortype = array(
// ...
E_STRICT => "Runtime Notice");?>
will throw a notice like
"Use of undefined constant E_STRICT - assumed 'E_STRICT'".
of course one could avoid this problem, with
<?php
if(defined('E_STRICT')) define('E_STRICT', 2048);
?>.
but this _could_ generate problems in future versions of php, if E_STRICT is set to 42 or something else.
for this reason i suggest
<?php
$errortype = array(
E_ERROR => 'error',
E_WARNING => 'warning',
E_PARSE => 'parsing error',
E_NOTICE => 'notice',
E_CORE_ERROR => 'core error',
E_CORE_WARNING => 'core warning',
E_COMPILE_ERROR => 'compile error',
E_COMPILE_WARNING => 'compile warning',
E_USER_ERROR => 'user error',
E_USER_WARNING => 'user warning',
E_USER_NOTICE => 'user notice');
if(defined('E_STRICT'))
$errortype[E_STRICT] = 'runtime notice';
?>.
<?php
// and instead of
// error_reporting(E_ALL | E_STRICT);
// one can use
error_reporting(E_ALL | (defined('E_STRICT')? E_STRICT : 0));
// to avoid that notice.
?>
prosit
seth
I keep seeing qualification lists for error types/error-nums as arrays; In user notes and in the manual itself. For example, in this manual entry's example, when trying to seperate behavior for the variable trace in the error report:
<?php //...
// set of errors for which a var trace will be saved
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
//and later...
if (in_array($errno, $user_errors)) {
//...whatever
}
//... ?>
I was under the impression that PHP error code values where bitwise flag values. Wouldn't bitwise masking be better? So I propose a slightly better way:
<?php //...
$user_errors = E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE;
//...blah...
if ($errno & $user_errors) {
//...whatever
}
//... ?>
Or for those of you who don't like the idea of using an integer as the condition in an if statement:
<?php
if (($errno & $user_errors) > 0) {
//...whatever
}
?>
I think that's much more efficient than using _yet another_ array() constuct and an in_array().
If I am wrong, and the E_* constants aren't supposed to be used in this fashion (ie, the constans aren't guaranteed to be bitwise, which would be odd since that's how they're setup in the php.ini file), then delete me. I just don't see why one should be using arrays when bitwise comparisons will work, considering the bitwise method should be MUCH more efficient.
Something to take care of: if track_errors is enabled, $php_errormsg will always be populated with error messages of warning (and possibly notice?) level, regardless of the error_reporting level set.
When configuring your error log file in php.ini, you can use an absolute path or a relative path. A relative path will be resolved based on the location of the generating script, and you'll get a log file in each directory you have scripts in. If you want all your error messages to go to the same file, use an absolute path to the file.
In some application development methodologies, there is the concept of an application root directory, indicated by "/" (even on Windows). However, PHP does not seem to have this concept, and using a "/" as the initial character in a log file path produces weird behavior on Windows.
If you are running on Windows and have set, in php.ini:
error_log = "/php_error.log"
You will get some, but not all, error messages. The file will appear at
c:\php_error.log
and contain internally generated error messages, making it appear that error logging is working. However, log messages requested by error_log() do NOT appear here, or anywhere else, making it appear that the code containing them did not get processed.
Apparently on Windows the internally generated errors will interpret "/" as "C:\" (or possibly a different drive if you have Windows installed elsewhere - I haven't tested this). However, the error_log process apparently can't find "/" - understandably enough - and the message is dropped silently.
Although the root user writes to the files 'error_log' and 'access_log', the Apache user has to own the file referenced by 'error_log = filename' or no log entries will be written.
; From php.ini
; Log errors to specified file.
error_log = /usr/local/apache/logs/php.errors
[root@www logs]$ ls -l /usr/local/apache/logs/php.errors
-rw-r--r-- 1 nobody root 27K Jan 27 16:58 php.errors
PHP5 only (only tested with php5.0).
If you, for some reason, prefer exceptions over errors and have your custom error handler (set_error_handler) wrap the error into an exception you have to be careful with your script.
Because if you, instead of just calling the exception handler, throws the exception, and having a custom exception handler (set_exception_handler). And an error is being triggered inside that exception handler, you will get a weird error:
"Fatal error: Exception thrown without a stack frame in Unknown on line 0"
This error is not particulary informative, is it? :)
This example below will cause this error.
<?php
class PHPErrorException extends Exception
{
private $context = null;
public function __construct
($code, $message, $file, $line, $context = null)
{
parent::__construct($message, $code);
$this->file = $file;
$this->line = $line;
$this->context = $context;
}
};
function error_handler($code, $message, $file, $line) {
throw new PHPErrorException($code, $message, $file, $line);
}
function exception_handler(Exception $e)
{
$errors = array(
E_USER_ERROR => "User Error",
E_USER_WARNING => "User Warning",
E_USER_NOTICE => "User Notice",
);
echo $errors[$e->getCode()].': '.$e->getMessage().' in '.$e->getFile().
' on line '.$e->getLine()."\n";
echo $e->getTraceAsString();
}
set_error_handler('error_handler');
set_exception_handler('exception_handler');
// Throw exception with an /unkown/ error code.
throw new Exception('foo', 0);
?>
There are however, easy fix for this as it's only cause is sloppy code.
Like one, directly call exception_handler from error_handler instead of throwing an exception. Not only does it remedy this problem, but it's also faster. Though this will cause a `regular` unhandled exception being printed and if only "designed" error messages are intended, this is not the ultimate solution.
So, what is there to do? Make sure the code in exception_handlers doesn't cause any errors! In this case a simple isset() would have solved it.
regards, C-A B.
