PDO une soupe et au lit !
par
, 20/05/2018 à 13h33 (9630 Affichages)
- Introduction
- Exemple pratique : structure de la table SQL
- PDO Script de connexion à la base de données
- Le bloc try & catch : afficher les exceptions
- Requête SELECT sans filtre : lister tous les enregistrements
- Requête SELECT avec filtre : lister les enregistrements selon critères
- Requête INSERT : ajouter un enregistrement
- Requête UPDATE : modifier un enregistrement
- Requête DELETE : supprimer un enregistrement
- Astuces et erreurs courantes
- Pour aller plus loin
- Les participants à ce billet collaboratif
1 - Introduction
PDO est une classe d’objets tout particulièrement dédiée à générer des variables PHP dynamiques (ici nous ne traiterons que des tableaux associatifs) en accédant à la base de données.
PDO permet d’utiliser des requêtes préparées, et utilisées à bon escient, les requêtes préparées permettent d’éviter une attaque de votre base par un navigateur client (injection SQL). Pour les mêmes raisons, PDO gère proprement l’échappement.
Ici, vous ne verrez QUE la technique des requêtes préparées par marqueurs anonymes. Pour utiliser la technique des requêtes préparées par marqueurs nommés, sauter au paragraphe 11 !
Et si vous vous dites : elle est bien gentille, Dendrite, mais j'en fais quoi moi après, de son tableau PHP hein ?
Ca me dit pas comment je vais le transformer en tableau HTML !
C'est par ici, la suite logique de ce billet...
De belles boucles sans frisottis
2 - Exemple pratique : structure de la table SQL
A - un identifiant unique
L'id ou identifiant, c'est une information unique pour reconnaître facilement un enregistrement. Dans la réalité, ça peut être votre numéro de Sécu, votre login sur Developpez ou le numéro de ticket que vous prenez pour faire la queue chez le boucher.
La façon la plus simple d'avoir un identifiant unique, c'est d'utiliser un chiffre et de faire ‘+1’ à chaque fois qu'une ligne est créée. Par défaut, un champ entier (INT) peut aller jusqu'à 2 147 483 647 (oui, plus de 2 milliards), ce qui veut dire qu'on peut créer une ligne toutes les secondes pendant 68 ans avant d'être à court de nombres.
B – auto-incrémentation
"auto-incrémenté", ça veut tout simplement dire qu'on va demander à la base de faire le ‘+1’ à notre place. Pas besoin de réfléchir et de chercher quel est le numéro de la dernière ligne enregistrée, ça se fait automatiquement.
C – La table contact
Si vous n’avez pas de base disponible, créez une base nommée ma_base dans votre PHPMYADMIN.
Et copiez-collez ce code SQL (dans la console SQL de PHPMYADMIN) qui vous construit et vous remplit une petite table de contacts.
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 CREATE TABLE IF NOT EXISTS `contact` ( `id` int(11) NOT NULL AUTO_INCREMENT, `nom` varchar(100) NOT NULL, `prenom` varchar(100) NOT NULL, `mail` varchar(200) NOT NULL, PRIMARY KEY (`id`), KEY `nom` (`nom`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; INSERT INTO `contact` (`id`, `nom`, `prenom`, `mail`) VALUES (1, 'ACCOYER', 'Alain', 'alain.accoyer@gmail.com'), (2, 'BRABOIS', 'Bernard', 'bbrabois@yahoo.fr'), (3, 'CHAZAL', 'Claire', 'chaz@wanadoo.fr'), (4, 'DENDRITE', 'Daisy', 'dendy@gmail.com'), (5, 'CHAZAL', 'Etienne', 'chazet@gmail.com'), (6, 'CHAZAL', 'Chantal', 'chacha@monfai.fr'), (7, 'CHAZAL', 'Kevin', 'kevcha@noos.fr'), (8, 'ZANZIBAR', 'Zoé', 'zanzo@orange.ocm'), (9, 'CASERATI', 'Michel', 'michoucase@voila.fr'), (10, 'FRIPON', 'Françoise', 'francoise.fripon@gmail.com');
3a - PDO - Script de connexion à la base de donnees
A la racine de votre site, dans le répertoire www si vous êtes sous WAMP, vous créez un fichier db_mysql.php.
Et vous collez le code suivant :
Bien sûr, vous changez ce qui a besoin de l’être dans les valeurs de votre connexion.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 <?php // @author : rawsrc - 2018 - Pour DVP // on vérifie si la fonction de connexion a déjà été définie afin d'éviter de la redéfinir if ( ! function_exists('db_connexion')) { function db_connexion() { // une fois ouverte, on renvoie toujours la même connexion static $pdo; // on vérifie si la connexion n'a pas déjà été initialisée if ( ! ($pdo instanceof PDO)) { // tentative d'ouverture de la connexion MySQL try { $pdo = new PDO('mysql:host=localhost;port=3306;dbname=ma_base;charset=utf8','root', '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false ]); } catch (PDOException $e) { throw new InvalidArgumentException('Erreur connexion à la base de données : '.$e->getMessage()); exit; } } // renvoi de la ressource : connexion à la base de données return $pdo; } } return db_connexion();
Comment tester votre connexion maintenant ?
En mettant juste cette ligne, sur un fichier test.php au même niveau que votre fichier db_mysql.php :
S'il ne génère rien, c'est à dire pas d'erreur : C'est que la connexion est bonne !
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part $db = include 'db_mysql.php';
Vous pouvez supprimer le fichier test.php et passer à la suite...
3b - PDO - fermer la connexion, c'est bien.
Et c'est tout simple en plus !
Là, pour les exemples, j'ouvre et je ferme à chaque requête parce que je souhaite vous livrer un code directement fonctionnel.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part unset($db);
Mais comprenez-bien que sur un script, vous ouvrirez la connexion, vous ferez peut-être dix requêtes, de select, d'update, d'insert, toujours avec la même connexion et vous ne la fermerez qu'en fin de page.
4 – Le bloc try catch : afficher les exceptions
Maintenant, vous pouvez mettre ceci sur un nouveau fichier test.php, pour comprendre à quoi sert un bloc try and catch, et la gestion des exceptions (messages d'erreurs).
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 try{ //ici vous écrivez tout votre script //jusquà la fin, sil y a une exception, elle sera interceptée par le catch //on fait exprès d'écrire une bêtise ici //$i=0; echo $i; } catch(Exception $e){ //s'il y a un probleme PHP ou SQL, que ce soit un warning ou une erreur fatale, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
5 - Requête SELECT sans filtre : lister tous les enregistrements
Testez bien la requête dans votre PHPMYADMIN d’abord !
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT * FROM contact ORDER BY nom, prenom;
Quand tout fonctionne, on crée une page "contact.php" que l'on positionne à la racine de notre site (toujours au même niveau que notre autre page "db_mysql.php". Elle contient ceci :
On n’a que la variable $sql à changer.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 <?php //pas de filtre $sql='SELECT * FROM contact ORDER BY nom, prenom;'; //on initialise notre tableau PHP $data=array(); $db = include 'db_mysql.php'; try{ //la ligne qui lance la requête préparée $stmt = $db->prepare($sql); //pas de filtres donc pas de paramètres $stmt->execute(); //$data est un tableau de tableaux associatifs directement exploitable ensuite dans une boucle foreach $data= $stmt->fetchAll(PDO::FETCH_ASSOC); unset($db); //$data est complet if(count($data)>0){ echo '<pre>'; print_r($data); echo '</pre>'; } //ceci n'est pas une exception //il n'y a peut-etre pas encore de donnees dans la table ! else{ echo 'Aucun resultat pour cette requete'; } } catch (Exception $e) { //s'il y a un probleme PHP ou SQL, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
6 - Requête SELECT avec filtre : lister les enregistrements selon critères
Si par ailleurs, vous souhaitez introduire des filtres à votre requête, votre page contact.php devra être construite comme suit :
On veut faire remonter tous les contacts dont le nom est « CHAZAL » et dont le prénom commence par « C » et dont l’id est strictement supérieur à 2, ce qui doit nous retourner 2 enregistrements :
Testez bien la requête dans votre PHPMYADMIN d’abord !
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT id, nom, prenom, mail FROM contact WHERE nom="CHAZAL" and prenom like "C%" and id > 2 ORDER BY nom, prenom;
On positionne la page contact.php à la racine de notre site. Elle contient ceci :
On doit changer la variable $sql et la ligne $stmt->execute pour placer les valeurs précises de filtres dans l’ordre.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 <?php //on supprime les guillemets dune chaîne SQL, PDO sen occupera $sql='SELECT id, nom, prenom, mail FROM contact WHERE nom= ? and prenom like ? and id > ? ORDER BY nom, prenom;'; //on initialise notre tableau PHP $data=array(); $db = include 'db_mysql.php'; try { //la ligne qui lance la requête préparée $stmt = $db->prepare($sql); //on affecte les marqueurs précis sur les filtres //en vrai, vous aurez plutôt des variables de type POST envoyées par un formulaire $nom='CHAZAL'; $prenom_debut='C%'; $id_superieur_a=2; //Attention, bien mettre dans l'ordre de la requête ! nom puis prenom_debut puis $id_superieur_a $stmt->execute(array($nom,$prenom_debut,$id_superieur_a)); //$data est un tableau de tableaux associatifs directement exploitable ensuite dans une boucle foreach $data= $stmt->fetchAll(PDO::FETCH_ASSOC); unset($db); //$data est complet if(count($data)>0){ echo '<pre>'; print_r($data); echo '</pre>'; } //ceci n'est pas une exception //il n'y a peut etre pas de CHAZAL avec un prénom qui commence par un C et dont lid est strictement supérieur à 2 else{ echo 'Aucun resultat pour cette requete'; } } catch (Exception $e) { //s'il y a un problème PHP ou SQL, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
7 - Requête INSERT : ajouter un enregistrement
Si par ailleurs, vous souhaitez insérer des données dans votre table, votre page contact.php devra être construite comme suit.
On veut insérer un nouveau contact.
Testez bien la requête dans votre PHPMYADMIN d’abord !
Si la requête SQL fonctionne, pensez-bien à supprimer Mme GAILLARD de votre table via PHPMYADMIN, avant de passer à la suite.
On positionne la page contact.php à la racine de notre site. Elle contient ceci :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part INSERT INTO contact (id, nom, prenom, mail) VALUES (NULL, 'GAILLARD', 'Geneviève', 'genevieve.gaillard@gmail.com');
On doit changer la variable $sql et la ligne $stmt->execute pour placer les valeurs précises de filtres dans l’ordre.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 <?php //on supprime les guillemets dune chaîne SQL, PDO sen occupera //on remplace lid auto-increment par NULL, la table sen chargera $sql='INSERT INTO contact (id, nom, prenom, mail) VALUES (NULL, ?, ?, ?)'; $db = include 'db_mysql.php'; try { //la ligne qui lance la requête préparée $stmt = $db->prepare($sql); //on affecte les marqueurs précis sur les filtres //en vrai, vous aurez plutôt des variables de type POST envoyées par un formulaire $nom='GAILLARD'; $prenom='Geneviève'; $mail='genevieve.gaillard@gmail.com'; //Attention, bien mettre dans l'ordre de la requête ! Nom puis prenom puis mail $stmt->execute(array($nom,$prenom,$mail)) ; // on peut récupérer le nombre de lignes affectées $nb_insert = $stmt->rowCount(); echo $nb_insert.' insertion effectuée<br/>'; unset($db); } catch (Exception $e) { //s'il y a un problème PHP ou SQL, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
8 - Requête UPDATE : modifier un enregistrement
Si par ailleurs, vous souhaitez modifier des données existantes dans votre table, votre page contact.php devra être construite comme suit.
On veut corriger le mail de Mme ZANZIBAR, car on a mis .ocm au lieu de .com.
Testez bien la requête dans votre PHPMYADMIN d’abord !
Si la requête SQL fonctionne, pensez-bien ensuite à remette l’erreur ‘orange.ocm’ via PHPMYADMIN, avant de passer à la suite.
On positionne la page contact.php à la racine de notre site. Elle contient ceci :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part UPDATE contact SET mail = 'zanzo@orange.com' WHERE contact.id = 8;
On doit changer la variable $sql et la ligne $stmt->execute pour placer les valeurs précises de filtres dans l’ordre.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 <?php //on supprime les guillemets dune chaîne SQL, PDO sen occupera $sql='UPDATE contact SET mail = ? WHERE contact.id = ?;'; $db = include 'db_mysql.php'; try { //la ligne qui lance la requête préparée $stmt = $db->prepare($sql); //on affecte les marqueurs précis sur les filtres //en vrai, vous aurez plutôt des variables de type POST envoyées par un formulaire $mail='zanzo@orange.com'; $id=8; //Attention, bien mettre dans l'ordre de la requête ! mail puis id $stmt->execute(array($mail,$id)) ; // on peut récupérer le nombre de lignes affectées $nb_update = $stmt->rowCount(); echo $nb_update.' modif effectuée<br/>'; unset($db); } catch (Exception $e) { //s'il y a un problème PHP ou SQL, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
9 - Requête DELETE : supprimer un enregistrement
Si par ailleurs, vous souhaitez supprimer des données dans votre table, votre page contact.php devra être construite comme suit.
On veut supprimer l’enregistrement Chantal CHAZAL, car son mail n’existe pas.
Testez bien la requête dans votre PHPMYADMIN d’abord !
Si la requête SQL fonctionne, pensez-bien à remettre Chantal CHAZAL dans votre table via PHPMYADMIN, avant de passer à la suite, et repérez son nouvel id !
On positionne la page contact.php à la racine de notre site. Elle contient ceci :
Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part DELETE FROM contact WHERE contact.id = 6;
On doit changer la variable $sql et la ligne $stmt->execute pour placer les valeurs précises de filtres dans l’ordre.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 <?php $sql='DELETE FROM contact WHERE contact.id = ?;'; $db = include 'db_mysql.php'; try { //la ligne qui lance la requête préparée $stmt = $db->prepare($sql); //on affecte le marqueur précis sur le filtre //en vrai, vous aurez plutôt des variables de type POST envoyées par un formulaire $id=6; $stmt->execute(array($id)); // on peut récupérer le nombre de lignes affectées $nb_delete = $stmt->rowCount(); echo $nb_delete.' suppression effectuée<br/>'; unset($db); } catch (Exception $e) { //s'il y a un problème PHP ou SQL, tout s'affichera ici print "Erreur ! " . $e->getMessage() . "<br/>"; }
10 - Astuces et erreurs courantes
1 - A proscrire totalement et pour toujours
Ceci est la porte ouverte aux injections SQL. PDO en soi ne prévient pas les injections SQL.
Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 $sql='SELECT id, nom, prenom, mail FROM contact WHERE nom="'.$_POST['nom'].'" and prenom like "'.$_POST['prenom_debut'].'" and id > '.$_POST['id_min'].' ORDER BY nom, prenom;';
https://fr.wikipedia.org/wiki/Injection_SQL
Il vous faut utiliser PDO + les requêtes préparées telles qu’exposées ci-dessus.
2 - PDO plus obscur ?
On peut se dire la chose suivante : Ce qui était bien avec la requête ci-dessus, c’est qu’un simple echo $sql; nous permettait de copier-coller et de tester dans phpmyadmin que tout était bon. Et ça, ce n’est plus possible avec PDO, le rendant plus obscur.
Pourtant, il faut juste inverser la démarche, et ça reste aussi simple. Comme montré dans cet article, on commence par une requête qui fonctionne dans phpmyadmin. Dans $sql, on met des points d’interrogation à la place des valeurs en dur… et enfin, on reporte les valeurs variables PHP dans le array() des paramètres.
11 – Pour aller plus loin
Ici nous avons fait le choix de n’utiliser QUE des marqueurs anonymes (points d’interrogation).
Pour utiliser des marqueurs nommés, car nombre de développeurs trouvent cette méthode plus lisible, merci de lire ce tutoriel qui va bien plus loin que ce petit article d’initiation:
PDO niveau 2 (placeholders)
https://fmaz.developpez.com/tutoriel...omprendre-pdo/
12 – Les participants à ce billet collaboratif
Ceci est un billet collaboratif : Un grand merci donc à tous les participants !
Dans l’ordre alphabétique :
- Andry.ayme
- Celira
- Dendrite
- Jreaux62
- MaitrePylos
- ProgElect
- Rawsrc
- Willy_k
Et merci à LaurentSc pour avoir testé les codes !