Aller au menu - Aller au contenu

Icône Lire des données

Mise à jour : 03/04/2010
Difficulté : Intermédiaire Intermédiaire Creative Commons BY-NC-SA
164 536 visites depuis 7 jours , dont 7 640 sur ce chapitre , classé 3/777
Nous retournons dans ce chapitre à nos pages PHP. Nous allons à partir de maintenant apprendre à communiquer avec une base de données via PHP. Ce sera l'occasion de découvrir le langage SQL, que nous étudierons tout au long des prochains chapitres.

Nous allons ici nous entraîner à lire des données dans une table. Il est vivement conseillé d'avoir un peu manipulé phpMyAdmin au préalable : cet outil sera le moyen pour vous de vérifier si les manipulations que vous faites en PHP ont bien l'impact que vous attendiez dans votre base de données.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Se connecter à la base de données en PHP

Pour pouvoir travailler avec la base de données en PHP, il faut d'abord s'y connecter.

Nous allons apprendre dans ce chapitre à lire des données dans une BDD (base de données). Or, je vous rappelle que PHP doit faire l'intermédiaire entre vous et MySQL. Problème : PHP ne peut pas dire à MySQL dès le début "Récupère-moi ces valeurs". En effet, MySQL demande d'abord un nom d'utilisateur et un mot de passe. S'il ne faisait pas ça, tout le monde pourrait accéder à votre BDD et lire les informations qu'elle contient (parfois confidentielles !).

Il va donc falloir que PHP s'authentifie : on dit qu'il établit une connexion avec MySQL. Une fois que la connexion sera établie, vous pourrez faire toutes les opérations que vous voudrez sur votre base de données !

Comment se connecte-t-on à la base de données en PHP ?



Bonne question ! En effet, PHP propose plusieurs moyens de se connecter à une base de données MySQL :

  • L'extension mysql_ : ce sont des fonctions qui permettent d'accéder à une base de données MySQL et donc de communiquer avec MySQL. Leur nom commence toujours par mysql_. Toutefois, ces fonctions sont vieilles et on recommande de ne plus les utiliser aujourd'hui.
  • L'extension mysqli_ : ce sont des fonctions améliorées d'accès à MySQL. Elles proposent plus de fonctionnalités et sont plus à jour.
  • L'extension PDO : c'est un outil complet qui permet d'accéder à n'importe quel type de base de données. On peut donc l'utiliser pour se connecter aussi bien à MySQL que PostgreSQL ou Oracle.


Ce sont toutes des extensions car PHP est très modulaire. On peut ajouter ou supprimer des éléments à PHP très facilement, car tout le monde n'a pas forcément besoin de toutes les fonctionnalités.

Quel moyen choisir parmi tous ceux-là ?


Vous l'aurez compris, les fonctions mysql_ ne sont plus à utiliser (on dit qu'elles sont obsolètes). Il reste à choisir entre mysqli_ et PDO. Nous allons ici utiliser PDO car c'est cette méthode d'accès aux bases de données qui va devenir la plus utilisée dans les prochaines versions de PHP. D'autre part, le gros avantage de PDO est que vous pouvez l'utiliser de la même manière pour vous connecter à n'importe quel autre type de base de données (PostgreSQL, Oracle...).

PDO permet de se connecter à n'importe quel type de base de données


Vous pourrez donc réutiliser ce que vous allez apprendre si vous choisissez d'utiliser une autre base de données que MySQL.

Activer PDO



Normalement, PDO est activé par défaut. Pour le vérifier, faites un clic gauche sur l'icône de WAMP dans la barre des tâches, puis allez dans le menu PHP / Extensions PHP et vérifiez que php_pdo_mysql est bien coché.

Vérifiez si l'extension PDO est activée


Et si je n'utilise pas WAMP ?


Vous pouvez ouvrir le fichier de configuration de PHP (qui s'appelle généralement php.ini) et rechercher la ligne qui contient php_pdo_mysql. Enlevez le point-virgule devant s'il y en a un pour activer l'extension :

Code : Autre
1
2
3
4
5
;extension=php_pdo_firebird.dll
;extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_odbc.dll


Si vous êtes sous Linux et que vous utilisez XAMPP, recherchez la ligne pdo_mysql.default_socket et complétez-la comme ceci

Code : Autre
1
pdo_mysql.default_socket = /opt/lampp/var/mysql/mysql.sock


Enregistrez le fichier puis redémarrez PHP. Il suffit pour cela de relancer votre logiciel favori, type WAMP, MAMP, XAMPP...

Se connecter à MySQL avec PDO



Maintenant que nous sommes certains que PDO est activé, nous pouvons nous connecter à MySQL. Nous allons avoir besoin de 4 renseignements :

  • Le nom de l'hôte : c'est l'adresse de l'ordinateur où MySQL est installé (comme une adresse IP). Le plus souvent, MySQL est installé sur le même ordinateur que PHP : dans ce cas, mettez la valeur localhost (qui signifie "sur le même ordinateur"). Néanmoins, il est possible que votre hébergeur web vous indique une autre valeur à renseigner (par exemple sql.hebergeur.com). Dans ce cas il faudra modifier cette valeur lorsque vous enverrez votre site sur le web.
  • La base : c'est le nom de la base de données à laquelle vous voulez vous connecter. Dans notre cas, la base s'appelle test. Nous l'avons créée avec phpMyAdmin dans le chapitre précédent.
  • Le login : il permet de vous identifier. Renseignez-vous auprès de votre hébergeur pour le connaître. Le plus souvent (chez un hébergeur gratuit) c'est le même login que vous utilisez pour le FTP.
  • Le mot de passe : il y a des chances pour que le mot de passe soit le même que celui que vous utilisez pour accéder au FTP. Renseignez-vous auprès de votre hébergeur.


Pour l'instant, nous faisons des tests sur notre ordinateur à la maison. On dit qu'on travaille "en local". Par conséquent, le nom de l'hôte sera localhost.
Quant au login et au mot de passe, par défaut le login est root et il n'y a pas de mot de passe.

Voici donc comment on doit faire pour se connecter à MySQL via PDO sur la base test :

Code : PHP
1
2
3
<?php
$bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '');
?>


Je ne comprends rien à ce code, c'est normal ? o_O


Oui, il faut reconnaître qu'il contient quelques nouveautés. En effet, PDO est ce qu'on appelle une extension orientée objet. C'est une façon de programmer un peu différente des fonctions classiques que l'on a appris à utiliser jusqu'ici.

Nous aurons l'occasion d'en apprendre plus au sujet de la programmation orientée objet (POO) plus loin dans le cours. Pour l'instant, je vous invite à réutiliser les codes que je vous propose en suivant mes exemples. Vous comprendrez les détails de leur mode de fonctionnement un peu plus tard.


La ligne de code qu'on vient de voir crée ce qu'on appelle un objet $bdd. Ce n'est pas vraiment une variable (même si ça y ressemble fortement), c'est un objet qui représente la connexion à la base de données. On crée la connexion en indiquant dans l'ordre dans les paramètres :

  • Le nom d'hôte (localhost)
  • La base de données (test)
  • Le login (root)
  • Le mot de passe (ici il n'y a pas de mot de passe, j'ai donc mis une chaîne vide)


Lorsque votre site sera en ligne, vous aurez sûrement un nom d'hôte différent ainsi qu'un login et un mot de passe comme ceci :

Code : PHP
1
2
3
<?php
$bdd = new PDO('mysql:host=sql.hebergeur.com;dbname=mabase', 'pierre.durand', 's3cr3t');
?>


Il faudra donc penser à changer cette ligne pour l'adapter à votre hébergeur en modifiant les informations en conséquence lorsque vous enverrez votre site sur le web.

Le premier paramètre (qui commence par mysql) s'appelle le DSN : Data Source Name. C'est généralement le seul qui change en fonction du type de base de données auquel on se connecte.


Tester la présence d'erreurs



Si vous avez renseigné les bonnes informations (nom d'hôte, base, login, mot de passe), rien ne devrait s'afficher à l'écran. Toutefois, s'il y a une erreur (vous vous êtes trompé de mot de passe ou de nom de base de données par exemple), PHP risque d'afficher toute la ligne qui pose l'erreur, ce qui inclut le mot de passe !

Vous ne voudrez pas que vos visiteurs puissent voir le mot de passe si une erreur survient lorsque votre site est en ligne. Il est préférable de traiter l'erreur. En cas d'erreur, PDO renvoie ce qu'on appelle une exception qui permet de "capturer" l'erreur.

Voici comment je vous propose de faire :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
try
{
	$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
	$bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
}
catch (Exception $e)
{
        die('Erreur : ' . $e->getMessage());
}
?>


Voilà encore un code un peu nouveau pour nous. Je ne vais pas rentrer dans le détail, car nous aurons l'occasion de parler de tout cela plus tard.
Néanmoins, je me doute que vous voudriez savoir comment ce code fonctionne au moins dans les grandes lignes. Voici le principe : PHP exécute les instructions à l'intérieur du bloc try{ } . Si une erreur se produit, il s'arrête et "saute" directement au niveau du catch{ } pour savoir quoi faire. Ici, on choisit d'afficher l'erreur et d'arrêter le script si on arrive dans le bloc catch.

Si au contraire tout se passe bien, PHP continue l'exécution du code et ne lit pas ce qu'il y a dans le bloc catch. Votre page PHP ne devrait donc rien afficher pour le moment.


Enfin, vous noterez qu'on crée un array $pdo_options que l'on envoie en paramètre sur la ligne suivante. L'objectif de cette manipulation est d'activer les exceptions PDO. Grâce à ce petit ajout (que je vous recommande d'effectuer systématiquement), nous pourrons récupérer les erreurs lorsqu'elles se produisent.

Oulah ! Tout ceci semble bien compliqué, je n'y comprends pas grand chose ! C'est grave docteur ?


Non pas du tout ! En fait, et j'insiste là-dessus, PDO nous fait utiliser des fonctionnalités de PHP que l'on n'a pas étudiées jusqu'à présent (programmation orientée objet, exceptions...). Contentez-vous pour le moment de réutiliser les codes que je vous propose et n'ayez crainte : nous reviendrons sur ces codes-là plus tard pour les expliquer dans le détail.

Si vous avez une page blanche, vous pouvez continuer. Si vous avez une erreur, lisez le message et essayez de comprendre ce qu'il signifie. Si vous êtes bloqué, n'hésitez pas à demander de l'aide sur les forums sinon vous ne pourrez pas aller plus loin.


Ce que vous devez retenir : utilisez ce modèle de blocs try/catch pour récupérer les erreurs relatives à la base de données, renvoyées par PDO. Cela vous permettra d'avoir un message clair (bon d'accord, en anglais) qui vous permettra de comprendre vos erreurs.

Récupérer les données

Nous allons dans un premier temps apprendre à lire des informations dans la base de données, puis nous verrons dans le chapitre suivant comment ajouter et modifier des données.

Pour travailler ici, il nous faut une base de données "toute prête" qui va nous servir de support pour travailler. Je vous invite à télécharger la table que j'ai créée pour vous :




Rien qu'au nom, vous pouvez vous douter que cette table contient quelque chose en rapport avec des jeux vidéo. En effet, vous allez le voir, cette table contient une liste d'une cinquantaine de jeux vidéo.

Pour cet exemple, plusieurs amis ont voulu répertorier tous les jeux vidéo qu'ils possèdent. La base de données est pour eux un moyen très pratique de classer et d'organiser tout cela, vous allez voir pourquoi. :)

Euh dis, qu'est-ce que je dois en faire de ce fichier jeux_video.sql ?


Inutile d'essayer de l'ouvrir, ça n'a pas d'intérêt. Il faut l'importer via l'onglet "Importer" de phpMyAdmin. Nous avons appris à le faire dans le chapitre précédent. Pensez à sélectionner votre base de données "test" au préalable.

Et voilà ! Vous devriez voir une nouvelle table apparaître à gauche : "jeux_video". Vous pouvez vous amuser à regarder ce qu'elle contient, pour vous faire une idée.

La table jeux_video apparaît maintenant dans phpMyAdmin


Voici les 5 premières entrées qu'elle contient (il y en a une cinquantaine en tout !) :

IDnompossesseurconsoleprixnbre_joueurs_maxcommentaires
1 Super Mario Bros Florent NES 4 1 Un jeu d'anthologie !
2 Sonic Patrick Megadrive 2 1 Pour moi, le meilleur jeu au monde !
3 Zelda : ocarina of time Florent Nintendo 64 15 1 Un jeu grand, beau et complet comme on en voit rarement de nos jours
4 Mario Kart 64 Florent Nintendo 64 25 4 Un excellent jeu de kart !
5 Super Smash Bros Melee Michel GameCube 55 4 Un jeu de baston délirant !

Pour le moment ne modifiez pas cette table. Notre objectif est de créer une page PHP qui va afficher ce que contient la table jeux_video.

Faire une requête



Maintenant arrive le grand moment que vous attendiez tous : on va parler à MySQL. On va donc commencer à parler en SQL ! Pour cela, on va faire ce qu'on appelle une requête. On va demander poliment à MySQL de nous dire tout ce que contient la table jeux_video.

Pour récupérer des informations de la base de données, nous avons besoin de notre objet qui représente la connexion à la base. Vous vous souvenez, il s'agit de $bdd. Nous allons effectuer la requête comme ceci :

Code : PHP
1
2
3
<?php
$reponse = $bdd->query('Tapez votre requête SQL ici');
?>


On demande ainsi à effectuer une requête sur la base de données.

"query" en anglais signifie "requête".


On récupère ce que la base de données nous a renvoyé dans un autre objet, que l'on a appelé ici $reponse.

Votre première requête SQL



Comme je vous l'ai dit, le SQL est un langage. C'est lui qui nous permet de communiquer avec MySQL.

Voici la première requête SQL que nous allons utiliser :

Code : SQL
1
SELECT * FROM jeux_video


Ceci peut se traduire par : « Prendre tout ce qu'il y a dans la table "jeux_video" ».
Analysons chaque terme de cette requête :

  • SELECT : en langage SQL, le premier mot indique quel type d'opération doit faire MySQL. Dans ce chapitre, nous ne verrons que SELECT. Ca demande à MySQL d'afficher ce que contient une table.
  • * : après le SELECT, on doit indiquer quels champs MySQL doit récupérer dans la table. Si on n'est intéressé que par les champs "nom" et "possesseur", il faudra taper :
    SELECT nom, possesseur FROM jeux_video
    Si vous voulez prendre tous les champs, tapez *. Cette petite étoile peut se traduire par "tout" : "Prendre tout ce qu'il y a..."
  • FROM : c'est un mot de liaison. Ca se traduit par "dans". FROM fait la liaison entre le nom des champs et le nom de la table
  • jeux_video : c'est le nom de la table dans laquelle il faut aller piocher.

Effectuons la requête avec la méthode que l'on vient de découvrir :

Code : PHP
1
2
3
<?php
$reponse = $bdd->query('SELECT * FROM jeux_video');
?>


$reponse contient maintenant la réponse de MySQL. :)

Afficher le résultat d'une requête



Le problème, c'est que $reponse contient quelque chose d'inexploitable. MySQL nous renvoie beaucoup d'informations et il faut les organiser.

Vous imaginez toutes les informations qui sont dedans ? Si c'est une table à 10 champs, avec 200 entrées, cela représente plus de 2000 informations ! Pour ne pas tout traiter d'un coup, on extrait cette réponse ligne par ligne, c'est-à-dire entrée par entrée.

Pour récupérer une entrée, on prend la réponse de MySQL et on y exécute fetch(), ce qui nous renvoie la première ligne.

Code : PHP
1
2
3
<?php
$donnees = $reponse->fetch();
?>


"fetch" en anglais signifie "va chercher".


$donnees est un array qui contient champ par champ les valeurs de la première entrée. Par exemple, si vous vous intéressez au champ console, vous utiliserez l'array $donnees['console'].

Il faudra faire une boucle pour parcourir chaque entrée une à une. A chaque fois que vous appellerez $reponse->fetch(), vous passez à l'entrée suivante. La boucle est donc répétée autant de fois qu'il n'y a d'entrées dans votre table.

Ouf ! Cela fait beaucoup d'informations à la fois. Je vous propose de résumer tout ce qu'on vient d'apprendre, de la connexion via PDO à l'affichage du résultat de la requête :

Code : PHP
 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
<?php
try
{
    // On se connecte à MySQL
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    // On récupère tout le contenu de la table jeux_video
    $reponse = $bdd->query('SELECT * FROM jeux_video');
    
    // On affiche chaque entrée une à une
    while ($donnees = $reponse->fetch())
    {
    ?>
        <p>
        <strong>Jeu</strong> : <?php echo $donnees['nom']; ?><br />
        Le possesseur de ce jeu est : <?php echo $donnees['possesseur']; ?>, et il le vend à  <?php echo $donnees['prix']; ?>   euros !<br />
        Ce jeu fonctionne sur <?php echo $donnees['console']; ?> et on peut y jouer à  <?php echo $donnees['nbre_joueurs_max']; ?> au maximum<br />
        <?php echo $donnees['possesseur']; ?> a laissé ses commentaires sur <?php echo $donnees['nom']; ?> : <em><?php echo    $donnees['commentaires']; ?></em>
        </p>
    <?php
    }
    
    $reponse->closeCursor(); // Termine le traitement de la requête

}
catch(Exception $e)
{
    // En cas d'erreur précédemment, on affiche un message et on arrête tout
    die('Erreur : '.$e->getMessage());
}


?>



Alors, vous avez vu ? o_O
Ca en fait un paquet de texte ! Il faut dire que la table que je vous ai donné contient une cinquantaine d'entrées, donc c'est normal que vous ayez beaucoup de résultats !

Concrètement que se passe-t-il ? On fait une boucle pour chaque entrée de la table. On commence par l'entrée n°1, puis l'entrée n°2 etc... A chaque fois qu'on fait une nouvelle boucle, on passe en revue une autre entrée.

Quelle est la différence entre $reponse et $donnees ?


$reponse contenait la réponse de MySQL en vrac, sous forme d'objet.
$donnees est un array renvoyé par le fetch(). A chaque fois qu'on fait une boucle, fetch va chercher dans $reponse l'entrée suivante et organise les champs dans l'array $donnees.

Je ne comprends pas la ligne while ($donnees = $reponse->fetch()) ?


En effet c'est un peu curieux et nouveau pour vous. Cette ligne fait 2 choses à la fois :
  • Elle va récupérer une nouvelle entrée et place son contenu dans $donnees
  • Elle vérifie si $donnees vaut vrai ou faux


Le fetch renvoie faux (false) dans $donnees lorsqu'il est arrivé à la fin des données, c'est-à-dire que toutes les entrées ont été passées en revue. Dans ce cas la condition du while vaut faux, et la boucle s'arrête.


Vous noterez à la fin la présence de la ligne

Code : PHP
1
<?php $reponse->closeCursor(); ?>


Elle provoque la "fermeture du curseur d'analyse des résultats". Cela signifie, en d'autres termes plus humains, que vous devez effectuer cet appel à closeCursor() à chaque fois que vous avez fini de traiter le retour d'une requête afin d'éviter d'avoir des problèmes à la requête suivante. Cela signifie qu'on a terminé le travail sur la requête.

Afficher seulement le contenu de quelques champs



Avec ce que je vous ai appris, vous devriez être capable d'afficher ce que vous voulez.
Personne ne vous oblige à afficher tous les champs ! Par exemple, si j'avais voulu lister juste les noms des jeux, j'aurais utilisé la requête SQL suivante :

Code : SQL
1
SELECT nom FROM jeux_video


Reprenons le code complet précédent et adaptons-le pour afficher un nom de jeu par ligne :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    $reponse = $bdd->query('SELECT nom FROM jeux_video');

    while ($donnees = $reponse->fetch())
    {
        echo $donnees['nom'] . '<br />';
    }
    
    $reponse->closeCursor();
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
?>



Ce code est très semblable au précédent mais c'est l'occasion pour vous de vous familiariser avec MySQL et PDO. Retenez bien en particulier les choses suivantes :

  • La connexion à la base de données n'a besoin d'être faite qu'une seule fois, au début de la page.
  • Il faut fermer les résultats de recherche avec closeCursor() après avoir traité chaque requête.

Les critères de sélection

Imaginons que je souhaite obtenir uniquement la liste des jeux disponibles de la console "Nintendo 64" et que je souhaite les trier par prix croissant. Ca paraît compliqué à faire ? Pas en SQL !

Vous allez voir qu'en modifiant nos requêtes SQL, il est possible de filtrer et trier très facilement vos données. Nous allons nous intéresser ici aux mots-clé suivants du langage SQL:
  • WHERE
  • ORDER BY
  • LIMIT


WHERE



Grâce au mot-clé WHERE, vous allez pouvoir trier vos données !

Supposons par exemple que je veuille lister uniquement les jeux appartenant à Patrick. La requête au début sera la même qu'avant, mais je rajouterai à la fin WHERE possesseur='Patrick'.
Ca nous donne la requête :

Code : SQL
1
SELECT * FROM jeux_video WHERE possesseur='Patrick'


Traduction : "Sélectionner tous les champs de la table jeux_video lorsque le champ possesseur est égal à Patrick".

Vous noterez que les chaînes de caractères doivent être placées entre apostrophes pour les délimiter, comme c'est ici le cas pour 'Patrick'. Elles ne sont en revanche pas nécessaires pour les nombres.


Un petit code pour voir ce que ça donne ?

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    $reponse = $bdd->query('SELECT nom, possesseur FROM jeux_video WHERE possesseur=\'Patrick\'');
    
    while ($donnees = $reponse->fetch())
    {
        echo $donnees['nom'] . ' appartient à ' . $donnees['possesseur'] . '<br />';
    }
    
    $reponse->closeCursor();
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
?>



Si vous vous amusez à changer le nom du possesseur (par exemple "WHERE possesseur='Michel'"), ça n'affichera que les jeux appartenant à Michel ! Essayez, vous verrez !

Il est par ailleurs possible de combiner plusieurs conditions. Par exemple, si je veux lister les jeux de Patrick qu'il vend à moins de 20 euros, je combinerai les critères de sélection à l'aide du mot-clé AND (qui signifie "et") :

Code : SQL
1
SELECT * FROM jeux_video WHERE possesseur='Patrick' AND prix < 20


Traduction : "Sélectionner tous les champs de jeux_video lorsque le possesseur est Patrick ET lorsque le prix est inférieur à 20".

Il existe aussi le mot-clé OR pour signifier "ou".


ORDER BY



ORDER BY nous permet d'ordonner nos résultats. Nous pourrions ainsi classer les résultats en fonction de leur prix ! La requête SQL serait :

Code : SQL
1
SELECT * FROM jeux_video ORDER BY prix


Traduction : "Sélectionner tous les champs de jeux_video et ordonner les résultats par prix croissant.".

Application :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    $reponse = $bdd->query('SELECT nom, prix FROM jeux_video ORDER BY prix');
    
    while ($donnees = $reponse->fetch())
    {
        echo $donnees['nom'] . ' coûte ' . $donnees['prix'] . ' EUR<br />';
    }
    
    $reponse->closeCursor();
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
?>



Et si je veux classer par ordre décroissant ?


Facile : il suffit de rajouter le mot-clé DESC à la fin :

Code : SQL
1
SELECT * FROM jeux_video ORDER BY prix DESC


Traduction : "Sélectionner tous les champs de jeux_video, et ordonner les résultats par prix décroissant.".

A noter : si on avait utilisé ORDER BY sur un champ contenant du texte, le classement aurait été fait par ordre alphabétique.


LIMIT



LIMIT nous permet de ne sélectionner qu'une partie des résultats (par exemple les 20 premiers). C'est très utile lorsqu'il y a beaucoup de résultats et que vous souhaitez les paginer (c'est-à-dire par exemple afficher les 30 premiers résultats sur la page 1, les 30 suivants sur la page 2, etc.).

Il faut rajouter à la fin de la requête le mot clé LIMIT, suivi de 2 nombres séparés par une virgule. Par exemple :

Code : SQL
1
SELECT * FROM jeux_video LIMIT 0, 20


Ces deux nombres ont un sens bien précis :
  • On indique tout d'abord à partir de quelle entrée on commence à lire la table. Ici, j'ai mis 0, ce qui correspond à la première entrée. Attention, cela n'a rien à voir avec le champ ID ! Imaginez qu'une requête retourne 100 résultats : LIMIT tronquera à partir du premier résultat si vous indiquez 0, à partir du 21ème si vous indiquez 20, etc.
  • Ensuite, le deuxième nombre indique combien d'entrées on doit sélectionner. Ici, j'ai mis 20, on prendra donc 20 entrées.


Quelques exemples :

  • LIMIT 0, 20 : affiche les 20 premières entrées.
  • LIMIT 5, 10 : affiche de la sixième à la quinzième entrée.
  • LIMIT 10, 2 : affiche la onzième et la douzième entrée.


Présentation du fonctionnement de LIMIT


Allez un petit exemple ! Si on veut afficher les 10 premiers jeux de la table, on utilisera le code suivant :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    $reponse = $bdd->query('SELECT nom FROM jeux_video LIMIT 0, 10');
    
    echo '<p>Voici les 10 premières entrées de la table jeux_video :</p>';
    while ($donnees = $reponse->fetch())
    {
        echo $donnees['nom'] . '<br />';
    }
    
    $reponse->closeCursor();
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
?>



Et voilà le travail ! :)

Bonjour, je suis masochiste, et avant de terminer cette section je souhaiterais mélanger toutes les requêtes SQL que je viens d'apprendre en une seule. C'est possible ?


Mais bien entendu mon petit. :diable:

Voilà de quoi te triturer les méninges :

Code : SQL
1
SELECT nom, possesseur, console, prix FROM jeux_video WHERE console='Xbox' OR console='PS2' ORDER BY prix DESC LIMIT 0,10


Il faut utiliser les mots-clés dans l'ordre que j'ai donné : WHERE puis ORDER BY puis LIMIT, sinon MySQL ne comprendra pas votre requête.


Essayez donc de traduire ça en français dans un premier temps, pour voir si vous avez compris, puis après testez cette requête chez vous pour voir si c'est bien ce à quoi vous vous attendiez.

Construire des requêtes en fonction de variables

Les requêtes que nous avons étudiées jusqu'ici étaient simples et effectuaient toujours la même opération. Or, les choses deviennent intéressantes quand on utilise des variables de PHP dans les requêtes.

La mauvaise idée : concaténer une variable dans une requête



Prenons cette requête qui récupère la liste des jeux appartenant à Patrick :

Code : PHP
1
2
3
<?php
$reponse = $bdd->query('SELECT nom FROM jeux_video WHERE possesseur=\'Patrick\'');
?>


Au lieu de toujours afficher les jeux de Patrick, on aimerait que cette requête soit capable de s'adapter au nom de la personne défini dans une variable, par exemple $_GET['possesseur']. Ainsi la requête pourrait s'adapter en fonction de la demande de l'utilisateur !

On pourrait être tenté de concaténer la variable dans la requête comme ceci :

Code : PHP
1
2
3
<?php
$reponse = $bdd->query('SELECT nom FROM jeux_video WHERE possesseur=\'' . $_GET['possesseur'] . '\'');
?>


Il est nécessaire d'entourer la chaîne de caractères d'apostrophes comme je vous l'ai indiqué précédemment, d'où la présence des antislash pour insérer les apostrophes : \'


Bien que ce code fonctionne, c'est l'illustration parfaite de ce qu'il ne faut pas faire et que pourtant beaucoup de sites font encore. En effet, si la variable $_GET['possesseur'] a été modifiée par un visiteur (et nous savons à quel point il ne faut pas faire confiance à l'utilisateur !), il y a un gros risque de faille de sécurité qu'on appelle Injection SQL. Un visiteur pourrait s'amuser à insérer une requête SQL au milieu de la vôtre et pourrait potentiellement lire tout le contenu de votre base de données, comme par exemple la liste des mots de passe de vos utilisateurs !

Le sujet des injections SQL est un peu complexe pour être détaillé ici. Si vous souhaitez en apprendre plus à ce sujet, je vous invite à consulter Wikipédia.


Nous allons utiliser un autre moyen plus sûr d'adapter nos requêtes en fonction de variables : les requêtes préparées.

La solution : les requêtes préparées



Le système de requêtes préparées a l'avantage d'être beaucoup plus sûr mais aussi plus rapide pour la base de données si la requête est exécutée plusieurs fois. C'est ce que je vous préconise d'utiliser si vous voulez adapter une requête en fonction d'une ou plusieurs variables.

Avec des marqueurs "?"



On va dans un premier temps "préparer" la requête sans sa partie variable, que l'on représentera avec un marqueur sous forme de point d'interrogation :

Code : PHP
1
2
3
<?php
$req = $bdd->prepare('SELECT nom FROM jeux_video WHERE possesseur = ?');
?>


Au lieu d'exécuter la requête avec query() comme la dernière fois, on appelle ici prepare().

La requête est alors prête, sans sa partie variable. Maintenant, nous allons exécuter la requête en appelant execute et en lui transmettant la liste des paramètres :


Code : PHP
1
2
3
4
<?php
$req = $bdd->prepare('SELECT nom FROM jeux_video WHERE possesseur = ?');
$req->execute(array($_GET['possesseur']));
?>


La requête est alors exécutée à l'aide des paramètres que l'on a indiqués sous forme d'array.

S'il y a plusieurs marqueurs, il faut indiquer les paramètres dans le bon ordre :

Code : PHP
1
2
3
4
<?php
$req = $bdd->prepare('SELECT nom FROM jeux_video WHERE possesseur = ? AND prix <= ?');
$req->execute(array($_GET['possesseur'], $_GET['prix_max']));
?>


Le premier point d'interrogation de la requête sera remplacé par le contenu de la variable $_GET['possesseur'] et le second point d'interrogation sera remplacé par le contenu de $_GET['prix_max']. Le contenu de ces variables aura été automatiquement sécurisé pour prévenir les risques d'injection SQL.

Essayons de construire une page capable de lister les jeux appartenant à une personne et dont le prix ne dépasse pas une certaine somme :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', '', $pdo_options);
    
    $req = $bdd->prepare('SELECT nom, prix FROM jeux_video WHERE possesseur = ? AND prix <= ? ORDER BY prix');
    $req->execute(array($_GET['possesseur'], $_GET['prix_max']));
    
    echo '<ul>';
    while ($donnees = $req->fetch())
    {
        echo '<li>' . $donnees['nom'] . ' (' . $donnees['prix'] . ' EUR)</li>';
    }
    echo '</ul>';
    
    $req->closeCursor();
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}
?>


Bien que la requête soit "sécurisée" (ce qui élimine les risques d'injection SQL), il faudrait néanmoins vérifier quand même que $_GET['prix_max'] contient bien un nombre et qu'il est compris dans un intervalle correct. Vous n'êtes donc pas dispensés d'effectuer des vérifications supplémentaires si vous estimez cela nécessaire.


Essayez d'appeler cette page (que l'on nommera par exemple selection_jeux.php) en modifiant les valeurs des paramètres, vous allez voir que la liste des jeux qui ressort change en fonction des paramètres envoyés ! Quelques exemples :



Avec des marqueurs nominatifs



Si la requête contient beaucoup de parties variables, il peut être plus pratique de nommer les marqueurs plutôt que d'utiliser des points d'interrogation.

Voici comment on s'y prendrait :

Code : PHP
1
2
3
4
<?php
$req = $bdd->prepare('SELECT nom, prix FROM jeux_video WHERE possesseur = :possesseur AND prix <= :prixmax');
$req->execute(array('possesseur' => $_GET['possesseur'], 'prixmax' => $_GET['prix_max']));
?>


Les points d'interrogations ont été remplacés par les marqueurs nominatifs :possesseur et :prixmax (ils commencent par le symbole deux-points comme vous le voyez).

Ces marqueurs sont remplacés par les variables à l'aide cette fois d'un array associatif. Cela permet parfois plus de clarté quand il y a beaucoup de paramètres. De plus, contrairement aux points d'interrogations, nous ne sommes cette fois plus obligés d'envoyer les variables dans le même ordre que la requête.

Q.C.M.

Pour quelle base de données est conçue l'extension PDO de PHP ?
Comment traduiriez-vous la requête suivante :
Code : SQL
1
SELECT utilisateur FROM liste_users
Quelles entrées récupère-t-on avec ce code ?Code : SQL
1
LIMIT 3, 10
Que récupère cette requête SQL ?Code : SQL
1
SELECT * FROM ma_table WHERE prix = 15
Que renvoie cette requête ?Code : SQL
1
SELECT * FROM abonnes WHERE ville='Avignon' LIMIT 0, 15 ORDER BY nom DESC
Par quoi sera remplacé le second point d'interrogation de cette requête préparée ?


Code : PHP
1
2
3
4
<?php
$req = $bdd->prepare('SELECT nom, prix FROM jeux_video WHERE possesseur = ? AND prix <= ?');
$req->execute(array($utilisateur, $prix));
?>

Statistiques de réponses au QCM

Vous êtes arrivés vivants jusqu'au bout ? Bravo ! :D

Vous venez d'apprendre une quantité de choses impressionnantes dans ce chapitre ! Une fois que vous aurez lu le chapitre suivant, vous commencerez à être capables de créer des scripts de news, de livre d'or, un forum, etc.
Vu que ce chapitre était d'une importance capitale, n'hésitez pas à le relire (après vous être reposés :p), car il faut vraiment que vous maîtrisiez les requêtes SQL et leur affichage avec PHP !
Chapitre précédent Sommaire Chapitre suivant

Partager

353 commentaires pour "Lire des données"
Note moyenne : 3.61 / 4 (2419 votes)
Pseudo Commentaire
Hors ligne Eddy Richard # Posté le 31/01/2012 à 09:47:17

Un cas à été oublié. Afficher les nom des jeux en fonction des "possesseur"!
Sinon un très bon tutoriel. :)

--
Eddy
Hors ligne kakashiel # Posté le 31/01/2012 à 23:26:42

Bonjour tout le monde, que voila un très bon tuto qui m'aide beaucoup dans la finition de mon site web !!! :D

Par contre(et oui par contre... :ange: ) j'ai un incommensurable problème !!!

Je n'arrive pas à afficher les accents des commentaires de la BDD ... Je m'explique en html l'utf-8 fonctionne très bien mais ne traduit pas les accents de ce rentrer dans la BDD j'ai donc modifier l'interclassement de mon champs commentaire dans la table jeux_video mais rien n'y fait
Help me !!! >_<
Hors ligne cyril-3-4 # Posté le 02/02/2012 à 18:57:32

Avis : Très bon

bonjour, et merci pour ce cour,
il très bien mais il manque une requête via une zone de saisie qui me serai utile pour mon site
exemple en tapant le nom du jeux on vois toutes les infos utile et si il existe dans la db
si quelqu'un peu m'aider SVP ??
merci par avance

Cyril.
 
Hors ligne kams2.6 # Posté le 06/02/2012 à 16:03:42
Avatar

Bonjour, je travaille sur mon ordi portable et quand je clique sur phpmyadmin pour creer une base de donné on m'affiche que je n'ai pas les droits d'acces sur ce serveur. Comment faire???
Merci d'avance pour votre aide
Hors ligne roland.vicaire # Posté le 08/02/2012 à 16:42:19

Bonjour,

Dans le tutoriel, au sujet de la sécurisation de requête, M@teo écrit Citation : M@teo
"Le contenu de ces variables aura été automatiquement sécurisé pour prévenir les risques d'injection SQL."


Pour lever toute ambigüité j'aimerais avoir une confirmation : le fait d'utiliser un prepare et un execute(array ) des variables que l'on veut utiliser est il suffisant pour sécuriser la requête contre les injections SQL ? , ou le "aura été automatiquement sécurisé" signifie qu'il faut que nous le fassions avant de passer les paramètres au execute (array)?

Pour ma part, suite à la lecture de votre tutoriel, je fais systématiquement des htmlspecialchars sur toutes les variables issues de POST / GET ou COOKIES, puis je ne les utilise qu'à traver un req->execute... Mais devant réaliser un petit site pour aider une asso, j'aimerais bien avoir votre avis.

Merci d'avance

Roland

Voir tous les commentaires