PDO : comprendre et corriger les erreurs les plus fréquentes

Formation

À Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Lieu

    Paris

Nous vous proposons des cours ouverts pour se former autrement, pour devenir acteur de votre vie. Nous vous aidons à prendre votre envol, mais ça ne s'arrête pas là. Notre volonté est de vous accompagner tout au long de votre vie, dans votre parcours professionnel.Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

Bonjour à tous ! :)

Vous venez d'apprendre le PHP grâce au cours de M@teo21 ? Ou bien vous connaissez déjà le PHP mais vous souhaitez abandonner l'API MySQL pour passer à PDO ? Vous vous embrouillez avec toutes ces nouveautés ?

Cet article a pour objectif de vous aider à comprendre votre code, et à corriger vous-même vos erreurs les plus simples.

Les prérequis sont les suivants :

  • avoir suivi le cours de M@teo21 sur le PHP et terminé la partie qui concerne la base de données (ou niveau équivalent) ;

PDO étant un ensemble de classes, quelques notions de POO pourront vous aider. Toutefois, je définirai les termes que j'utilise dans la première partie.

Cet article n'a pas pour vocation de vous apprendre à utiliser PDO, mais de vous apprendre à comprendre ce que vous faites avec. Vous devez déjà savoir utiliser les principales méthodes des classes de PDO.

Un peu de vocabulaireIntroduction

Pour commencer, je vous propose un petit rappel sur le vocabulaire de base de la POO, car PDO est composé de trois classes. Notez que je ne vous ferai pas de cours sur la POO, d'autres s'en sont déjà chargés (cours de M@teo21, cours de vyk12). Je me contenterai de rappeler la définition de quelques mots-clés.

Si vous êtes à l'aise avec la POO, vous pouvez sauter cette partie. Si vous avez le moindre doute, je vous conseille de la lire tout de même. Vous n'en aurez que pour quelques minutes et ça ne pourra vous faire que du bien ! ;)

Quelques définitionsClasse

La classe est le moule qui permettra de créer des objets. Elle contient les attributs et les méthodes qui définissent l'objet. Par exemple, PDO est une classe. Il en va de même pour PDOStatement et PDOException.

Attribut

Un attribut, parfois nommé variable d'instance, est une variable propre à l'objet. Lorsque l'on conçoit une classe, il faut se poser la question « De quoi est constitué mon objet ? » pour trouver quels attributs lui donner. Par exemple, pour un objet "Client", on pourra répondre à cette question en disant qu'un client est constitué d'un numéro de client, d'un prénom, d'un nom, d'une adresse, d'un numéro de téléphone etc. On créera donc autant d'attributs.

Méthode

Une méthode est une fonction propre à l'objet. Lorsque l'on conçoit une classe, il faut se poser la question « Que peut faire mon objet ? » pour trouver quelles méthodes implémenter. Par exemple, un client peut changer de nom, d'adresse, de numéro de téléphone etc.

Instance

Une instance est tout simplement un exemplaire de notre objet. En PHP, le code suivant crée une instance de l'objet "Client" qui sera accessible via la variable $client :

<?php $client = new Client();

Cette instruction utilise le moule (la classe Client) pour créer une instance (ou occurrence) de cette classe. Cette instance possède tous les attributs et toutes les méthodes propres à la classe Client.

Récapitulatif<?php class Classe // Ici on déclare la classe. { // Ici on déclare les attributs de la classe : private $attribut1 = 0; private $attribut2 = ''; // Ceci est une méthode de la classe Classe : public function methode() { // Instructions de la méthode. } } $classe = new Classe(); // On construit une instance de la classe Classe. /* * Cette instance possède tous les attributs et toutes les méthodes * de la classe Classe : attribut1, attribut2 et methode(). */ Une convention d'écriture à connaître

Pour désigner la méthode d'une classe, les programmeurs ont l'habitude de faire précéder son nom de celui de sa classe puis d'un double deux-points "::" , afin de savoir au premier coup d'œil à quelle classe elle appartient, et de ne pas la confondre avec une méthode homonyme d'une autre classe.
Par exemple, pour désigner la méthode methode() de la classe Classe j'écrirai Classe::methode(), et pour la méthode query() de la classe PDO j'écrirai PDO::query().

Ce sera tout pour le vocabulaire ! Si vous n'avez pas compris ces quelques termes, je vous conseille de jeter un œil à l'un des cours que j'ai cités tout à l'heure :

  • la POO en PHP selon M@teo21 ;

  • la POO en PHP selon vyk12.

Les options de configurationIntroduction
  • Ma requête ne fonctionne pas, et pourtant je n'ai aucun message d'erreur !

  • J'ai une erreur "Call to a member function fetch() on a non-object". Je ne comprends pas, pourtant j'appelle la méthode comme dans le tuto !

Hé oui ! Il faut savoir que par défaut, PDO n'affiche pas les erreurs SQL. Or, en tant que développeur, vous devez aimer les messages d'erreurs ! Si, si ! Sans eux, on n'a aucune idée de l'endroit où l'on s'est trompé. Parfois même, ils nous disent ce qui ne va pas.
La preuve qu'ils sont utiles : PDO n'affiche pas les erreurs, et vous êtes perdu. ;)

Des erreurs mystérieuses

Bon, j'ai compris pourquoi quand je faisais une erreur SQL, je n'avais pas de message d'erreur. Mais pourquoi est-ce que parfois j'ai une erreur sur le fetch(), alors ?

Hé bien tout d'abord, il faut se souvenir que l'on travaille avec deux langages :

  • PHP ;

  • SQL.

Or, PDO ne vous montre pas les erreurs SQL. Les erreurs PHP ne sont pas influencées par PDO, elles sont influencées par la configuration de PHP.
Autrement dit, l'erreur que vous pouvez voir sur le fetch() est une erreur PHP causée indirectement par une erreur SQL que vous ne voyez pas.

Prenons un code de base de sélection de données avec PDO :

<?php $stmt = $pdo->query('SELECT id, auteur, contenu, date FROM messages'); while($message = $stmt->fetch()) { // Utilisation des données. }

Admettons que, pour une raison ou pour une autre, ma requête échoue. Que va-t-il se passer ? Regardons la documentation de la méthode PDO::query().

Citation : php.net

PDO::query() retourne un objet PDOStatement, ou FALSE si une erreur survient.

Un objet de la classe PDOStatement ? Hé oui, si vous avez la curiosité de jeter un œil à la documentation de cette classe, vous vous apercevrez que c'est cette classe qui possède la méthode fetch(). Si ma requête réussit, $stmt sera donc une instance de la classe PDOStatement. Mais si elle échoue, elle contiendra uniquement… FALSE ! :o

Vous avez compris ? Si la requête échoue, il n'y a pas d'objet PDOStatement (pas d'objet du tout même, on obtient un booléen !). Sans objet, pas de méthode. Par conséquent, PHP nous prévient qu'on essaie d'appeler une méthode sur quelque chose qui n'est pas un objet, et que c'est donc impossible !

Et pourquoi aucun message d'erreur n'est affiché parfois ?

Tout simplement parce que dans le cas d'une requête de type UPDATE ou DELETE, on n'utilise pas (ou rarement) la valeur de retour de la méthode.
Vous l'aurez compris, il devient urgent de demander poliment à PDO de nous prévenir en cas de problème.

Afficher les erreurs SQL

Pour modifier les paramètres de PDO, nous avons deux solutions. Soit on donne les options directement au constructeur, soit on utilise la méthode PDO::setAttribute(). Je vais vous montrer ces deux méthodes, vous choisirez celle qui vous fait plaisir.

Il faut également savoir que l'on peut demander à PDO de nous avertir de deux façons :

  • avec une erreur type "WARNING" ;

  • avec une exception.

Vous connaissez déjà les erreurs WARNING. Un exemple ? Vous y avez droit si vous oubliez de donner un paramètre à une fonction : "Warning: Wrong parameter count for intval()". Si vous choisissez ce mode, vous aurez une erreur de ce type en cas d'erreur SQL.
En ce qui concerne les exceptions, vous en avez déjà vu au moins une ! Souvenez-vous, quand vous construisiez votre objet PDO :

Citation : Cours de PHP

<?php try { $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ''); } catch (Exception $e) { die('Erreur : ' . $e->getMessage()); }

Ici, $e est une exception. Les exceptions sont lancées par l'instruction throw et peuvent être interceptées par un bloc catch(). Je ne vous en dis pas plus, je ne compte pas vous faire un cours sur les exceptions. Si vous êtes curieux, vous chercherez de votre côté.

Demander un WARNING

Sans plus attendre, voici comment demander à PDO d'afficher des erreurs WARNING en cas de problème.
Vous pouvez passer un array en quatrième paramètre du constructeur. Cet array devra avoir pour clé le nom de l'attribut à modifier, et pour valeur… la valeur de l'attribut à modifier. En ce qui nous concerne, l'attribut à modifier est PDO::ATTR_ERRMODE et sa valeur PDO::ERRMODE_WARNING. On le comprend très bien : ATTR mis pour "attribut", et ERRMODE pour "error mode".
Sinon, vous pouvez utiliser la méthode PDO::setAttribute(). Elle prend deux paramètres : l'attribut à modifier et sa nouvelle valeur.

Voyez plutôt :

<?php // Je donne les paramètres au constructeur : $pdo = new PDO('mysql:host=localhost;dbname=DBNAME', 'root', '', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); <?php // Je construis mon objet, puis je donne le paramètre à PDO::setAttribute() : $pdo = new PDO('mysql:host=localhost;dbname=DBNAME', 'root', ''); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); Demander une EXCEPTION

Allez, je suis sûr que vous pouvez trouver tout seul en cherchant la bonne valeur de l'attribut dans la liste des constantes prédéfinies de PDO.

PDO::ERRMODE_EXCEPTION ? Oui, bravo ! Regardez ce que ça donne :

<?php // Je donne les paramètres au constructeur : $pdo = new PDO('mysql:host=localhost;dbname=DBNAME', 'root', '', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )); <?php // Je construis mon objet, puis je donne le paramètre à PDO::setAttribute() : $pdo = new PDO('mysql:host=localhost;dbname=DBNAME', 'root', ''); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

Et voilà, vos erreurs ne sont plus silencieuses ! Si vous choisissez les exceptions, mettez vos requêtes dans un bloc try/catch pour pouvoir les attraper. Un exemple ? Le voici :

<?php try { $pdo = new PDO('mysql:host=localhost;dbname=DBNAME', 'root', '', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )); $stmt = $pdo->query('SELECT id, auteur, contenu, DATE_FORMAT(date, "%W %d %M %Y à %Hh%i") as date FROM messages'); $messages = $stmt->fetchAll(PDO::FETCH_OBJ); } catch(Exception $e) { exit('<b>Catched exception at line '. $e->getLine() .' :</b> '. $e->getMessage()); } foreach($messages as $message) { echo '<p>Le ', $message->date, ' par ', $message->auteur, ' : <br />', $message->contenu, '</p>'; } D'autres attributs à modifier !

Si vous regardez plus en détail la liste des constantes de PDO que je vous ai montrée tout à l'heure, vous vous apercevrez que ERRMODE n'est pas le seul attribut modifiable. Par exemple, j'aime bien modifier le DEFAULT_FETCH_MODE, plutôt que de le donner à chaque fois à mes méthodes PDOStatement::fetch() ou PDOStatement::fetchAll().
Si vous êtes attentif, vous remarquerez que toutes les constantes qui commencent par PDO::ATTR_ sont des attributs que l'on peut modifier. Par exemple pour le fetch mode par défaut : PDO::ATTR_DEFAULT_FETCH_MODE fera l'affaire. Les valeurs possibles pour cet attribut sont les constantes qui commencent par PDO::FETCH_.

En bonus, voici comment je construis mon propre objet PDO. À vous d'adapter ce code selon vos goûts et vos besoins :

<?php try { $db_config = array(); $db_config['SGBD'] = 'mysql'; $db_config['HOST'] = 'localhost'; $db_config['DB_NAME'] = 'tests'; $db_config['USER'] = 'root'; $db_config['PASSWORD'] = ''; $db_config['OPTIONS'] = array( // Activation des exceptions PDO : PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Change le fetch mode par défaut sur FETCH_ASSOC ( fetch() retournera un tableau associatif ) : PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); $pdo = new PDO($db_config['SGBD'] .':host='. $db_config['HOST'] .';dbname='. $db_config['DB_NAME'], $db_config['USER'], $db_config['PASSWORD'], $db_config['OPTIONS']); unset($db_config); } catch(Exception $e) { trigger_error($e->getMessage(), E_USER_ERROR); }

N'hésitez pas à parcourir la documentation des trois classes qui composent PDO pour apprendre à les utiliser.

Sécuriser ses requêtesIntroduction

On parle beaucoup des injections SQL. Cette technique consiste à écrire du code SQL dans un champ de texte pour détourner l'utilisation d'une requête a priori inoffensive pour une utilisation malveillante.
Sur les forums, je lis souvent « avec PDO, pas besoin de sécuriser ses requêtes, ça le fait tout seul ».
Ceci est faux.

Cette affirmation résulte d'une confusion entre PDO et les requêtes préparées. Comme je l'ai déjà dit, cet article n'a pas vocation à vous apprendre à utiliser ce genre de chose. D'autres s'en chargent bien mieux que moi dans le tutoriel de M@teo21 ou celui de Draeli.
En revanche, je vais vous expliquer dans quel cas il faut se protéger, et comment.

Une histoire de types

Il y a deux catégories de variables que l'on utilise dans une requête SQL : les nombres (int, float, double…) et les chaînes de caractères.
Or, une injection SQL est constituée de code SQL, et donc de texte. Cela signifie qu'une variable qui contient uniquement un nombre n'est pas dangereuse.

Seulement voilà, il existe une règle très importante en informatique : never trust user input, soit en français "ne faites jamais confiance aux données entrées par l'utilisateur". En effet, celui-ci peut se tromper ou pire : tenter d'insérer un code malveillant !
Avant d'utiliser une variable utilisateur (c'est-à-dire les variables dont la valeur peut être influencée par l'utilisateur) censée contenir un nombre, il faut vérifier qu'elle en contient effectivement un.

Pour cela plusieurs solutions s'offrent à vous. Soit vous faites une condition avec une fonction is_type(), comme par exemple is_int(). Soit vous convertissez (on peut aussi dire "transtyper") cette valeur en nombre.
Voici deux façons de procéder pour réaliser cette conversion (ou "cast" en anglais) :

<?php // Première méthode : en précisant le type de destination. $id = (int) $_GET['id']; // Seconde méthode : en utilisant la...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

PDO : comprendre et corriger les erreurs les plus fréquentes

Prix sur demande