Alain Barraud Mémento informatique  
 
Accueil Logithèque - SE Photo - vidéo Internet - protocoles Site Web PC - Réseau Archives
Page ouverte le 04/03/2010
retour sommaire PHP
Logo PHP
Partie 3 : Lire des données

On va revenir ici à nos pages PHP. On va apprendre à communiquer avec une base de données via PHP. Ce sera l'occasion de découvrir le langage SQL, qu'on verra tout au long des prochains chapitres.
On va ici s'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 nous de vérifier si les manipulations qu'on fait en PHP ont bien l'impact qu'on attend dans notre base de données.
Sommaire

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.

On va apprendre dans ce chapitre à lire des données dans une BDD (base de données). Or, pour rappel, PHP doit faire l'intermédiaire entre nous 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 à notre BDD et lire les informations qu'il y a dedans (parfois confidentielles !).

Il faut donc que PHP s'authentifie : on dit qu'il établit une connexion avec MySQL. Une fois que la connexion sera établie, on pourra faire toutes les opérations qu'on voudra sur notre base de données !
Comment se connecte-t-on à la base de données en PHP ?
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&aecute;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.
question Quel moyen choisir parmi tous ceux-là ?
On l'aura compris, les fonctions mysql_ ne sont plus à utiliser (on dit qu'elles sont obsolètes). Il reste à choisir entre mysqli_ et PDO. On va ici utiliser PDO car c'est cette méthode d'accès aux bases de données qui va devenir la plus utilisée. D'ailleurs, le gros avantage de PDO est qu'on peut l'utiliser de la même manière pour se connecter à n'importe quel autre type de base de données (PostgreSQL, Oracle…).
Activer PDO
Normalement, PDO est maintenant activé par défaut. Pour le vérifier, faire un clic gauche sur l'icône de WAMP dans la barre des tâches, puis aller dans le menu "PHP / Extensions PHP" et vérifier que "php_pdo_mysql" est bien coché.

pdo
question Et si je n'utilise pas WAMP ?
On peut ouvrir le fichier de configuration de PHP (qui s'appelle généralement "php.ini") et rechercher la ligne qui contient "php_pdo_mysql". Enlever le point-virgule devant s'il y en a un pour activer l'extension :
Code : Autre
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
Enregistrer le fichier puis redémarrer PHP. Il suffit pour cela de relancer son logiciel favori, type WAMP, MAMP, XAMPP…
Se connecter à MySQL avec PDO
Maintenant qu'on est certain que PDO est activé, on peut se connecter à MySQL. On va avoir besoin de 3 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, mettre la valeur localhost. Néanmoins, il est possible que notre hébergeur web nous indique une autre valeur à renseigner (par exemple sql.herbergeur.com). Dans ce cas il faudra modifier cette valeur lorsqu'on enverra notre site sur le web.
  • La base : c'est le nom de la base de données à laquelle on veut se connecter. Dans notre cas, la base s'appelle "test".
  • Le login : ça permet de s'identifier. Se renseigner auprès de son hébergeur pour le connaître. Le plus souvent (chez un hébergeur gratuit) c'est le même login qu'on utilise pour le FTP.
  • Le mot de passe : là encore, il y a des chances pour que le mot de passe soit le même que celui qu'on utilise pour accéder au FTP. Se renseigner auprès de son hébergeur.
Pour l'instant, on fait des tests sur son ordinateur à la maison. On dit qu'on travail "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 comment on devrait faire pour se connecter à MySQL via PDO sur la base test :
Code PHP
<?php
$bdb = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
?>
question Je ne comprends rien à ce code, c'est normal ?
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 qu'on a vu jusqu'ici.
On aura l'occasion d'en apprendre plus au sujet de la programmation orientée objet (POO) plus loin dans le tuto. Pour l'instant, réutilisons les codes proposés en suivant les exemples.

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 :
  • 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 notre site sera en ligne, on aura sûrement un nom d'hôte différent ainsi qu'un login et un mot de passe comme ceci :
Code PHP
<?php
$bdb = new PDO('mysql:host=sql.hebergeur.com;dbname=mabase', 'pierre.durand', 's3cr3t');
?>
Penser à changer cette ligne pour l'adapter à son hébergeur en modifiant les informations en conséquence lorsqu'on enverra son site sur le web.
alt 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 que l'on utilise.
Tester la présence d'erreurs
Si on a 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 (on s'est 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 !
Pour éviter que ça n'arrive lorsque notre site sera en ligne, il est préférable de traiter l'erreur. En cas d'erreur, PDO renvoie ce qu'on appelle une exception. Il faut "capturer" l'erreur. Voici comment je vous propose de faire :
Code PHP
<?php
try
{
    $bdb = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch (Exception $e)
{
    die('Erreur : ' . $e->getMessage());
}
?>
Voilà encore un code un peu nouveau pour nous. Sans trop rentrer dans le détail là encore, car nous aurons l'occasion d'en parler plus tard, il faut savoir que PHP essaie d'exécuter les instructions à l'intérieur du bloc try. S'il y a une erreur, il rentre dans le bloc catch et fait ce qu'on lui demande (ici, on arrête l'exécution de la page en affichant un message décrivant l'erreur).
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. Notre page PHP ne devrait donc rien afficher pour le moment.
question Oulah ! Tout ceci semble bien compliqué, je n'y comprends pas grand chose ! C'est grave docteur ?
Non pas du tout ! En fait, 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…). Contentons-nous pour le moment de réutiliser les codes proposés et pas de crainte : on reviendra sur ces codes-là plus tard pour les expliquer dans le détail.
Pour le moment, il ne sert à rien de vouloir tout comprendre, sinon à s'embrouiller l'esprit.

Récupérer les données

On va dans un premier temps apprendre à lire des informations dans la base de données, puis on verra dans le chapitre suivant comme 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. On est invité à télécharger la table créée pour nous :
Lien que l'on retrouve dans le chapitre correspondant sur http://www.siteduzero.com/tutoriel-3-14506-lire-des-donnees.html
Le fichier s'appelle : jeux_video.sql. Cette table contient une liste d'une cinquantaine de jeux vidéo.
question qu'est-ce que je fais 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. On a vu comment faire dans le chapitre précédent. Penser à sélectionner notre base de données "test" au préalable.
On devrait voir une nouvelle table apparaître à gauche : "jeux_video". On peut s'amuser à regarder ce qu'elle contient, pour se faire une idée.

base : jeux_video

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

IDnompossesseurconsoleprixnbre_joueurs_maxcommentaires
1Super Mario BrosFlorentNES41Un jeu d'anthologie !
2SonicPatrickMegadrive21Pour moi, le meilleur jeu au monde !
3Zelda : ocarina of timeFlorentNintendo 64151Un jeu grand, beau et complet comme on en voit rarement de nos jours
4Mario Kart 64FlorentNintendo 64254Un excellent jeu de kart !
5Super Smash Bros MeleeMichelGameCube554Un jeu de baston délirant !
Pour le moment ne pas modifier cette table. L' objectif est de créer une page PHP qui va afficher ce que contient la table "jeux_video".
Faire une requête
On y arrive : on va parler à MySQL. 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, on a besoin de notre objet qui représente la connexion à la base. Rappelons-nous, il s'agit de $bdd. On va effectuer la requête comme ceci :
Code PHP
$reponse = $bdd->query('Tapez votre requête SQL ici');
On demande ainsi à effectuer une requête sur la base de données.
alt "query" 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".
On va voir comment demander à MySQL tout ce qu'il y a dans la table "jeux_video".
Notre première requête SQL
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
SELECT * FROM jeux_video
Ce qui 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 on veut prendre tous les champs, taper *. 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 voir :
Code PHP
<?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 un joyeux bazar pas bien organisé.
Imaginer 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
<?php
$donnees = $reponse->fetch();
?>
alt "fetch" signifie "va chercher"

$donnees est un array qui contient champ par champ les valeurs de la première entrée. Par exemple, si on s'intéresse au champ console, on utilisera l'array $donnees['console'].
Il faudra faire une boucle pour parcourir chaque entrée une à une. A chaque fois qu'on appellera $reponse->fetch(), on passe à l'entrée suivante. La boucle est donc répétée autant de fois qu'il y a d'entrées dans notre table.

Pour résumer tout ce qu'on vient de voir, de la connexion via PDO à l'affichage du résultat de la requête :
Code PHP
<?php
try
{
    //on se connecte à MySQL
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch(Exception $e)
{
    //En cas d'erreur, on affiche un message et on arrête tout
    die('Erreur : '.$e->getMessage());
}

//Si tout va bien, on peut continuer

//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 pocesseur de ce jeu est : <?php echo $donnees['pocesseur']; ?>, 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é ces commentaires sur <?php echo $donnees['nom']; ?> : <em><?php echo $donnees['commentaires']; ?></em>
    </p>
<?php
}

$reponse->closeCursor(); //Termine le traitement de la requête

?>
Quand on essaie ce code, cela fait un paquet de texte. Normal, la table contient une cinquantaine d'entrées, donc ça fait 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.
question 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.
question Je ne comprends pas la ligne while ($donnees = $reponse->fetch()) ?
En effet c'est un peu curieux et nouveau. 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 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.

Noter à la fin le présence de la ligne :
Code PHP
<?php $reponse->closeCursor(); ?>
Elle provoque la "fermeture du curseur d'analyse des résultats". Cela signifie, en d'autres termes plus humains, qu'on doit effectuer cet appel à closeCursor() à chaque fois qu'on a fini de traiter le retour d'une requête afin d'éviter d'avoir des problèmes à la requête suivante.
Afficher seulement le contenu de quelques champs
Avec ce que l'on a vu, on devrait être capable d'afficher ce qu'on veut.
Personne ne nous 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
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
<?php
try
{
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}

$reponse = $bdd->query('SELECT nom FROM jeux_video');

while ($donnees = $reponse->fetch())
{
    echo $donnees['nom']; . '<br />';
}

$reponse->closeCursor();

?>
Ce code est très semblable au précédent mais et permet de se familiariser avec MySQL et PDO. Bien retenir en particulier :
  • 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

Supposons que l'on veuille obtenir uniquement la liste des jeux disponibles de la console "Nintendo 64" et qu'on souhaite les trier par prix croissant. Ca paraît compliqué à faire ?
Pas en SQL !
On va voir qu'en modifiant nos requêtes SQL, il est possible de filtrer et trier très facilement ses données. On va s'intéresser ici aux mots-clé suivants du langages SQL:
  • WHERE
  • ORDER BY
  • LIMIT
WHERE
Avec le mot-clé WHERE, on va pouvoir trier ses données !
Supposons par exemple qu'on veuille lister uniquement les jeux appartenant à Patrick. La requête au début sera la même qu'avant, mais on rajoutera à la fin WHERE possesseur='Patrick'.
Ce qui donne :
Code : SQL
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".
alt Noter que les chaînes de caractères doivent être placées entre apostrophes pour les délimiter, comme ici pour 'Patrick'. Elles ne sont en revanche pas nécessaires pour les nombres.
Au final, cela donne :
Code PHP
<?php
try
{
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}

$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();

?>
Il est possible de combiner plusieurs conditions. Par exemple, si je veux lister les jeux de Patrick qu'il vend à moins de 20 euros, j'utiliserai comme requ&ecric;te SQL :
Code : SQL
SELECT * FROM jeux_video WHERE possesseur='Patrick' AND prix < 20
ORDER BY
ORDER BY permet d'ordonner les résultats. On pourrait ainsi classer les résultats en fonction de leur prix ! La requête SQL serait :
Code : SQL
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
<?php
try
{
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}

$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();

?>
question Et si je veux classer par ordre décroissant ?
Facile : il suffit de rajouter le mot-clé DESC à la fin :
Code : SQL
SELECT * FROM jeux_video ORDER BY prix DESC
alt 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 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 qu'on souhaite 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
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 ! Imaginons qu'une requête retourne 100 résultats : LIMIT tronquera à partir du premier résultat si on indique 0, à partir du 21ème si on indique 20, etc.
  • Ensuite, le deuxième nombre indique combien d'entrées on doit sélectionner. Ici, on a mis 20, on prendra donc 20 entrées.
Par exemple :
  • LIMIT 0, 20 : affiche les 20 premières entrées.
  • LIMIT 5, 10 : affiche les entrées nº 6 à 15.
  • LIMIT 10, 2 : affiche les entrées nº 11 et 12.
Si on veut afficher les 10 premiers jeux de la table :
Code PHP
<?php
try
{
    $bdd = new PDO('mysql:host=localhost;dbname=test', 'root', ' ');
}
catch(Exception $e)
{
    die('Erreur : '.$e->getMessage());
}

$reponse = $bdd->query('SELECT nom, prix 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();

?>

Pour terminer en beauté !
question Peut-on mélanger toutes les requêtes SQL qu'on a vu en une seule ?
Bien sur, la réponse est oui !
Voilà de quoi se torturer :
Code : SQL
SELECT nom, possesseur, console, prix FROM jeux_video WHERE console='xbox' OR console='PS2' ORDER BY prix DESC LIMIT 0,10
erreur Il faut utiliser les mots-clés dans l'ordre donné : WHERE puis ORDER BY puis LIMIT, sinon MySQL ne comprendra pas la requête.