Si une erreur se produit au cours de la requête, mysqli_query() renvoie FALSE. Nous devons tester cette valeur de retour pour agir en conséquence, le plus souvent par l'arrêt du traitement en cours et l'affichage d'un message ou le déroutement vers une autre page.
Une erreur peut avoir généralement 3 causes :
L'exemple suivant essaye de faire une insertion dans la table auteurs avec un clé primaire déjà existante.
Comme nous ne gérons pas les erreurs, le message 'La mise à jour à été effectuée correctement.' s'affiche et laisse croire que la requête INSERT s'est correctement déroulée alors que ce n'est pas le cas.
Un autre exemple avec une requête SELECT et un mauvais nom de table.
On a ici l'affichage d'un message signalant une erreur lors de l'appel de la fonction mysqli_fetch_assoc() à laquelle nous avons passé un booléen alors qu'elle attend un objet mysqli_result . L'erreur provient en réalité de mysqli_query(), mais comme nous ne testons pas la valeur de retour nous avons des erreurs en cascade.
Il est primordial de tester la valeur de retour de la fonction mysqli_query() avant de continuer quelque traitement que ce soit.
Nous gérerons le plus simplement possible les erreurs de requêtes
avec l'opérateur or. Avec cet opérateur or PHP permet d'appeler une seconde fonction
uniquement si le résultat d'une première est évalué à FALSE.
Les appels à mysqli_query()
devront toujours être effectués comme suit :
$r = mysqli_query($bd, $sql)
or bdErreur($bd, $sql);
En effet, l'opérateur or, comme les autres opérateurs logiques and, && et || est un opérateur "paresseux", ce qui signifie que ces opérateurs n'évaluent pas leur deuxième opérande quand l'évaluation du premier opérande suffit pour connaître le résultat de l'opération logique. Donc:
$r = mysqli_query($bd, $sql) or bdErreur($bd, $sql);est donc strictement équivalente à :
$r = mysqli_query($bd, $sql);
if (!$r){
bdErreur($bd, $sql);
}
La première instruction est simplement plus concise.
Dans la gestion des erreurs nous distinguerons 2 cas : le site est en phase de développement (message explicatif pour le débuggage) ou le site est en phase de production ( message sibyllin et tracking dans un fichier d'erreurs).
Deux fonctions nous permettent d'en savoir un peu plus sur les erreurs MySQL :
Il est particulièrement important que l'on ait le texte complet de la requête SQL qui provoque une erreur car :
La fonction de gestion d'erreurs sera placée dans notre bibliothèque de fonctions habituelle (bib_fonctions.php)
//_____________________________________________________________
/**
* Gestion d'une erreur de requête à la base de données.
*
* @param resource $bd Connecteur sur la bd ouverte
* @param string $sql requête SQL provoquant l'erreur
*/
function bdErreur($bd, $sql) {
$errNum = mysqli_errno($bd);
$errTxt = mysqli_error($bd);
// Collecte des informations facilitant le debugage
$msg = '<h4>Erreur de requête</h4>'
."<b>Erreur mysql :</b> $errNum"
."<br> $errTxt"
."<br><br><b>Requête :</b><br><pre>$sql</pre>"
.'<br><br><b>Pile des appels de fonction :</b>';
$tdStyle = 'style="border: 1px solid black;padding: 4px 10px"';
// Récupération de la pile des appels de fonction
$msg .= '<table style="border-collapse: collapse">'
."<tr><td $tdStyle>Fonction</td>"
."<td $tdStyle>Appelée ligne</td>"
."<td $tdStyle>Fichier</td></tr>";
$appels = debug_backtrace();
for ($i = 0, $iMax = count($appels); $i < $iMax; $i++) {
$msg .= "<tr style='text-align: center'><td $tdStyle>"
.$appels[$i]['function']."</td><td $tdStyle>"
.$appels[$i]['line']."</td><td $tdStyle>"
.$appels[$i]['file'].'</td></tr>';
}
$msg .= '</table>';
bdErreurExit($msg);
}
//_____________________________________________________________
/**
* Arrêt du script si erreur base de données.
* Affichage d'un message d'erreur si on est en phase de
* développement, sinon stockage dans un fichier log.
*
* @param string $msg Message affiché ou stocké.
*/
function bdErreurExit($msg) {
ob_end_clean(); // Supression de tout ce qui
// a pu être déja généré
// Si on est en phase de développement, on affiche le message
if (IS_DEV) {
htmlDebut('Erreur base de données');
echo $msg;
htmlFin();
exit();
}
// Si on est en phase de production on stocke les
// informations de débuggage dans un fichier d'erreurs
// et on affiche un message sibyllin.
$buffer = date('d/m/Y H:i:s')."\n$msg\n";
error_log($buffer, 3, 'erreurs_bd.txt');
htmlDebut('Maintenance en cours');
// Gros mensonge
echo 'Notre site est momentanément indisponible ',
'pour cause de maintenance. Merci de ré-essayer ',
'dans quelques instants.';
htmlFin();
exit();
}
La seule véritable nouveauté par rapport à notre fonction de gestion des erreurs de connexion est l'utilisation de la fonction debug_backtrace() pour générer la pile des fonctions appelées qui va nous permettre de suivre à la trace le traitement provoquant l'erreur.
Dans cet exemple l'erreur provoquée résulte d'appel d'appel d'appel de fonctions pour qu'on voie bien l'utilité de debug_backtrace().
Avec le tableau affichant la pile des appels de fonction, on voit bien tout le traitement qui a causé l'erreur détectée en ligne 30 de notre code.