=== PDO : Procédure Décidément Obscure !

Résolu/Fermé
heliconius Messages postés 539 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 - 16 avril 2020 à 18:02
heliconius Messages postés 539 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 - 17 avril 2020 à 17:58
Bonjour,

On m'a conseillé d'abandonner l'interface PHP mysql au profit de mysqli ou mieux de PDO. J'ai trouvé sur le net un livre de Christophe Villeneuve : "PHP et MySQL - MySQLi - PDO". C'est commandé, mais avec le confinement, je ne l'aurai pas avant une bonne semaine, peut-être...

En attendant, j'ai commencé à chercher dans PHP.net. Entre-nous, je me rends compte qu'avec mon interface mysql par rapport à PDO, je fais office de dinosaure et qu'il était effectivement temps que je me mette à jour. Quoiqu'il en soit, avec PDO je peux maintenant :
- me connecter à la base voulue et l'utilisateur voulu,
- insérer, modifier et supprimer des enregistrements,
- sélectionner des informations pour les afficher,
- récupérer le dernier ID d'insertion [ lastInsertId() ] pour utilisation dans une autre requête,
- bref, que du très courant.

Je ne suis pas très à l'aise avec les requêtes qu'on prépare à l'avance pour les exécuter par la suite avec les bons paramètres. Je n'ai pas encore vraiment intégré l'avantage. Cela viendra j'espère mais je peux toutefois déjà travailler sur la base.

Mais je galère avec la gestion des erreurs (les try avec les catch, etc...). J'ai essayé un try et catch sur une connexion en provoquant volontairement une erreur (mot de passe erroné ou base inexistante). Ça me sort un truc du genre :
Échec lors de la connexion : SQLSTATE[28000] [1045] Access denied for user 'lou'@'163.126.57.28' (using password: YES)

Je cherche à ce qu'il n'y ait aucun affichage mais que le numéro d'erreur puisse être récupéré dans une variable pour décider moi-même de la manière dont l'erreur sera affichée. C'est comme lorsqu'on tente de saisir un doublon, j'aimerais récupérer le numéro d'erreur et afficher moi-même à ma manière au lieu de crasher le script, qui plus est, en fournissant des indications de nom de serveur (ou IP) et de nom d'utilisateur. Et là, je ne comprends rien : on parle d'exception... alors que pour moi c'est une erreur... Bref, c'est un peu la galère...

En attendant que ce bouquin arrive (dont j'ai lu, après l'avoir commandé, des commentaires pas forcément flatteurs, y a-t-il une âme charitable pour débroussailler très succinctement cette gestion d'erreur (pas la peine de faire un livre) avec interception du numéro ou encore en proposant des liens de pages ou de PDF à imprimer (lecture plus facile) où c'est clairement expliqué ?

Merci beaucoup.

Configuration: Windows / Firefox 52.0

1 réponse

jordane45 Messages postés 38451 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 9 mars 2025 4 739
17 avril 2020 à 08:29
Bonjour,

Ta question n'a pas de rapport avec mysql ... mais avec l'utillisation des try/catch (qui peuvent (doivent) s'utiliser ailleurs que avec le PDO...)
Je déplace donc ta question dans le forum php.

la variable $e contient plusieurs choses,
public function getMessage();                 // Exception message
    public function getCode();                    // User-defined Exception code
    public function getFile();                    // Source filename
    public function getLine();                    // Source line
    public function getTrace();                   // An array of the backtrace()
    public function getTraceAsString();           // Formated string of trace

et au lieu d'en faire un echo.. rien ne t’empêche de stocker dans une variable.

1
heliconius Messages postés 539 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 141
17 avril 2020 à 15:49
OK. Merci.

Voici mon script de connexion (qui remplacera mon init.php). J'essaye de faire différents tests avec PDO::ERRMODE_EXCEPTION, PDO::ERRMODE_SILENT pour voir les différences et choisir ce qui convient le mieux pour ce que j'ai à faire. Dans le script ci-dessous j'ai essayé les deux sans voir de différence. Intérêt ? Pourquoi ?

J'essaye aussi avec ce script de connexion de provoquer différentes erreurs (mauvais mot de passe ou utilisateur, base inexistante, mauvais host, etc...) pour découvrir leur numéro d'erreur (à traiter par le switch())

- Si j'essaye d'utiliser un serveur de BDD sur un hôte existant et connecté sur lequel ce serveur n'est pas installé, l'erreur retournée est 0
- Si je mets un nom de base inexistante, l'erreur retournée est 1044
- Si je mets un mot de passe erroné ou un utilisateur inexistant sur ce serveur, l'erreur retournée est 1045.
- si je me connecte à un hôte sur lequel MySQL est installé mais auquel je n'ai pas accès, ou avec un numéro de port incorrect ou s'il n'y a pas de serveur MySQL installé, l'erreur retournée est 2003.
- En revanche, si je définis un SERVER avec un numéro IP inexistant (IP dynamique non encore connectée) ou un hôte probablement protégé par un firewall (www.microsoft.com, www.darty.fr, etc...) aucune erreur n'est retournée mais le script reste en attente de connexion jusqu'à un Ctrl-C. Y a-t-il moyen d'éviter cela et de retourner l'erreur correspondante ?

<?php
// fichier init.php
// version 0.1 du 17/04/2020 15:00

// define("DBTYPE",              "pgsql");
// define("PORT",            "port=5432");
define("DBTYPE",              "mysql");
define("PORT",            "port=3306");
define("SERVER",  "host=111.22.33.44"); // IP ou FQDN
define("BASE",        "dbname=myBase");
define("USER",               "dbuser");
define("PASS",             "dbpasswd");

define("DSN", DBTYPE.":".PORT.";".SERVER.";".BASE);

try {
   $cnx = new PDO(DSN, USER, PASS);   // Connexion au serveur
   $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
}
catch(PDOException $e) {
    switch($e->getCode()) {
        case 0    : echo "Pilote ".DBTYPE." non installé"; break;
        case 1044 : echo "Base non joignable";             break;
        case 1045 : echo "Utilisateur non identifié";      break;
        case 2003 : echo "Serveur non joignable";          break;
        default   : echo "Erreur ".$e->getCode();          break;
    }
    echo "\n";
    // print_r($e);
    die();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Ci-dessous, fonctions utiles en permanence
// ...
?>
0
jordane45 Messages postés 38451 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 9 mars 2025 4 739 > heliconius Messages postés 539 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023
17 avril 2020 à 15:57
Tout est dans la doc.....

Pour le "mode d'erreur"

PDO::ATTR_ERRMODE : rapport d'erreurs
- PDO::ERRMODE_SILENT : assigne simplement les codes d'erreur.

- PDO::ERRMODE_WARNING: émet une alerte E_WARNING.

- PDO::ERRMODE_EXCEPTION : émet une exception.


</code>

Pour le Timeout
<block>
PDO::ATTR_TIMEOUT: Précise la durée de timeout en secondes. Tous les pilotes ne supportent pas cette option et sa signification peut différer en fonctions des pilotes. Par exemple, sqlite attendra pendant cette période pour obtenir un verrou en écriture sur le fichier, mais les autres pilotes considèreront ceci comme un timeout de connexion ou de lecture. Requiert int.
0
heliconius Messages postés 539 Date d'inscription mardi 1 juillet 2008 Statut Membre Dernière intervention 23 juin 2023 141 > jordane45 Messages postés 38451 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 9 mars 2025
17 avril 2020 à 17:58
OK.
Vu pour PDO::ERRMODE_SILENT et/ou PDO:ERRMODE_EXCEPTION.

Pour le PDO:ATTR_TIMEOUT, j'ai du "bidouilller" :
try {
   $cnx = new PDO(DSN, USER, PASS); // Connexion au serveur
   $cnx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
   $cnx->setAttribute(PDO::ATTR_TIMEOUT, 2);   // marche pas
   $cnx->setAttribute(PDO::ATTR_TIMEOUT => 2); // marche pas
   $cnx->setAttribute(PDO::ATTR_TIMEOUT = 2);  // marche pas
}

J'ai dû procéder tel que ;
$options = array (
             PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
             PDO::ATTR_TIMEOUT => 2
           );
try {
   $cnx = new PDO(DSN, USER, PASS, $options); // Connexion au serveur
}

Là, c'est bon. Sinon, je n'ai pas su définir le timeout avec $cnx->setAttrubute()
Qu'est-ce qui n'allait pas ?

En tout cas, un grand merci pour ton aide. J'hésitais sérieusement avec MySQLi et PDO mais finalement t'as été le déclencheur. Je pense qu'après m'être fait la main sur cette API, je vais m'attaquer à revoir tout mon site. Là, je vais avoir de quoi m'occuper... Merci.

PS: Je fermerai le fil d'ici un à deux jours si je n'ai plus d'autres questions à poser.
0