Comment empêcher PHP d’afficher les messages d’erreurs en mode production

Pendant le débogage d'un programme, plutôt que d'utiliser un débogueur, nous choisissons parfois d'afficher une variable à l'écran pour vérifier sa valeur. Mais pour nous assurer que cet affichage ne pourra pas avoir lieu lorsque le site sera en production (en cas où on oublierait d'effacer l'instruction qui l'affiche), nous utilisons notre fonction maison echo_debug().

Il serait intéressant d'appliquer la même logique aux messages d'erreur générés par PHP. En effet, lorsqu'un programme PHP rencontre du code pour lequel il a un message à envoyer, comme par exemple une erreur fatale, un avertissement ou l'utilisation d'une fonction obsolète, le message est automatiquement affiché à l'écran. Ce comportement est très pratique pendant la phase de développement. Cependant, une fois le site en production, ces messages peuvent ouvrir des trous de sécurité puisque le nom et le chemin du fichier concerné sont affichés.

▼Publicité

Par exemple, si un site PHP utilise une fonction obsolète, comme par exemple mysql_query(), on obtiendra le message d'avertissement suivant :

« Deprecated: mysql_query(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in C:\... on line 26 ».

Si ce message est affiché lorsque le site est en production, l'usager malveillant saura qu'il peut exploiter les failles connues de mysql_query() sur ce site (entre autres, cette extension ne permettait pas d'effectuer des requêtes préparées). De plus, il connaîtra le chemin physique du dossier où le site Web est installé, ce qui lui ouvrira d'autres portes pour accomplir ses méfaits.

Configuration du serveur : error_reporting vs display_errors

Dans le fichier php.ini, les configurations error_reporting et display_errors contrôlent la gestion et l'affichage des erreurs. 

La configuration error_reporting indique s'il faut ou non gérer les erreurs de tel ou tel niveau de gravité. 

Par défaut, sous EasyPHP, les erreurs gérées seront consignées dans le fichier :

    C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\binaries\apache\logs\error.log

C'est une configuration dans httpd.conf qui spécifie l'utilisation de ce fichier.

Fichier httpd.conf

# ErrorLog: The location of the error log file.

# If you do not specify an ErrorLog directive within a <VirtualHost>

# container, error messages relating to that virtual host will be

# logged here.  If you *do* define an error logfile for a <VirtualHost>

# container, that host's errors will be logged there and not here.

#

ErrorLog "logs/error.log"

La configuration display_errors, quant à elle, indique si les erreurs gérées doivent être affichées à l'écran ou non. 

Il est donc possible d'empêcher l'affichage des erreurs en initialisant error_reporting à 0 ou display_errors à Off. L'avantage de travailler au niveau de display_errors est qu'il sera possible de demander à PHP de garder une trace des erreurs dans un fichier de log plutôt que de les afficher. Et pour pouvoir les loguer, il faut qu'elles soient gérées.

Donc, pour empêcher l'affichage des erreurs, on peut modifier php.ini pour qu'il utilise la configuration suivante :

Fichier php.ini

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Error handling and logging ;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

...

display_errors = Off

Le problème avec cette approche est double :

  • Il ne sera pas possible de modifier le comportement automatiquement quand on passe du mode débogage au mode production.
  • Chez certains hébergeurs, il n'est pas possible de modifier les configurations dans php.ini.

Heureusement, il est possible de modifier les configurations par programmation dans certains contextes.

Instruction PHP pour gérer l'affichage des messages

Il est possible de modifier les configurations de php.ini par programmation à l'aide de la fonction ini_set(). La fonction error_reporting(), quant à elle, permettra en plus choisir les niveaux de messages que PHP doit gérer.

L'extrait de code suivant permet de n'afficher les erreurs PHP que lorsque le programme est en mode débogage. Un simple changement de valeur pour la variable $debug modifiera les configurations.

Ex :

PHP

$debug = false;

...

 

if ($debug) {

    // gère et affiche tous les niveaux d'erreurs en mode débogage

    error_reporting(E_ALL);

    ini_set('display_errors', '1');

}

else {

    // en mode production, ne gère pas certains niveaux pour des raisons de performance (ceux précédés de ~), tel que suggéré dans php.ini

    // même pour les niveaux gérés, aucun message ne sera affiché

    error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);

    ini_set('display_errors', '0');

}

Notez bien : si le code PHP ne compile pas, aucune ligne de code ne sera exécutée et le message indiquant qu'il y a eu erreur sera toujours affiché puisque l'instruction demandant de ne pas les afficher ne sera pas exécutée.

Ce serait le cas, par exemple, si le développeur avait oublié un point-virgule à la fin d'une instruction. On obtiendrait une page blanche avec un message du genre « Parse error: syntax error ... ».

Dans ce cas, seules les configurations dans php.ini seront prises en compte.

Problème avec les hébergements partagés

Si votre site est publié en hébergement partagé (c'est généralement le cas pour les forfaits d'hébergement bon marché), vous n'aurez pas accès au fichier php.ini. Vous devez néanmoins vous assurer qu'en cas de plantage (les instructions ini_set() ne seront alors pas exécutées), votre site n'affiche pas un message ouvrant un trou de sécurité.

En effet, les utilisateurs malveillants pourraient tenter d'accéder à une faille de type full path disclosure, c'est-à-dire l'affichage d'un message qui donne le chemin d'accès physique du site Web sur le serveur. S'ils réussissent, ils utiliseront ce chemin pour tenter d'afficher le contenu d'un fichier sensible, comme par exemple celui qui effectue la connexion à la base de données et qui contient donc le code d'usager MySQL ainsi que son mot de passe.

Pour empêcher l'affichage des messages d'erreur PHP lors d'un plantage, il est possible, chez certains hébergeurs, d'ajouter une configuration dans le fichier .htaccess.

Ex :

Fichier .htaccess (configuration Apache)

php_flag display_startup_errors off

php_flag display_errors off

Ceci ne fonctionnera qu'aux conditions suivantes :

  • L'hébergement est effectué sur un serveur Apache (certains utilisent IIS).
  • Chez l'hébergeur, PHP n'est pas installé en tant que module CGI.

Pour savoir si les erreurs fatales seront affichées ou non, vous pouvez utiliser la fonction ini_get(). dans un fichier .php qui n'utilise aucun ini_set(). Vous obtiendrez alors la valeur de la configuration display_errors qui a été initialisée dans php.ini. Et si vous avez modifié sa valeur dans .htaccess et que le fichier est pris en compte, vous verrez alors la valeur initialisée dans .htaccess.

Ex :

PHP

echo "display_errors : " . ini_get('display_errors');

Il est également possible d'obtenir d'un coup l'affichage de toutes les configurations en utilisant phpinfo(). Mais attention : ceci affichera des informations sensibles alors on ne doit pas le faire lorsque le site est en ligne. Ceci ne sera donc pas utile dans le cas présent.

PHP

phpinfo();

Puisque vous n'avez aucun contrôle sur les configurations permettant ou non d'utiliser .htaccess, vous n'aurez pas d'autre choix que de contacter votre hébergeur si vous constatez que les erreurs fatales sont affichées à l'écran.

Pour bien tester le comportement du programme pour les différents niveaux d'erreurs

Les lignes de code suivantes généreront des messages PHP. Utilisez-les pour bien tester le code définissant le comportement de PHP face aux erreurs rencontrées.

E_ERROR

Si on tente d'appeler une fonction qui n'existe pas, cela provoquera une erreur de niveau E_ERROR.

Tout le code sera exécuté jusqu'à ce que l'appel problématique soit rencontré. L'exécution du code sera arrêté dès que la ligne causant l'erreur sera rencontrée.

Ex :

PHP

fonction_inexistante();

E_PARSE

Une erreur E_PARSE survient lorsque le programme ne compile pas. À ce moment, aucune ligne de code ne sera exécutée, pas même les lignes situées avant le code problématique. Les appels à error_reporting() et à ini_set() ne seront donc pas exécutés.

Seules les configurations dans php.ini détermineront si les messages doivent être affichés ou non.

Pour provoquer l'erreur, on peut simplement omettre un point-virgule à la fin d'une instruction.

Ex :

PHP

echo "Salut"

E_WARNING

On générera un avertissement si on tente d'ouvrir un fichier qui n'existe pas.

PHP

$file=fopen("fichierinexistant.txt", "r");

E_NOTICE

Une notice sera affichée si on tente d'utiliser une variable qui n'est pas initialisée.

PHP

echo "Affichage d'une variable non initialisée : " . $blabla;

E_STRICT

Le code générant un message de niveau E_STRICT varie selon la version de PHP utilisée.

Dans la version 5.5.8, le fait d'appeler statiquement une méthode non statique génère ce type d'erreur.

PHP

class Ma_classe {

    public function Test() {

 

}

 

Ma_classe::Test();

E_DEPRECATED

L'utilisation de mysql_query() plutôt que $mysqli->query() générera un message indiquant que cette fonction est obsolète.

PHP

$resultat = mysql_query('SELECT * FROM client');

Pour plus d'information

« ini_set ». PHP. http://php.net/manual/fr/function.ini-set.php

« error_reporting ». PHP. http://php.net/manual/fr/function.error-reporting.php

« Gestion des erreurs - constantes pré-définies ». PHP http://php.net/manual/fr/errorfunc.constants.php

« Configuration à l'exécution ». PHP. http://php.net/manual/fr/errorfunc.configuration.php

« PHP The Right Way - Error Reporting ». PHP The Right Way. http://www.phptherightway.com/#error_reporting

« Les erreurs (e_all, e_warning, e_error) ». Oseox. http://oseox.fr/php/erreur.html

« Advanced PHP Error Handling via htaccess ». Perishable Press. https://perishablepress.com/advanced-php-error-handling-via-htaccess/

Merci de partager ! Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInPin on PinterestShare on StumbleUponEmail this to someone
Catégories