Vous êtes sur la page 1sur 961

Rfrence

PHP &
MySQL
Luke Welling
Laura Thomson

Rseaux
et tlcom

Dveloppement
Web

Gnie logiciel

Scurit

Systme
4e dition
dexploitation
PHP
& MySQL
4e dition

Luke Welling & Laura Thomson


Pearson Education France a apport le plus grand soin la ralisation de ce livre afin de vous four-
nir une information complte et fiable. Cependant, Pearson Education France nassume de respon-
sabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces
personnes qui pourraient rsulter de cette utilisation.

Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions
thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle.

Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices
ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou
programmes.

Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs
propritaires respectifs.

Publi par Pearson Education France Titre original : PHP and MySQL Web Development,
47 bis, rue des Vinaigriers Fourth edition
75010 PARIS
Tl. : 01 72 74 90 00 Traduit et rvis de lamricain par ric Jacoboni
www.pearson.fr (dition prcdente : Patrick Fabre et David de Loenzien)

Mise en pages : TyPAO


ISBN original : 978-0-672-32916-6
ISBN : 978-2-7440-4103-7 Copyright 2009 by Pearson Education, Inc.
Copyright 2009 Pearson Education France
All rights reserved
Tous droits rservs
Addison-Wesley Professional
800 East 96th Street, Indianapolis
Indiana 46240 USA

Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la
proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans
le respect des modalits prvues larticle L. 122-10 dudit code.

No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including
photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.
Table des matires

Introduction ...................................................................................................................... 1
Les points forts de ce livre .......................................................................................... 1
Ce que vous apprendrez en lisant ce livre .................................................................. 2
Prsentation de PHP ................................................................................................... 2
Prsentation de MySQL ............................................................................................. 3
Pourquoi utiliser PHP et MySQL ? ............................................................................ 4
Quelques avantages de PHP ....................................................................................... 4
Performances ................................................................................................... 5
Adaptabilit ..................................................................................................... 5
Intgration avec les bases de donnes ............................................................. 5
Bibliothques intgres ................................................................................... 5
Cot ................................................................................................................. 6
Facilit dapprentissage de PHP ...................................................................... 6
Support orient objet ...................................................................................... 6
Portabilit ........................................................................................................ 6
Souplesse dans le processus de dveloppement ............................................. 6
Code source ..................................................................................................... 7
Disponibilit du support et de la documentation ............................................. 7
Nouveauts de PHP 5 ................................................................................................. 7
Quelques avantages de MySQL .................................................................................. 8
Performances ................................................................................................... 8
Cot rduit ....................................................................................................... 8
Simplicit demploi ......................................................................................... 8
Portabilit ........................................................................................................ 9
Code source ..................................................................................................... 9
Disponibilit du support .................................................................................. 9
Nouveauts de MySQL 5 ........................................................................................... 9
Organisation de ce livre .............................................................................................. 10
Encore un mot ............................................................................................................. 11
IV PHP & MySQL

Partie I

Utilisation de PHP

1 PHP : les bases ............................................................................................................. 15


Utilisation de PHP ...................................................................................................... 16
Formulaires HTML .................................................................................................... 16
Code du formulaire ......................................................................................... 16
Traitement du formulaire ................................................................................ 18
Incorporation de code PHP dans du code HTML ...................................................... 18
Balises PHP ..................................................................................................... 19
Styles des balises PHP .................................................................................... 20
Instructions de PHP ......................................................................................... 20
Espaces ........................................................................................................... 21
Commentaires ................................................................................................. 22
Ajout de contenu dynamique ...................................................................................... 22
Appel de fonctions .......................................................................................... 23
Fonction date() ................................................................................................ 24
Accs aux variables des formulaires .......................................................................... 24
Variables des formulaires ................................................................................ 24
Concatnation de chanes ................................................................................ 28
Variables et littraux ........................................................................................ 28
Identificateurs ............................................................................................................. 29
Cration de variables .................................................................................................. 30
Affectation de valeurs des variables ........................................................................ 30
Types des variables .......................................................................................... 30
Types de donnes du PHP ............................................................................... 30
Intrt du typage .............................................................................................. 31
Transtypage ..................................................................................................... 32
Variables dynamiques ...................................................................................... 32
Constantes ................................................................................................................... 33
Porte des variables .................................................................................................... 33
Oprateurs ................................................................................................................... 35
Oprateurs arithmtiques ................................................................................ 35
Oprateur de chanes ....................................................................................... 36
Oprateurs daffectation .................................................................................. 36
Oprateurs de comparaison ............................................................................. 39
Oprateurs logiques ......................................................................................... 40
Oprateurs sur les bits ..................................................................................... 41
Autres oprateurs ............................................................................................ 42
Utilisation des oprateurs : calcul des totaux dun formulaire ................................... 44
Priorit et associativit des oprateurs : ordre dvaluation des expressions ............ 46
Table des matires V

Fonctions sur les variables .......................................................................................... 47


Test et dfinition des types de variables .......................................................... 48
Test de ltat dune variable ............................................................................ 49
Rinterprtation des variables ......................................................................... 49
Structures de contrle ................................................................................................. 50
Prise de dcision avec des structures conditionnelles ................................................ 50
Instructions if ................................................................................................... 50
Blocs de code .................................................................................................. 51
Instructions else ............................................................................................... 51
Instructions elseif ............................................................................................ 52
Instructions switch ........................................................................................... 53
Comparaison des diffrentes structures conditionnelles ................................. 55
Structures de rptition : itrations ............................................................................. 55
Boucles while .................................................................................................. 56
Boucles for et foreach ..................................................................................... 58
Boucles dowhile ........................................................................................... 59
Interruption de lexcution dune structure de contrle ou dun script ...................... 59
Employer lautre syntaxe des structures de contrle .................................................. 60
Utiliser declare ........................................................................................................... 60
Prochaine tape : enregistrement de la commande du client ...................................... 61

2 Stockage et rcupration des donnes ....................................................................... 63


Stockage des donnes en vue dun usage ultrieur .................................................... 63
Stockage et rcupration des commandes de Bob ...................................................... 64
Prsentation des fonctions de traitement des fichiers ................................................. 65
Ouverture dun fichier ................................................................................................ 65
Modes douverture des fichiers ....................................................................... 65
Utilisation de fopen() pour ouvrir un fichier ................................................... 66
Ouverture de fichiers via FTP ou HTTP ......................................................... 69
Problmes douverture de fichiers ................................................................... 70
criture dans un fichier ............................................................................................... 72
Paramtres de la fonction fwrite() ................................................................... 73
Formats de fichiers .......................................................................................... 73
Fermeture dun fichier ................................................................................................ 74
Lecture dans un fichier ............................................................................................... 76
Ouverture dun fichier en lecture : fopen() ...................................................... 77
Dtermination du moment o doit sarrter la lecture : feof() ........................ 77
Lecture dune ligne la fois : fgets(), fgetss() et fgetcsv() .............................. 77
Lecture de lintgralit du contenu dun fichier : readfile(), fpassthru()
et file() ............................................................................................................. 79
Lecture dun caractre : fgetc() ....................................................................... 80
Lecture dune longueur arbitraire : fread() ..................................................... 80
VI PHP & MySQL

Autres fonctions utiles pour la manipulation des fichiers .......................................... 81


Vrification de lexistence dun fichier : file_exists() ...................................... 81
Dtermination de la taille dun fichier: filesize() ............................................. 81
Suppression dun fichier : unlink() .................................................................. 81
Navigation dans un fichier : rewind(), fseek() et ftell() ................................... 81
Verrouillage des fichiers ............................................................................................. 83
Une meilleure solution : les systmes de gestion de base de donnes ....................... 84
Problmes poss par lusage de fichiers plats ................................................. 84
La solution apporte par les SGBDR ces problmes ................................... 85
Pour aller plus loin ...................................................................................................... 86
Pour la suite ................................................................................................................ 86

3 Utilisation de tableaux ................................................................................................. 87


Quest-ce quun tableau ? ........................................................................................... 87
Tableaux indices numriques ................................................................................... 89
Initialisation des tableaux indices numriques ............................................. 89
Accs au contenu des tableaux ........................................................................ 90
Utilisation de boucles pour accder au contenu dun tableau ......................... 91
Tableaux avec des indices diffrents .......................................................................... 91
Initialisation dun tableau ................................................................................ 91
Accs aux lments du tableau ....................................................................... 92
Utilisation de boucles ...................................................................................... 92
Oprateurs sur les tableaux ......................................................................................... 94
Tableaux multidimensionnels ..................................................................................... 95
Tri de tableaux ............................................................................................................ 99
Utilisation de la fonction sort() ....................................................................... 99
Utilisation des fonctions asort() et ksort() pour trier des tableaux ................ 100
Tri dans lordre inverse ................................................................................... 100
Tri de tableaux multidimensionnels ........................................................................... 100
Tris dfinis par lutilisateur ............................................................................. 101
Tris dfinis par lutilisateur, dans lordre inverse ............................................ 103
Rordonner des tableaux ............................................................................................ 103
Utilisation de la fonction shuffle() ................................................................... 103
Utilisation de la fonction array_reverse() ....................................................... 105
Chargement de tableaux partir de fichiers ............................................................... 105
Autres manipulations de tableaux .............................................................................. 109
Parcours dun tableau : each, current(), reset(), end(), next(), pos() et prev() .... 109
Application dune fonction donne chaque lment dun tableau :
array_walk() .................................................................................................... 110
Comptage des lments dun tableau :
count(), sizeof() et array_count_values() ........................................................ 111
Conversion de tableaux en variables scalaires : extract() ................................ 112
Table des matires VII

Pour aller plus loin ...................................................................................................... 114


Pour la suite ................................................................................................................ 114

4 Manipulation de chanes et dexpressions rgulires ............................................... 115


Application modle : formulaire intelligent de saisie dun message (Smart Form Mail) 115
Mise en forme de chanes .......................................................................................... 118
lagage des chanes : chop(), Itrim() et trim() ................................................ 118
Mise en forme des chanes en vue de leur prsentation .................................. 119
Mise en forme de chanes en vue de leur enregistrement :
addslashes() et stripslashes() .......................................................................... 123
Fusion et scission de chanes au moyen des fonctions de traitement de chane ......... 125
Utilisation des fonctions explode(), implode() et join() .................................. 125
Utilisation de la fonction strtok() .................................................................... 126
Utilisation de la fonction substr() ................................................................... 127
Comparaison de chanes ............................................................................................. 128
Comparaison des chanes : strcmp(), strcasecmp() et strnatcmp() .................. 128
Longueur dune chane : la fonction strlen() ................................................... 129
Recherche et remplacement de sous-chanes avec les fonctions
de traitement de chanes ............................................................................................. 129
Recherche de sous-chanes dans des chanes : strstr(), strchr(), strrchr()
et stristr() ......................................................................................................... 130
Dtermination de la position dune sous-chane dans une chane :
strpos() et strrpos() ......................................................................................... 131
Substitution de sous-chanes : str_replace() et substr_replace() .................... 132
Introduction aux expressions rgulires ..................................................................... 134
Notions de base ............................................................................................... 134
Ensembles et classes de caractres .................................................................. 135
Rptition ........................................................................................................ 136
Sous-expressions ............................................................................................. 137
Dnombrement de sous-expressions ............................................................... 137
Ancrage au dbut ou la fin dune chane ...................................................... 137
Branchement ................................................................................................... 138
Recherche littrale de caractres spciaux ...................................................... 138
Rcapitulatif sur les caractres spciaux ......................................................... 138
Application au cas du formulaire "intelligent" de courrier lectronique ........ 139
Recherche de sous-chanes au moyen dexpressions rgulires ................................. 141
Remplacement de sous-chanes au moyen dexpressions rgulires .......................... 141
Dcoupage de chanes au moyen dexpressions rgulires ............................. 142
Pour aller plus loin ...................................................................................................... 142
Pour la suite ............................................................................................................... 143

5 Rutilisation de code et criture de fonctions ........................................................... 145


Avantages de la rutilisation du code ......................................................................... 145
Cot ................................................................................................................. 145
VIII PHP & MySQL

Fiabilit ........................................................................................................... 146


Cohrence ........................................................................................................ 146
Utilisation des instructions require() et include() ....................................................... 146
Extensions des noms de fichiers et require() ................................................... 147
Utilisation require() pour crer des modles de site web ........................................... 149
Utilisation des options de configuration auto_prepend_file et auto_append_file 154
Utilisation de fonctions en PHP ................................................................................. 155
Appel de fonctions .......................................................................................... 155
Appel dune fonction indfinie ........................................................................ 157
Casse et noms des fonctions ........................................................................... 158
Dfinir ses propres fonctions ? ................................................................................... 158
Structure de base dune fonction ................................................................................ 159
Attribution dun nom une fonction ............................................................... 160
Paramtres .................................................................................................................. 161
Porte .......................................................................................................................... 163
Passer des paramtres par rfrence et par valeur ...................................................... 166
Utilisation du mot-cl return ..................................................................................... 167
Retour de valeurs des fonctions .................................................................................. 169
Rcursivit .................................................................................................................. 170
Pour aller plus loin ...................................................................................................... 172
Pour la suite ................................................................................................................ 172

6 PHP orient objet ........................................................................................................ 173


Concepts de la programmation oriente objet ............................................................ 173
Classes et objets .............................................................................................. 173
Polymorphisme ............................................................................................... 175
Hritage ........................................................................................................... 176
Cration de classes, dattributs et doprations en PHP ............................................. 176
Structure dune classe ..................................................................................... 176
Constructeurs ................................................................................................... 177
Destructeurs ..................................................................................................... 177
Instanciation des classes ............................................................................................. 178
Utilisation des attributs de classe ................................................................................ 178
Contrler laccs avec private et public ..................................................................... 180
Appel des oprations dune classe .............................................................................. 181
Implmentation de lhritage en PHP ......................................................................... 182
Contrler la visibilit via lhritage avec private et protected ................................... 183
Redfinition (overriding) ................................................................................ 184
Empcher lhritage et les redfinitions avec final .......................................... 186
Hritage multiple ............................................................................................. 186
Implmentation dinterfaces ........................................................................... 187
Conception de classes ................................................................................................. 187
Implmentation dune classe ...................................................................................... 189
Table des matires IX

Comprendre les fonctionnalits orientes objet avances de PHP ............................. 197


Constantes de classe ........................................................................................ 197
Mthodes statiques .......................................................................................... 197
Vrification du type de classe et indication de type ........................................ 198
Clonage dobjets ............................................................................................. 199
Classes abstraites ............................................................................................. 199
Surcharge de mthodes avec call() ............................................................. 200
Utiliser autoload() ...................................................................................... 201
Implmentation des itrateurs et itrations ..................................................... 201
Conversion de classes en chanes .................................................................... 203
Utiliser lAPI dintrospection .......................................................................... 203
Pour la suite ................................................................................................................ 204

7 Gestion des exceptions ................................................................................................. 205


Notions relatives la gestion des exceptions ............................................................ 205
La classe Exception ........................................................................................ 207
Exceptions dfinies par lutilisateur .......................................................................... 208
Exceptions dans le garage de Bob ................................................................... 210
Exceptions et autres mcanismes de gestion des erreurs en PHP .............................. 213
Lectures complmentaires .......................................................................................... 214
Prochaine tape ........................................................................................................... 214

Partie II

Utilisation de MySQL

8 Conception dune base de donnes web .................................................................... 217


Concepts des bases de donnes relationnelles ............................................................ 218
Tables ............................................................................................................... 218
Colonnes .......................................................................................................... 219
Lignes .............................................................................................................. 219
Valeurs ............................................................................................................. 219
Cls .................................................................................................................. 219
Schmas ........................................................................................................... 221
Relations .......................................................................................................... 221
Conception dune base de donnes web ..................................................................... 222
Penser aux objets rels que vous modlisez .................................................... 222
viter denregistrer des informations redondantes .......................................... 224
Utiliser des valeurs de colonne atomiques ...................................................... 225
Choisir des cls pertinentes ............................................................................. 226
Penser aux questions que vous poserez votre base de donnes .................... 226
X PHP & MySQL

viter les architectures ayant beaucoup dattributs vides ............................... 227


Rcapitulatif sur les types de tables ................................................................ 228
Architecture dune base de donnes web ................................................................... 228
Architecture ..................................................................................................... 228
Pour aller plus loin ...................................................................................................... 230
Pour la suite ................................................................................................................ 230

9 Cration dune base de donnes web ......................................................................... 231


Note sur lutilisation du moniteur MySQL ................................................................ 232
Comment ouvrir une session MySQL ........................................................................ 233
Cration des bases de donnes et des utilisateurs ....................................................... 235
Configuration des utilisateurs et des privilges .......................................................... 235
Introduction au systme de privilges de MySQL ..................................................... 235
Principe des privilges minimaux ................................................................... 236
Configuration des utilisateurs : la commande GRANT ................................... 236
Types et niveaux des privilges ....................................................................... 238
La commande REVOKE .................................................................................. 241
Exemples dutilisation de GRANT et de REVOKE ......................................... 241
Configurer un utilisateur pour le Web ........................................................................ 242
Utiliser la bonne base de donnes .............................................................................. 243
Cration des tables de la base de donnes .................................................................. 244
Signification des autres mots-cls ................................................................... 245
Analyse des types de colonnes ........................................................................ 246
Examiner la base de donnes avec SHOW et DESCRIBE ............................... 248
Cration dindex ............................................................................................. 249
Identificateurs MySQL ............................................................................................... 250
Types des colonnes ..................................................................................................... 251
Types numriques ............................................................................................ 251
Types de dates et dheures ............................................................................... 253
Types de chanes .............................................................................................. 254
Pour aller plus loin ...................................................................................................... 256
Pour la suite ................................................................................................................ 256

10 Travailler avec une base de donnes MySQL ......................................................... 257


Quest-ce que SQL ? .................................................................................................. 257
Insertion de donnes dans une base de donnes ......................................................... 258
Rcupration des donnes dans la base de donnes ................................................... 260
Rcuprer des donnes ayant des critres spcifiques .................................... 262
Rcuprer des donnes dans plusieurs tables .................................................. 264
Rcuprer les donnes dans un ordre particulier ............................................. 269
Groupement et agrgation des donnes ........................................................... 270
Choisir les lignes renvoyer ........................................................................... 272
Utiliser des sous-requtes ............................................................................... 273
Table des matires XI

Mise jour des enregistrements de la base de donnes .............................................. 276


Modification des tables aprs leur cration ................................................................ 276
Supprimer des enregistrements de la base de donnes ............................................... 279
Supprimer des tables ................................................................................................... 279
Supprimer une base de donnes entire ...................................................................... 279
Pour aller plus loin ...................................................................................................... 280
Pour la suite ................................................................................................................ 280

11 Accs une base de donnes MySQL partir du Web avec PHP ........................ 281
Fonctionnement des architectures de bases de donnes web ..................................... 281
Principales tapes dans linterrogation dune base de donnes partir du Web ............ 285
Vrifier et filtrer les donnes saisies par lutilisateur ................................................. 285
tablissement de la connexion ................................................................................... 286
Choisir une base de donnes utiliser ........................................................................ 287
Interroger la base de donnes ..................................................................................... 288
Rcuprer les rsultats de la requte .......................................................................... 289
Dconnexion de la base de donnes ........................................................................... 290
Ajouter des informations dans la base de donnes ..................................................... 290
Utiliser des instructions prpares .............................................................................. 294
Autres interfaces PHP pour les bases de donnes ...................................................... 295
Utilisation dune interface de base de donnes gnrique : PEAR::MDB2 ............... 296
Pour aller plus loin ...................................................................................................... 298
Pour la suite ................................................................................................................ 298

12 Administration MySQL avance .............................................................................. 299


Les dtails du systme des privilges ......................................................................... 299
La table user .................................................................................................... 301
Les tables db et host ........................................................................................ 303
Les tables tables_priv, columns_priv et procs_priv ....................................... 305
Contrle daccs : utilisation des tables de privilges par MySQL ................ 306
Mise jour des privilges : quel moment les modifications
prennent-elles effet ? ....................................................................................... 307
Scuriser une base de donnes MySQL ..................................................................... 308
MySQL du point de vue du systme dexploitation ........................................ 308
Mots de passe .................................................................................................. 308
Privilges des utilisateurs ................................................................................ 309
Problmes relatifs au Web ............................................................................... 310
Obtenir plus dinformations sur les bases de donnes ................................................ 311
Obtenir des informations avec SHOW ............................................................. 311
Obtenir des informations sur les colonnes avec DESCRIBE .......................... 314
Comprendre le fonctionnement des requtes avec EXPLAIN ......................... 314
Astuces gnrales doptimisation ............................................................................... 320
Optimisation de larchitecture ......................................................................... 320
XII PHP & MySQL

Permissions ..................................................................................................... 320


Optimisation des tables ................................................................................... 320
Utilisation des index ........................................................................................ 321
Utiliser des valeurs par dfaut ......................................................................... 321
Autres astuces .................................................................................................. 321
Sauvegarder votre base de donnes MySQL .............................................................. 321
Restauration de votre base de donnes MySQL ......................................................... 322
Implmenter la rplication ......................................................................................... 323
Configurer le matre ....................................................................................... 323
Raliser le transfert de donnes initial ............................................................ 324
Configurer lesclave ou les esclaves ............................................................... 325
Pour aller plus loin ...................................................................................................... 325
Pour la suite ................................................................................................................ 326

13 Programmation MySQL avance ............................................................................. 327


Linstruction LOAD DATA INFILE ........................................................................... 327
Les moteurs de stockage ............................................................................................ 327
Les transactions .......................................................................................................... 329
Comprendre la dfinition des transactions ..................................................... 329
Utiliser des transactions avec InnoDB ........................................................... 330
Les cls trangres ..................................................................................................... 331
Les procdures stockes ............................................................................................ 332
Un exemple simple .......................................................................................... 333
Variables locales .............................................................................................. 335
Curseurs et structures de contrle .................................................................. 336
Pour aller plus loin ...................................................................................................... 340
Pour la suite ................................................................................................................ 340

Partie III

Scurit

14 Scurit des applications web ................................................................................... 343


Stratgies de scurit .................................................................................................. 343
Partir du bon pied ............................................................................................ 343
Trouver un quilibre entre la scurit et la facilit dutilisation ..................... 344
Surveiller la scurit ........................................................................................ 345
Une approche de base ...................................................................................... 345
Identifier les menaces auxquelles nous devrons faire face ......................................... 345
Accs ou modification de donnes confidentielles .......................................... 346
Perte ou destruction des donnes .................................................................... 346
Dni de service ................................................................................................ 347
Table des matires XIII

Injection de code malicieux ............................................................................ 347


Compromission dun serveur .......................................................................... 348
Savoir qui lon a affaire ........................................................................................... 348
Les pirates ....................................................................................................... 348
Utilisateurs victimes de machines infectes .................................................... 348
Employs mcontents ...................................................................................... 349
Voleurs de matriel .......................................................................................... 349
Nous-mmes .................................................................................................... 349
Scuriser son code ...................................................................................................... 349
Filtrage des donnes fournies par les utilisateurs ............................................ 350
Protger les sorties .......................................................................................... 354
Organiser le code ............................................................................................. 356
Contenu du code .............................................................................................. 357
Considrations sur le systme de fichiers ........................................................ 358
Stabilit du code et bogues ............................................................................. 359
Apostrophes dexcution et exec ..................................................................... 360
Scuriser le serveur web et PHP ................................................................................. 361
Garder les logiciels jour ............................................................................... 361
Lire le fichier php.ini ....................................................................................... 362
Configurer le serveur web ............................................................................... 363
Applications web chez des hbergeurs ............................................................ 364
Scuriser le serveur de base de donnes ..................................................................... 365
Utilisateurs et systme de permissions ............................................................ 366
Envoi de donnes au serveur ........................................................................... 367
Connexion au serveur ...................................................................................... 367
Excution du serveur ....................................................................................... 368
Protger le rseau ....................................................................................................... 368
Installation de pare-feux .................................................................................. 369
Utilisation dune DMZ .................................................................................... 369
Prparation contre les attaques DoS et DDoS ................................................. 370
Scurit des ordinateurs et du systme dexploitation ................................................ 370
Maintenir jour le systme dexploitation ...................................................... 370
Ne lancer que ce qui est ncessaire ................................................................. 371
Scuriser physiquement le serveur .................................................................. 371
Se prparer aux dsastres ............................................................................................ 372
Pour la suite ................................................................................................................ 373

15 Authentification avec PHP et MySQL ..................................................................... 375


Identification des visiteurs .......................................................................................... 375
Implmenter un contrle daccs ................................................................................ 377
Stockage des mots de passe ............................................................................. 379
Chiffrement des mots de passe ........................................................................ 381
Protger plusieurs pages .................................................................................. 383
XIV PHP & MySQL

Authentification de base ............................................................................................. 384


Utiliser lauthentification de base avec PHP .............................................................. 385
Utiliser lauthentification de base avec les fichiers .htaccess dApache ................ 387
Utiliser lauthentification mod_auth_mysql ............................................................... 391
Installation de mod_auth_mysql ..................................................................... 391
Utilisation de mod_auth_mysql ...................................................................... 392
Cration dune authentification personnalise ............................................................ 393
Pour aller plus loin ...................................................................................................... 393
Pour la suite ................................................................................................................ 394

16 Transactions scurises avec PHP et MySQL ......................................................... 395


Transactions scurises ............................................................................................... 395
Lordinateur de lutilisateur ............................................................................. 396
Internet ............................................................................................................ 398
Votre systme .................................................................................................. 399
Utilisation de SSL ....................................................................................................... 400
Filtrer les donnes saisies ........................................................................................... 403
Stockage scuris ........................................................................................................ 404
Stockage des numros de cartes de crdit .................................................................. 406
Utilisation du chiffrement avec PHP .......................................................................... 406
Installation de GPG ......................................................................................... 407
Pour aller plus loin ...................................................................................................... 415
Pour la suite ................................................................................................................ 415

Partie IV

Techniques PHP avances

17 Interaction avec le systme de fichiers et le serveur ............................................... 419


Introduction au dpt de fichiers ................................................................................ 419
Code HTML dun formulaire de dpt de fichiers .......................................... 421
criture du code PHP pour le traitement du fichier ....................................... 422
Problmes frquents ........................................................................................ 426
Utilisation des fonctions de manipulation des rpertoires .......................................... 427
Lecture du contenu de rpertoires ................................................................... 427
Obtention dinformations sur le rpertoire courant ......................................... 431
Cration et suppression de rpertoires ............................................................ 431
Interaction avec le systme de fichiers ....................................................................... 432
Obtention dinformations sur les fichiers ........................................................ 432
Modification des proprits dun fichier ......................................................... 435
Cration, suppression et dplacement de fichiers ........................................... 436
Utilisation de fonctions dexcution de programmes ................................................. 437
Table des matires XV

Interaction avec lenvironnement : getenv() et putenv() ............................................. 439


Pour aller plus loin ...................................................................................................... 440
Pour la suite ................................................................................................................ 440

18 Utilisation des fonctions de rseau et de protocole ................................................. 441


Vue densemble des protocoles rseau ...................................................................... 441
Envoi et rception de courriers lectroniques ............................................................. 442
Utilisation des donnes dautres sites web ................................................................ 443
Utilisation de fonctions de recherche rseau .............................................................. 445
Utilisation de FTP ....................................................................................................... 450
Sauvegarde dun fichier ou cration dun enregistrement miroir dun fichier 450
Tlchargement de fichiers vers un serveur .................................................... 457
viter les dpassements de dlai ..................................................................... 457
Autres fonctions FTP ...................................................................................... 457
Pour aller plus loin ...................................................................................................... 458
Pour la suite ................................................................................................................ 458

19 Gestion de la date et de lheure ................................................................................ 459


Obtention de la date et de lheure partir dun script PHP ........................................ 459
Utilisation de la fonction date() ...................................................................... 459
Utilisation des tiquettes temporelles Unix ..................................................... 462
Utilisation de la fonction getdate() ................................................................. 464
Validation de dates avec checkdate() .............................................................. 465
Formatage des tiquettes temporelles ............................................................ 465
Conversion entre des formats de date PHP et MySQL ............................................... 467
Calculs de dates avec PHP .......................................................................................... 469
Calculs de dates avec MySQL .................................................................................... 471
Utiliser des microsecondes ......................................................................................... 472
Utilisation des fonctions PHP de calendrier ............................................................... 473
Pour aller plus loin ...................................................................................................... 474
Pour la suite ................................................................................................................ 474

20 Gnration dimages via PHP ................................................................................. 475


Configuration du support des images dans PHP ......................................................... 476
Formats graphiques .................................................................................................... 477
JPEG ................................................................................................................ 477
PNG ................................................................................................................. 477
WBMP ............................................................................................................. 478
GIF .................................................................................................................. 478
Cration dimages ....................................................................................................... 478
Canevas de limage ........................................................................................ 479
Dessin ou impression de texte dans une image ............................................... 480
XVI PHP & MySQL

Production de limage finale ........................................................................... 482


Nettoyage final ................................................................................................ 483
Utilisation dimages produites automatiquement dans dautres pages ................... 483
Utilisation de texte et de polices pour crer des images ............................................. 484
Dfinition du canevas de base ......................................................................... 487
"Faire tenir" le texte sur le bouton ................................................................... 488
Positionnement du texte .................................................................................. 491
criture du texte sur le bouton ........................................................................ 492
Fin du traitement ............................................................................................. 492
Reprsentation graphique de donnes numriques ..................................................... 493
Autres fonctions de cration et de manipulation dimages ........................................ 501
Pour aller plus loin ...................................................................................................... 501
Pour la suite ................................................................................................................ 501

21 Utilisation du contrle de session en PHP ............................................................... 503


Quest-ce que le contrle de session ? ........................................................................ 503
Fonctionnalit de base dune session ......................................................................... 504
Quest-ce quun cookie ? ................................................................................ 504
Cration de cookies partir dun script PHP .................................................. 505
Utilisation des cookies avec des sessions ........................................................ 505
Stockage de lID de session ............................................................................ 506
Implmentation dun contrle de session simple ....................................................... 506
Dmarrage dune session ................................................................................ 506
Enregistrement des variables de session ......................................................... 507
Utilisation de variables de session .................................................................. 507
Suppression des variables et destruction de la session .................................... 508
Un exemple de session simple .................................................................................... 508
Configuration du contrle de session ......................................................................... 510
Authentification avec le contrle de session .............................................................. 512
Pour aller plus loin ...................................................................................................... 517
Pour la suite ................................................................................................................ 518

22 Autres fonctions et possibilits offertes par PHP .................................................... 519


valuation de chanes : eval() ..................................................................................... 519
Achvement de lexcution : die() et exit() ................................................................ 520
Srialisation de variables et dobjets ......................................................................... 521
Obtention dinformations sur lenvironnement PHP .................................................. 522
Liste des extensions charges .......................................................................... 522
Identification du propritaire dun script ......................................................... 523
Dtermination de la date de dernire modification dun script ....................... 523
Modification temporaire de lenvironnement dexcution ......................................... 523
Table des matires XVII

Colorisation du code source ....................................................................................... 524


Utiliser PHP en ligne de commande .......................................................................... 525
Pour la suite ................................................................................................................ 526

Partie V

Crer des projets avec PHP et MySQL

23 Utilisation de PHP et de MySQL dans des projets importants ............................. 529


Appliquer les rgles du gnie logiciel au dveloppement web .................................. 529
Planification et mise en uvre dun projet dapplication web ................................... 530
Rutilisation du code .................................................................................................. 531
crire du code facile maintenir ................................................................................ 532
Standards de programmation ........................................................................... 532
Dcomposer le code ........................................................................................ 536
Utiliser une structure standard pour vos rpertoires ........................................ 537
Documenter et partager les fonctions dveloppes en interne ........................ 537
Implmenter un contrle de versions .......................................................................... 537
Choisir un environnement de dveloppement ............................................................ 539
Documenter vos projets .............................................................................................. 539
Prototypage ................................................................................................................. 540
Sparation de la logique et du contenu ....................................................................... 541
Optimisation du code .................................................................................................. 542
Quelques optimisations simples ...................................................................... 542
Utilisation des produits de Zend ..................................................................... 543
Tests .......................................................................................................................... 543
Pour aller plus loin ...................................................................................................... 545
Pour la suite ................................................................................................................ 545

24 Dbogage .................................................................................................................... 547


Les erreurs de programmation .................................................................................... 547
Erreurs de syntaxe ........................................................................................... 547
Erreurs en cours dexcution ........................................................................... 549
Erreurs de logique ........................................................................................... 555
Aide au dbogage des variables .................................................................................. 557
Les niveaux derreur ................................................................................................... 559
Modifier les paramtres daffichage des erreurs ......................................................... 560
Dclencher vos propres erreurs .................................................................................. 562
Grer correctement les erreurs ................................................................................... 562
Pour la suite ................................................................................................................ 565
XVIII PHP & MySQL

25 Authentification des utilisateurs et personnalisation ............................................ 567


Composants de la solution .......................................................................................... 568
Identification des utilisateurs et personnalisation .......................................... 568
Enregistrer les liens vers les sites favoris ........................................................ 569
Sites suggrs .................................................................................................. 569
Rsum de la solution ................................................................................................. 570
Implmentation de la base de donnes ....................................................................... 572
Implmentation du site de base .................................................................................. 573
Implmentation de lauthentification des utilisateurs ................................................. 576
Enregistrement ................................................................................................ 576
Connexion ....................................................................................................... 583
Dconnexion ................................................................................................... 586
Modifier les mots de passe .............................................................................. 587
Rinitialiser les mots de passe oublis ............................................................ 589
Implmentation de lenregistrement et de la rcupration des favoris ............................. 594
Ajouter des liens .............................................................................................. 594
Afficher les favoris .......................................................................................... 597
Supprimer des favoris ...................................................................................... 598
Implmentation de la suggestion de sites ................................................................... 600
Pour aller plus loin ...................................................................................................... 604
Pour la suite ................................................................................................................ 604

26 Implmentation dun panier virtuel ........................................................................ 605


Les composants ......................................................................................................... 606
Implmenter un catalogue en ligne ................................................................. 606
Conserver une trace des achats effectus par lutilisateur ............................... 606
Implmenter un systme de paiement ............................................................. 607
Crer une interface dadministration ............................................................... 608
Prsentation de la solution .......................................................................................... 608
Implmentation de la base de donnes ....................................................................... 612
Implmentation du catalogue en ligne ........................................................................ 615
Liste des catgories ......................................................................................... 617
Liste des livres dune catgorie ....................................................................... 619
Afficher les informations relatives un livre .................................................. 621
Implmentation du panier virtuel ............................................................................... 622
Utiliser le script show_cart.php ..................................................................... 623
Afficher le panier virtuel ................................................................................. 626
Ajouter des articles dans le panier virtuel ....................................................... 628
Enregistrer le panier virtuel modifi ............................................................... 630
Afficher une barre den-tte de rsum ........................................................... 631
Rglement des achats ...................................................................................... 631
Implmentation du paiement ...................................................................................... 638
Implmentation dune interface dadministration ...................................................... 640
Table des matires XIX

Pour aller plus loin ...................................................................................................... 648


Utilisation dun systme existant ................................................................................ 649
Pour la suite ................................................................................................................ 649

27 Implmentation dun webmail ................................................................................. 651


Composants de la solution .......................................................................................... 651
Les protocoles de courrier POP3 et IMAP ...................................................... 652
Gestion de POP3 et IMAP en PHP ................................................................. 652
Rsum de la solution ................................................................................................. 654
Cration de la base de donnes ................................................................................... 656
Architecture du script ................................................................................................. 657
Connexion et dconnexion ......................................................................................... 663
Configuration de comptes de courrier ........................................................................ 666
Cration dun compte de courrier ................................................................... 668
Modifier un compte de courrier existant ......................................................... 670
Supprimer un compte de courrier .................................................................... 670
Lecture du courrier .................................................................................................... 671
Choisir un compte .......................................................................................... 671
Consulter le contenu dune bote aux lettres .................................................. 674
Lecture dun e-mail ......................................................................................... 676
Afficher les en-ttes dun message .................................................................. 680
Suppression des messages ............................................................................... 681
Envoyer du courrier .................................................................................................... 681
Envoyer un nouveau message ......................................................................... 682
Rpondre un message ou le faire suivre ....................................................... 683
Pour aller plus loin ...................................................................................................... 685
Pour la suite ................................................................................................................ 686

28 Implmentation dun gestionnaire de listes de diffusion ....................................... 687


Composants de la solution ......................................................................................... 687
Configuration de la base de donnes ............................................................... 688
Transfert des fichiers ....................................................................................... 689
Envoyer des e-mails incluant des pices jointes ............................................. 689
Prsentation de la solution .......................................................................................... 690
Configuration de la base de donnes .......................................................................... 692
Architecture du script ................................................................................................. 694
Implmentation de la connexion ............................................................................... 701
Cration dun nouveau compte ....................................................................... 702
Ouvrir une session ........................................................................................... 704
Implmentation des fonctions de lutilisateur ............................................................ 707
Consultation des listes ..................................................................................... 708
Affichage des informations dune liste ............................................................ 713
Affichage des archives dune liste ................................................................... 715
XX PHP & MySQL

Inscriptions et dsinscriptions ......................................................................... 716


Modification des paramtres dun compte ...................................................... 717
Changement des mots de passe ....................................................................... 718
Fermeture de session ....................................................................................... 720
Implmentation des fonctions administratives ........................................................... 720
Cration dune nouvelle liste .......................................................................... 721
Transfert vers le serveur dun nouveau bulletin .............................................. 723
Gestion du transfert de plusieurs fichiers ........................................................ 726
Prvisualisation du bulletin ............................................................................. 730
Envoi du bulletin ............................................................................................. 731
Pour aller plus loin ...................................................................................................... 736
Pour la suite ................................................................................................................ 737

29 Implmentation dun forum web ............................................................................. 739


Comprendre le processus ............................................................................................ 739
Composants de la solution .......................................................................................... 740
Prsentation de la solution .......................................................................................... 742
Conception de la base de donnes .............................................................................. 743
Afficher larborescence des articles ............................................................................ 746
Ouverture et fermeture des fils de discussion .................................................. 749
Affichage des articles ...................................................................................... 752
Utilisation de la classe treenode ...................................................................... 753
Afficher des articles particuliers ................................................................................. 759
Ajouter de nouveaux articles ...................................................................................... 761
Extensions ................................................................................................................... 768
Utiliser un systme existant ........................................................................................ 769
Pour la suite ................................................................................................................ 769

30 Production de documents personnaliss en PDF .................................................... 771


Prsentation du projet ................................................................................................. 771
valuation des formats de documents ........................................................................ 772
Papier ............................................................................................................... 772
Texte ASCII ..................................................................................................... 772
HTML ............................................................................................................. 773
Formats des traitements de texte ..................................................................... 773
Rich Text Format ............................................................................................. 774
PostScript ........................................................................................................ 775
Portable Document Format ............................................................................. 776
Les composants de la solution .................................................................................... 777
Systme dvaluation ...................................................................................... 777
Logiciel de gnration des documents ............................................................ 777
Prsentation de la solution .......................................................................................... 780
Poser les questions du QCM ........................................................................... 781
Table des matires XXI

valuation des rponses .................................................................................. 783


Production du certificat RTF ........................................................................... 786
Production dun certificat PDF partir dun modle ...................................... 789
Production dun document PDF avec PDFlib ................................................ 793
Un script "Bonjour tout le monde" pour PDFlib ............................................. 793
Production dun certificat avec PDFlib ........................................................... 798
Gestion des problmes avec les en-ttes ..................................................................... 805
Pour aller plus loin ...................................................................................................... 806
La suite ....................................................................................................................... 806

31 Connexion des services web avec XML et SOAP ................................................ 807


Prsentation du projet : manipuler XML et les services web .................................... 807
Introduction XML ........................................................................................ 808
Introduction aux services web ........................................................................ 811
Composants de la solution ......................................................................................... 813
Utilisation de linterface des services web dAmazon ................................... 813
Analyse XML : rponses REST ..................................................................... 814
Utilisation de SOAP avec PHP ....................................................................... 815
Mise en cache ................................................................................................. 815
Prsentation de la solution ......................................................................................... 815
Cur de lapplication ...................................................................................... 820
Affichage des livres dune catgorie ............................................................... 826
La classe AmazonResultSet ............................................................................ 828
Utilisation de REST pour effectuer une requte et rcuprer un rsultat ....... 836
Utilisation de SOAP pour effectuer une requte et rcuprer un rsultat ...... 842
Mise en cache des rponses une requte ..................................................... 844
Construction du panier virtuel ........................................................................ 846
Passer la commande auprs dAmazon ........................................................... 850
Installation du code du projet .................................................................................... 850
Extension du projet .................................................................................................... 851
Pour aller plus loin ..................................................................................................... 851

32 Construction dapplications web 2.0 avec Ajax ...................................................... 853


Introduction Ajax .................................................................................................... 854
Requtes et rponses HTTP ........................................................................... 854
DHTML et XHTML ....................................................................................... 856
CSS .................................................................................................................. 856
Programmation ct client ............................................................................. 858
Programmation ct serveur .......................................................................... 858
XML et XSLT ................................................................................................. 858
Prsentation dAjax ................................................................................................... 859
Lobjet XMLHTTPRequest .............................................................................. 859
Communication avec le serveur ...................................................................... 861
XXII PHP & MySQL

Utilisation de la rponse du serveur ............................................................... 863


Rassemblement des composants .................................................................... 865
Ajouter des lments Ajax des projets existants ..................................................... 868
Ajouter des lments Ajax PHPbookmark ................................................... 869
Pour aller plus loin ..................................................................................................... 882
En savoir plus sur le DOM (Document Object Model) ................................... 882
Bibliothques JavaScript pour les applications Ajax ..................................... 883
Sites consacrs au dveloppement Ajax ......................................................... 883

Partie VI

Annexes

Annexe A Installation de PHP et de MySQL ............................................................... 887


Installation dApache, PHP et MySQL sous Unix ..................................................... 888
Installation partir de binaires ........................................................................ 888
Installation partir des sources ....................................................................... 889
Installation de MySQL .................................................................................... 890
Installation de PHP .......................................................................................... 892
Modification du fichier httpd.conf ................................................................... 895
Test du fonctionnement de PHP ..................................................................... 896
Test du fonctionnement de SSL ...................................................................... 897
Installation dApache, de PHP et de MySQL sous Windows ..................................... 898
Installation de MySQL sous Windows ............................................................ 898
Installation dApache sous Windows .............................................................. 900
Installation de PHP sous Windows .................................................................. 902
Installation de PEAR .................................................................................................. 904
Autres configurations .................................................................................................. 905

Annexe B Ressources web .............................................................................................. 907


Ressources PHP .......................................................................................................... 907
Ressources MySQL et SQL ........................................................................................ 910
Ressources Apache ..................................................................................................... 910
Dveloppement web ................................................................................................... 910

Index .................................................................................................................................. 911


Introduction

Vous vous intressez au dveloppement web avec PHP et MySQL ? Ce livre est fait
pour vous ! Vous y trouverez nos expriences les plus utiles sur PHP et MySQL, deux
des plus passionnants outils de dveloppement web du moment.

Les points forts de ce livre


Ce livre vous expliquera comment crer des sites web interactifs, de leur expression la
plus simple des sites interactifs du Web 2.0 en passant par les sites de commerce lec-
tronique scuriss et complexes. Vous apprendrez galement vous servir des technologies
open-source.
Ce livre est destin aux lecteurs qui connaissent dj au minimum les bases du
langage HTML et ont lhabitude de programmer dans un langage de programmation
moderne, mais qui ne connaissent pas ncessairement la programmation sur Internet
ou les bases de donnes relationnelles. Si vous tes un programmeur dbutant, ce
livre devrait galement vous intresser, mais il vous faudra peut-tre un peu plus de
temps pour lassimiler. Nous avons essay de noublier aucun concept fondamental,
toutefois, certains dentre eux seront prsents assez rapidement. Ce livre est donc
principalement destin aux lecteurs qui souhaitent matriser PHP et MySQL pour
implmenter un site web commercial ou de qualit professionnelle. Si vous utilisez
dj un langage de dveloppement pour le Web, cet ouvrage devrait vous mettre rapi-
dement sur la bonne voie.
Nous avons crit la premire dition de ce livre lorsque nous nous sommes rendu
compte que tous les ouvrages existants consacrs PHP se limitaient une simple
numration de ses fonctions. Ces livres sont naturellement trs utiles, mais ils ne sont
daucune aide lorsque votre patron ou un client vous demande : "Implmentez-moi un
panier virtuel pour mon site de commerce lectronique." Nous avons fait de notre
mieux pour que tous nos exemples soient aussi utiles que possible. La plupart des
programmes peuvent tre utiliss directement sur votre site web ; les autres ne ncessi-
teront que quelques modifications mineures.
2 PHP & MySQL

Ce que vous apprendrez en lisant ce livre


Si vous avez dj implment des sites web en HTML pur, vous avez dj compris les
limites de cette approche : ils sont tout simplement trop statiques. Ils restent identiques
jusqu ce que vous les mettiez jour vous-mme. En outre, les utilisateurs ne peuvent
pas interagir avec ce type de site, en tout cas de manire intressante.
Lutilisation dun langage comme PHP et dune base de donnes comme MySQL
permet de rendre vos sites dynamiques : ils pourront alors tre personnaliss et mis
jour en temps rel.
Ds les premiers chapitres, nous nous sommes dlibrment concentrs sur des applications
relles et pratiques. Nous commencerons par tudier un systme simple de commande en
ligne, et nous continuerons avec les diffrentes parties de PHP et de MySQL.
Nous aborderons ensuite diffrents aspects du commerce lectronique et de la scurit,
puisquil sagit de deux composants importants des sites web, et nous montrerons
comment les implmenter avec PHP et MySQL.
Dans la dernire section de ce livre, nous verrons comment attaquer le dveloppement
de projets rels et passerons en revue la conception, la planification et limplmentation
des projets suivants :
m authentification des utilisateurs et personnalisation dun site ;
m paniers virtuels ;
m systmes de messagerie web ;
m gestionnaires de listes de diffusion ;
m forums web ;
m production de documents PDF ;
m services web avec XML et SOAP ;
m applications web 2.0 avec Ajax.
Tous ces projets sont utilisables tels quels ou peuvent tre modifis en fonction de vos
besoins. Nous les avons choisis parce que nous pensons quils sont reprsentatifs des
applications web auxquelles les programmeurs sont le plus souvent confronts. Si vos
besoins sont diffrents, ce livre devrait toutefois vous aider atteindre vos objectifs.

Prsentation de PHP
PHP est un langage de script ct serveur qui a t conu spcifiquement pour le Web.
Le code PHP est inclus dans une page HTML et sera excut chaque fois quun visiteur
Introduction 3

affichera la page. Le code PHP est interprt au niveau du serveur web et gnre du
code HTML ou toute autre donne affichable dans le navigateur de lutilisateur.
PHP a t conu en 1994 par Rasmus Lerdorf. Il a ensuite t adopt par dautres
personnes talentueuses et rcrit quatre fois avant de devenir le produit abouti que nous
connaissons aujourdhui. En novembre 2007, il tait install sur plus de 21 millions de
domaines et sa croissance est rapide. Vous trouverez des statistiques plus rcentes sur le
site http://www.php.net/usage.php.
PHP est un projet open-source, ce qui signifie que vous pouvez vous procurer son code,
lutiliser, le modifier et le redistribuer gratuitement.
PHP signifiait lorigine Personal Home Page, mais ce nom a t chang en un acro-
nyme rcursif comme GNU (Gnus Not Unix) : il signifie maintenant PHP Hypertext
Preprocessor.
La dernire version principale de PHP est la version 5. Elle bnficie dune rcriture
complte du moteur Zend et de quelques amliorations importantes au niveau du
langage.
La page daccueil de PHP est accessible ladresse http://www.php.net.
La page de Zend Technologies, lentreprise des fondateurs de PHP, se trouve ladresse
http://www.zend.com.

Prsentation de MySQL
MySQL est un systme de gestion de bases de donnes relationnelles (SGBDR) robuste
et rapide. Une base de donnes permet de manipuler les informations de manire effi-
cace, de les enregistrer, de les trier, de les lire et dy effectuer des recherches. Le serveur
MySQL contrle laccs aux donnes pour sassurer que plusieurs utilisateurs peuvent
se servir simultanment dune mme base de donnes pour y accder rapidement et
pour garantir que seuls les utilisateurs autoriss peuvent accder aux donnes. MySQL
est donc un serveur multi-utilisateur et multithread. Il utilise SQL (Structured Query
Language), le langage standard des requtes de bases de donnes. MySQL est disponi-
ble depuis 1996, mais son dveloppement remonte 1979. Il sagit de la base de
donnes open-source la plus employe au monde et elle a reu le Linux Journal
Readers Choice Award plusieurs reprises.
MySQL est dsormais disponible sous une double licence. Vous pouvez lutiliser
gratuitement sous licence open-source (GPL) condition de respecter les termes de
cette licence. Si vous souhaitez distribuer une application non GPL incluant MySQL,
vous pouvez aussi acheter une licence commerciale.
4 PHP & MySQL

Pourquoi utiliser PHP et MySQL ?


Lors de limplmentation dun site web, vous avez le choix entre de nombreux produits.

Vous devez notamment choisir :

m la plate-forme matrielle du serveur web ;

m un systme dexploitation ;

m un logiciel de serveur web ;

m un systme de gestion de base de donnes ;

m un langage de programmation ou de script.

Certains de ces choix dpendent directement des autres. Tous les systmes dexploitation
ne fonctionnent pas sur toutes les plates-formes ; par exemple, tous les serveurs web ne
reconnaissent pas tous les langages de programmation, etc.

Dans ce livre, nous ne nous intresserons pas particulirement au matriel, votre


systme dexploitation ou votre logiciel de serveur web. Nous nen avons pas besoin
car lune des caractristiques intressantes de PHP et de MySQL tient ce quils fonc-
tionnent avec tous les systmes dexploitation les plus connus et avec la plupart des
autres.

Un script PHP peut, dans la plupart des cas, tre crit de faon tre portable entre les
systmes dexploitation et les serveurs web. Certaines fonctions sont directement lies
aux spcificits dun systme de fichiers particulier, mais elles sont clairement identifies
comme telles dans le manuel de rfrence et dans ce livre.

Quels que soient votre plate-forme, votre systme dexploitation ou votre serveur web,
nous pensons que PHP et MySQL sont des options trs intressantes.

Quelques avantages de PHP


Les principaux concurrents de PHP sont Perl, ASP.NET de Microsoft, Ruby (avec ou
sans Rails), Java Server Pages (JSP) et ColdFusion.
Par rapport tous ces produits, PHP possde plusieurs avantages significatifs :
m les performances ;
m ladaptabilit ;
m des interfaces vers diffrents systmes de bases de donnes ;
Introduction 5

m des bibliothques intgres pour la plupart des tches web ;


m un faible cot ;
m la simplicit dutilisation et dapprentissage ;
m un bon support orient objet ;
m la portabilit ;
m la souplesse dans le processus de dveloppement ;
m la disponibilit de son code source ;
m la disponibilit du support et de la documentation.

Performances
PHP est trs rapide. Avec un seul serveur dentre de gamme, vous pouvez servir des
millions de requtes par jour. Les tests de performances publis par Zend Technologies
(http://www.zend.com) montrent que PHP dpasse tous ses concurrents.

Adaptabilit
PHP utilise ce que Rasmus Lerdorf dsigne souvent comme une architecture "sans
partage". Cela signifie que vous pouvez implmenter de faon efficace et peu de frais
une ferme de serveurs en ajoutant des machines en fonction de vos besoins.

Intgration avec les bases de donnes


PHP dispose de connexions natives vers la plupart des systmes de bases de donnes.
Outre MySQL, vous pouvez vous connecter directement aux bases de donnes
PostgreSQL, Oracle, dbm, FilePro, DB2, Informix, InterBase et Sybase, pour ne citer
quelles. PHP 5 possde galement une interface SQL intgre, SQLite, pour grer les
fichiers plats.
En fait, grce au standard ODBC (Open Database Connectivity), vous pouvez vous
connecter nimporte quelle base de donnes possdant un pilote ODBC, ce qui est le
cas des produits Microsoft, notamment.
Outre ces bibliothques natives, PHP dispose dune couche dabstraction pour laccs
aux bases de donnes : PDO (PHP Database Objects) autorise ainsi une certaine coh-
rence et facilite la prise en compte de la scurit lors de laccs aux bases.

Bibliothques intgres
PHP ayant t conu pour tre utilis sur le Web, il possde de nombreuses fonc-
tions intgres permettant deffectuer la plupart des tches de programmation web.
6 PHP & MySQL

Vous pouvez ainsi gnrer des images en temps rel, vous connecter des services
web et dautres services rseaux, analyser des documents XML, envoyer du courrier
lectronique, manipuler les cookies et produire des documents PDF avec seulement
quelques lignes de code.

Cot
PHP est gratuit. Vous pouvez vous procurer la dernire version du langage sur le site
http://www.php.net, sans payer quoi que ce soit.

Facilit dapprentissage de PHP


La syntaxe de PHP repose sur celle dautres langages de programmation, essentiel-
lement C et Perl. Si vous savez dj programmer en C, en Perl ou en un autre
langage analogue, comme C++ ou Java, lapprentissage de PHP sera quasiment
immdiat.

Support orient objet


PHP 5 possde des fonctionnalits orientes objet bien conues. Si vous avez appris
programmer en Java ou en C++, vous disposerez en PHP des fonctionnalits (et, gn-
ralement, de la syntaxe) dont vous avez lhabitude : lhritage, les attributs et les mtho-
des privs et protgs, les classes et les mthodes abstraites, les interfaces, les
constructeurs et les destructeurs, notamment. Vous dcouvrirez galement des mcanis-
mes moins courants, comme les itrateurs. Certaines de ces fonctionnalits taient
disponibles dans PHP 3 et 4, mais le support orient objet de la version 5 est bien plus
complet.

Portabilit
PHP est disponible sur de nombreux systmes dexploitation. Vous pouvez crire votre
code PHP pour des systmes dexploitation Unix libres et gratuits, comme Linux ou
FreeBSD, pour des versions commerciales dUnix comme Solaris, IRIX, OS-X ou pour
les diffrentes versions de Windows.
Un code PHP bien crit pourra donc gnralement tre utilis sans modification sur un
autre systme.

Souplesse dans le processus de dveloppement


PHP permet dimplmenter simplement les traitements simples, mais vous pouvez tout
aussi facilement implmenter de grosses applications laide dun framework reposant
sur les patrons de conception, comme Modle-Vue-Contrleur (MVC).
Introduction 7

Code source
Le code source de PHP est disponible gratuitement. Contrairement aux produits
commerciaux, dont les sources ne sont pas distribus, vous avez donc la possibilit de
modifier le langage ou dy ajouter de nouvelles caractristiques.
Vous navez par consquent plus besoin dattendre que les concepteurs distribuent des
correctifs logiciels et navez plus craindre la disparition de la socit ou larrt du
support du produit que vous utilisez.

Disponibilit du support et de la documentation


Zend Technologies (www.zend.com), lentreprise qui est lorigine du moteur de PHP,
finance son dveloppement en offrant des services de support et des logiciels lis sous
forme commerciale.
La documentation et la communaut PHP fournissent un grand nombre de ressources et
dinformations compltes sur le langage.

Nouveauts de PHP 5
Il se peut que vous soyez rcemment pass de lune des versions PHP 4.x PHP 5.
Comme on est en droit de lattendre dans une nouvelle version majeure, dimportantes
modifications ont vu le jour et le moteur Zend de PHP a t rcrit pour cette version.
Voici les principales nouvelles fonctionnalits :
m un meilleur support orient objet construit autour dun modle objet entirement
nouveau (voir Chapitre 6) ;
m la gestion des exceptions pour un traitement volutif des erreurs, facilitant la main-
tenance (voir Chapitre 7) ;
m SimpleXML pour une gestion simplifie des donnes XML (voir Chapitre 31).
Parmi les autres modifications, notons encore le dplacement de certaines extensions de
linstallation PHP par dfaut dans la bibliothque PECL, lamlioration de la gestion
des flux et lajout de SQLite.
Au moment o nous crivons ce livre, la version courante de PHP est la 5.2 et la
version 5.3 se profile lhorizon. PHP 5.2 ajoute un certain nombre de fonctionnalits
intressantes :
m une nouvelle extension pour filtrer les entres, afin damliorer la scurit ;
m lextension JSON pour amliorer linteroprabilit avec JavaScript ;
m le suivi de la progression des dpts de fichiers ;
8 PHP & MySQL

m une meilleure gestion des dates et des heures ;


m de nombreuses bibliothques clientes amliores et des performances encore
accrues (le moteur Zend utilise une meilleure gestion de la mmoire) ;
m de nombreux bogues corrigs.

Quelques avantages de MySQL


Les principaux concurrents de MySQL sont PostgreSQL, Microsoft SQL Server et Oracle.
MySQL possde sur eux plusieurs avantages :
m des performances leves ;
m un cot rduit ;
m une simplicit de configuration et dapprentissage ;
m sa portabilit ;
m laccessibilit de son code source ;
m la disponibilit du support.

Performances
MySQL est indniablement un systme rapide. Vous pouvez consulter les statistiques
de ses performances sur le site http://web.mysql.com/why-mysql/benchmark.html.
La plupart des tests montrent que MySQL est bien plus rapide que ses concurrents, de
plusieurs ordres de grandeur. En 2002, eWeek a publi un banc dessais qui comparait
cinq bases de donnes alimentant une application web. Le meilleur rsultat a plac ex
quo MySQL et Oracle, qui est pourtant un produit bien plus cher.

Cot rduit
MySQL est disponible gratuitement sous une licence open-source ou, pour un prix trs
raisonnable, sous licence commerciale. Vous devez vous procurer une licence si vous
souhaitez redistribuer MySQL dans une application et que vous ne souhaitiez pas que
lapplication se trouve sous licence open-source. Si vous ne comptez pas distribuer
votre application (ce qui est gnralement le cas de la plupart des applications web) ou
si vous travaillez sur un logiciel open-source, il nest pas ncessaire dacheter une
licence.

Simplicit demploi
La plupart des bases de donnes modernes utilisent SQL. Si vous connaissez dj
dautres SGBDR, vous ne devriez pas avoir de problme pour vous adapter. En outre,
Introduction 9

MySQL est plus simple installer que la plupart des produits similaires. La courbe
dapprentissage ncessaire lacquisition des comptences dun administrateur de base
de donnes (DBA, ou DataBase Administrator) est bien plus courte que celle des autres
bases de donnes.

Portabilit
MySQL peut tre utilis sur un grand nombre de systmes Unix, ainsi quavec
Windows.

Code source
Comme pour PHP, vous pouvez vous procurer le code source de MySQL. Pour la
plupart des utilisateurs, ce point nest pas important, mais il doit vous tranquilliser
lesprit en vous assurant une continuit future et en vous offrant des possibilits en cas
durgence.

Disponibilit du support
Tous les produits open-source nont pas une entreprise parente qui propose des services
de support, de formations, de consultation et de certification : vous pouvez obtenir tout
cela de la part de MySQL AB (www.mysql.com).

Nouveauts de MySQL 5
Parmi les modifications majeures introduites par MySQL 5, nous citerons les suivantes :
m les vues ;
m les procdures stockes (voir Chapitre 13) ;
m un support minimal des triggers ;
m le support des curseurs.
On peut galement noter une meilleure compatibilit avec le standard ANSI et des
amliorations en matire de vitesse.
Si vous utilisez toujours une ancienne version 4.x ou 3.x du serveur MySQL, vous
devez savoir que les fonctionnalits suivantes ont t ajoutes aux diffrentes versions
depuis la version 4.0 :
m support des sous-requtes ;
m types GIS pour stocker les donnes gographiques ;
m support amlior pour linternationalisation ;
10 PHP & MySQL

m moteur de stockage transactionnel InnoDB inclus en standard ;


m cache de requtes MySQL pour amliorer fortement la vitesse des requtes rptitives
souvent produites par les applications web.
Ce livre utilise MySQL 5.1 (Beta Community Edition), qui ajoute les fonctionnalits
suivantes :
m partitionnement ;
m rplication par lignes ;
m programmation des vnements ;
m tables de log ;
m amliorations de MySQL Cluster, du schma dinformations, des processus de
sauvegarde ;
m nombreuses corrections de bogues.

Organisation de ce livre
Ce livre est dcoup en cinq parties.
La premire partie prsente les diffrents lments du langage PHP, ainsi que quelques
exemples. Tous ces exemples sont pratiques, issus de notre exprience dans limpl-
mentation dun site de commerce lectronique, et non thoriques. La prsentation de
PHP dbute avec le Chapitre 1 : si vous connaissez dj le langage, vous pouvez passer
directement au chapitre suivant. Si vous dbutez en PHP ou en programmation, en
revanche, il peut tre intressant de vous y arrter un peu plus longuement. Si vous
connaissez dj PHP 4, consultez quand mme le Chapitre 6 car les fonctionnalits
orientes objet ont sensiblement chang.
La deuxime partie aborde les concepts ncessaires lutilisation des systmes de bases
de donnes relationnelles, comme MySQL, lutilisation de SQL, linterconnexion de
votre base de donnes MySQL avec le monde extrieur, en passant par PHP et certains
concepts avancs de MySQL, comme la scurit et les optimisations.
La troisime partie est consacre aux problmes gnraux qui peuvent survenir lors du
dveloppement dun site web dans nimporte quel langage. Les problmes les plus
importants concernent la scurit. Nous verrons ensuite comment vous pouvez tirer
profit de PHP et de MySQL pour authentifier vos utilisateurs et collecter, transmettre et
enregistrer vos donnes en toute scurit.
La quatrime partie sintresse plus prcisment aux principales fonctions intgres dans
PHP. Nous avons slectionn des groupes de fonctions qui vous intresseront srement
Introduction 11

lorsque vous implmenterez un site web. Vous y apprendrez notamment ce quest linte-
raction avec le serveur, linteraction avec le rseau, la gnration dimages, les manipu-
lations de date et dheure et les variables de sessions.
La cinquime et dernire partie est notre prfre : nous y tudierons quelques probl-
mes rels, comme la gestion et le suivi de projets importants, ainsi que le dbogage des
applications. Nous prsenterons galement quelques projets mettant en vidence la
puissance et la flexibilit de PHP et de MySQL.

Encore un mot
Nous esprons que ce livre vous satisfera et que vous serez aussi passionn par
lapprentissage de PHP et de MySQL que nous lavons t lorsque nous avons
commenc nous servir de ces logiciels. Leur utilisation est un plaisir part entire.
Vous serez bientt mme de rejoindre les milliers de dveloppeurs web qui se servent
de ces outils puissants et robustes pour construire des sites web dynamiques.
I
Utilisation de PHP

1 PHP : les bases


2 Stockage et rcupration des donnes
3 Utilisation de tableaux
4 Manipulation de chanes et dexpressions rgulires
5 Rutilisation de code et criture de fonction
6 PHP orient objet
7 Gestion des exceptions
1
PHP : les bases

Ce chapitre expose succinctement la syntaxe et les constructions du langage PHP. Les


programmeurs PHP y trouveront peut-tre loccasion de complter leurs connaissances sur
le sujet. Ltude de ce chapitre sera plus facile et plus rapide pour ceux qui possdent des
notions de base sur dautres langages de programmation, comme C, Perl ou ASP.
Dans cet ouvrage, lapprentissage qui vous est propos repose sur de nombreux exem-
ples du monde rel, tirs de lexprience des auteurs en matire de conception de sites
web. Les manuels de programmation exposent souvent la syntaxe de base en
sappuyant sur des exemples simples mais notre parti pris est diffrent. Nous pensons
quil est prfrable dapprendre un langage de programmation en ralisant des projets
oprationnels, plutt quassimiler un recueil de fonctions et un expos de la syntaxe qui
napportent gure plus que le manuel en ligne.
En consquence, nous vous proposons de vous faire la main sur les exemples donns
ici ; vous pouvez les saisir ou les charger partir du site Pearson (www.pearson.fr),
les modifier, en isoler des extraits et apprendre les adapter vos besoins.
Dans ce chapitre, vous verrez comment utiliser les variables, les oprateurs et les
expressions en construisant un formulaire de commande en ligne. Nous tudierons
galement les types de variables et les priorits des oprateurs. Vous apprendrez ensuite
accder aux variables des formulaires et manipuler celles-ci afin de calculer le
montant total et les taxes dans un bon de commande mis par un client.
Nous poursuivrons le dveloppement de cet exemple en insrant dans notre script PHP
le code ncessaire un contrle de la validit des donnes entres par lutilisateur.
cette occasion, nous prsenterons le concept de valeurs boolennes, ainsi que plusieurs
exemples dutilisation des instructions if, else et switch et de loprateur ?:.
Enfin, nous aborderons les boucles en crivant du code PHP gnrant une structure de
tableau HTML de faon rptitive.
16 Partie I Utilisation de PHP

Utilisation de PHP
La ralisation et lexcution des exemples prsents dans cet ouvrage ncessitent davoir
accs un serveur web sur lequel PHP est install. Pour tirer le meilleur parti des exemples
et des cas dcole traits ici, il est conseill de les excuter et dessayer de les modifier.
Pour cela, vous avez besoin dune installation de test o vous puissiez exprimenter loisir.
Si PHP nest pas install sur votre ordinateur, vous devez commencer par procder
son installation ou contacter votre administrateur systme pour quil sen charge. Vous
trouverez lAnnexe A, "Installation de PHP et de MySQL", une description de la
procdure dinstallation.

Formulaires HTML
Le traitement des formulaires HTML constitue une des applications les plus courantes
que doivent prendre en charge les langages de script excuts ct serveur. Cest pour-
quoi nous allons commencer lapprentissage de PHP par limplmentation dun formu-
laire de commande pour une entreprise fictive de vente de pices dtaches dnomme
Le garage de Bob. Vous trouverez tout le code relatif cette application modle dans le
rpertoire chapitre01 sur le site Pearson.

Code du formulaire
Nous allons partir du stade o le programmeur de lentreprise a tabli un formulaire
permettant aux clients de passer des commandes (voir Figure 1.1). Il sagit dun formu-
laire simple, comparable aux nombreux autres publis sur le Web.

Figure 1.1
Le formulaire initial
de Bob nenregistre
que les articles
et leurs quantits
respectives.

partir de ce formulaire, Bob veut en premier lieu rcuprer la liste des articles
commands par son client, tablir le montant total de la commande, ainsi que le
montant des taxes payer sur cette commande.
Chapitre 1 PHP : les bases 17

Une partie du code HTML gnrant ce formulaire est prsente dans le Listing 1.1.

Listing 1.1 : orderform.html Code HTML gnrant le formulaire basique


de commande de Bob

<form action="processorder.php" method=post>


<table border=0>
<tr bgcolor=#cccccc>
<td width=150>Articles</td>
<td width=15>Quantit</td>
</tr>
<tr>
<td>Pneus</td>
<td align="center"><input type="text" name="qte_pneus"
size="3" maxlength="3"></td>
</tr>
<tr>
<td>Huiles</td>
<td align="center"><input type="text" name="qte_huiles"
size="3" maxlength="3"></td>
</tr>
<tr>
<td>Bougies</td>
<td align="center"><input type="text" name="qte_bougies"
size="3" maxlength="3"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Passer commande">
</td>
</tr>
</table>
</form>

Tout dabord, notez que lattribut action de la balise form de ce formulaire a pour
valeur le nom du script PHP qui va traiter la commande du client (et que nous crirons un
peu plus loin). En gnral, la valeur affecte lattribut action est lURL charger lorsque
lutilisateur appuie sur le bouton submit. Les donnes saisies par lutilisateur dans le
formulaire sont alors transmises cette URL, via la mthode spcifie dans lattribut
method, cest--dire soit get (dans ce cas, les donnes sont spcifies la fin de lURL),
soit post (dans ce cas, les donnes sont transmises sous forme dun paquet spar).
Notez galement les noms des champs du formulaire (qte pneus, qte huiles et
qte bougies) : comme nous les utiliserons dans notre script PHP, il est important de
choisir des noms explicites facilement mmorisables. Certains diteurs HTML gnrent
par dfaut des noms de champs tels que field23 mais il est difficile de sen souvenir
lorsque lon crit ensuite le script. Pour faciliter votre travail de programmeur PHP,
nous vous conseillons dadopter des noms qui refltent la nature des donnes entres
dans les champs.
18 Partie I Utilisation de PHP

Vous devriez mme adopter une convention pour dnommer les noms des champs lors
de la cration dun site web ; de cette faon, les noms des champs se conformeront au
mme format sur lensemble du site. Une telle convention peut, par exemple, stipuler
que les noms de champ sont obtenus en abrgeant les mots et en remplaant les espaces
par des blancs souligns.

Traitement du formulaire
Pour traiter le formulaire, nous devons crer le script processorder.php auquel renvoie
la valeur de lattribut action de la balise form. Dans votre diteur de texte, tapez le code
suivant et sauvegardez-le sous ce nom :
<html>
<head>
<title>Le garage de Bob Rsultats de la commande</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Rsultats de la commande</h2>
</body>
</html>

Vous remarquerez que ces lignes ne sont que du code HTML. Nous allons prsent leur
ajouter du code PHP.

Incorporation de code PHP dans du code HTML


Sous la balise de titre <h2>, saisissez les lignes suivantes :
<?
echo <p>Commande traite.;
?>

Enregistrez votre fichier, puis chargez-le dans votre navigateur web en remplissant le
formulaire de Bob et en cliquant sur le bouton Passer commande. La Figure 1.2 montre
le rsultat que vous devez alors obtenir.

Figure 1.2
Le texte pass une
instruction echo de
PHP est affich dans
le navigateur web.
Chapitre 1 PHP : les bases 19

Notez comment le code PHP a t incorpor dans un fichier HTML "normal". Affichez
la source de la page dans votre navigateur. Voici le code que vous devriez voir :
<html>
<head>
<title>Le garage de Bob - Rsultats de la commande</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Rsultats de la commande</h2>
<p>Commande traite.
</body>
</html>

Le code PHP brut nest pas affich tel quel dans le navigateur. En effet, linterprteur
PHP analyse le script et le remplace par le rsultat de son excution. partir dun
script PHP, nous pouvons ainsi produire du code HTML directement affichable dans un
navigateur, sans que le navigateur comprenne le langage PHP.
Cet exemple illustre le concept de programmation web ct serveur : le code PHP est
interprt et excut sur le serveur web, contrairement au code JavaScript et aux autres
technologies ct client, qui sont interprtes et excutes par le navigateur, sur lordi-
nateur de lutilisateur.
Le code contenu dans le fichier considr ici se compose de quatre lments :
m du HTML ;
m des balises PHP ;
m des instructions PHP ;
m des espaces.
Nous pouvons galement y ajouter des commentaires.
La plupart des lignes de cet exemple sont simplement du code HTML.

Balises PHP
Dans lexemple prcdent, le code PHP commence par les caractres <? et se
termine par les caractres ?>. Cette syntaxe est comparable la syntaxe des balises
du HTML, qui commencent elles aussi par le caractre < (infrieur ) et se terminent
par le caractre > (suprieur ). Ces symboles sont appels balises PHP et indiquent
au serveur web o commence et o finit le code PHP. Tout texte plac entre ces bali-
ses est interprt comme du code PHP et tout texte situ en dehors est trait comme
du code HTML normal. Les balises PHP permettent ainsi de "schapper" du
contexte HTML.
Il existe diffrents types de balises. Examinons-les plus en dtail.
20 Partie I Utilisation de PHP

Styles des balises PHP


Il existe actuellement quatre styles diffrents de balises PHP. Les diffrents fragments
de code qui suivent sont quivalents.
m Style XML :
<?php echo "<p>Commande traite.";?>

Il sagit du style de balise qui sera employ dans ce livre. Ce style est le style de rf-
rence utiliser avec PHP 3 et PHP 4 car ladministrateur du serveur ne peut pas le
dsactiver, ce qui vous garantit sa disponibilit sur tous les serveurs et qui est particu-
lirement important si vous crivez des applications qui peuvent tre utilises sur
diffrentes installations. Ce style de balise est compatible avec des documents XML
(eXtensible Markup Language). Nous vous conseillons dutiliser ce style de balise.
m Style abrg :
<? echo "<p>Commande traite.";?>

Ce style de balise est le plus simple ; il respecte le style des instructions de traite-
ment SGML (Standard Generalized Markup Language). Pour utiliser ce type de
balise, qui est le plus rapide saisir au clavier, vous devez autoriser loption
open tag dans votre fichier de configuration ou compiler PHP en activant les bali-
ses abrges. Vous trouverez plus dinformations concernant ce style de balise dans
lAnnexe A. Nous vous dconseillons de lutiliser car il ne fonctionnera pas dans de
nombreux environnements puisquil nest plus activ par dfaut.
m Style SCRIPT :
<SCRIPT LANGUAGE=php> echo "<p>Commande traite."; </SCRIPT>

Ce style de balise est le plus long et le plus familier pour les utilisateurs de Java-
Script ou de VBScript. Vous pouvez ladopter si votre diteur HTML pose problme
avec les autres styles de balise.
m Style ASP :
<% echo "<p>Commande traite.";%>

Ce style de balise est analogue au style utilis dans les pages ASP (Active Server Pages)
ou ASP.NET. Pour lemployer, vous devez activer le paramtre de configuration
asp tags. Vous navez aucune raison dutiliser ce style, sauf si votre diteur de texte est
orient ASP ou ASP.NET. Notez que, par dfaut, ce style de balise est dsactiv.

Instructions de PHP
Pour informer linterprteur PHP des actions entreprendre, il faut insrer des instruc-
tions entre les balises PHP douverture et de fermeture.
Chapitre 1 PHP : les bases 21

Dans lexemple considr ici, nous nutilisons quun seul type dinstruction :
echo "<p>Commande traite.";

Vous lavez dj probablement devin, lemploi de la construction echo se traduit par


un rsultat trs simple : laffichage dans la fentre du navigateur de la chane qui lui est
passe en paramtre. Notez le point-virgule plac la fin de linstruction echo. Le
point-virgule semploie pour sparer les instructions PHP les unes des autres, tout
comme le point semploie pour sparer des phrases en franais. Si vous avez dj
programm en C ou en Java, cette syntaxe ne vous est pas trangre.
Loubli dun point-virgule en fin dinstruction est une erreur de syntaxe trs rpandue.
Cette erreur est toutefois facile dtecter et corriger.

Espaces
Les caractres despacement, tels que les nouvelles lignes (retour chariot), les espaces
et les tabulations, constituent ce que lon appelle des espaces. Vous le savez probable-
ment dj, les navigateurs ignorent les espaces dans le code HTML. Il en va de mme
avec le moteur PHP.
Soit les deux fragments HTML suivants :
<h1>Bienvenue dans le garage de Bob!</h1><p>Que voulez-vous commander aujourdhui?

et
<h1>Bienvenue dans le garage
de Bob!</h1>
<p>Que voulez-vous commander
aujourdhui?

Lexcution de ces deux fragments donne le mme rsultat laffichage parce quils
apparaissent comme identiques pour le navigateur web. Vous pouvez toutefois utiliser
des espaces dans votre code HTML et vous tes mme fortement encourag le faire
avec soin pour amliorer la lisibilit de votre code. Il en va de mme en PHP. Rien ne
vous oblige insrer des espaces entre des instructions PHP, mais vous obtiendrez des
programmes PHP beaucoup plus lisibles si vous placez vos instructions sur des lignes
spares. Par exemple :
echo bonjour;
echo tous;

et
echo bonjour ;echo tous;

sont quivalentes, mais la premire version est bien plus lisible.


22 Partie I Utilisation de PHP

Commentaires
Les commentaires placs dans les programmes sont en quelque sorte des indications
crites lintention des personnes qui lisent le code. Vous pouvez insrer des commen-
taires pour expliquer les actions du script, indiquer lauteur du script, expliquer pour-
quoi limplmentation a t effectue de telle manire, donner la date de dernire
modification et ainsi de suite. En gnral, tous les scripts PHP contiennent des
commentaires, lexception peut-tre des plus simples.
Linterprteur PHP ignore tout le texte plac dans un commentaire. Plus prcisment,
lanalyseur PHP saute les commentaires, comme sil sagissait despaces.
Le langage PHP supporte les commentaires de style C, C++ et shell.
Voici un commentaire de plusieurs lignes crit dans le style C et qui pourrait figurer au
dbut dun script PHP :
/* Auteur: Bob Smith
Date de dernire modification: 10 avril
Ce script traite les commandes client.
*/
Les commentaires sur plusieurs lignes doivent tre encadrs par les paires de caractres
/* et */. Tout comme en C, il est interdit dimbriquer des commentaires multiligne.
Vous pouvez galement insrer des commentaires dune seule ligne, soit dans le style
C++ :
echo <p>Commande traite.; // Dbut de laffichage
soit dans le style des scripts shell :
echo <p>Commande traite.; # Dbut de laffichage
Avec ces deux derniers styles, tout le texte plac aprs le symbole de commentaire ( # ou
//) est considr comme du commentaire tant que la fin de la ligne ou la balise PHP de
clture na pas t atteinte.
Dans la ligne de code suivante, le texte avant la balise fermante, voici un commen
taire, fait partie dun commentaire. Le texte aprs la balise fermante, pas ici, est
trait comme du HTML parce quil se trouve aprs la balise fermante :
// voici un commentaire?> pas ici

Ajout de contenu dynamique


Jusquici, tout ce que nous avons cod en PHP aurait tout aussi bien pu tre cod en
HTML, avec le mme rsultat.
Le principal intrt dun langage de script ct serveur rside dans la cration de
contenu dynamique. Il sagit l dun atout important, parce quun contenu se modifiant
Chapitre 1 PHP : les bases 23

pour sadapter aux besoins de chaque utilisateur, ou en fonction du temps, incite les
internautes revenir sur votre site. Le langage PHP permet facilement de mettre en
uvre un tel effet dynamique.
Commenons par un exemple simple. Remplacez le code PHP prcdemment insr
dans le fichier processorder.php par le code suivant :
<?php
echo <p>Commmande traite ;
echo date(H:i, \l\e j-m-Y);
echo </p>;
?>
Dans ce fragment, nous nous servons de la fonction date() prdfinie du langage PHP
pour indiquer au client la date et lheure du traitement de sa commande. Laffichage qui
en rsulte sera diffrent chaque nouvelle excution du script. La Figure 1.3 montre un
exemple de laffichage gnr par lexcution du script.

Figure 1.3
La fonction PHP date()
renvoie une chane
de date mise en forme.

Appel de fonctions
Examinez lappel de la fonction date() dans le fragment de code considr ici. Lappel
a t ralis avec la syntaxe standard. Le langage PHP comprend une riche bibliothque
de fonctions pour le dveloppement dapplications web et la plupart de ces fonctions
requirent que des donnes leur soient passes pour renvoyer un rsultat.
Soit lappel de fonction suivant :
date(H:i, \l\e j-m-Y)
Notez quune chane (des donnes textuelles) est passe la fonction dans une paire de
parenthses. Llment entre les parenthses est appel le paramtre, ou argument de la
fonction. Ces arguments constituent les entres utilises par la fonction pour gnrer le
rsultat spcifique attendu.
24 Partie I Utilisation de PHP

Fonction date()
La fonction date() attend que le paramtre qui lui est pass soit une chane de format,
spcifiant le style voulu pour la sortie. Chacune des lettres de la chane reprsente une
partie de la date et de lheure. H est lheure dans un format sur 24 heures avec des zros
den-tte si ncessaire, i reprsente les minutes avec un zro den-tte si ncessaire,
j reprsente le jour du mois sans zro den-tte, m reprsente le numro du mois et
J reprsente lanne, sous un format quatre chiffres. Les caractres prcds dun
antislash reprsentent du texte littral (vous trouverez la liste complte des formats pris
en charge par la fonction date() au Chapitre 19).

Accs aux variables des formulaires


Le principal objectif dun formulaire de commande est la collecte des informations
relatives aux commandes des clients. Rcuprer les donnes saisies par le client dans un
tel formulaire se rvle trs facile avec PHP mais la mthode employe dpend de la
version que vous utilisez et dun paramtrage dans votre fichier php.ini.

Variables des formulaires


Dans votre script PHP, vous pouvez accder chacun des champs dun formulaire par le
biais de variables dont les noms font rfrence au nom du champ de formulaire associ.
Dans le langage PHP, les noms de variables sont reconnaissables du fait de la prsence du
prfixe dollar ($). Loubli du signe dollar constitue une erreur de programmation courante.
En fonction de votre version et de votre installation PHP, vous disposez de trois manires
pour accder aux donnes dun formulaire via des variables. Ces mthodes ne portent
pas de noms officiels, cest pourquoi nous les avons appeles les styles "abrg",
"mdium" et "long". Dans tous les cas, il est possible daccder dans le script chacun
des champs de formulaire soumis au script.
Vous pouvez accder au contenu du champ qte pneus des manires suivantes :
$qte_pneus // style abrg
$_POST[qte_pneus] // style mdium
$HTTP_POST_VARS[qte_pneus] // style long

Dans cet exemple, ainsi que dans tout le reste de cet ouvrage, nous avons adopt le
style mdium de rfrencement des variables de formulaire (autrement dit,
$ POST[qte pneus]), mais nous crons des versions abrges des variables pour des
raisons de commodit (cette approche est recommande depuis PHP 4.2.0).
Pour vos programmes personnels, vous pouvez choisir une approche diffrente mais
vous devez tre conscient des enjeux ; cest pourquoi nous prsentons ds maintenant
les diffrentes mthodes.
Chapitre 1 PHP : les bases 25

En bref :
m Si le style abrg ($qte pneus) est pratique, il exige que le paramtre de configuration
register globals soit activ. Son activation ou sa dsactivation par dfaut dpend de
la version de PHP. Dans toutes les versions depuis 4.2.0, il a t dsactiv par dfaut.
Ce style favorisant les erreurs susceptibles de rendre votre code vulnrable aux atta-
ques, il est dsormais dconseill. Ce serait de toute faon une mauvaise ide de lutili-
ser dans du nouveau code car il y a de fortes chances pour quil disparaisse en PHP 6.
m Le style mdium ($ POST[qte pneus]) est maintenant lapproche recommande.
Il est assez pratique mais nest apparu quavec PHP 4.1.0 ; il ne fonctionnera donc
pas sur de trs anciennes installations.
m Le style long ($HTTP POST VARS[qte pneus]) est le plus "bavard". Notez
cependant quil a t dclar obsolte (deprecated) et quil est en consquence
vraisemblable quil disparatra dans le long terme. Ce style tait auparavant le
plus portable mais peut maintenant tre dsactiv via la directive de configuration
register long arrays, qui amliore les performances. L aussi, il est dconseill
de lutiliser dans du nouveau code, sauf si lon a de trs bonnes raisons de penser
que le script sera install sur un serveur ancien.
Lorsquon emploie le style abrg, les variables du script portent les mmes noms que
les champs du formulaire HTML, cest pourquoi il nest pas ncessaire de dclarer les
variables ou dentreprendre quoi que ce soit pour les crer dans le script. Les variables
sont passes au script de la mme faon que des arguments le sont une fonction. Avec
le style abrg, on peut donc se contenter dutiliser une variable comme $qte pneus car
le champ du formulaire la cre automatiquement dans le script de traitement.
Ce type daccs pratique aux variables est attrayant mais, avant dactiver
register globals, il convient de sintresser aux raisons pour lesquelles lquipe
charge du dveloppement de PHP la dsactive.
Le fait de pouvoir accder directement aux variables est trs pratique mais cela facilite
lapparition derreurs de programmation susceptibles de compromettre la scurit de
vos scripts. Lorsque les variables dun formulaire deviennent automatiquement des
variables globales, il ny a plus de sparation vidente entre les variables cres par le
programmeur et les variables douteuses directement envoyes par lutilisateur.
Si vous ne prenez pas la prcaution de donner toutes vos variables une valeur initiale,
les utilisateurs de vos scripts peuvent donc passer des variables et des valeurs, sous la
forme de variables de formulaire, qui se mlangeront aux vtres. En consquence, si
vous choisissez le style abrg pour accder aux variables, vous devez vous assurer de
donner une valeur initiale vos variables.
Le style mdium implique la rcupration des variables de formulaire partir dun
des tableaux $ POST, $ GET ou $ REQUEST. Un tableau $ GET ou $ POST contiendra
26 Partie I Utilisation de PHP

tous les dtails de toutes les variables du formulaire. Le choix du tableau dpend de
la mthode (GET ou POST, respectivement) utilise pour lenvoi du formulaire.
En outre, une combinaison de toutes les donnes envoyes via POST ou GET sera dispo-
nible par le biais de $ REQUEST.
Si le formulaire utilise la mthode POST, la valeur entre dans le champ qte pneus sera
enregistre dans $ POST[qte pneus]. Si cest la mthode GET qui est employe, cette
valeur sera contenue dans $ GET[qte pneus]. Dans les deux cas, la valeur sera
disponible dans $ REQUEST[qte pneus].
Ces tableaux font partie des tableaux "superglobaux", dont nous reparlerons lorsque
nous voquerons la porte des variables.
Si vous utilisez une version trs ancienne de PHP, il est possible que vous nayez pas
accs aux tableaux $ POST ou $ GET : dans les versions antrieures la 4.1.0, les
mmes informations taient enregistres dans des tableaux appels $HTTP POST VARS et
$HTTP GET VARS. Cest ce que nous appelons le style long. Comme nous lavons indi-
qu prcdemment, ce style a t dclar "obsolte". Il ny a pas dquivalent au tableau
$ REQUEST dans ce style.
Avec le style long, vous pouvez accder la rponse de lutilisateur via
$HTTP POST VARS[qte pneus] ou $HTTP GET VARS[qte pneus].
Les exemples dans ce livre ont t tests avec la version 5.2 de PHP et ils seront parfois
incompatibles avec des versions de PHP antrieures la version 4.1.0. Cest pourquoi nous
vous recommandons dutiliser, dans la mesure du possible, une version rcente de PHP.
Prenons un autre exemple. Le style mdium de rfrencement des variables utilisant un
type de variable appel tableau (lesquels ne seront vraiment tudis quau Chapitre 3),
nous commencerons lcriture du script en crant des copies de variables plus faciles
manipuler.
Pour copier la valeur dune variable dans une autre, servez-vous de loprateur daffec-
tation, qui, en PHP, est le signe "gal" (=). La ligne de code suivante cre une nouvelle
variable appele $qte pneus et y copie le contenu de $ POST[qte pneus] :
$qte_pneus = $_POST[qte_pneus];

Insrez le bloc de code qui suit au dbut du script. Tous les autres scripts prsents dans
ce livre et qui traitent des donnes issues de formulaire commenceront par un bloc du
mme genre. Ce bloc ne gnrant pas de sortie, il importe peu quil soit plac avant ou
aprs la balise <html> ou les autres balises HTML du dbut de votre page. En gnral,
nous le plaons au tout dbut du script afin quil soit facilement reprable.
<?php
// Cre des noms de variables abrges
$qte_pneus = $_POST[qte_pneus];
Chapitre 1 PHP : les bases 27

$qte_huiles = $_POST[qte_huiles];
$qte_bougies = $_POST[qte_bougies];
?>

Ce code cre trois nouvelles variables ($qte pneus, $qte huiles et $qte bougies) et
les dfinit de manire quelles contiennent les donnes envoyes via la mthode POST
du formulaire.
Pour que le script ait un effet visible, ajoutez les lignes de code suivantes la fin de
votre script PHP :
echo <p>Rcapitulatif de votre commande:</p>;
echo $qte_pneus . pneus<br />;
echo $qte_huiles . bidons d\huile<br />;
echo $qte_bougies . bougies<br />;

ce stade, vous navez pas vrifi le contenu des variables afin de vous assurer que les
valeurs entres dans chaque champ de formulaire soient cohrentes. Essayez dentrer
de manire dlibre des donnes errones et observez ce qui se passe. Aprs avoir lu la
suite de ce chapitre, vous souhaiterez peut-tre ajouter ce script du code pour la vali-
dation des donnes.

ATTENTION
Utiliser directement les donnes de lutilisateur pour les afficher dans le navigateur comme
ici est une opration risque du point de vue de la scurit. Vous devriez filtrer ces donnes
comme on lexplique au Chapitre 4. Les problmes de scurit sont prsents au Chapitre 14.

Si vous chargez le fichier ainsi cr dans votre navigateur, le script affichera une sortie
comme celle de la Figure 1.4. Les valeurs affiches dpendent videmment de celles
qui ont t entres dans le formulaire.

Figure 1.4
Les variables saisies
par lutilisateur dans le
formulaire sont facile-
ment accessibles dans
processorder.php.
28 Partie I Utilisation de PHP

Les quelques points intressants relever propos de cet exemple sont examins dans
les sous-sections qui suivent.

Concatnation de chanes
Dans ce script, la fonction echo sert afficher la valeur saisie par lutilisateur dans
chacun des champs du formulaire, suivie dun texte indiquant la signification de la
valeur affiche. Examinez attentivement les instructions echo : le nom de la variable et
le texte qui le suit sont spars par un point (.), comme dans la ligne de code suivante :
echo $qte_pneus . pneus<br>;

Le caractre point reprsente ici loprateur de concatnation de chanes et sutilise


pour accoler des chanes de caractres (des fragments de texte) les unes aux autres.
Vous y aurez souvent recours lorsque vous enverrez au navigateur des donnes en sortie
avec echo car la concatnation de chanes permet dviter la rptition des commandes
echo.
Toutes les variables simples peuvent galement tre insres dans des chanes enca-
dres par des apostrophes doubles passes la fonction echo (les tableaux sont plus
dlicats prendre en charge et cest pourquoi nous nous intresserons la combinaison
des tableaux et des chanes au Chapitre 4).
Par exemple :
echo "$qte_pneus pneus<br />";

Cette ligne quivaut linstruction prsente plus haut. Chacun de ces deux formats est
correct et le choix de lun ou lautre est surtout une affaire de got personnel. Le
processus qui consiste remplacer un nom de variable par sa valeur dans une telle
chane est appel "interpolation". Cette fonctionnalit est spcifique aux chanes entre
apostrophes doubles : elle ne fonctionne pas avec les chanes entre apostrophes simples
de cette manire. Si vous excutez la ligne de code suivante :
echo $qte_pneus pneus<br />;

le navigateur affichera simplement "$qte pneus pneus<br />". Lorsque la variable est
encadre par des apostrophes doubles, son nom est remplac par sa valeur. Si elle est
place entre des apostrophes simples, son nom, ou tout autre texte, est envoy tel quel
au navigateur.

Variables et littraux
La variable et la chane concatnes lune avec lautre dans chacune des instructions
echo sont deux entits de nature diffrente. Une variable est un symbole reprsentant
des donnes, tandis quune chane constitue les donnes elles-mmes. Lorsque des
donnes brutes sont spcifies directement dans un programme, comme cest le cas
Chapitre 1 PHP : les bases 29

dans lexemple considr ici, les donnes sont qualifies de "littrales", pour marquer la
diffrence avec une variable. $qte pneus est une variable, cest--dire un symbole dsi-
gnant les donnes saisies par le client. En revanche, pneus<br /> est un littral (cette
chane na pas besoin dtre interprte pour tre envoye au navigateur).
Nous nen avons pas tout fait fini sur ce point. Dans la dernire instruction cite, PHP
remplace dans la chane le nom de variable $qte pneus par la valeur stocke dans la
variable.
Nous avons dj mentionn deux types de chanes : celles encadres par des apostro-
phes doubles et celles encadres par des apostrophes simples. PHP tente dvaluer les
chanes entre apostrophes doubles, ce qui conduit au rsultat du traitement de linstruc-
tion prcdente. Les chanes places entre apostrophes simples sont traites comme des
littraux.
Il existe galement un troisime type de chane : les "documents sur place". Leur
syntaxe (<<<) est familire aux utilisateurs de Perl et a t ajoute PHP 4. Elle permet
de spcifier des chanes longues de manire soigne, en utilisant un marqueur de fin qui
sera utilis pour terminer la chane. Lexemple suivant cre et affiche une chane de trois
lignes :
echo <<<FIN
ligne1
ligne2
ligne3
FIN

Le lexme FIN est entirement arbitraire, mais il ne doit pas apparatre dans le contenu
de la chane. Pour fermer un document sur place, il suffit de placer le lexme au dbut
dune ligne.
Les documents sur place sont interpols, comme les chanes entre apostrophes doubles.

Identificateurs
Les noms des variables sont des identificateurs (tout comme les noms de fonctions et de
classes les fonctions et les classes sont traites aux Chapitres 5 et 6). Le choix des
identificateurs doit tre effectu en respectant quelques rgles simples :
m La longueur dun identificateur nest pas limite. Un identificateur peut se composer
de lettres, de nombres et de blancs souligns.
m Un identificateur ne peut pas commencer par un chiffre.
m En PHP, les identificateurs sont sensibles la casse ( la prsence de minuscules et
de majuscules). $qte pneus est un identificateur diffrent de $Qte Pneus. Le non-
respect de la casse constitue une erreur de programmation commune. Les noms des
30 Partie I Utilisation de PHP

fonctions font exception cette rgle puisquils peuvent tre orthographis sans
respect de la casse.
m Une variable peut porter le mme nom quune fonction. Cette pratique est toutefois
dconseille parce quelle prte confusion. Par ailleurs, vous ne pouvez pas crer
une fonction portant le mme nom quune autre fonction.

Cration de variables
Vous pouvez dclarer et utiliser vos propres variables en plus des variables passes au
script partir du formulaire HTML.
Lune des particularits de PHP est quil nest pas ncessaire de dclarer des variables
avant de les utiliser. Une variable est automatiquement cre lorsquune valeur lui est
affecte pour la premire fois (voir la section suivante pour plus de dtails ce sujet).

Affectation de valeurs des variables


Laffectation de valeurs des variables seffectue au moyen de loprateur daffectation
=. Sur le site de Bob, nous devons calculer le nombre total darticles commands, ainsi
que le montant total de la commande. Pour stocker ces nombres, nous pouvons crer
deux variables, que nous initialiserons la valeur zro.
Ajoutez les lignes de code qui suivent la fin de votre script PHP :
$qte_totale = 0;
$montant_total = 0.00;
Chacune de ces instructions cre une variable et lui affecte une valeur littrale. Il est
galement possible daffecter la valeur dune variable une autre variable, comme le
montrent les instructions suivantes :
$qte_totale = 0;
$montant_total = $qte_totale;

Types des variables


Le type des variables fournit une indication de la nature des donnes qui y sont conser-
ves. PHP fournit plusieurs types de donnes. Diverses donnes peuvent tre stockes
dans diffrents types de donnes.

Types de donnes du PHP


Le langage PHP prend en charge les types de donnes de base suivants :
m Entier. Utilis pour les nombres entiers.
m Flottant (aussi appel Double). Utilis pour les nombres rels.
Chapitre 1 PHP : les bases 31

m Chane. Utilis pour les chanes de caractres.


m Boolen. Utilis pour exprimer les valeurs vraies ou fausses.
m Tableau. Utilis pour stocker plusieurs lments de donnes de mme type (voir
Chapitre 3).
m Objet. Utilis pour stocker des instances de classes (voir Chapitre 6).
Il existe galement deux types spciaux : NULL et ressource. Les variables auxquelles
il na pas t donn de valeur spcifique, celles qui sont considres comme non dfi-
nies et celles auxquelles il a t affect la valeur spcifique NULL sont considres
comme tant du type NULL. Certaines fonctions prdfinies (comme les fonctions de
base de donnes) retournent des variables du type ressource : elles reprsentent des
ressources externes (comme des connexions de base de donnes). Il est extrmement
rare que lon soit amen manipuler directement une variable du type ressource, mais
elles sont frquemment renvoyes par des fonctions et doivent tre passes comme
paramtres dautres fonctions.

Intrt du typage
On dit que PHP est un langage faiblement typ ou quil utilise un typage dynamique.
Dans la plupart des langages de programmation (C, par exemple), une variable ne
peut appartenir qu un seul type de donnes, qui doit tre prcis avant toute utilisa-
tion de la variable. En PHP, le type dune variable est dtermin par la valeur qui lui est
affecte.
Lorsque nous avons cr $qte totale et $montant total, par exemple, leurs types
initiaux ont t dtermins lors de lexcution des instructions suivantes :
$qte_totale = 0;
$montant_total = 0.00;

La valeur entire 0 ayant t affecte la variable $qte totale, celle-ci prend le type
entier. Selon la mme logique, $montant total est de type flottant.
Bien que cela puisse sembler trange, nous pourrions ajouter la ligne suivante notre
script :
$montant_total = Bonjour;

La variable $montant total serait alors de type chane car PHP adapte le type de
chaque variable aux donnes qui y sont contenues, chaque instant.
Cette capacit du langage PHP modifier les types des variables " la vole" peut se
rvler extrmement utile. Souvenez-vous que PHP dtecte "automatiquement" le type
des donnes stockes dans chaque variable et quil renvoie par consquent toujours les
donnes avec le type appropri, lorsque vous rcuprez le contenu dune variable.
LivrePHP&MSQL.book Page 32 Mardi, 25. novembre 2008 1:02 13

32 Partie I Utilisation de PHP

Transtypage
Si PHP est un langage faiblement typ, il donne nanmoins la possibilit de forcer le
type dune valeur ou dune variable par un transtypage (casting). Le principe est identi-
que au transtypage du langage C. Il suffit de spcifier le type temporaire entre parenthses,
juste avant la variable concerne.
Nous pourrions ainsi dclarer les deux variables cites prcdemment, $qte_totale et
$montant_total, en effectuant un transtypage comme suit :
$qte_totale = 0;
$montant_total = (double)$qte_totale;

Linterprteur PHP analyse la seconde instruction de la manire suivante : "Prendre la


valeur stocke dans $qte_totale, linterprter comme une variable de type flottant
et la stocker dans $montant_total". La variable $montant_total prend alors le type
flottant. Le transtypage naffectant pas les types des variables soumises au transtypage,
$qte_totale reste de type entier.

Variables dynamiques
PHP admet un autre type de variable : les variables dynamiques. Celles-ci permettent
de changer les noms des variables de manire dynamique.
Comme vous pouvez le constater, PHP autorise une grande souplesse pour manipuler
les types et les noms de variables. Si tous les langages de programmation autorisent
la modification du contenu des variables, seuls quelques-uns permettent de modifier le
type dune variable et rares sont les langages autoriser la modification des noms
de variables.
Le principe dune variable dynamique consiste utiliser la valeur dune variable
comme nom dune autre variable. Nous pourrions crire la ligne de code suivante :
$nom_var = qte_pneus;

puis utiliser $$nom_var en lieu et place de $qte_pneus. Nous pourrions alors dfinir la
valeur de $qte_pneus de la manire suivante :
$$nom_var = 5;

ce qui est strictement quivalent :


$qte_pneus = 5;

Ce concept peut sembler abscons, mais vous en saisirez mieux lutilit lorsque nous
lappliquerons dans lexemple donn dans la section consacre aux boucles for, un peu
plus loin dans cet ouvrage. Plutt qunumrer et utiliser chaque variable dun formu-
laire sparment, nous utiliserons une boucle et une mme variable pour traiter automa-
tiquement toutes les variables du formulaire.
Chapitre 1 PHP : les bases 33

Constantes
Comme nous lavons mentionn plus haut, nous pouvons modifier la valeur stocke dans
une variable. Nous pouvons galement dclarer des constantes. Tout comme une variable,
une constante stocke une valeur mais, contrairement une variable, cette valeur est fixe
"une fois pour toutes" et ne peut plus tre modifie un autre endroit du script.
Dans notre exemple du site de Bob, les prix des diffrents articles proposs la vente
pourraient tre stocks dans des constantes. La dfinition dune constante seffectue au
moyen de la fonction define :
define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(PRIX_BOUGIES, 4);
Ajoutez ces lignes de code votre script. Nous disposons prsent de trois constantes
qui peuvent tre utilises pour calculer le total de la commande passe par le client.
Vous remarquerez que tous les noms de constante sont ici spcifis en majuscules. Cette
convention est emprunte au langage C : elle permet de distinguer dun coup dil
variables et constantes. Elle nest pas obligatoire, mais fortement recommande parce
quelle facilite la lecture et la maintenance du code.
Contrairement aux variables, les constantes ne sont pas prfixes par le caractre dollar.
Pour utiliser la valeur dune constante, il suffit de spcifier son nom. Pour utiliser lune
des constantes cres prcdemment, nous pourrions donc crire :
echo PRIX_PNEUS;
Outre les constantes cres par le programmeur, PHP utilise un grand nombre de constantes
prdfinies. Pour en connatre la liste, utilisez la fonction phpinfo() :
phpinfo();
Lappel phpinfo fournit, entre autres, la liste de toutes les variables et constantes
prdfinies dans PHP. Nous tudierons et utiliserons plusieurs de ces constantes et
variables dans la suite de cet ouvrage.
Lune des autres distinctions entre les variables et les constantes tient ce que les constantes
ne peuvent stocker que des donnes de type boolen, entier, flottant ou chane, cest--
dire des types scalaires.

Porte des variables


La "porte" dune variable dsigne les emplacements au sein dun script o la variable
est visible. Les six rgles de porte de base dans PHP sont les suivantes :
m Les variables superglobales prdfinies sont visibles nimporte quel endroit dun
script.
34 Partie I Utilisation de PHP

m Les constantes, une fois dclares, sont toujours visibles globalement ; autrement
dit, elles peuvent tre utilises lintrieur et lextrieur de fonctions.
m Les variables globales dclares dans un script sont visibles dans tout le script, mais
pas lintrieur des fonctions.
m Une variable utilise lintrieur dune fonction et qui est dclare comme tant
globale fait rfrence la variable globale de mme nom.
m Les variables cres lintrieur de fonctions et dclares comme statiques sont
invisibles en dehors de la fonction mais conservent leur valeur entre deux excutions
de la fonction (nous reviendrons sur ce mcanisme au Chapitre 5).
m Les variables cres lintrieur dune fonction sont locales la fonction et cessent
dexister lorsque cette dernire se termine.
partir de PHP 4.2, les tableaux $ GET et $ POST ainsi que dautres variables spciales
utilisent des rgles particulires pour leur porte. Celles-ci sont appeles variables
superglobales ou autoglobales et sont visibles nimporte quel endroit du script, aussi
bien lintrieur qu lextrieur des fonctions.
Voici la liste complte des variables superglobales :
m $GLOBALS. Tableau de toutes les variables globales (comme le mot-cl global, ce
tableau vous permet daccder des variables globales dans une fonction avec
$GLOBALS[ma_variable], par exemple).
m $ SERVER. Tableau des variables denvironnement du serveur.
m $ GET. Tableau des variables passes au script par le biais de la mthode GET.
m $ POST. Tableau des variables passes au script par le biais de la mthode POST.
m $ COOKIE. Tableau des variables des cookies.
m $ FILES. Tableau des variables associes aux transferts de fichiers.
m $ ENV. Tableau des variables denvironnement.
m $ REQUEST. Tableau de toutes les variables entres par lutilisateur, ce qui comprend
les entres de $ GET, $ POST et $ COOKIE (mais pas celles de $ FILES depuis
PHP 4.3.0).
m $ SESSION. Tableau des variables de session.
Nous tudierons chacune de ces variables mesure de nos besoins et reviendrons plus
en dtail sur la notion de porte des variables lorsque nous examinerons les fonctions et
les classes. Jusque-l, toutes les variables que nous utiliserons seront de porte globale.
Chapitre 1 PHP : les bases 35

Oprateurs
Les oprateurs sont reprsents par des symboles et servent manipuler des valeurs et
des variables en les soumettant des oprations. Pour calculer les totaux et la taxe du
bon de commande client de Bob, nous devons recourir des oprateurs.
Nous avons dj mentionn deux oprateurs : loprateur de concatnation de chanes .
et loprateur daffectation =. Dans les sections qui suivent, nous allons passer en revue
la liste complte des oprateurs disponibles en PHP.
En gnral, les oprateurs peuvent prendre un, deux ou trois arguments, la majorit
dentre eux prenant deux arguments. Par exemple, loprateur daffectation prend deux
arguments : lemplacement de stockage gauche du symbole = et une expression,
place sa droite. Ces arguments sont appels oprandes. Un oprande est un lment
auquel sapplique loprateur.

Oprateurs arithmtiques
Les oprateurs arithmtiques de PHP sont trs simples : il sagit en fait des oprateurs
mathmatiques traditionnels. Le Tableau 1.1 numre les oprateurs arithmtiques.

Tableau 1.1 : Oprateurs arithmtiques de PHP

Oprateur Nom Exemple


+ Addition $a+$b
Soustraction $a $b
* Multiplication $a * $b
/ Division $a / $b
% Modulo $a% $b

Avec chacun de ces oprateurs, nous pouvons stocker le rsultat de lopration, comme
ici :
$resultat = $a+$b;

Laddition et la soustraction fonctionnent comme nous pouvons nous y attendre. Ces


oprateurs effectuent respectivement laddition et la soustraction des valeurs stockes
dans les variables $a et $b.
Loprateur de soustraction ( ) sutilise galement comme oprateur unaire (cest--
dire un oprateur qui ne prend quun seul argument ou oprande) pour indiquer des
nombres ngatifs, comme dans lexemple suivant :
$a = -1;
36 Partie I Utilisation de PHP

Le fonctionnement de la multiplication et de la division est lui aussi conforme au fonc-


tionnement attendu. Notez lusage du caractre astrisque (*) pour loprateur de multi-
plication au lieu du symbole classique de multiplication et lusage de la barre oblique
pour loprateur de division, au lieu du symbole classique de la division.
Loprateur modulo renvoie le reste de la division de la variable $a par la variable $b.
Soit le fragment de code suivant :
$a = 27;
$b = 10;
$resultat = $a % $b;

La valeur stocke dans la variable $resultat est le reste obtenu aprs division de 27 par
10, cest--dire 7.
Les oprateurs arithmtiques sont gnralement appliqus des entiers ou des
nombres rels (doubles). Lorsquils sont appliqus des chanes, linterprteur PHP
tente de convertir les chanes en nombres. Lorsque les chanes contiennent un "e" ou un
"E", PHP les lit comme tant en notation scientifique et les convertit en nombres rels ;
sinon il les convertit en nombres entiers. PHP examine si la chane commence par des
chiffres et, si cest le cas, les utilise comme valeur numrique. Si ce nest pas le cas,
linterprteur PHP considre que la valeur de la chane est zro.

Oprateur de chanes
Nous avons dj vu et utilis lunique oprateur de chane admis par PHP : loprateur
. de concatnation de chanes. Cet oprateur semploie pour accoler deux chanes lune
lautre. Il gnre et stocke son rsultat la manire de loprateur daddition.
$a = "Le garage ";
$b = "de Bob";
$resultat = $a.$b;

Aprs lexcution de ces instructions, la variable $resultat contient la chane Le


garage de Bob.

Oprateurs daffectation
Nous avons dj voqu loprateur daffectation =. Cet oprateur doit toujours tre
dsign comme tant loprateur daffectation et se lit "reoit". Ainsi :
$qte_totale = 0;

se lit "$qte totale reoit la valeur zro". Nous reviendrons sur ce point un peu plus
loin dans ce chapitre, lorsque nous tudierons les oprateurs de comparaison, mais si
vous lappelez "gal" vous risquez dtre surpris.
Chapitre 1 PHP : les bases 37

Valeurs renvoyes par une affectation


Loprateur daffectation renvoie une valeur, comme les autres oprateurs. Ainsi,
lexcution de lexpression :
$a+$b
renvoie la valeur obtenue en ajoutant la variable $a la variable $b. De la mme
manire, vous pouvez crire :
$a = 0;
La valeur renvoye par cette expression est zro.
Cette technique vous permet de former des expressions telles que :
$b = 6+ ($a = 5);
Cette expression initialise la variable $b 11. Ce principe est vrai pour toutes les affec-
tations : la valeur dune instruction daffectation est la valeur affecte loprande
plac gauche de loprateur.
Lors de lcriture dune expression arithmtique, vous pouvez employer des parenthses
pour lever la priorit dune sous-expression, comme dans la ligne de code donne plus
haut. Le principe est ici exactement le mme quen mathmatiques.

Oprateurs combins laffectation


Outre loprateur daffectation, PHP admet tout un ensemble doprateurs daffectation
combins. Chacun de ces oprateurs se prsente comme une possibilit abrge pour
effectuer une opration spcifique sur une variable et pour en affecter le rsultat cette
variable. Ainsi, lexpression :
$a += 5;
est quivalente lexpression :
$a = $a+5;
Il existe des oprateurs combins laffectation pour chaque oprateur arithmtique et
pour loprateur de concatnation de chane.
Le Tableau 1.2 dresse une vue rcapitulative de tous les oprateurs combins laffec-
tation et indique leurs effets.

Tableau 1.2 : Oprateurs combins laffectation

Oprateur Exemple quivalant


+= $a += $b $a = $a+$b
= $a = $b $a = $a $b
*= $a *= $b $a = $a * $b
38 Partie I Utilisation de PHP

Tableau 1.2 : Oprateurs combins laffectation (suite)

Oprateur Exemple quivalant


/= $a /= $b $a = $a / $b
%= $a%= $b $a = $a% $b
.= $a .= $b $a = $a . $b

Oprateurs de pr/postincrmentation et de pr/postdcrmentation


Les oprateurs de pr/postincrmentation (++) et de pr/postdcrmentation ( ) sont
quivalents aux oprateurs += et =, quelques dtails prs.
Tous les oprateurs dincrmentation ont deux effets : dune part ils incrmentent,
dautre part ils affectent une valeur. Soit les instructions suivantes :
$a = 4;
echo ++$a;
La seconde instruction utilise loprateur de princrmentation, ainsi nomm parce
quil figure avant loprande $a. Lorsque linterprteur PHP rencontre cet oprateur, il
commence par incrmenter $a de 1, puis il renvoie la valeur ainsi incrmente. Dans ce
cas prcis, $a est incrmente la valeur 5, puis la valeur 5 est renvoye et affiche. La
valeur de lexpression complte est 5 (notez que la valeur stocke dans $a a bien t
modifie : PHP ne se contente pas de retourner simplement $a+1).
Lorsque loprateur ++ figure aprs loprande, il est qualifi doprateur de postincr-
mentation. Leffet produit est diffrent. Soit les instructions suivantes :
$a=4;
echo $a++;
Dans ce cas, linterprteur PHP accomplit le traitement inverse : il renvoie et affiche
dabord la valeur de $a et ce nest quensuite quil lincrmente. La valeur de lexpres-
sion complte est dans ce cas 4, cest--dire la valeur qui est affiche. Cependant, une
fois que linstruction a t excute, $a contient la valeur 5.
Loprateur de dcrmentation ( ) a un comportement analogue, si ce nest que la
valeur de loprande est dcrmente au lieu dtre incrmente.

Oprateur de rfrence
Loprateur de rfrence & (esperluette) peut tre utilis avec loprateur daffectation.
Normalement, lorsquune variable est affecte une autre, linterprteur PHP effectue
une copie de la premire variable quil stocke quelque part dans la mmoire de lordi-
nateur. Par exemple, considrez les instructions suivantes :
$a = 5;
$b = $a;
Chapitre 1 PHP : les bases 39

Ces lignes de code conduisent la cration dune copie de $a et au stockage de cette


copie dans $b. Par la suite, si la valeur de $a est modifie, la valeur de $b restera
inchange :
$a = 7; // $b vaut toujours 5

Loprateur de rfrence & permet dviter de faire une copie, comme le montre lexemple
suivant :
$a = 5;
$b = &$a;
$a = 7; // les variables $a et $b ont toutes les deux la valeur 7

Les rfrences peuvent tre un peu difficiles comprendre, mais il suffit de considrer
quune rfrence sapparente un alias plutt qu un pointeur. $a et $b pointent toutes
deux vers la mme section de mmoire, mais vous pouvez modifier cela en rinitialisant
lune delles comme ceci :
unset($a);

Cette instruction ne change pas la valeur de $b (7) mais rompt le lien entre $a et la
valeur 7 stocke en mmoire.

Oprateurs de comparaison
Les oprateurs de comparaison servent comparer deux valeurs entre elles. Les expres-
sions contenant de tels oprateurs renvoient les valeurs logiques true (vrai) ou false
(faux), selon le rsultat de la comparaison.

Oprateur dgalit
Loprateur dgalit == (deux signes gal) permet de dterminer si deux valeurs sont
gales. Par exemple, nous pourrions utiliser lexpression :
$a == $b

pour tester si les valeurs stockes dans $a et $b sont identiques. Linterprteur PHP
renvoie la valeur true si les valeurs sont gales et la valeur false si elles sont diff-
rentes.
Loprateur dgalit se confond facilement avec loprateur daffectation. Une telle
confusion est dautant plus dangereuse quelle ne provoque pas une erreur mais conduit
simplement un rsultat qui nest pas celui escompt. En effet, les valeurs non nulles
sont gnralement values comme true tandis que les valeurs nulles sont values
comme false. Supposons que deux variables soient initialises de la manire suivante :
$a = 5;
$b = 7;
40 Partie I Utilisation de PHP

Sil est amen tester lexpression $a = $b, linterprteur PHP renvoie la valeur true et
la raison est facile comprendre : la valeur de lexpression $a = $b est la valeur affecte
loprande qui figure gauche de loprateur daffectation, cest--dire ici 7. Cette
valeur tant non nulle, lexpression est value comme true. Si votre intention initiale
tait de tester lexpression $a == $b (au lieu de $a = $b), qui serait value comme false
par linterprteur PHP, vous avez introduit dans votre code une erreur logique qui peut se
rvler trs difficile dtecter. Vous devez par consquent vous montrer trs prudent lors-
que vous avez recours loprateur daffectation ou loprateur dgalit et vrifier
systmatiquement que vous ne confondez pas ces deux oprateurs.
Cette confusion entre les oprateurs daffectation et dgalit est trs courante et
vous vous y heurterez probablement plusieurs fois au cours de votre carrire de
programmeur.

Autres oprateurs de comparaison


PHP comprend tout un jeu doprateurs de comparaison. Ceux-ci sont dcrits dans le
Tableau 1.3.
Loprateur didentit (===) ne renvoie true que si ces deux oprandes sont gaux et du
mme type. Par exemple, 0==0 sera vrai, mais 0===0 ne le sera pas car lun des
zros est un entier et lautre est une chane.

Tableau 1.3 : Oprateurs de comparaison de PHP

Oprateur Nom Exemple


== gal $a == $b
=== Identique $a === $b
!= Diffrent $a!= $b
<> Diffrent $a <> $b
< Infrieur $a < $b
> Suprieur $a > $b
<= Infrieur ou gal $a <= $b
>= Suprieur ou gal $a!= $b

Oprateurs logiques
Les oprateurs logiques servent combiner les rsultats de conditions logiques. Par exem-
ple, considrons le cas dune variable $a dont la valeur est comprise entre 0 et 100. Pour
Chapitre 1 PHP : les bases 41

vrifier que la valeur de $a est bien situe dans cette plage, il nous faudrait tester les condi-
tions $a >= 0 et $a <= 100 en nous servant de loprateur ET de la manire suivante :
$a >= 0 && $a <=100

Le langage PHP comprend les oprateurs logiques ET, OU, OU EXCLUSIF et NON.
Le Tableau 1.4 dcrit ces diffrents oprateurs.

Tableau 1.4 : Oprateurs logiques de PHP

Oprateur Nom Exemple Rsultat


! NON !$b Renvoie true si $b est faux et vice versa.
&& ET $a && $b Renvoie true lorsque $a et $b sont tous deux vrais ; sinon
false.
|| OU $a || $b Renvoie true lorsque soit $a, soit $b est vrai et lorsque $a
et $b sont tous les deux vrais ; sinon renvoie false.
and ET $a and $b Identique &&, mais avec une priorit plus basse.
or OU $a or $b Identique ||, mais avec une priorit plus basse.
xor OU $a xor $b Renvoie true si $a ou $b est vrai, mais pas les deux.
EXCLUSIF Renvoie false si $a et $b valent tous les deux vrais ou
tous les deux faux.

Les oprateurs and et or ont une priorit plus faible que celle des oprateurs && et ||. Nous
reviendrons sur la notion de priorit des oprateurs un peu plus loin dans ce chapitre.

Oprateurs sur les bits


Les oprateurs sur les bits permettent de traiter les nombres entiers sous la forme de
suites de bits utilises pour les reprsenter.
Bien que ces oprateurs soient peu utiles dans le contexte des programmes PHP, vous
en trouverez une description exhaustive dans le Tableau 1.5.

Tableau 1.5 : Oprateurs bits bits de PHP

Oprateur Nom Exemple Rsultat


& ET bit bit $a & $b Les bits positionns 1 dans $a et dans $b sont
positionns 1 dans le rsultat.
| OU bit bit $a | $b Les bits positionns 1 dans $a ou dans $b sont
positionns 1 dans le rsultat.
~ NON bit bit ~$a Les bits qui sont positionns 1 dans $a sont
(complment un) positionns 0 dans le rsultat, et vice versa.
42 Partie I Utilisation de PHP

Tableau 1.5 : Oprateurs bits bits de PHP (suite)

Oprateur Nom Exemple Rsultat


^ OU EXCLUSIF $a ^ $b Les bits positionns 1 dans $a ou $b, mais pas
bit bit dans les deux, sont positionns 1 dans le rsultat.
<< Dcalage gauche $a << $b Dcale les bits de $a de $b positions vers la gauche.
>> Dcalage droite $a >> $b Dcale les bits de $a de $b positions vers la droite.

Autres oprateurs
Outre les oprateurs dcrits jusquici, PHP dispose de plusieurs autres oprateurs.
Loprateur virgule (,) semploie pour sparer les arguments dune fonction ainsi que
les lments dune liste. Il est gnralement utilis lintrieur de parenthses.
Les deux oprateurs spciaux new et > sutilisent respectivement pour instancier une classe
et pour accder aux membres dune classe. Nous les tudierons en dtail au Chapitre 6.
Il existe encore trois autres oprateurs, que nous allons brivement dcrire dans les
prochaines sous-sections.

Loprateur ternaire
Loprateur ternaire ?: sutilise de la manire suivante :
condition? valeur si vraie: valeur si fausse

Il est donc quivalent la version expression de linstruction if else (cette dernire


est traite plus loin dans ce chapitre).
Voici un exemple simple dapplication :
($note > 50? Reu: Recal);

Cette expression permet de dterminer si les tudiants sont reus ou recals leur examen.

Loprateur de suppression derreur


Loprateur de suppression derreur @ peut sutiliser devant nimporte quelle expression,
cest--dire devant tout ce qui produit ou contient une valeur. Soit linstruction suivante :
$a = @(57/0);

En labsence de loprateur @, cette ligne de code produit un message derreur de division


par zro. La prsence de loprateur @ vite laffichage de ce message.
Si vous utilisez loprateur @, prvoyez du code de gestion des erreurs pour dtecter les
erreurs qui se produisent. Si vous avez configur PHP en activant le paramtre
Chapitre 1 PHP : les bases 43

track errors, les messages derreur gnrs seront automatiquement stocks dans la
variable globale $php errormsg.

Loprateur dexcution
Loprateur dexcution se compose en fait dune paire doprateurs : ``, ou backticks.
Il sagit l non pas dune paire dapostrophes simples mais dapostrophes inverses.
Linterprteur PHP essaye dexcuter tout ce qui est insr entre les deux apostrophes
inverses comme une commande lance sur la ligne de commande du serveur. La valeur
de lexpression est alors le rsultat de lexcution de la commande.
Par exemple, sur un systme dexploitation de type Unix, vous pouvez crire :
$out = `ls -la`;
echo <pre>.$out.</pre>;

ou, de la mme manire, sur un serveur Windows :


$out = `dir c:`;
echo <pre>.$out.</pre>;

Lexcution de chacun de ces fragments de code produit une liste du contenu du rper-
toire et la stocke dans la variable $out. Celle-ci peut ensuite tre passe en paramtre la
fonction echo pour un affichage dans le navigateur ou traite dune tout autre manire.
Au Chapitre 17, nous tudierons dautres faons dexcuter des commandes sur un
serveur.

Oprateurs de tableau
Loprateur [ ] permet daccder aux lments dun tableau. On se sert galement de
loprateur => dans certains contextes de tableau. Ces oprateurs seront examins au
Chapitre 3.
Vous avez galement accs un certain nombre dautres oprateurs de tableau. Nous
les prsenterons en dtail au Chapitre 3, mais ils sont inclus ici par souci dexhaus-
tivit.

Tableau 1.6 : Oprateurs de tableau de PHP

Oprateur Nom Utilisation Rsultat


+ Union $a + $b Renvoie un tableau contenant tout dans $a et $b.
== galit $a == $b Renvoie true si $a et $b possdent les mmes lments.
=== Identit $a === $b Renvoie true si $a et $b possdent les mmes lments
dans le mme ordre.
44 Partie I Utilisation de PHP

Tableau 1.6 : Oprateurs de tableau de PHP

Oprateur Nom Utilisation Rsultat


!= Ingalit $a!= $b Renvoie true si $a et $b ne sont pas gaux.
<> Ingalit $a <> $b Renvoie true si $a et $b ne sont pas gaux.
!== Non-identit $a!== $b Renvoie true si $a et $b ne sont pas identiques.

Vous remarquerez que les oprateurs de tableau du Tableau 1.6 ont tous des opra-
teurs quivalents qui fonctionnent avec les variables scalaires. Pour autant que vous
vous souveniez que + opre une addition avec les types scalaires et une union avec les
tableaux, les comportements devraient tre cohrents. Vous ne pouvez pas comparer
des tableaux des types scalaires de manire utile.

Loprateur de type
Il nexiste quun seul oprateur de type : instanceof. Cet oprateur est utilis dans la
programmation oriente objet, mais nous le mentionnons ici par souci dexhaustivit (la
programmation oriente objet est prsente au Chapitre 6).
instanceof vous permet de vrifier si un objet est une instance dune classe parti-
culire, comme dans cet exemple :
class classeExemple{};
$monObjet = new classeExemple();
if ($monObjet instanceof classeExemple)
echo "monObjet est une instance de classeExemple";

Utilisation des oprateurs : calcul des totaux dun formulaire


Maintenant que vous connaissez les oprateurs du langage PHP, nous allons pouvoir
calculer les totaux et la taxe du formulaire de commande de Bob.
Pour cela, ajoutez le code suivant la fin de votre script PHP :
$qte_totale = 0;
$qte_totale = $qte_pneus+ $qte_huiles+ $qte_bougies;
echo Articles commands: .$qte_totale.<br />;

$montant_total = 0.00;

define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(SPARKPRICE, 4);

$montant_total = $qte_pneus * PRIX_PNEUS


+ $qte_huiles * PRIX_HUILES
Chapitre 1 PHP : les bases 45

+ $qte_bougies * PRIX_BOUGIES;

echo Sous-total: . number_format($montant_total, 2).<br />;

$taux_taxe= 0.10; // le taux de la taxe est de 10%


$montant_total = $montant_total * (1 + $taux_taxe);
echo Total avec les taxes: . number_format($montant_total, 2).
<br />;

Si vous actualisez la page dans votre navigateur, vous devriez obtenir un rsultat
comme celui de la Figure 1.5.

Figure 1.5
Les totaux de la
commande client
ont t calculs, mis
en forme et affichs.

Comme vous pouvez le constater, ce morceau de code fait intervenir plusieurs opra-
teurs. Les oprateurs daddition (+) et de multiplication (*) y sont utiliss pour calculer
les montants, tandis que loprateur de concatnation de chanes ( .) sert mettre en
forme la sortie des donnes dans la fentre du navigateur.
Par ailleurs, nous faisons appel la fonction number format() pour mettre en forme les
totaux sous forme de chanes deux dcimales. Cette fonction appartient la bibliothque
mathmatique de PHP.
Si vous examinez attentivement les calculs effectus dans le dernier fragment de code
ajout votre script, vous vous interrogerez peut-tre sur lordre dans lequel ces calculs
sont effectus. Considrez par exemple linstruction :
$montant_total = $qte_pneus* PRIX_PNEUS
+$qte_huiles* PRIX_HUILES
+$qte_bougies * PRIX_BOUGIES;

Le total obtenu semble correct (voir Figure 1.5), mais pourquoi les multiplications ont-
elles t effectues avant les additions ? La rponse cette question rside dans la
notion de priorit des oprateurs, cest--dire dans lordre selon lequel linterprteur
PHP value les oprateurs.
46 Partie I Utilisation de PHP

Priorit et associativit des oprateurs : ordre dvaluation


des expressions
En gnral, chaque oprateur est associ un niveau de priorit qui dtermine lordre selon
lequel cet oprateur sera valu dans une expression contenant plusieurs op-rateurs.
Les oprateurs ont une autre proprit : lassociativit, qui est lordre selon lequel des
oprateurs de mme priorit sont valus. Lassociativit dun oprateur peut tre dfinie
de gauche droite ou bien de droite gauche, ou alors cest quelle nest pas pertinente.
Le Tableau 1.7 dcrit les priorits et les associativits des oprateurs de PHP.
Les oprateurs de plus faible priorit sont en haut du tableau et la priorit des oprateurs
augmente mesure que lon descend dans le tableau.
Tableau 1.7 : Priorits des oprateurs de PHP

Associativit Oprateur
de gauche droite ,
de gauche droite or
de gauche droite xor
de gauche droite and
de droite gauche print
de gauche droite = += = *= /= .=%= &= |= ^= ~= <<= >>=
de gauche droite ?:
de gauche droite ||
de gauche droite &&
de gauche droite |
de gauche droite ^
de gauche droite &
non pertinent ==!= ===!==
non pertinent < <= > >=
de gauche droite << >>
de gauche droite + .
de gauche droite * /%
de droite gauche ! ~ ++ (int) (double) (string) (array) (object) @
de droite gauche []
non pertinent new
non pertinent ()
Chapitre 1 PHP : les bases 47

Notez que nous navons pas encore tudi loprateur de plus forte priorit : la tradi-
tionnelle paire de parenthses. Celle-ci sutilise pour renforcer la priorit dune partie
dune expression, afin de forcer son valuation et de contourner les rgles de priorit
des oprateurs.
Considrez linstruction qui suit, tire du dernier exemple tudi :
$montant_total = $montant_total * (1+$taux_taxe);
Si nous avions crit :
$montant_total = $montant_total * 1+$taux_taxe;
loprateur de multiplication aurait t valu en premier puisque sa priorit est plus
forte que celle de loprateur daddition. Le rsultat obtenu aurait alors t incorrect. En
utilisant des parenthses, nous pouvons contraindre linterprteur PHP valuer en
premier la sous-expression 1+$taux taxe.
Vous pouvez insrer dans une expression autant de paires de parenthses que nces-
saire. Le jeu de parenthses le plus interne est valu en premier.
Notez galement la prsence dans ce tableau dun autre oprateur que nous navons pas
encore couvert : linstruction print, qui quivaut echo.
Nous utiliserons gnralement echo dans ce livre, mais vous pouvez utiliser print si
vous le trouvez plus lisible. print et echo ne sont ni lun ni lautre vritablement des
fonctions mais peuvent tous deux tre appels comme des fonctions avec des paramtres
entre parenthses. Tous les deux peuvent galement tre traits comme des oprateurs : il
suffit de placer la chane afficher aprs le mot-cl echo ou print.
Le fait dappeler print comme une fonction lamne renvoyer une valeur (1), ce qui
peut se rvler utile si vous souhaitez produire une sortie lintrieur dune expression
plus complexe, mais cela signifie que print est un peu plus lent que echo.

Fonctions sur les variables


Avant den terminer avec les variables et les oprateurs, nous devons encore examiner
les fonctions sur les variables. Il sagit dune bibliothque de fonctions permettant de
manipuler et de tester les variables de diffrentes manires.

INFO
Ce livre ainsi que la documentation de php.net font rfrence au type de donnes mixed. Ce
type de donnes nexiste pas mais, PHP tant caractris par une extrme souplesse pour les
types de donnes, de nombreuses fonctions acceptent plusieurs types de donnes (quand ce
nest pas tous) comme argument. Lorsque lon peut employer des arguments de plusieurs
types de donnes, nous le signalons par le type mixed.
48 Partie I Utilisation de PHP

Test et dfinition des types de variables


La plupart des fonctions de variables sutilisent pour tester le type des variables.
Les deux fonctions de variables les plus gnrales sont gettype() et settype(). Les
prototypes de ces fonctions (cest--dire les descriptions des arguments quelles attendent
et des valeurs quelles renvoient) sont les suivants :
string gettype(mixed var);
bool settype(mixed var, chane type);
gettype() semploie en lui passant une variable. La fonction dtermine alors le type de
la variable et renvoie une chane contenant le nom du type : bool, int, double, string,
array, object, resource ou NULL. Elle renvoie unknown type sil ne sagit pas dun des
types PHP standard.
Pour utiliser settype(), il faut passer la fonction la variable dont le type doit tre
modifi, ainsi quune chane contenant le nom du nouveau type appliquer la variable
(voir la liste donne dans le paragraphe prcdent). Voici des instructions illustrant
lusage de ces deux fonctions de variables :
$a = 56;
echo gettype($a).<br>;
settype($a, double);
echo gettype($a).<br>;
Lors du premier appel de la fonction gettype(), la variable $a est de type entier (int).
Aprs lappel de settype(), $a est du type double.
PHP fournit galement des fonctions testant un certain type de variable. Chacune
de ces fonctions prend une variable comme argument et retourne soit true, soit false.
Ces fonctions sont les suivantes :
m is array().
m is double(), is float(), is real() (la mme fonction).
m is long(), is int(), is integer() (la mme fonction).
m is string().
m is bool().
m is object().
m is resource().
m is null().
m is scalar(). Teste si la variable est scalaire (entier, boolen, chane ou double).
m is numeric(). Teste si la variable est un nombre ou une chane numrique.
m is callable(). Teste si la variable est le nom dune fonction valide.
Chapitre 1 PHP : les bases 49

Test de ltat dune variable


PHP fournit plusieurs fonctions pour tester ltat dune variable.
La premire de ces fonctions est isset(), dont le prototype est le suivant :
bool isset(mixed var[, mixed var[,]]);

Cette fonction prend un nom de variable comme argument et renvoie true si la variable
existe et false dans le cas contraire. Vous pouvez galement passer une liste de variables
spares par des virgules et isset() renverra true si toutes les variables sont dfinies.
Vous pouvez supprimer une variable au moyen de la fonction unset(), qui fait pendant
la fonction isset(). La fonction unset() a le prototype suivant :
void unset(mixed var[, mixed var[,]]);

La fonction unset() supprime la ou les variables qui lui sont passes en paramtre.
La fonction empty() dtermine si une variable existe et contient une valeur non vide et non
nulle. Elle renvoie true ou false selon le rsultat obtenu. Son prototype est le suivant :
bool empty(mixed var);

Examinons un exemple utilisant ces trois fonctions. Tapez les lignes suivantes la fin
de votre script :
echo isset($qte_pneus): .isset($qte_pneus).<br />;
echo isset($absent): .isset($absent).<br />;
echo empty($qte_pneus): .empty($qte_pneus).<br />;
echo empty($absent): .empty($absent).<br />;

Actualisez la page dans votre navigateur pour observer le rsultat produit par cette srie
dinstructions.
La fonction isset() applique la variable $qte pneus devrait retourner la valeur 1
(true), quelle que soit la valeur saisie dans le champ de formulaire associ cette
variable. Le rsultat retourn par la fonction empty() applique cette variable dpend
en revanche de la valeur saisie (ou non saisie) dans le champ de formulaire.
La variable $absent nexistant pas, la fonction isset() applique ce nom de varia-
ble retourne un rsultat vide (false), tandis que la fonction empty() renvoie 1 (true).
Ces fonctions se rvlent donc trs pratiques pour dterminer si lutilisateur du formu-
laire a ou non rempli les champs qui lui sont proposs.

Rinterprtation des variables


PHP met votre disposition des fonctions qui permettent de mettre en uvre lquivalent
dun transtypage des variables. Voici trois fonctions permettant de raliser cette opration :
int intval(mixed var[, int base]);
float floatval(mixed var);
string strval(mixed var);
50 Partie I Utilisation de PHP

Chacune de ces fonctions prend une variable en paramtre et renvoie la valeur de cette
variable aprs avoir ralis sa conversion dans le type appropri. La fonction intval()
peut galement vous permettre de spcifier la base pour la conversion lorsque la varia-
ble convertir est une chane (vous pouvez ainsi convertir des chanes hexadcimales
en entiers, par exemple).

Structures de contrle
Dans un langage de programmation, les structures de contrle permettent de contrler
le flux dexcution au sein dun programme ou dun script. Les structures de contrle
peuvent tre classes en deux groupes : les structures conditionnelles (ou de branche-
ment) et les structures de rptition, ou boucles. Les sections qui suivent sont consacres
ltude de chacune de ces structures en PHP.

Prise de dcision avec des structures conditionnelles


Pour quun programme rponde pertinemment son utilisateur, il faut quil soit capable
de prendre des dcisions. Les constructions dun programme qui indiquent quune
dcision doit tre prise sont appeles "structures conditionnelles".

Instructions if
Nous pouvons utiliser une structure if pour prendre une dcision. Pour cela, nous
devons spcifier une condition. Si la condition est vraie, le bloc de code qui la suit
est excut. Les conditions des instructions if doivent tre spcifies entre paren-
thses ().
Par exemple, si le formulaire de commande en ligne de lentreprise de Bob est renvoy
par un client sans aucun article command, cest sans doute que le client a actionn par
inadvertance le bouton "Passer commande" avant davoir fini de remplir le formulaire.
Au lieu dafficher le message "Commande traite", le navigateur pourrait alors produire
un texte plus appropri, comme "Votre commande ne contient aucun article !".
Laffichage dun tel avertissement simplmente trs facilement au moyen dune
instruction if :
if( $qte_totale == 0 )
echo Votre commande ne contient aucun article!<br />;
La condition utilise ici est $qte totale == 0. Rappelez-vous que loprateur dgalit
(==) est diffrent de loprateur daffectation (=).
La condition $qte totale == 0 est vraie si la variable $qte totale est gale zro. Si
$qte totale est diffrente de zro, la condition est fausse. Lorsque la condition est
value comme vraie (true), linstruction echo est excute.
Chapitre 1 PHP : les bases 51

Blocs de code
Dans les structures conditionnelles telles quune structure if, il est souvent ncessaire
dexcuter plusieurs instructions. Dans ce cas, vous navez pas besoin de placer une
nouvelle instruction if avant chaque instruction excuter : il suffit de regrouper les instruc-
tions de manire former un bloc. Pour dclarer un bloc, encadrez-le par des accolades :
if( 0 == $qte_totale )
{
echo <p style="color:red">;
echo Votre commande ne contient aucun article!;
echo </p>;
}
Les trois lignes de code places ici entre accolades forment un bloc de code. Lorsque la
condition est value comme vraie, tout le bloc (cest--dire les trois lignes qui le consti-
tuent) est excut. Lorsque la condition se rvle fausse, le bloc est intgralement
ignor par linterprteur PHP.

INFO
Comme nous lavons dj mentionn, linterprteur PHP ignore la mise en forme du code. Il
est par consquent fortement recommand dindenter votre code pour en amliorer la lisi-
bilit. Des mises en retrait judicieuses permettent de discerner dun seul coup dil les lignes
des structures conditionnelles qui sont excutes lorsque les conditions sont satisfaites, les
instructions qui sont regroupes en blocs et les instructions qui font partie de boucles ou de
fonctions. Dans les exemples prcdents, linstruction qui dpend de linstruction if et les
instructions qui constituent le bloc sont indentes.

Instructions else
Souvent, il ne suffit pas de dcider quune action doit tre accomplie : il faut aussi choisir
celle qui, parmi un ensemble dactions, doit tre excute.
Une instruction else permet de spcifier une action alternative accomplir lorsque la
condition spcifie dans une instruction if se rvle fausse. Dans lexemple de lentre-
prise de Bob, il est ncessaire dalerter les clients sils transmettent une commande
vide. Par ailleurs, sils soumettent une commande valide, il faut leur renvoyer un rcapitu-
latif de leur commande, pas un message davertissement.
Pour prsenter aux clients soit une alerte, soit un rcapitulatif, nous pouvons introduire
une instruction else dans notre code, comme suit :
if( $qte_totale == 0 )
{
echo Votre commande ne contient aucun article!<br>;
}
else
{
echo $qte_pneus . pneus<br>;
echo $qte_huiles . bidons d\huile<br>;
echo $qte_bougies . bougies<br>;
}
52 Partie I Utilisation de PHP

Vous pouvez ainsi construire des processus logiques complexes en imbriquant des
instructions if les unes dans les autres. Dans le code qui suit, le message davertissement
ne saffichera que lorsque la condition $qte totale == 0 est value comme vraie et
chaque ligne de ce rcapitulatif ne sera produite que si sa propre condition est vraie.
if( $qte_totale == 0)
{
echo Votre commande ne contient aucun article!<br>;
}
else
{
if ( $qte_pneus > 0 )
echo $qte_pneus . pneus<br>;
if ( $qte_huiles > 0 )
echo $qte_huiles . bidons d\huile<br>;
if ( $qte_bougies > 0 )
echo $qte_bougies . bougies<br>;
}

Instructions elseif
Dans bon nombre de situations de prise de dcision, vous devez choisir entre plus de
deux possibilits. Linstruction elseif permet alors de crer une suite de plusieurs
options ; cest une combinaison dune instruction else et dune instruction if. Lorsque
lon prcise une suite de conditions, le programme peut tester chaque condition, jusqu
en trouver une qui soit vraie.
Pour les grosses commandes de pneus, Bob accorde des remises ses clients. Le prin-
cipe de ces remises est le suivant :
m moins de 10 pneus achets, aucune remise ;
m 10-49 pneus achets, 5 % de remise ;
m 50-99 pneus achets, 10 % de remise ;
m 100 pneus achets ou plus, 15 % de remise.
Nous pouvons crire le code pour calculer la remise accorde en utilisant des conditions et
des instructions if et elseif, ainsi que loprateur ET (&&) pour combiner deux conditions :
if( $qte_pneus < 10 )
$remise = 0;
elseif( $qte_pneus >= 10 && $qte_pneus <= 49 )
$remise = 5;
elseif( $qte_pneus>= 50 && $qte_pneus <= 99 )
$remise = 10;
elseif( $qte_pneus > 100 )
$remise = 15;
Notez que vous pouvez indiffremment crire elseif ou else if (avec ou sans espace
intermdiaire).
Dans cette cascade dinstructions elseif, une seule instruction (ou un seul bloc
dinstruction) sera excute. Ce point na pas dimportance dans ce cas prcis parce que
Chapitre 1 PHP : les bases 53

les diffrentes conditions spcifies sexcluent mutuellement les unes des autres (une
seule est vraie un moment donn). En revanche, lorsque plusieurs conditions dun
ensemble peuvent tre vraies simultanment, seule linstruction (ou le bloc dinstructions)
qui suit la premire condition value comme vraie sera excute.

Instructions switch
Une instruction switch est comparable une instruction if, si ce nest quelle permet
dimplmenter une condition susceptible de prendre plus de deux valeurs diffrentes.
Dans une instruction if, la condition peut tre value soit comme vraie, soit comme
fausse alors quavec une instruction switch la condition peut prendre diffrentes
valeurs, pourvu quelles soient toutes du mme type (entier, chane ou double). Vous
devez alors faire appel une instruction case pour grer chaque valeur possible de la
condition et ajouter, ventuellement, un cas par dfaut pour prendre en compte toutes
les situations qui ne correspondent aucune des instructions case.
Bob aimerait connatre la forme de publicit qui se rvle la plus profitable son
commerce. cette fin, il souhaite inclure un sondage dans le formulaire de commande.
Insrez ce code HTML dans votre formulaire de commande et vous obtiendrez le rsultat
montr la Figure 1.6 :
<tr>
<td>Comment avez-vous eu connaissance de notre site?</td>
<td><select name="trouver">
<option value = "a">Client rgulier</option>
<option value = "b">Par un spot publicitaire</option>
<option value = "c">Dans un annuaire tlphonique</option>
<option value = "d">Par un ami</option>
</select>
</td>
</tr>

Figure 1.6
Le formulaire de
commande demande
aux visiteurs comment
ils ont connu le site de
Bob.
54 Partie I Utilisation de PHP

Ce code HTML ajoute la variable de formulaire trouver, qui peut prendre les valeurs
"a", "b", "c" ou "d". Son traitement en PHP pourrait seffectuer au moyen dune srie
dinstructions if et elseif, comme ici :
if($trouver == a)
echo <P>Client rgulier.</P>;
elseif($trouver == b)
echo <P>Client attir par un spot TV. </P>;
elseif($trouver == c)
echo <P>Client attir par un annuaire tlphonique. </P>;
elseif($trouver == d)
echo <P>Client attir par un ami. </P>;
else
echo <P>Impossible de savoir comment ce client nous a
trouvs.</P>;

Nous pourrions galement parvenir au mme rsultat avec une instruction switch :
switch($trouver)
{
case a:
echo <P>Client rgulier. </P>;
break;
case b:
echo <P> Client attir par un spot TV. </P>;
break;
case c:
echo <P>Client attir par un annuaire tlphonique. </P>;
break;
case c:
echo <P>Client attir par un ami. </P>;
break;
default:
echo <P>Impossible de savoir comment ce client nous a
trouvs.</P>;
break;
}

Ces deux exemples supposent que vous ayez extrait $trouver du tableau $ POST.
Une instruction switch se comporte un peu diffremment dune instruction if ou dune
instruction elseif. Une instruction if naffecte quune seule instruction, moins quun
bloc de code nait t dlibrment cr avec une paire daccolades. Une instruction
switch a le comportement inverse : lorsquune instruction case dune structure switch
est active, linterprteur PHP excute les instructions qui suivent jusqu rencontrer
une instruction break. En labsence dinstruction break, une structure switch conduit
lexcution de tout le code succdant linstruction case value comme vraie. Lors-
que linterprteur PHP atteint une instruction break, il excute la ligne de code qui suit
la structure switch.
Chapitre 1 PHP : les bases 55

Comparaison des diffrentes structures conditionnelles


Pour le dbutant, le choix entre les diffrentes structures conditionnelles disponibles
peut se rvler ardu.
Le choix de lune ou de lautre est, en effet, assez dlicat puisque tout processus qui
peut tre implment au moyen dinstructions else, elseif ou switch peut galement
ltre au moyen dune srie dinstructions if. Essayez dadopter la structure condition-
nelle qui soit la plus lisible dans le contexte du problme trait. Cest ensuite lexp-
rience qui vous permettra de trouver les rponses les plus appropries.

Structures de rptition : itrations


Les ordinateurs sont particulirement apprciables lorsquil sagit daccomplir de
manire automatique des tches rptitives. Si une action doit tre entreprise de la
mme manire plusieurs fois de suite, vous pouvez utiliser une boucle pour rpter
lexcution dun mme fragment de code au sein dun programme.
Bob veut afficher un tableau donnant le cot dexpdition de la commande, qui sera
ajout la commande du client. Ce cot dexpdition dpend de la distance parcourue
par la commande entre lentrept et le client et peut tre calcul par une simple formule.
Le rsultat recherch est montr la Figure 1.7.

Figure 1.7
Ce tableau donne les
frais dexpdition en
fonction de la distance.

Le Listing 1.2 contient le code HTML qui produit ce tableau. Vous pouvez constater
quil est long et rptitif.

Listing 1.2 : freight.html Code HTML gnrant le tableau des cots dexpdition
pays par Bob

<html>
<body>
<table border ="0" cellpadding ="3">
<tr>
56 Partie I Utilisation de PHP

<td bgcolor ="#CCCCCC" align ="center">Distance</td>


<td bgcolor ="#CCCCCC" align ="center">Cot</td>
</tr>
<tr>
<td align =right>50</td>
<td align =right>5</td>
</tr>
<tr>
<td align =right>100</td>
<td align =right>10</td>
</tr>
<tr>
<td align =right>150</td>
<td align =right>15</td>
</tr>
<tr>
<td align =right>200</td>
<td align =right>20</td>
</tr>
<tr>
<td align =right>250</td>
<td align =right>25</td>
</tr>
</table>
</body>
</html>

Du fait de sa structure rptitive, ce code HTML pourrait tre gnr partir dun script
plutt que manuellement. Nous disposons pour cela des structures de rptition qui
permettent dexcuter une instruction ou un bloc de code de manire rptitive.

Boucles while
La boucle while est la structure de rptition la plus simple de PHP. Tout comme
une structure if, elle repose sur le test dune condition. Une boucle while diffre
toutefois dune structure if par le fait quelle excute le bloc de code qui la suit tant
que la condition reste vraie alors quune structure if nexcute quune fois ce bloc
de code si la condition est vraie. Une boucle while sutilise en gnral lorsquon
ignore le nombre de rptitions effectuer pour faire passer la condition de "vrai"
"faux". Lorsque le nombre de rptitions est connu lavance, mieux vaut employer
une boucle for.
Voici la structure de base dune boucle while :
while( condition ) expression;

La boucle while qui suit produit laffichage des nombres compris entre 1 et 5 :
$nbre = 1;
while ($nbre <= 5 )
Chapitre 1 PHP : les bases 57

{
echo $nbre . "<BR />";
$nbre++;
}

La condition est teste avant chaque itration : si elle est fausse, le bloc nest pas
excut et lexcution de la boucle prend fin. Linterprteur PHP passe alors linstruction
qui suit la boucle while.
Nous pouvons utiliser une boucle while pour accomplir une tche un peu plus utile,
comme afficher le tableau des cots dexpdition montr la Figure 1.7.
Le code donn dans le Listing 1.3 utilise une boucle while pour gnrer le tableau des
frais dexpdition.

Listing 1.3 : freight.php Gnration du tableau des frais dexpdition en PHP

<html>

<body>
<table border="0" cellpadding="3">
<tr>
<td bgcolor="#CCCCCC" align="center">Distance</td>
<td bgcolor="#CCCCCC" align="center">Cot</td>
</tr>
<?php
$distance = 50;
while ($distance <= 250 )
{
echo "<tr>\n <td align=right>$distance</td>\n";
echo " <td align =right>". $distance / 10 ."</td>\n</tr>\n";
$distance += 50;
}
?>
</table>
</body>
</html>

Pour que le code HTML produit par ce script soit plus lisible, vous devez ajouter des
sauts de lignes et des espaces. Comme on la dj voqu, les navigateurs les ignore-
ront, mais ils seront utiles aux lecteurs. Examinez le code HTML produit par vos scripts
pour vous assurer quil reste lisible.
Dans le Listing 1.3, vous pouvez constater que lon a ajout la squence \n dans certai-
nes chanes. Cette squence reprsente le caractre de nouvelle ligne et produira donc
un saut de ligne lorsquil sera affich.
58 Partie I Utilisation de PHP

Boucles for et foreach


Lemploi que nous avons fait de la boucle while dans lexemple prcdent est trs
classique. Nous avons dfini un compteur au dbut de la boucle. Avant chaque itration, le
compteur est test par une condition. la fin de chaque itration, le compteur est
modifi.
Il est possible dcrire ce style de boucle de manire plus compacte avec une boucle
for.
La structure dune boucle for est la suivante :
for( expression1; condition; expression2)
expression3;

m expression1 est excute une fois au dbut de la boucle et contient normalement la


valeur initiale dun compteur.
m Lexpression condition est teste avant chaque itration. Si condition se rvle
fausse, lexcution de la boucle sinterrompt. Cette expression est gnralement
utilise pour tester si le compteur a atteint une certaine limite.
m expression2 est excute la fin de chaque itration et cest gnralement l que
lon met jour la valeur du compteur.
m expression3 est excute une fois par itration. Cette expression est gnralement
un bloc de code et constitue le corps de la boucle.
Nous pouvons rcrire la boucle while du Listing 1.3 avec une boucle for. Le code
PHP devient alors :
<?php
for($distance = 50; $distance <= 250; $distance += 50)
{
echo "<tr>\n <td align=right>$distance</td>\n";
echo " <td align=right>". $distance / 10 ."</td>\n</tr>\n";
}
?>

Les deux versions proposes ici, avec une boucle while et avec une boucle for, sont
identiques dun point de vue fonctionnel mais la boucle for apparat lgrement plus
compacte (elle contient deux lignes de moins que la boucle while).
Ces deux types de boucles sont quivalents : aucun nest meilleur que lautre. Dans
chaque situation, il vous appartient de choisir celui qui vous semble le plus intuitif.
Notez quil est possible de combiner des variables dynamiques avec une boucle for
pour traiter automatiquement une suite de champs de formulaire. Si, par exemple, le
Chapitre 1 PHP : les bases 59

formulaire contient des champs nom1, nom2, nom3, etc., vous pouvez implmenter leur
traitement de la manire suivante :
for ($i=1; $i <= $nbre_noms; $i++)
{
$temp= "nom$i";
echo $$temp.<br />; // ou tout autre traitement ncessaire
}

En crant dynamiquement les noms des variables, nous pouvons accder successivement
aux diffrents champs du formulaire.
Signalons quil existe galement une boucle foreach spcifiquement conue pour les
tableaux. Nous montrerons comment lutiliser au Chapitre 3.

Boucles dowhile
Le dernier type de boucle quil nous reste tudier a un comportement lgrement
diffrent. La structure gnrale dune boucle dowhile est la suivante :
do
expression;
while( condition );

Une boucle dowhile diffre dune boucle while en ce que sa condition est teste la
fin de chaque itration. Il sensuit que dans une boucle dowhile linstruction ou le bloc
formant le corps de la boucle est systmatiquement excut une fois au moins.
Dans lexemple qui suit, o la condition se rvle fausse demble et ne peut jamais tre
vraie, la boucle est excute une premire fois avant que la condition ne soit value et
que lexcution de la boucle prenne fin :
$nbre = 100;
do
{
echo $nbre . <BR />;
}
while ($nbre < 1 );

Interruption de lexcution dune structure de contrle


ou dun script
Pour interrompre lexcution dun morceau de code, trois approches sont envisageables,
selon leffet recherch.
Pour arrter lexcution dune boucle, vous pouvez utiliser linstruction break, comme
nous lavons dj fait dans la section traitant de la structure switch. Lorsquune instruc-
tion break est insre dans une boucle, lexcution du script se poursuit la ligne du
script qui suit la boucle.
60 Partie I Utilisation de PHP

Pour interrompre lexcution dune itration dune boucle et passer directement


litration suivante, vous pouvez employer linstruction continue.
Pour interrompre dfinitivement lexcution dun script PHP, vous pouvez utiliser
linstruction exit. Celle-ci est particulirement utile lors du traitement des erreurs.
Lexemple donn plus haut pourrait ainsi tre modifi de la manire suivante :
if( $qte_totale == 0)
{
echo Votre commande ne contient aucun article!<br>;
exit;
}

Lappel de la fonction exit empche linterprteur PHP dexcuter le reste du script.

Employer lautre syntaxe des structures de contrle


Pour toutes les structures de contrle que nous avons examines, il existe une syntaxe
alternative. Elle consiste remplacer laccolade ouvrante ({) par un signe deux points
(:) et laccolade fermante par un nouveau mot-cl, qui sera endif, endswitch,
endwhile, endfor ou endforeach, selon la structure de contrle utilise. Aucune
syntaxe alternative nest propose pour les boucles do...while.
Par exemple, le code suivant :
if( $qte_totale == 0)
{
echo Votre commande ne contient aucun article!<br />;
exit;
}

pourrait tre converti dans cette nouvelle syntaxe en utilisant les mots-cls if et endif :
if( $qte_totale == 0):
echo Votre commande ne contient aucun article!<br />;
exit;
endif;

Utiliser declare
Une autre structure de contrle de PHP, la structure declare, nest pas utilise aussi
frquemment pour la programmation quotidienne que ne le sont les autres structures.
La forme gnrale de cette structure de contrle est la suivante :
declare (directive)
{
// bloc
}
Chapitre 1 PHP : les bases 61

Cette structure sert dfinir des directives dexcution pour le bloc de code autrement
dit, des rgles spcifiant de quelle manire le code qui suit doit tre excut. Actuelle-
ment, seule une directive dexcution, appele ticks, a t implmente. Elle se dfinit
en insrant la directive ticks=n et vous permet dexcuter une fonction spcifique
toutes les n lignes dans le bloc de code, ce qui est principalement utile pour le profilage
et le dbogage.
La structure de contrle declare nest mentionne ici que par souci dexhaustivit.
Nous prsenterons quelques exemples concernant lutilisation des fonctions tick aux
Chapitres 23 et 24.

Prochaine tape : enregistrement de la commande du client


Vous savez prsent recevoir et manipuler la commande dun client. Au cours du
prochain chapitre, nous verrons comment enregistrer cette commande de sorte
pouvoir la retrouver et la traiter ultrieurement.
2
Stockage et rcupration
des donnes

Maintenant que vous savez accder aux donnes saisies dans un formulaire HTML et
manipuler ces donnes, nous pouvons examiner les moyens de stockage de ces infor-
mations qui permettent de les retrouver et de les utiliser ultrieurement. Dans notre
exemple, les commandes passes en ligne par les clients doivent tre enregistres, de
sorte pouvoir les traiter et les satisfaire ultrieurement.
Dans ce chapitre, nous verrons comment, dans le contexte de lexemple prcdent,
crire dans un fichier la commande transmise par un client et comment la lire ensuite
partir de ce fichier. Nous verrons galement quun tel stockage ne constitue pas toujours
une bonne solution. Si le nombre de commandes est lev, lemploi dun systme de
gestion de base de donnes comme MySQL devient indispensable.

Stockage des donnes en vue dun usage ultrieur


Deux modes de stockage des donnes sont envisageables : dans des fichiers "plats" ou
dans une base de donnes.
Un fichier plat peut tre enregistr sous de nombreux formats. En gnral, toutefois,
lexpression "fichier plat" dsigne un simple fichier texte. Dans notre exemple, nous
crirons les commandes client dans un fichier texte, raison dune commande par ligne.
Ce mode de stockage est trs simple mettre en uvre mais se rvle assez limit,
comme nous le verrons un peu plus loin dans ce chapitre. Si les informations traiter
atteignent un certain volume, lusage dune base de donnes est fortement recommand.
Les fichiers plats restent nanmoins trs utiles dans certaines situations et mritent que
vous sachiez les manipuler.
64 Partie I Utilisation de PHP

Lcriture et la lecture dans des fichiers seffectuent quasiment de la mme manire


dans tous les langages de programmation. Si vous connaissez un peu la program-
mation C ou les scripts shell Unix, les principes dcrits ici vous seront donc trs
familiers.

Stockage et rcupration des commandes de Bob


Dans ce chapitre, nous considrerons une version lgrement modifie du formulaire de
commande examin dans le premier chapitre. Nous partirons de ce formulaire et du
code PHP que nous avons crit pour traiter les donnes entres par les clients.

INFO
Vous trouverez tous les scripts HTML et PHP utiliss dans ce chapitre dans le rpertoire
chapitre 02 tlcharger sur le site Pearson.

Nous avons modifi le formulaire pour lui ajouter un champ permettant de saisir
ladresse de livraison du client (voir Figure 2.1).

Figure 2.1
Dans cette version du for-
mulaire de commande
de lentreprise de Bob,
un champ supplmentaire
est propos pour la saisie
de ladresse de livraison.

Le champ de formulaire pour ladresse de livraison sappelle adresse:, vous pouvez


donc accder sa valeur via $ REQUEST[adresse], $ POST[adresse] ou
$ GET[adresse], selon la mthode de soumission du formulaire (pour plus dinfor-
mations, consultez le Chapitre 1). Nous crirons dans le mme fichier chaque nouvelle
commande transmise par un client. Puis nous construirons une interface web grce
laquelle lquipe de Bob pourra visualiser les commandes reues.
Chapitre 2 Stockage et rcupration des donnes 65

Prsentation des fonctions de traitement des fichiers


Lcriture dans un fichier seffectue en trois tapes :
1. Ouverture du fichier. Si le fichier nexiste pas encore, il doit tre cr.
2. criture des donnes dans le fichier.
3. Fermeture du fichier.
De la mme manire, la lecture des donnes dun fichier seffectue en trois tapes :
1. Ouverture du fichier. Si louverture du fichier se rvle impossible (par exemple
parce que le fichier nexiste pas), nous devons le dtecter et interrompre correctement
le processus engag.
2. Lecture des donnes dans le fichier.
3. Fermeture du fichier.
Lors de la lecture de donnes dans un fichier, vous pouvez prciser la proportion du
fichier qui sera lue chaque opration de lecture. Nous allons dcrire en dtail les diff-
rentes possibilits qui se prsentent.
Pour linstant, commenons par ouvrir un fichier.

Ouverture dun fichier


En PHP, louverture dun fichier seffectue au moyen de la fonction fopen(). Lors de
louverture dun fichier, vous devez spcifier le mode douverture, cest--dire la
manire dont vous voulez lutiliser.

Modes douverture des fichiers


Lorsque vous ouvrez un fichier, vous devez vous prononcer sur trois points :
1. Vous avez la possibilit douvrir un fichier en lecture seule, en criture seule, ou
bien encore en lecture et en criture.
2. Pour crire des donnes dans le fichier, vous pouvez soit remplacer le contenu exis-
tant par vos nouvelles donnes ("craser" le contenu), soit ajouter les nouvelles
donnes la suite du contenu existant. Vous pourriez galement souhaiter terminer
votre programme de manire contrle au lieu dcraser un fichier si le fichier existe
dj.
3. Si vous crivez un fichier dans un systme qui diffrencie les fichiers binaires des
fichiers texte, vous devez spcifier le type souhait pour votre fichier.
La fonction fopen() permet de spcifier vos choix concernant ces trois points.
66 Partie I Utilisation de PHP

Utilisation de fopen() pour ouvrir un fichier


Supposons que nous voulions enregistrer une commande client dans le fichier regrou-
pant les commandes de lentreprise de Bob. Nous pouvons ouvrir ce fichier en criture
de la manire suivante :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", w);

Lorsquelle est invoque, la fonction fopen() attend deux, trois ou quatre paramtres.
Le plus souvent, vous nen donnerez que deux, comme dans la ligne de code prc-
dente.
Le premier paramtre est le nom du fichier ouvrir. Ce nom peut ventuellement conte-
nir un chemin daccs, comme dans linstruction prcdente (le fichier orders.txt est
enregistr dans le rpertoire orders). Nous avons utilis la variable prdfinie de PHP
$ SERVER[DOCUMENT ROOT] mais, comme il est peu pratique de manipuler des variables
aux noms longs, nous lui avons attribu un nom abrg.
Cette variable pointe sur la racine de larborescence des documents du serveur web. La
paire de points ("..") signifie "le rpertoire pre du rpertoire racine des documents" :
ce rpertoire est donc situ lextrieur de larborescence des documents pour des
raisons de scurit. En effet, ce fichier doit demeurer inaccessible partir du Web, sauf
par le biais de linterface que nous allons fournir cet effet. Un tel chemin daccs est
qualifi de relatif, parce quil dcrit un emplacement dans le systme de fichier par
rapport la racine de larborescence des documents.
Puisque nous prfrons utiliser le style abrg pour le rfrencement des variables, il
nous faut ajouter la ligne suivante au dbut de notre script :
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];

pour copier le contenu de la variable exprime dans le style long dans une variable au
nom abrg.
De la mme faon que nous disposons de plusieurs possibilits pour accder des
donnes de formulaire, il y a diffrentes possibilits pour accder aux variables prdfi-
nies du serveur. Selon la configuration de votre serveur, vous pouvez dsigner la racine
de larborescence des documents par :
m $ SERVER[DOCUMENT ROOT]
m $DOCUMENT ROOT
m $HTTP SERVER VARS[DOCUMENT ROOT]
Comme pour les donnes de formulaire, nous conseillons dutiliser le premier style.
Il est galement possible dindiquer un chemin daccs absolu, cest--dire partant du
rpertoire racine (/ dans un systme Unix et gnralement C:\ dans un systme
Chapitre 2 Stockage et rcupration des donnes 67

Windows). Sur notre serveur Unix, ce chemin serait de la forme /home/book/orders.


Le problme de cette approche, surtout si vous faites hberger votre site sur le serveur
dun tiers, est que le chemin absolu peut changer. Nous lavons appris nos dpens
lorsque les administrateurs systme ont dcid de modifier la structure des rpertoires
sans crier gare et quil nous a fallu prcipitamment changer les chemins absolus dans un
grand nombre de scripts.
Lorsque aucun chemin daccs nest spcifi, le fichier est cr ou recherch dans le
mme rpertoire que celui contenant le script. Ce comportement peut toutefois diffrer
si PHP est excut par le biais dun wrapper CGI ; il dpend aussi de la configuration du
serveur.
Dans un environnement Unix, vous devez utiliser des barres obliques ( /) dans les
chemins daccs aux rpertoires tandis que, sur une plate-forme Windows, vous pouvez
aussi bien employer des barres obliques que des barres obliques inverses ( \). Si vous
utilisez des barres obliques inverses lors dun appel fopen, vous devez les "protger"
pour quelles soient correctement interprtes. Pour cela, il suffit de doubler les barre
obliques inverses, comme ici :
$fp = fopen("$DOCUMENT_ROOT\\..\\orders\\orders.txt", w);

Trs peu de gens utilisent des barres obliques inverses (pour faire court, on les appelle
souvent antislashes) pour spcifier des chemins daccs en PHP car le code qui en
rsulte ne pourrait sexcuter que sur Windows. Si vous utilisez des barres obliques, au
contraire, votre code fonctionnera sans modification aussi bien sur des ordinateurs
Windows quUnix.
Le deuxime paramtre passer la fonction fopen() est le mode douverture du
fichier, qui doit tre spcifi sous la forme dune chane. Celui-ci indique lusage prvu
pour le fichier. Dans lexemple considr ici, nous avons utilis la valeur w, ce qui
signifie que le fichier doit tre ouvert en criture. Le Tableau 2.1 rcapitule les diff-
rents modes douverture disponibles.

Tableau 2.1 : Rcapitulatif des diffrents modes douverture dun appel fopen

Mode Nom du mode Signification


r Lecture Le fichier est ouvert en lecture, partir de son dbut.
r+ Lecture Le fichier est ouvert en lecture et en criture, partir de
son dbut.
w criture Le fichier est ouvert en criture, partir de son dbut. Si le
fichier existe dj, son contenu est cras. Dans le cas
contraire, le fichier est cr.
68 Partie I Utilisation de PHP

Tableau 2.1 : Rcapitulatif des diffrents modes douverture dun appel fopen (suite)

Mode Nom du mode Signification


w+ criture Le fichier est ouvert en criture et en lecture, partir de
son dbut. Si le fichier existe dj, son contenu est cras.
Dans le cas contraire, le fichier est cr.
x criture prudente Le fichier est ouvert en criture, partir de son dbut. Si le
fichier existe dj, il nest pas ouvert : fopen() renvoie
false et PHP produit un avertissement.
x+ criture prudente Le fichier est ouvert en criture et en lecture, partir de
son dbut. Si le fichier existe dj, il nest pas ouvert :
fopen() renvoie false et PHP produit un avertissement.
a Ajout Le fichier est ouvert en ajout (criture) uniquement, en
commenant la fin du contenu existant. Si le fichier
nexiste pas, PHP tente de le crer.
a+ Ajout Le fichier est ouvert en ajout (criture) et lecture, en
commenant la fin du contenu existant. Si le fichier
nexiste pas, PHP tente de le crer.
b Binaire Utilis en conjonction avec lun des autres modes
douverture dans les systmes de fichiers faisant la
distinction entre les fichiers binaires et les fichiers texte
(cest le cas des systmes Windows, mais pas dUnix).
Les dveloppeurs PHP recommandent dutiliser toujours
cette option pour une portabilit optimale. Il sagit du
mode par dfaut.
t Texte Utilis en conjonction avec lun des autres modes. Il nest
propos en option que sur les systmes Windows et nous
dconseillons de lutiliser, sauf avant davoir port votre
code pour quil fonctionne avec loption b.

Le choix du mode douverture dpend de la manire dont le systme doit tre utilis.
Dans lexemple donn ici, le choix du mode "w" implique que le fichier ne pourra conte-
nir quune seule commande client la fois : chaque entre dune nouvelle commande,
la commande existante sera efface et remplace par la nouvelle. Ce choix nest
videmment pas le plus judicieux et le mode "a" apparat plus appropri (avec le mode
binaire, selon la recommandation) :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);

Le troisime paramtre de fopen() est facultatif. Il permet de rechercher un fichier dans


la liste des rpertoires indique par include path (qui est dfinie dans la configuration
Chapitre 2 Stockage et rcupration des donnes 69

de PHP ; voir lAnnexe A). Pour effectuer une telle recherche, le troisime param-
tre doit valoir 1. Si vous demandez PHP de se servir de la valeur du paramtre
include path, il est inutile de fournir un nom de rpertoire ou un chemin daccs :
$fp = fopen(orders.txt, ab, true);

Le quatrime paramtre est galement facultatif. La fonction fopen() permet aux noms
de fichiers dtre prfixs avec un protocole (comme http://) et ouverts un emplace-
ment distant. Certains protocoles autorisent un paramtre supplmentaire. Nous traiterons
de cet usage de la fonction fopen() dans les sections suivantes de ce chapitre.
Si fopen() russit ouvrir le fichier, elle renvoie une ressource qui est un descripteur
du fichier et qui doit tre enregistr dans une variable ($fp dans le cas prsent). Cette
variable permet ensuite daccder au fichier pour y lire ou y crire des donnes.

Ouverture de fichiers via FTP ou HTTP


De la mme manire que vous pouvez ouvrir des fichiers locaux en lecture ou en cri-
ture, fopen() vous permet douvrir des fichiers via FTP (File Transfer Protocol) ou
HTTP (Hyper Text Transfer Protocol). Vous pouvez empcher cette fonctionnalit en
dsactivant la directive allow url fopen dans le fichier php.ini. Si vous rencontrez
des problmes pour ouvrir les fichiers distants avec fopen(), vrifiez votre fichier
php.ini.
Lorsque le nom de fichier utilis commence par ftp://, une connexion FTP en mode
passif est ouverte sur le serveur indiqu et fopen() renvoie un pointeur sur le dbut du
fichier.
Lorsque le nom de fichier utilis commence par http://, une connexion HTTP est
ouverte sur le serveur indiqu et fopen() renvoie un pointeur sur la rponse fournie. Si
vous utilisez le mode HTTP avec danciennes versions de PHP, vous devez terminer les
noms de rpertoires par des barres obliques, comme ici :
http://www.example.com/

Ncrivez pas :
http://www.example.com

Avec cette dernire formulation (sans barre oblique finale), le serveur web effectuera
normalement une redirection HTTP de sorte vous renvoyer vers la premire adresse
(avec la barre oblique finale). Faites lessai avec votre navigateur.
Notez bien que la casse (lusage de minuscules/majuscules) na pas dimportance
dans les noms de domaines mais peut en avoir dans les noms et chemins daccs des
fichiers.
70 Partie I Utilisation de PHP

Problmes douverture de fichiers


Une des erreurs les plus frquemment commises louverture des fichiers consiste
essayer douvrir un fichier sans bnficier de la permission adquate. Cette erreur
survient couramment sur les systmes dexploitation de type Unix, mais vous pouvez
galement la voir apparatre occasionnellement sous Windows. Dans une telle situation
derreur, PHP envoie un avertissement comme celui de la Figure 2.2.

Figure 2.2
PHP affiche un avertissement explicite lorsque louverture dun fichier est impossible.

Face une telle erreur, vous devez vrifier que lutilisateur sous le compte duquel le script
sexcute bnficie des permissions daccs adquates pour le fichier utiliser. Selon la
manire dont est configur votre serveur, le script peut tre excut sous le compte du
serveur web ou sous celui du propritaire du rpertoire contenant le script.
Dans la plupart des systmes, les scripts sont excuts sous le compte du serveur web.
Si, par exemple, votre script est plac dans le rpertoire ~/public_html/chapitre02/ dun
systme Unix, vous pouvez crer un rpertoire accessible tout le monde en criture
afin dy stocker la commande :
mkdir ~/orders
chmod 777 ~/orders
Chapitre 2 Stockage et rcupration des donnes 71

Gardez bien lesprit le danger que constituent les rpertoires et les fichiers dans
lesquels tout le monde peut crire. Vous devez imprativement viter dautoriser lcri-
ture dans des rpertoires directement accessibles partir du Web. Cest pour cette raison
que, dans lexemple dcrit ici, le rpertoire orders se situe deux sous-rpertoires en
amont, sous le rpertoire public_html. Nous aborderons plus en dtail cet aspect de la
scurit au Chapitre 13.
Si un mauvais paramtrage des permissions daccs constitue lerreur la plus commune
lors de louverture dun fichier, dautres erreurs peuvent galement tre commises.
Lorsquun fichier ne peut pas tre ouvert, il est capital que vous en soyez inform, pour
viter de tenter dy lire ou dy crire des donnes.
Lorsque lappel de la fonction fopen() choue, celle-ci renvoie la valeur false. Vous
pouvez alors traiter lerreur survenue avec plus de convivialit en supprimant le
message derreur PHP et en produisant votre propre message derreur :
@ $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);

if (!$fp)
{
echo <p><strong>Nous ne pouvons pas traiter votre commande .
pour le moment. Ressayez plus tard.</strong></p> .
</body></html>;
exit;
}

La prsence du symbole @ avant lappel de la fonction fopen() informe PHP quil doit
supprimer toute erreur produite par lappel la fonction. Il est gnralement prfrable
dtre inform lorsquun problme survient mais, dans le cas prsent, nous nous occu-
perons des erreurs un autre endroit du script.
Cette ligne peut galement tre crite de la manire suivante :
$fp = @fopen("$DOCUMENT_ROOT/../orders/orders.txt", a);

Mais cette formulation rend moins vident le recours loprateur de suppression des
erreurs.
La mthode dcrite ici est un moyen trs simple de grer les erreurs. Nous prsenterons
une mthode plus lgante au Chapitre 7. Chaque chose en son temps.
Linstruction if teste la variable $fp pour dterminer si lappel fopen a renvoy un
descripteur de fichier valide. Si ce nest pas le cas, elle affiche un message derreur et
interrompt lexcution du script. La page se terminant alors ce stade, nous avons
inclus les balises de fermeture HTML appropries de manire produire un code
HTML valide.
72 Partie I Utilisation de PHP

Avec cette dernire approche, le rsultat obtenu lexcution du script est celui de la
Figure 2.3.

Figure 2.3
Pour plus de convivia-
lit, vous pouvez
afficher vos propres
messages derreur
la place des avertis-
sements produits par
PHP.

criture dans un fichier


Lcriture dans un fichier est une opration assez simple raliser en PHP. Vous pouvez
utiliser lune ou lautre des fonctions fwrite() et fputs() ; la seconde est un alias de la
premire. Dans notre exemple, lappel fwrite() peut seffectuer de la manire
suivante :
fwrite($fp, $chaine_sortie);
Cette instruction demande linterprteur PHP dcrire la chane stocke dans la variable
$chaine sortie dans le fichier dcrit par $fp.
La fonction file put contents() est une alternative fwrite(). Elle possde le
prototype suivant :
int file_put_contents ( string nomfichier,
string donnees
[, int drapeaux
[, resource contexte]])
Cette fonction crit la chane contenue dans donnees dans le fichier nomfichier sans
requrir dappel la fonction fopen() (ni fclose()). Cette fonction est apparue avec
PHP5, tout comme file get contents() que nous prsenterons bientt. Les param-
tres facultatifs drapeaux et contexte sont le plus souvent utiliss lors de lcriture vers
des fichiers distants en utilisant par exemple HTTP ou FTP (nous prsenterons ces
fonctions au Chapitre 18).
Chapitre 2 Stockage et rcupration des donnes 73

Paramtres de la fonction fwrite()


La fonction fwrite() prend trois paramtres, le troisime tant facultatif. Le prototype
de fwrite() est le suivant :
int fputs(resource descripteur, string chane[, int longueur]);

Le troisime paramtre, longueur, indique le nombre maximal doctets crire. Lors-


que ce paramtre est fourni, la fonction fwrite() crit le contenu de chane dans le
fichier dcrit par descripteur, jusqu atteindre la fin de la chane ou jusqu avoir crit
le nombre doctets spcifi dans longueur.
Vous pouvez connatre la longueur dune chane en utilisant la fonction intgre
strlen() de PHP, comme ceci :
fwrite($fp, $chaine_sortie, strlen($chaine_sortie));

Vous pouvez utiliser ce troisime paramtre lors de lcriture en mode binaire, car il
permet dviter certains problmes de compatibilit entre les plates-formes.

Formats de fichiers
Lors de la cration dun fichier de donnes comme celui que nous avons cr dans notre
exemple, le choix du format de stockage des donnes vous appartient (bien sr, si vous
prvoyez dutiliser le fichier de donnes avec une autre application, vous devez en tenir
compte dans votre choix).
Construisons une chane reprsentant un enregistrement dans notre fichier de donnes.
Nous pouvons procder comme ceci :
$chaine_sortie = "$date\t$qte_pneus pneus\t$qte_huiles bidons " .
"dhuile\t$qte_bougies bougies\t$montant_total \t" .
"$adresse\n";

Dans cet exemple simple, chaque commande est stocke dans une ligne distincte du
fichier des commandes. Lcriture dun enregistrement par ligne nous permet en effet
dutiliser un sparateur denregistrement simple : le caractre de nouvelle ligne. Les
caractres de nouvelle ligne sont invisibles et sont reprsents par la squence "\n".
Pour chaque nouvelle commande, les champs de donnes sont crits dans le mme
ordre et sont distingus les uns des autres par le caractre de tabulation, reprsent par
la squence "\t". Mieux vaut choisir un dlimiteur de champ qui facilite ensuite la
rcupration des donnes.
Le sparateur ou dlimiteur doivent tre des caractres peu susceptibles dtre contenus
dans les donnes entres, faute de quoi nous devrions traiter ces donnes pour retirer ou
protger toutes les instances du dlimiteur. Nous reviendrons sur le traitement des
donnes fournies en entre au Chapitre 4. Pour lheure, nous supposerons quaucun
client na introduit de tabulation au cours de sa saisie dans le formulaire de commande.
74 Partie I Utilisation de PHP

Il est difficile, mais pas impossible, quun utilisateur dun formulaire HTML insre une
tabulation ou un saut de ligne dans un champ de saisie HTML dune seule ligne.
En utilisant un sparateur de champ spcial, nous pourrons par la suite scinder plus
facilement les donnes en variables distinctes lorsque nous voudrons rcuprer les
donnes contenues dans le fichier. Nous reviendrons sur ce point au Chapitre 3. Pour
linstant, nous nous contenterons de traiter chaque commande comme une chane dun
seul tenant.
Le Listing 2.1 donne un exemple du contenu du fichier orders.txt aprs lcriture de
quelques commandes.

Listing 2.1 : orders.txt Exemple de contenu possible

20:30, le 31-03 4 pneus 1 bidons dhuile 6 bougies 434.00 22 rue de la pompe, Paris
20:42, le 31-03 1 pneus 0 bidons dhuile 0 bougies 100.00 33 grande rue, Toulouse
20:43, le 31-03 0 pneus 1 bidons dhuile 4 bougies 26.00 27 rue des acacias, Bordeaux

Fermeture dun fichier


Lorsque vous en avez fini avec un fichier, vous devez le fermer au moyen de la fonction
fclose() :
fclose($fp);

La fonction fclose() renvoie la valeur true si la fermeture du fichier a russi, ou false


en cas dchec. Le risque dchec tant moins grand pour une opration de fermeture de
fichier que pour une opration douverture, nous avons choisi ici de ne pas vrifier cette
opration.
Le listing complet de la version finale de processorder.php est prsent dans le
Listing 2.2.

Listing 2.2 : processorder.php Version finale du script de traitement des commandes

<?php
// Cre des noms de variables abrges
$qte_pneus = $_POST[qte_pneus];
$qte_huiles = $_POST[qte_huiles];
$qte_bougies = $_POST[qte_bougies];
$adresse = $_POST[adresse];

$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob Rsultats de la commande</title>
</head>
<body>
Chapitre 2 Stockage et rcupration des donnes 75

<h1>Le garage de Bob</h1>


<h2>Rsultats de la commande</h2>
<?php
$date = date(H:i, \l\e j-m-Y);
echo <p>Commmande traite ;
echo $date;
echo </p>;

echo <p>Rcapitulatif de votre commande:</p>;

$qte_totale = 0;
$qte_totale = $qte_pneus + $qte_huiles + $qte_bougies;
echo Articles commands: . $qte_totale . <br />;

if( $qte_totale == 0)
{
echo "Vous navez rien command!<br />";
}
else
{
if ( $qte_pneus > 0 )
echo $qte_pneus . pneus<br />;
if ( $qte_huiles > 0 )
echo $qte_huiles . " bidons dhuile<br />";
if ( $qte_bougies > 0 )
echo $qte_bougies . bougies<br />;
}

$montant_total = 0.00;

define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(PRIX_BOUGIES, 4);

$montant_total = $qte_pneus * PRIX_PNEUS


+ $qte_huiles * PRIX_HUILES
+ $qte_bougies * PRIX_BOUGIES;

$montant_total = number_format($montant_total, 2, ., );

echo <p>Total de la commande: . $montant_total . </p>;


echo <p>Adresse de livraison: . $adresse . </p>;

$chaine_sortie = "$date\t$qte_pneus pneus\t$qte_huiles bidons " .


"dhuile\t$qte_bougies bougies\t$montant_total \t" .
"$adresse\n";

// Ouverture du fichier en mode ajout


@ $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);

if (!$fp)
{
echo <p><strong>Nous ne pouvons pas traiter votre commande .
pour le moment. Ressayez plus tard.</strong></p> .
</body></html>;
exit;
76 Partie I Utilisation de PHP

fwrite($fp, $chaine_sortie, strlen($chaine_sortie));


fclose($fp);

echo <p>Commande sauvegarde.</p>;


?>
</body>
</html>

Lecture dans un fichier


ce stade de notre projet modle, les clients de Bob peuvent transmettre leurs
commandes via le Web, mais pour que les employs puissent traiter ces commandes ils
doivent pouvoir ouvrir les fichiers qui les contiennent. Nous allons donc crer une inter-
face web qui permettra aux employs de lire facilement ces fichiers. Le code de cette
interface est prsent dans le Listing 2.3.

Listing 2.3 : vieworders.php Interface web pour louverture et la lecture des fichiers

<?php
//cration du nom de variable abrg
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob - Commandes des clients</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Commandes des clients</h2>
<?php
@$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", rb);

if (!$fp)
{
echo <p><strong>Aucune commande en attente.
. Essayez plus tard.</strong></p>;
exit;
}

while (!feof($fp))
{
$commande = fgets($fp, 999);
echo $commande .<br />;
}

fclose($fp);
?>
</body>
</html>
Chapitre 2 Stockage et rcupration des donnes 77

Ce script met en uvre la srie doprations voque prcdemment : ouverture du


fichier, lecture dans le fichier et fermeture du fichier. Son excution avec le fichier de
donnes dcrit dans le Listing 2.1 produit le rsultat montr la Figure 2.4.

Figure 2.4
Lexcution du script
vieworders.php affiche
dans la fentre du navi-
gateur web toutes les
commandes enregistres
dans le fichier orders.txt.

Examinons en dtail les diffrentes fonctions utilises dans ce script.

Ouverture dun fichier en lecture : fopen()


L aussi, louverture du fichier seffectue au moyen de la fonction fopen(). Dans ce
cas, toutefois, on utilise le mode "rb" pour indiquer PHP que le fichier doit tre ouvert
en lecture seule :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", rb);

Dtermination du moment o doit sarrter la lecture : feof()


Dans le Listing 2.3, on se sert dune boucle while pour lire le fichier jusqu la fin.
Cette boucle teste si la fin du fichier est atteinte au moyen de la fonction feof() :
while (!feof($fp))

La fonction feof() prend comme seul paramtre un descripteur de fichier et renvoie


true si ce descripteur est positionn la fin du fichier. Le terme feof est labrviation
de lexpression "File End Of File" (fichier fin de fichier).
Dans notre exemple (comme en gnral dans toutes les situations de lecture dans un
fichier), la lecture du contenu se poursuit jusqu rencontrer la fin du fichier (EOF).

Lecture dune ligne la fois : fgets(), fgetss() et fgetcsv()


Dans le Listing 2.2, on lit le contenu du fichier laide de la fonction fgets() :
$commande= fgets($fp, 999);

La fonction fgets() lit une ligne la fois dans un fichier. Dans notre exemple, la
lecture se poursuit jusqu ce que linterprteur rencontre un caractre de nouvelle ligne
78 Partie I Utilisation de PHP

(\n), EOF ou jusqu ce que 998 octets aient t lus dans le fichier. Le nombre maximal
doctets lus est la longueur indique en deuxime paramtre, moins un.
Vous disposez de plusieurs fonctions pour lire le contenu dun fichier. La fonction
fgets() convient bien pour les fichiers au format texte seul qui doivent tre traits par
morceaux.
La fonction fgetss() constitue une variante intressante de la fonction fgets(). Son
prototype est le suivant :
string fgetss(resource fp, int longueur, string [balises_autorises]);

fgetss() est trs semblable fgets(), si ce nest quelle supprime toutes les balises
PHP et HTML contenues dans la chane lue. Pour empcher la suppression de certaines
balises, il suffit de les numrer dans la chane balises_autorises. La fonction
fgetss() sutilise par mesure de scurit lors de la lecture dun fichier crit par un tiers
ou contenant des donnes saisies par lutilisateur. La prsence de code HTML dans un
fichier peut en effet perturber la mise en forme que vous avez soigneusement mise en
place. Par ailleurs, ne pas vrifier la prsence de code PHP dans un fichier peut permettre
un utilisateur malveillant de prendre le contrle de votre serveur.
La fonction fgetcsv () est une autre variante de la fonction fgets(). Voici son proto-
type :
array fgetcsv ( resource fp, int longueur [, string dlimiteur [,
string encadrement]])

La fonction fgetcsv() semploie pour dcouper les lignes dun fichier en fonction dun
caractre de dlimitation (par exemple un caractre de tabulation comme ici ou une
virgule comme dans de nombreux fichiers produits par les tableurs et dautres applica-
tions). fgetscv() permet, par exemple, de reconstruire sparment les variables dune
commande plutt que les traiter sous la forme dune ligne de texte. Cette fonction
sutilise de la mme manire que fgets(), mais vous devez lui passer en paramtre le
dlimiteur utilis pour sparer les champs. Linstruction :
$commande = fgetcsv($fp, 100, "\t");

provoque la lecture dune ligne du fichier et son dcoupage selon chaque tabulation
(\t). Le rsultat obtenu est renvoy sous forme de tableau ($commande dans le
Listing 2.2). Les tableaux sont traits au Chapitre 3.
La valeur du paramtre longueur doit tre choisie de manire tre suprieure au
nombre de caractres de la ligne la plus longue du fichier lire.
Le paramtre encadrement indique le caractre qui encadre chacun des champs dune
ligne. Sil nest pas prcis, il prend comme valeur par dfaut lapostrophe double ( ").
Chapitre 2 Stockage et rcupration des donnes 79

Lecture de lintgralit du contenu dun fichier : readfile(), fpassthru()


et file()
Au lieu de lire un fichier ligne par ligne, vous pouvez lire son contenu dun seul trait.
Pour cela, vous disposez de quatre possibilits.
La premire mthode consiste utiliser la fonction readfile(). Le code du Listing 2.2
peut alors tre remplac par une seule instruction :
readfile("$DOCUMENT_ROOT/../orders/orders.txt");
Lappel de la fonction readfile() ouvre le fichier, affiche son contenu sur la sortie
standard (le navigateur web), puis ferme le fichier. Cette fonction a le prototype
suivant :
int readfile(string nomFichier, [int utiliser include path[, resource contexte]]);
Le second paramtre de la fonction readfile() est facultatif ; il indique si PHP doit
rechercher le fichier dans le include path. Ce paramtre fonctionne de la mme
manire que pour la fonction fopen(). Le paramtre facultatif contexte nest utilis
que lorsque des fichiers sont ouverts distance, par exemple via HTTP. Nous traiterons
de cette utilisation plus en dtail au Chapitre 18. La fonction readfile() renvoie le
nombre total doctets lus dans le fichier.
La deuxime mthode pour lire lintgralit dun fichier consiste utiliser la fonction
fpassthru(). Dans ce cas, vous devez pralablement ouvrir le fichier avec fopen().
Vous passez ensuite le descripteur de fichier en paramtre fpassthru(), qui renverra
sur la sortie standard le contenu du fichier compris entre la position du pointeur et la fin
du fichier. Cette fonction ferme le fichier une fois quelle en a termin.
Le script du Listing 2.2 peut ainsi tre remplac par les deux instructions suivantes :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", rb);
fpassthru($fp);
Si la lecture russit, la fonction fpassthru() renvoie la valeur true. Elle renvoie false
en cas dchec.
La fonction file () offre une troisime possibilit de lecture de lintgralit du
contenu dun fichier. Cette fonction est identique readfile(), si ce nest quau lieu de
diriger le contenu du fichier vers la sortie standard elle le stocke dans un tableau. Nous
reviendrons sur cette possibilit au Chapitre 3. Notez simplement ce stade que cette
fonction sutilise de la manire suivante :
$tab_contenu = file($DOCUMENT_ROOT/../orders/orders.txt");
Lexcution de cette instruction provoque lenregistrement du contenu du fichier dans
un tableau appel $tab contenu. Chaque ligne du fichier est stocke dans le tableau
sous la forme dun lment distinct. Avec les anciennes versions de PHP, cette fonction
ntait pas compatible avec les formats de fichier binaires.
80 Partie I Utilisation de PHP

Enfin, la quatrime possibilit consiste utiliser la fonction file get contents().


Cette fonction est identique readfile(), sauf quelle renvoie le contenu du fichier
sous la forme dune chane au lieu de lafficher dans le navigateur.

Lecture dun caractre : fgetc()


Le traitement dun fichier peut galement consister lire son contenu caractre par
caractre, au moyen de la fonction fgetc(). Cette fonction prend comme unique para-
mtre un descripteur de fichier et renvoie le caractre suivant dans ce fichier. Nous
pouvons remplacer la boucle while du Listing 2.2 par une boucle utilisant fgetc() :
while (!feof($fp))
{
$car = fgetc($fp);
if (!feof($fp))
echo ($car == "\n"? <br />: $car);
}

Ce code lit un caractre la fois dans le fichier, via fgetc(), et le stocke dans la variable
$car. Le processus se rpte jusqu ce que la fin du fichier soit atteinte. Les caractres
de fin de ligne (\n) sont ensuite remplacs par des sauts de ligne HTML (<br />).
Ce petit traitement vise simplement purer la mise en forme. Si vous essayiez daffi-
cher le fichier en laissant les caractres de nouvelles lignes entre les enregistrements, la
totalit du fichier serait imprime sur une seule ligne (vous pouvez essayer par vous-
mme). En effet, les navigateurs web ignorent les caractres de nouvelles lignes quils
considrent comme des espaces : vous devez donc les remplacer par des sauts de ligne
HTML (<br />). Loprateur ternaire permet deffectuer ce remplacement de faon
simple et lgante.
Lutilisation de la fonction fgetc() au lieu de la fonction fgets() a une consquence
mineure : le caractre EOF est renvoy par la fonction fgetc(), ce qui nest pas le cas
avec la fonction fgets(). Il sensuit quaprs la lecture du caractre il est ncessaire
de tester nouveau feof() pour viter que le caractre EOF ne soit affich par le navi-
gateur.
La lecture dun fichier caractre par caractre na de sens que dans des contextes trs
particuliers, o les caractres doivent tre lus les uns aprs les autres.

Lecture dune longueur arbitraire : fread()


La dernire mthode de lecture dun fichier que nous allons tudier est la fonction
fread(). Celle-ci permet de lire un nombre quelconque doctets dans un fichier.
Le prototype de cette fonction est le suivant :
string fread(resource fp, int longueur);
Chapitre 2 Stockage et rcupration des donnes 81

Cette fonction lit "longueur" octets ou lit jusqu la fin du fichier ou du paquet rseau,
si celle-ci survient avant que longueur octets aient t lus.

Autres fonctions utiles pour la manipulation des fichiers


PHP offre plusieurs autres fonctions qui peuvent se rvler utiles pour manipuler des
fichiers.

Vrification de lexistence dun fichier : file_exists()


La fonction file exists() permet de dterminer si un fichier existe, sans mme
louvrir. En voici un exemple dutilisation :
if (file_exists("$DOCUMENT_ROOT/../orders/orders.txt"))
echo "Des commandes sont en attente de traitement.";
else
echo "Il ny a pas de commande en attente.";

Dtermination de la taille dun fichier: filesize()


La fonction filesize() renvoie la taille dun fichier en octets :
echo filesize("$DOCUMENT_ROOT/../orders/orders.txt");
Vous pouvez utiliser cette fonction avec la fonction fread() pour lire tout un fichier (ou
une fraction dun fichier) dun seul trait. Le code du Listing 2.2 pourrait ainsi tre
remplac par les instructions suivantes :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", rb);
echo nl2br(fread($fp, filesize("$DOCUMENT_ROOT/../orders/orders.txt" )));
fclose( $fp );
La fonction nl2br() convertit les caractres \n en sauts de ligne XHTML (<br />)
dans la sortie.

Suppression dun fichier : unlink()


Si vous souhaitez dtruire le contenu du fichier de commandes aprs lavoir trait, utilisez
la fonction unlink() (PHP ne contient pas de fonction dnomme "delete") :
unlink("$DOCUMENT_ROOT/../orders/orders.txt");
Cette fonction renvoie false lorsque le fichier ne peut pas tre supprim, ce qui peut
arriver si, par exemple, vous navez pas les permissions suffisantes ou si le fichier
nexiste pas.

Navigation dans un fichier : rewind(), fseek() et ftell()


Vous pouvez manipuler et connatre la position du pointeur dans le fichier au moyen des
fonctions rewind(), fseek () et ftell().
82 Partie I Utilisation de PHP

La fonction rewind () dplace le pointeur de fichier au dbut du fichier. La fonction


ftell () renvoie la position du pointeur dans le fichier, en nombre doctets compts
depuis le dbut du fichier. Par exemple, nous pourrions ajouter les lignes suivantes la
fin du Listing 2.2, avant lappel fclose() :
echo La position finale du pointeur de fichier est . (ftell($fp));
echo <br />;
rewind($fp);
echo "Aprs lappel rewind(), cette position is " . (ftell($fp));
echo <br />;
Le rsultat obtenu lexcution du script serait alors celui montr la Figure 2.5.

Figure 2.5
Aprs lecture des commandes, le pointeur de fichier est positionn la fin du fichier, cest--dire
279 octets par rapport au dbut du fichier. Lappel de la fonction rewind replace le pointeur la
position 0, cest--dire au dbut du fichier.

La fonction fseek() permet de dplacer le pointeur de fichier une position spcifique


dans le fichier. Son prototype est le suivant :
int fseek ( resource fp, int offset [, int dpart])
Lappel de la fonction fseek() provoque le dplacement du pointeur de fichier fp de
offset octets par rapport lemplacement dpart. La valeur par dfaut du paramtre
facultatif dpart est SEEK SET, ce qui correspond au dbut du fichier. Les autres valeurs
possibles sont SEEK CUR (lemplacement courant dans le fichier) et SEEK END (la fin du
fichier).
Lappel de la fonction rewind() quivaut donc un appel de la fonction fseek() avec
la valeur 0 pour le paramtre offset. La fonction fseek() peut, par exemple, servir
dterminer lenregistrement qui constitue le milieu dun fichier ou effectuer une
recherche dichotomique. Toutefois, si vous avez besoin de raliser ce genre doprations
sur un fichier de donnes, il est prfrable de recourir une base de donnes.
Chapitre 2 Stockage et rcupration des donnes 83

Verrouillage des fichiers


Considrons une situation o deux clients tentent simultanment de commander un
mme produit (ce cas se produit souvent ds lors que les sites connaissent un minimum
daffluence). Quadvient-il lorsquun client invoque la fonction fopen() et commence
saisir sa commande, tandis quun autre client appelle lui aussi fopen() et entre des
donnes ? Quel est alors le contenu final du fichier ? La premire commande suivie de
la seconde, ou inversement ? Ou le fichier ne contiendra-t-il quune seule des deux
commandes ? Ou bien encore les deux commandes se mlangeront-elles ? La rponse
ces questions dpend du systme dexploitation utilis ; elle est souvent impossible
donner.
Le verrouillage des fichiers permet dviter ce type de problme. Celui-ci est impl-
ment en PHP par la fonction flock(), qui doit tre appele aprs louverture dun
fichier et avant toute lecture ou criture de donnes dans ce fichier.
La fonction flock() a le prototype suivant :
bool flock(resource fp, int operation [, int &blocage_possible])

Vous devez passer la fonction flock() un descripteur de fichier ouvert et une constante
reprsentant le type de verrouillage voulu. Elle renvoie true lorsque le verrouillage
russit et false en cas dchec. Le troisime paramtre facultatif contiendra la valeur
true si lacquisition du verrou entrane le blocage du processus courant (autrement dit,
sil doit attendre).
Le Tableau 2.2 prsente les valeurs possibles pour le paramtre operation. Ces valeurs
ayant t modifies partir de PHP 4.0.1, nous prsentons ici les deux ensembles de
valeurs possibles.

Tableau 2.2 : Valeurs possibles pour le paramtre operation de la fonction flock()

Valeur dopration Signification


LOCK_SH (anciennement 1) Verrouillage en lecture. Le fichier peut tre partag avec
dautres lecteurs.
LOCK_EX (anciennement 2) Verrouillage en criture. Ce type de verrouillage est exclusif :
le fichier ne peut tre partag.
LOCK_UN (anciennement 3) Libre le verrouillage existant.
LOCK_NB (anciennement 4) Verrouillage non bloquant.

Pour que flock() serve quelque chose, vous devez lutiliser dans tous les scripts qui
manipulent le fichier verrouiller.
84 Partie I Utilisation de PHP

Notez que flock() ne fonctionne pas avec NFS (Network File System) ou dautres
systmes de fichiers rseaux. Cette fonction est galement inoprante avec danciens
systmes de fichiers ne prenant pas en charge les verrous (FAT, par exemple). Sur
certains des systmes dexploitation pour lesquels cette fonction est implmente au
niveau processus, le verrouillage obtenu ne sera pas fiable si vous utilisez une API de
serveur multithread.
Pour utiliser les verrous dans notre exemple, nous pouvons modifier processorder.php
de la manire suivante :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);
flock($fp, LOCK_EX); // verrouillage du fichier en criture
fwrite($fp, $chaine_sortie);
flock($fp, LOCK_UN); // libration du verrou en criture
fclose($fp);
Vous devez galement modifier vieworders.php de la manire suivante :
$fp = fopen("$DOCUMENT_ROOT /../orders/orders.txt", rb);
flock($fp, LOCK_SH); // verrouillage du fichier en lecture
// Lecture du fichier
flock($fp, LOCK_UN); // libration du verrou en lecture
fclose($fp);
Grce aux modifications que nous venons dapporter notre exemple, notre code est un
peu plus fiable, mais il ne lest pas encore suffisamment. Que se passera-t-il si deux
scripts tentent simultanment dacqurir un verrou ? Il sensuivra une situation de
concurrence dont lissue ne peut pas tre dtermine. Ce cas de figure peut se rvler
problmatique et tre vit par lemploi dun SGBD (systme de gestion de base de
donnes).

Une meilleure solution : les systmes de gestion de base de donnes


Jusqu prsent, tous les exemples considrs utilisaient des fichiers plats. Dans la
deuxime partie de ce livre, nous verrons comment utiliser MySQL, un systme de
gestion de base de donnes relationnelle (SGBDR).

Problmes poss par lusage de fichiers plats


Lutilisation de fichiers plats pose divers problmes :
m Ds lors quun fichier devient volumineux, sa manipulation peut se rvler trs
lente.
m La recherche dun enregistrement ou dun ensemble denregistrements dans un
fichier plat est une opration difficile. Lorsque les enregistrements sont ordon-
ns, il est possible de mettre en uvre une procdure de recherche tenant compte
des longueurs fixes des champs pour effectuer une recherche sur un champ cl.
Chapitre 2 Stockage et rcupration des donnes 85

Seulement, si vous voulez trouver des motifs dinformation (par exemple lister tous
les clients qui vivent Paris), il vous faudra lire chaque enregistrement et le vrifier
individuellement.
m La gestion des accs concurrents est problmatique. Nous avons vu comment
verrouiller des fichiers, mais nous avons galement mentionn le risque persistant
de situation concurrentielle. Des accs concurrents peuvent galement tre
lorigine de goulots dtranglements. Si le trafic sur le site prend de lampleur, il
peut arriver que de nombreux utilisateurs aient attendre le dverrouillage du
fichier pour valider leur commande. De trop longues attentes font fuir les clients.
m Dans toutes les manipulations de fichiers dcrites jusquici, les traitements taient
mis en uvre de faon squentielle, cest--dire en partant du dbut du fichier et en
parcourant le contenu du fichier jusqu la fin. Sil apparat ncessaire dinsrer ou
de supprimer des enregistrements partir du milieu du fichier (accs direct), le
mode de traitement squentiel peut poser problme : il implique de lire et de placer
en mmoire lintgralit du fichier, dapporter les modifications et de rcrire
nouveau le fichier. La charge du traitement peut alors devenir trs lourde avec des
fichiers de donnes volumineux.
m Au-del de la limite offerte par les permissions sur les fichiers, il nexiste pas de
moyen simple dimplmenter des niveaux daccs diffrents aux donnes.

La solution apporte par les SGBDR ces problmes


Les systmes de gestion de base de donnes relationnelle (SGBDR) apportent des solutions
tous les problmes voqus plus haut :
m Ils permettent daccder bien plus rapidement aux donnes. MySQL, le SGBDR
tudi dans cet ouvrage, est apparu comme le plus rapide du march.
m Ils peuvent tre facilement interrogs afin den extraire des ensembles de donnes
rpondant des critres spcifiques.
m Ils intgrent des mcanismes prenant en charge les accs concurrents, ce qui
dispense le programmeur de sen proccuper.
m Ils permettent un accs direct aux donnes.
m Ils comprennent des systmes de privilges intgrs. MySQL est particulirement
performant dans ce domaine.
Le principal avantage dun SGBDR est que toutes (ou presque) les fonctionnalits
requises pour un systme de stockage des donnes sont dj implmentes. Vous
pouvez bien sr crire votre propre bibliothque de fonctions PHP, mais pourquoi rin-
venter la roue ?
86 Partie I Utilisation de PHP

Dans la Partie II de cet ouvrage, "Utilisation de MySQL", nous examinerons le fonc-


tionnement des bases de donnes relationnelles en gnral et nous verrons plus spcifi-
quement comment configurer et utiliser MySQL pour crer des sites web reposant sur
des bases de donnes.
Si vous mettez en place un systme simple et que vous ne pensiez pas avoir besoin
dune base de donnes sophistique, tout en souhaitant viter le verrouillage et les
autres problmes lis lutilisation dun fichier plat, il peut tre intressant de consid-
rer lextension SQLite de PHP. Cette extension fournit une interface SQL vers les
fichiers plats. Dans ce livre, nous traiterons principalement de lutilisation de MySQL.
Pour plus dinformations sur SQLite, consultez les sites http://sqlite.org/ et http://
www.php.net/sqlite.

Pour aller plus loin


Pour plus dinformations sur linteraction avec le systme de fichiers, vous pouvez vous
reporter directement au Chapitre 17. Ce chapitre explique comment modifier les
permissions et les noms de fichiers, comment travailler avec les rpertoires et comment
interagir avec lenvironnement du systme de fichiers.
Vous pouvez galement consulter la section du manuel en ligne de PHP (http://
fr2.php.net/filesystem) consacre au systme de fichier.

Pour la suite
Au cours du Chapitre 3, nous tudierons les tableaux et nous verrons comment les utiliser
pour traiter des donnes dans des scripts PHP.
3
Utilisation de tableaux

Ce chapitre montre comment utiliser une construction de programmation importante :


les tableaux. Les variables examines dans les chapitres prcdents taient de type
scalaire, cest--dire quelles ne stockaient chacune quune seule valeur. Un tableau, en
revanche, est une variable stockant un ensemble ou une srie de valeurs. Un mme
tableau peut contenir de nombreux lments, chacun deux pouvant tre une valeur
unique, comme un texte ou un nombre, ou un autre tableau. Un tableau comprenant
dautres tableaux est dit "multidimensionnel".
PHP supporte les tableaux indics par des nombres et les tableaux associatifs. Les
tableaux indics par des nombres devraient vous tre familiers si vous avez dj utilis
un langage de programmation. En revanche, vous navez peut-tre jamais vu de
tableaux associatifs, bien que vous ayez pu rencontrer ailleurs des choses similaires,
comme les mappages, les hachages ou les dictionnaires. Les tableaux associatifs
permettent dindicer les lments par des valeurs plus significatives que des nombres :
des mots, par exemple.
Dans ce chapitre, nous poursuivrons la construction de lapplication du garage de Bob
commence dans les chapitres prcdents, en nous servant de tableaux pour faciliter la
manipulation des informations rptitives comme les commandes des clients. Lusage
de tableaux nous permettra dcrire un code plus concis pour raliser certaines des
oprations sur les fichiers du Chapitre 2.

Quest-ce quun tableau ?


Nous avons tudi les variables scalaires au Chapitre 1. Une variable scalaire est un
emplacement de la mmoire dsign par un nom et dans lequel peut tre stocke une
valeur. De la mme manire, un tableau est un emplacement de la mmoire dsign par
88 Partie I Utilisation de PHP

un nom et dans lequel peut tre enregistr un ensemble de valeurs. Un tableau permet
par consquent de regrouper des valeurs scalaires.
Dans lapplication du garage de Bob dont nous avons commenc llaboration, nous
utiliserons un tableau pour stocker la liste des articles vendus. La Figure 3.1 montre une
liste de trois articles regroups dans un tableau nomm $produits (nous verrons un peu
plus loin comment crer une telle variable).

Pneus Huiles Bougies

produit

Figure 3.1
Les articles vendus par lentreprise de Bob peuvent tre enregistrs dans un tableau.

Ds lors que des informations sont enregistres dans un tableau, elles peuvent tre
soumises diverses manipulations trs intressantes. Cest ainsi quavec les construc-
tions de boucles dcrites au Chapitre 1, vous pouvez vous simplifier la tche en effec-
tuant les mmes actions sur chacune des valeurs du tableau. Lensemble des
informations enregistres dans un tableau peut tre manipul comme sil sagissait
dune seule entit. Ainsi, avec une simple ligne de code, toutes les valeurs dun tableau
peuvent tre passes une fonction. Pour, par exemple, trier les articles de Bob par
ordre alphabtique, il nous suffira de passer le tableau qui les contient la fonction
sort().
Les valeurs stockes dans un tableau sont appeles lments du tableau. chaque
lment dun tableau est associ un indice (galement appel cl) qui permet daccder
cet lment.
Dans la plupart des langages de programmation, les tableaux ont des indices numriques
qui commencent gnralement 0 ou 1.
PHP permet dutiliser des nombres ou des chanes comme indices de tableau. Vous
pouvez utiliser des tableaux indics par des nombres, selon la manire traditionnelle, ou
choisir les valeurs que vous souhaitez pour les cls, afin de rendre lindexation plus
comprhensible et utile. Vous avez peut-tre dailleurs dj employ cette technique si
vous avez utilis des tableaux associatifs, des mappages, des hachages ou des diction-
naires dans dautres langages de programmation. Lapproche peut varier lgrement
selon que vous utilisez des tableaux classiques indics par des nombres ou tableaux
indics par des valeurs personnalises. Nous commencerons cette tude par les
tableaux indices numriques avant de passer aux cls dfinies par lutilisateur.
Chapitre 3 Utilisation de tableaux 89

Tableaux indices numriques


Ce type de tableau existe dans la plupart des langages de programmation. En PHP, les
indices commencent par dfaut zro, mais cette valeur initiale peut tre modifie.

Initialisation des tableaux indices numriques


Pour crer le tableau montr la Figure 3.1, utilisez la ligne de code suivante :
$produits = array( Pneus, Huiles, Bougies );

Cette instruction cre un tableau $produits contenant les trois valeurs Pneus,
Huiles et Bougies. Notez que, comme echo, array() est une construction du
langage plutt quune fonction.
Selon le contenu enregistrer dans un tableau, il nest pas forcment ncessaire
dinitialiser manuellement ce contenu comme on la fait dans linstruction prcdente.
Si les donnes placer dans un tableau sont dj contenues dans un autre tableau, il
suffit de copier un tableau dans lautre au moyen de loprateur =.
Une srie de nombres croissants peut tre automatiquement enregistre dans un tableau
grce la fonction range(), qui se charge elle-mme de crer le tableau requis. La ligne
qui suit cre un tableau $nombres dont les lments sont les nombres entiers compris
entre 1 et 10 :
$nombres = range(1,10);

La fonction range() possde un troisime paramtre facultatif qui vous permet de dfi-
nir la taille du pas entre les valeurs. Par exemple, pour crer un tableau des nombres
impairs compris entre 1 et 10, procdez de la manire suivante :
$impairs = range(1, 10, 2);

La fonction range() peut galement tre utilise avec des caractres, comme dans cet
exemple :
$lettres = range(a, z);

Lorsque des informations sont contenues dans un fichier stock sur disque, le tableau
peut tre directement charg partir du fichier. Nous reviendrons sur ce point un peu
plus loin dans ce chapitre, dans la section "Chargement de tableaux partir de fichiers".
Lorsque des informations sont contenues dans une base de donnes, le tableau peut
tre directement charg partir de la base de donnes. Cette possibilit est traite au
Chapitre 11.
PHP offre galement diverses fonctions permettant dextraire des parties dun tableau
ou de rorganiser les lments. Certaines de ces fonctions seront dcrites plus loin dans
ce chapitre, dans la section "Autres manipulations de tableaux".
90 Partie I Utilisation de PHP

Accs au contenu des tableaux


Laccs au contenu dune variable implique dindiquer le nom de cette variable. Pour
accder au contenu dune variable de type tableau, vous devez utiliser le nom de la
variable et une cl (ou un indice). La cl ou lindice indique les valeurs stockes
auxquelles vous voulez accder. La cl ou lindice doivent tre spcifis entre crochets,
juste aprs le nom de la variable.
Par exemple, servez-vous de $produits[0], $produits[1] et $produits[2] pour acc-
der au contenu du tableau $produits.
Par dfaut, llment dindice zro est le premier lment du tableau. Le principe de
numrotation de PHP est identique celui de nombreux autres langages de programma-
tion comme C, C++ ou Java. Si toutefois vous ne connaissez aucun de ces langages, il
vous faudra peut-tre un peu de temps pour vous y accoutumer.
Tout comme pour les autres variables, la modification du contenu des lments dun
tableau seffectue au moyen de loprateur =. La ligne de code qui suit remplace le
premier lment du tableau $produits, Pneus, par llment Fusibles :
$produits[0] = Fusibles;

Linstruction qui suit ajoute un nouvel lment, Fusibles, la fin du tableau ;


$produits a dsormais quatre lments :
$produits[3] = Fusibles;

La ligne de code suivante affiche le contenu du tableau :


echo "$produits[0] $produits[1] $produits[2] $produits[3]";

Bien que lanalyse des chanes par PHP soit particulirement bien labore, vous pouvez
commettre des erreurs dans ce domaine. Si vous avez des problmes avec des tableaux
ou des variables non correctement interprts lorsquils sont encadrs par des apostro-
phes doubles, mettez-les hors de ceux-ci ou utilisez la syntaxe complexe prsente au
Chapitre 4. La prcdente instruction echo fonctionnera correctement, mais vous
rencontrerez plusieurs autres exemples au cours de ce chapitre dans lesquels les variables
sont situes en dehors des chanes encadres par des apostrophes doubles.
Tout comme les autres variables PHP, les tableaux ne ncessitent pas une initialisation
ou une cration pralables. Ils sont automatiquement crs leur premire utilisation.
Le code qui suit conduit la cration du mme tableau $produits que celui que lon a
cr plus haut avec array() :
$produits[0] = Pneus;
$produits[1] = Huiles;
$produits[2] = Bougies;
Chapitre 3 Utilisation de tableaux 91

Si le tableau $produits nexiste pas encore, la premire ligne cre un nouveau tableau
form dun seul lment. Les lignes qui suivent ajoutent des valeurs au tableau qui vient
dtre cr. Le tableau est redimensionn dynamiquement lorsque vous lui ajoutez des
lments. Cette possibilit de redimensionnement nexiste pas dans la plupart des autres
langages de programmation.

Utilisation de boucles pour accder au contenu dun tableau


Lorsquun tableau est indic par une srie de nombres, son contenu peut tre affich
plus facilement grce une boucle for :
for ( $i = 0; $i<3; $i++ ) {
echo "$produits[$i] ";

Cette boucle produit une sortie identique celle obtenue prcdemment, tout en tant
plus compacte. La possibilit dutiliser ainsi une simple boucle pour accder chaque
lment dun tableau est une particularit apprciable des tableaux.
Nous pouvons galement nous servir dune boucle foreach, qui a t spcialement
conue pour tre utilise avec les tableaux :
foreach ($produits as $element){
echo $element . ;

Ce code enregistre tour tour chacun des lments du tableau dans la variable $element
et affiche le contenu de celle-ci.

Tableaux avec des indices diffrents


Dans le tableau $produits, nous avons laiss PHP utiliser des indices par dfaut pour
chacun des lments. Cela signifie que le premier est llment 0, le deuxime,
llment 1, et ainsi de suite. Avec PHP, vous pouvez galement choisir les cls ou les
indices qui serviront indexer un tableau.

Initialisation dun tableau


Linstruction qui suit cre un tableau dont les cls sont les noms des articles et les
valeurs sont les prix :
$prix = array(Pneus=>100, Huiles=>10, Bougies=>4 );

Le symbole entre les cls et les valeurs est simplement un signe gal immdiatement
suivi par un symbole suprieur .
92 Partie I Utilisation de PHP

Accs aux lments du tableau


L encore, laccs au contenu du tableau seffectue en spcifiant le nom de la variable
et une cl. Pour accder au contenu du tableau $prix, nous pouvons donc utiliser les
expressions $prix[ Pneus ], $prix[ Huiles ] et $prix[ Bougies ].
Les lignes de code qui suivent crent le mme tableau $prix que le prcdent mais,
au lieu de produire demble un tableau form de trois lments, cette version cre
dabord un tableau comprenant un seul lment, puis lui ajoute deux lments
supplmentaires.
$prix = array( Pneus=>100 );
$prix[Huile] = 10;
$prix[Bougies] = 4;

Voici une autre variante de ce fragment de code dont lexcution produit un rsultat
identique. Ce code ne cre pas explicitement le tableau, mais conduit indirectement sa
cration lors de lajout du premier lment :
$prix[Pneus] = 100;
$prix[Huiles] = 10;
$prix[Bougies] = 4;

Utilisation de boucles
Nous ne pouvons pas utiliser un simple compteur avec une boucle for pour parcourir le
tableau prcdent puisquil nest pas indic par des nombres. Cependant, nous pouvons
faire appel une boucle foreach ou aux constructions list() et each().
Avec un tableau associatif, la boucle foreach peut adopter une syntaxe lgrement
diffrente. Vous pouvez lutiliser exactement comme dans lexemple prcdent ou y
ajouter les cls :
foreach ($prix as $nom => $montant) {
echo "$nom: $montant<br />";

Le fragment de code qui suit affiche le contenu du tableau $prix avec each() :
while( $element = each( $prix ) ) {
echo $element[ key ];
echo : ;
echo $element[ value ];
echo <br />;
}

Lexcution de ce code produit le rsultat montr la Figure 3.2.


Chapitre 3 Utilisation de tableaux 93

Figure 3.2
Utilisation dune instruction
each() pour parcourir
un tableau.

Au Chapitre 1, nous avons tudi la boucle while et linstruction echo. Le fragment de


code prcdent met en uvre la fonction each, que nous rencontrons ici pour la
premire fois. Cette fonction renvoie llment courant dun tableau et dplace le poin-
teur du tableau sur llment suivant. Dans ce code, la fonction each() est invoque au
sein dune boucle while, afin de renvoyer successivement les diffrents lments du
tableau. Lexcution de cette boucle prend fin lorsque linterprteur PHP atteint la fin
du tableau.
Dans ce code, la variable $element est un tableau. Lappel de la fonction each()
renvoie en effet un tableau de quatre lments. Les emplacements indics par key et 0
contiennent la cl de llment courant, tandis que les emplacements indics par value
et 1 contiennent la valeur de llment courant. Ici, nous avons choisi dutiliser des
noms plutt que des numros pour dsigner les emplacements. Au final, toutefois, ces
deux choix sont quivalents.
Il existe une manire plus lgante et plus commune dobtenir ce rsultat, en utilisant la
fonction list() pour dcouper le tableau en un ensemble de valeurs. Nous pouvons
ainsi sparer deux des valeurs renvoyes par la fonction each() de la manire suivante :
$list( $nom, $montant ) = each( $prix );

Dans cette ligne de code, la fonction each() est utilise pour obtenir llment
courant du tableau $prix, le renvoyer sous forme de tableau et pour passer
llment suivant. On utilise galement la fonction list() pour transformer les
lments 0 et 1 du tableau renvoy par la fonction each() en deux nouvelles variables
appeles $nom et $montant.
Nous pouvons parcourir tout le contenu du tableau $prix et lafficher dans la fentre du
navigateur au moyen des deux lignes de code suivantes :
while ( list( $nom, $montant ) = each( $prix ) ) {
echo "$nom: $montant<br />";
}

Lexcution de ces lignes de code produit le mme rsultat que celui de la Figure 3.2,
mais elles sont plus lisibles car la fonction list () permet daffecter des noms aux
variables.
94 Partie I Utilisation de PHP

Avec la fonction each(), le tableau mmorise la position courante. Si vous devez utili-
ser deux fois le mme tableau dans un script, il faut par consquent replacer la position
courante du tableau au dbut de celui-ci avec la fonction reset(). Pour afficher une
seconde fois les prix des articles, il nous faudrait donc excuter les lignes de code
suivantes :
reset($prix);
while ( list( $nom, $montant ) = each( $prices ) ) {
echo "$nom: $montant<br />";

Oprateurs sur les tableaux


Un jeu spcial doprateurs ne sapplique quaux tableaux. La plupart dentre eux
possdent un quivalent dans les oprateurs scalaires, comme vous pouvez le remarquer
dans le Tableau 3.1.

Tableau 3.1 : Oprateurs de tableaux

Oprateur Nom Exemple Rsultat


+ Union $a + $b Union de $a et $b. Le tableau $b est ajout
$a, mais les cls en double ne sont pas
ajoutes.
== galit $a == $b True si $a et $b contiennent les mmes
lments.
=== Identit $a === $b True si $a et $b contiennent les mmes
lments, de mme type et dans le mme
ordre.
!= Ingalit $a!= $b True si $a et $b ne contiennent pas les
mmes lments.
<> Ingalit $a <> $b Identique !=.
!== Non-identit $a!== $b True si $a et $b ne contiennent pas les
mmes lments, de mme type et dans le
mme ordre.

Ces oprateurs sont assez vidents comprendre, mais lunion requiert quelques
explications supplmentaires. Cet oprateur tente dajouter les lments de $b la
fin de $a. Si des lments de $b possdent les mmes cls que certains lments qui
Chapitre 3 Utilisation de tableaux 95

se trouvent dj dans $a, ils ne seront pas ajouts. Autrement dit, aucun lment de
$a nest cras.
Vous remarquerez que les oprateurs de tableaux du Tableau 3.1 possdent tous des
oprateurs quivalents qui fonctionnent sur les variables scalaires. Pour autant que vous
vous souveniez que + ralise laddition sur les types scalaires et lunion sur les tableaux,
les comportements sont logiques. Vous ne pouvez pas comparer de manire utile des
tableaux des types scalaires.

Tableaux multidimensionnels
Les tableaux ne sont pas ncessairement de simples listes de cls et de valeurs. Chaque
lment dun tableau peut lui-mme tre un autre tableau. Cette proprit permet de
crer des tableaux deux dimensions, qui peuvent tre assimils une matrice, ou grille,
caractrise par une largeur et une hauteur, cest--dire un nombre dtermin de lignes
et de colonnes.
Par exemple, nous pourrions avoir recours un tableau deux dimensions pour stocker
plusieurs informations relatives chaque article vendu par lentreprise de Bob.
la Figure 3.3, chaque ligne dun tableau deux dimensions reprsente un article
particulier et chaque colonne reprsente un attribut (ou un type dinformation) relatif
aux produits.

Code Description Prix

PNE Pneus 100


produ t

HUI Huiles 10

BOU Bougies 4

attr buts dun produit

Figure 3.3
Un tableau deux dimensions permet de stocker plus dinformations relatives aux articles vendus
par lentreprise de Bob.

Voici le code PHP qui pourrait tre utilis pour gnrer le tableau de la Figure 3.3 :
$produits = array( array( PNE, Pneus, 100 ),
array( HUI, Huiles, 10 ),
array( BOU, Bougies, 4 ) );
96 Partie I Utilisation de PHP

Ces lignes font bien apparatre que le tableau $produits se compose dsormais de trois
autres tableaux.
Souvenez-vous que, pour accder un lment dun tableau unidimensionnel, il faut
spcifier le nom du tableau et la cl de llment. Dans un tableau deux dimensions,
laccs seffectue de manire comparable, si ce nest qu chaque lment sont asso-
cies deux cls : une ligne et une colonne (la ligne la plus en haut est la ligne 0, tandis
que la colonne la plus gauche est la colonne 0).
Nous pourrions ainsi afficher le contenu du tableau considr ici en accdant dans
lordre et manuellement chaque lment, comme ici :
echo |.$produits[0][0].|.$produits[0][1].|.$produits[0][2].|<br />;
echo |.$produits[1][0].|.$produits[1][1].|.$produits[1][2].|<br />;
echo |.$produits[2][0].|.$produits[2][1].|.$produits[2][2].|<br />;

Nous pourrions obtenir le mme rsultat en insrant une boucle for dans une autre
boucle for, de la manire suivante :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
for ( $colonne = 0; $colonne < 3; $colonne++ ) {
echo |.$produits[$ligne][$colonne];
}
echo |<br />;
}

Chacune de ces deux variantes conduit au mme affichage dans la fentre du navigateur
web, cest--dire :
|PNE|Pneus|100|
|HUI|Huiles|10|
|BOU|Bougies|4|

La seule diffrence est que la seconde variante est bien plus courte que la premire dans
le cas de tableaux volumineux.
Au lieu de dsigner les colonnes par des numros, vous pouvez choisir dutiliser des
noms de colonnes (voir Figure 3.3). Pour cela, vous pouvez utiliser des tableaux asso-
ciatifs. Pour enregistrer le mme ensemble darticles dans un tableau associatif dont les
noms de colonnes seraient identiques ceux de la Figure 3.3, vous pouvez crire le
code suivant :
$produits = array( array( Code => PNE,
Description => Pneus,
Prix => 100
),
array( Code => HUI,
Description => Huiles,
Prix => 10
),
Chapitre 3 Utilisation de tableaux 97

array( Code => BOU,


Description => Bougies,
Prix =>4
)
);

Un tel tableau se rvle plus facile manipuler lorsquil sagit de rcuprer une seule
valeur. Il est en effet plus ais de se souvenir que la description dun article est stocke
dans la colonne Description, que de se souvenir quelle est stocke dans la colonne 1.
Avec les indices descriptifs, il nest pas ncessaire de mmoriser quune valeur est stocke
la position [x][y]. Les donnes peuvent y tre facilement retrouves en spcifiant les
noms explicites des lignes et des colonnes.
Nous sommes en revanche privs de la possibilit dutiliser une boucle for pour
parcourir successivement les diffrentes colonnes du tableau. Le fragment de code qui
suit permet dafficher le contenu de ce tableau :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
echo |.$produits[$ligne][Code].|.
$produits[$ligne][Description].|.
$produits[$ligne][Prix].|<br />;
}

Avec une boucle for nous pouvons parcourir le tableau "externe" $produits indic par
des nombres. Chaque ligne de notre tableau $produits constitue un tableau avec des
indices descriptifs. Les fonctions each() et list() peuvent ensuite tre insres dans
une boucle while pour parcourir les diffrents tableaux internes contenus dans
$produits. Voici le code form dune boucle while imbrique dans une boucle for :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
while ( list( $cle, $valeur ) = each( $produits[ $ligne ] ) )
{
echo |$valeur;
}
echo |<br />;
}

Vous ntes pas limit deux dimensions : en suivant le mme principe, rien nempche
de crer un tableau dont les lments sont constitus de tableaux, eux-mmes constitus
de tableaux, et ainsi de suite.
Un tableau trois dimensions se caractrise par une largeur, une hauteur et une profon-
deur. Si vous prfrez vous reprsenter un tableau deux dimensions comme un tableau
compos de lignes et de colonnes, vous pouvez vous reprsenter un tableau trois
dimensions comme un empilement de tels tableaux. Chaque lment est alors rfrenc
par sa couche, sa ligne et sa colonne.
98 Partie I Utilisation de PHP

Si Bob classe ses articles en diffrentes catgories, un tableau trois dimensions


permettra de stocker cette information supplmentaire. La Figure 3.4 montre la structure
que pourrait avoir un tel tableau.

Figure 3.4
Ce tableau trois Pices camions
dimensions permet
its Code Description Prix
de classer les articles rodu
en catgories.
des p

Pices motos
orie

Code Description Prix


catg

Pices voitures

Code Description Prix

VOI PNE Pneus 100


produit

VOI HUI Huiles 10

VOI BOU Bougies 4

attributs dun produit

Dans le fragment de code qui suit, il apparat clairement quun tableau trois dimensions
est un tableau contenant des tableaux de tableaux :
$categories = array( array ( array( VOI_PNE, Pneus, 100 ),
array( VOI_HUI, Huiles, 10 ),
array( VOI_BOU, Bougies, 4 )
),
array ( array( MOT_PNE, Pneus, 120 ),
array( MOT_HUI, Huiles, 12 ),
array( MOT_BOU, Bougies, 5 )
),
array ( array( CAM_PNE, Pneus, 150 ),
array( CAM_HUI, Huiles, 15 ),
array( CAM_BOU, Bougies, 6 )
)
);

Ce tableau ne comprenant que des cls numriques, nous pouvons nous servir de
boucles for imbriques pour afficher son contenu :
for ( $couche = 0; $couche < 3; $couche++ ) {
echo "Couche $couche<br />";
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
for ( $colonne = 0; $colonne < 3; $colonne++ ) {
Chapitre 3 Utilisation de tableaux 99

echo |.$categories[$couche][$ligne][$colonne];
}
echo |<br />;
}
}

Compte tenu de la manire dont sont crs les tableaux multidimensionnels, vous
pouvez trs bien produire des tableaux quatre, cinq ou six dimensions. Le langage
PHP nimpose en ralit aucune limite sur le nombre de dimensions dun tableau.
Toutefois, les constructions plus de trois dimensions sont difficiles visualiser.
Des tableaux trois dimensions ou moins suffisent gnralement traiter la plupart des
problmes et situations du monde rel.

Tri de tableaux
Il est souvent trs utile de trier les donnes apparentes qui sont stockes dans un
tableau. Le tri dun tableau unidimensionnel est une opration trs simple.

Utilisation de la fonction sort()


Les deux lignes de code qui suivent trient un tableau dans lordre alphabtique :
$produits = array( Pneus, Huiles, Bougies );
sort($produits);

Aprs lexcution de ce code, les lments contenus dans le tableau sont classs dans
lordre suivant : Bougies, Huiles, Pneus.
Il est galement possible de trier des valeurs en suivant lordre numrique. Prenons le
cas dun tableau contenant les prix des articles vendus par Bob. Le contenu de ce
tableau pourrait tre tri par ordre numrique croissant, au moyen des instructions
suivantes :
$prix = array( 100, 10, 4 );
sort($prix);

Les prix seraient alors classs dans lordre suivant : 4, 10, 100.
Notez que la fonction sort() est sensible la casse ( lutilisation de majuscules/
minuscules). Les lettres majuscules sont classes avant les lettres minuscules : "A" est
infrieur "Z", mais "Z" est infrieur "a".
La fonction admet galement un second paramtre facultatif. Vous pouvez passer lune
des constantes SORT REGULAR (par dfaut), SORT NUMERIC ou SORT STRING. Cette capa-
cit spcifier le type de tri est utile lorsque vous comparez des chanes qui peuvent
contenir des nombres, comme 2 et 12. Numriquement, 2 est infrieur 12 mais, en tant
que chane, 12 est infrieure 2.
100 Partie I Utilisation de PHP

Utilisation des fonctions asort() et ksort() pour trier des tableaux


Si nous enregistrons des articles et leurs prix dans un tableau cls descriptives, nous
devrons avoir recours diffrents types de fonctions de tri pour obtenir que les cls et
les valeurs correspondantes restent associes lors du tri.
La premire instruction qui suit cre un tableau contenant les trois articles dcrits
prcdemment, avec les prix correspondants, tandis que la deuxime ligne de code trie
ce tableau par ordre de prix croissants :
$prix = array( Pneus=>100, Huiles=>10, Bougies=>4 );
asort($prix);

La fonction asort() trie le contenu du tableau qui lui est fourni en paramtre daprs la
valeur de chaque lment. Dans le tableau considr ici, les valeurs sont les prix tandis
que les cls sont les descriptions textuelles. Pour trier le tableau non pas en fonction des
prix, mais des descriptions, cest la fonction ksort() qui doit tre employe. La fonc-
tion ksort() effectue un tri sur la base des cls et non pas des valeurs. Le fragment de
code qui suit gnre un tableau tri en tenant compte de lordre alphabtique des cls
(Bougies, Huiles, Pneus) :
$prix = array( Pneus=>100, Huiles=>10, Bougies=>4 );
ksort($prix);

Tri dans lordre inverse


Nous venons dexaminer les fonctions de tri sort(), asort() et ksort(), qui effectuent
toutes trois des tris par ordre croissant. chacune de ces fonctions correspond une
fonction de tri inverse, dont la fonctionnalit est identique si ce nest quelle procde
un tri dcroissant. Ces versions inverses des fonctions de tri sont respectivement
rsort(), arsort() et krsort().
Les fonctions de tri inverses sutilisent de la mme manire que les fonctions de tri vues
jusquici. La fonction rsort() permet de trier par ordre dcroissant un tableau unidi-
mensionnel indic numriquement. La fonction arsort() trie par ordre dcroissant un
tableau unidimensionnel selon les valeurs des lments. Quant la fonction krsort(),
elle trie un tableau unidimensionnel par ordre dcroissant, selon les cls des lments.

Tri de tableaux multidimensionnels


Le tri dun tableau plusieurs dimensions, ou en suivant un ordre autre que les ordres
alphabtique ou numrique, est plus compliqu. En effet, PHP sait comparer deux
nombres ou deux chanes de caractres mais, dans un tableau multidimensionnel,
chaque lment est lui-mme un tableau, or PHP ne connat pas demble les critres
retenir pour comparer deux tableaux. Par consquent, vous devez crer une mthode
Chapitre 3 Utilisation de tableaux 101

pour oprer cette comparaison. Le plus souvent, la comparaison de mots ou de nombres


est triviale. En revanche, pour des objets complexes, elle peut se rvler problmatique.

Tris dfinis par lutilisateur


Soit le tableau dj considr prcdemment et dont la dfinition est la suivante :
$produits = array( array( PNE, Pneus, 100 ),
array( HUI, Huiles, 10 ),
array( BOU, Bougies, 4 ) );
Ce tableau contient trois articles vendus par lentreprise de Bob, avec un code, une
description et un prix par article.
quel rsultat aboutira le tri de ce tableau ? Deux types dordres au moins pourraient
ici tre utiles : un tri des articles par ordre alphabtique des descriptions ou par ordre
numrique des prix. Chacun de ces tris peut tre implment en utilisant la fonction
usort() et en indiquant linterprteur PHP le critre sur lequel la comparaison doit
seffectuer. Pour cela, nous allons devoir crire notre propre fonction de comparaison.
Le fragment de code donn ci-aprs conduit au tri du tableau selon lordre alphabtique
des descriptions, cest--dire par rapport la deuxime colonne du tableau :
function compare($x, $y){
if ( $x[1] == $y[1] ) {
return 0;
} else if ( $x[1] < $y[1] ){
return -1;
} else
return 1;
}
}

usort($produits, compare);
Jusquici, nous nous sommes servis dun certain nombre de fonctions prdfinies de
PHP. Pour trier notre tableau, nous avons eu besoin de dfinir notre propre fonction.
Lcriture de fonctions personnalises est traite en dtail au Chapitre 5 mais, pour
lheure, en voici une brve introduction.
En PHP, la dfinition dune fonction requiert le mot-cl function. Pour dfinir une
fonction personnalise, vous devez lui attribuer un nom, quil est conseill de choisir
soigneusement. Ici, par exemple, nous avons choisi dappeler notre fonction
compare(). Nombre de fonctions attendent des paramtres. Notre fonction compare()
en prend deux : un appel x et un appel y. Cette fonction sert comparer les deux
valeurs qui lui sont passes en paramtre et dterminer leur ordre.
Pour cet exemple, les paramtres x et y contiendront deux des tableaux contenus dans le
tableau principal et qui reprsentent chacun un article diffrent. Pour accder au champ
Description du tableau x, nous devons crire $x[1]. En effet, la Description est le
102 Partie I Utilisation de PHP

deuxime lment dans chacun des "sous-tableaux" et la numrotation commence


zro. $x[1] et $y[1] permettent donc de comparer les champs Description stocks
dans les tableaux passs comme arguments la fonction compare().
Lorsque lexcution dune fonction sachve, celle-ci peut renvoyer une rponse au
code qui la appele. On dit alors que la fonction renvoie une valeur. Pour cela, vous
devez utiliser le mot-cl return. Par exemple, la ligne de code return 1; renvoie la
valeur 1 au code qui a appel la fonction.
Pour tre utilisable par usort(), compare() doit comparer x et y et renvoyer 0 si x est
gal y, un nombre ngatif si x est infrieur y et un nombre positif si x est suprieur
y. Notre fonction compare renvoie donc 0, 1 ou 1 selon les valeurs x et y qui lui sont
fournies.
La dernire ligne du code prcdent appelle la fonction prdfinie usort() en lui
passant en paramtre le nom du tableau trier ($produits) et le nom de la fonction de
comparaison personnalise (compare()).
Pour trier notre tableau sur dautres critres, il suffit dcrire une autre fonction de
comparaison. Pour, par exemple, trier le tableau en fonction des prix, la comparaison
doit porter sur la troisime colonne des tableaux. La dfinition de la fonction compare()
devrait alors tre la suivante :
function compare($x, $y) {
if ( $x[2] == $y[2] ) {
return 0;
} else if ( $x[2] < $y[2] ) {
return -1;
} else
return 1;
}
}

Lappel usort($produits, compare) entrane le tri du tableau par ordre de prix


croissants.
La prfixe "u" de la fonction usort() est labrviation de user (utilisateur) car cette
fonction requiert la spcification dune fonction de comparaison dfinie par lutilisa-
teur. De la mme manire, les versions uasort() et uksort() des fonctions asort et
ksort ncessitent galement quune fonction de comparaison dfinie par lutilisateur
leur soit passe en paramtre.
La fonction uasort() fait pendant la fonction asort() et sutilise pour trier un
tableau indic numriquement selon les valeurs. Si ces valeurs sont des nombres ou du
texte, utilisez asort mais, si ce sont des objets plus complexes, comme des tableaux,
dfinissez une fonction de comparaison et utilisez uasort().
Chapitre 3 Utilisation de tableaux 103

La fonction uksort() fait pendant la fonction ksort() et sutilise pour trier un


tableau associatif selon ses cls. Si ces cls sont des nombres ou du texte, utilisez ksort
mais, si ce sont des objets plus complexes, comme des tableaux, dfinissez une fonction
de comparaison et utilisez uksort().

Tris dfinis par lutilisateur, dans lordre inverse


Chacune des fonctions sort(), asort() et ksort() a sa fonction quivalente
commenant par "r" pour produire un tri dans lordre inverse. Les tris dfinis par
lutilisateur nont pas de variantes "inverses", mais vous pouvez quand mme trier
en ordre inverse un tableau multidimensionnel en fonction dun ordre inverse en
crivant une fonction de comparaison qui renvoie les valeurs opposes. Il suffit que
la fonction de comparaison renvoie 1 lorsque $x est infrieur $y et 1 lorsque $x est
suprieur $y :
function compareInverse($x, $y) {
if ( $x[2] == $y[2] ) {
return 0;
} else if ( $x[2] < $y[2] ) {
return 1;
} else
return -1;
}
}

Dans notre exemple, lappel de usort($produits, compareInverse) produirait un


tableau tri par ordre de prix dcroissants.

Rordonner des tableaux


Dans certaines applications, il peut tre ncessaire de "rordonner" des tableaux selon
dautres critres. La fonction shuffle() permet de "mlanger" les lments dun
tableau, cest--dire de les ordonner de manire alatoire. La fonction
array reverse() permet quant elle dobtenir une copie dun tableau dans laquelle
tous les lments ont t tris dans lordre inverse.

Utilisation de la fonction shuffle()


Bob aimerait que la page daccueil de son site prsente quelques-uns des produits
proposs la vente. Il voudrait montrer trois des articles de son catalogue choisis au
hasard et faire en sorte que ceux-ci soient diffrents chaque nouvelle visite de ses
clients, pour prserver lintrt de ces derniers. Ceci est trs facile raliser si tous les
articles sont stocks dans un tableau. Lexcution du code du Listing 3.1 permet daffi-
cher trois images choisies au hasard : le contenu du tableau est rordonn de manire
alatoire et seuls ses trois premiers lments sont affichs.
104 Partie I Utilisation de PHP

Listing 3.1 : bobs_front_page.php Utilisation de PHP pour produire une page


daccueil dynamique sur le site web du garage de Bob

<?php
$images = array(pneu.jpg, huile.jpg, bougie.jpg,
porte.jpg, volant.jpg,
thermostat.jpg, essuie_glace.jpg,
joint.jpg, plaquette_frein.jpg);

shuffle($images);
?>
<html>
<head>
<title>Le garage de Bob</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<div align="center">
<table width = 100%>
<tr>
<?php
for ( $i = 0; $i < 3; $i++ ) {
echo <td align="center"><img src=";
echo $images[$i];
echo " width="100" height="100"></td>;
}
?>
</tr>
</table>
</div>
</body>
</html>

Le code du Listing 3.1 effectuant une slection alatoire dimages, il conduit laffi-
chage dune page diffrente chaque chargement ou presque (voir Figure 3.5).

Figure 3.5
La fonction shuffle()
est utilise ici pour
afficher trois articles
choisis au hasard.
Chapitre 3 Utilisation de tableaux 105

Utilisation de la fonction array_reverse()


La fonction array reverse() prend un tableau en paramtre et en cre un nouveau
dont le contenu est celui de dpart tri dans lordre inverse. Considrons par exemple le
cas dun tableau contenant un dcompte de dix un. Il ya plusieurs faons de produire
un tel tableau.
La fonction range() cre gnralement une srie croissante que vous pouvez trier par
ordre dcroissant en utilisant array reverse() ou rsort(). Nous pouvons galement
crer les lments du tableau un un, au moyen dune boucle for, comme ici :
$nombres = array();
for($i = 10; $i > 0; $i--) {
array_push( $nombres, $i );
}
Une boucle for peut procder par ordre dcroissant : il suffit de choisir une valeur
initiale suffisamment leve et dutiliser loprateur pour dcrmenter le compteur
dune unit chaque rptition de la boucle.
Le code prcdent commence par crer un tableau vide, puis remplit peu peu ce
tableau grce la fonction array push (), laquelle ajoute chaque nouvel lment la
fin du tableau. La fonction array pop() fait pendant la fonction array push() : elle
supprime et renvoie llment situ la fin du tableau qui lui est pass en paramtre.
Nous pouvons galement utiliser la fonction array reverse() pour trier dans lordre
inverse un tableau produit avec range() :
$nombres = range(1,10);
$nombres = array_reverse($nombres);
Notez que la fonction array reverse() renvoie une copie modifie du tableau qui lui
est pass en paramtre. Si, comme ici, vous ne souhaitez pas conserver le tableau initial,
il suffit de lcraser avec la nouvelle copie.
Si vos donnes correspondent simplement une plage dentiers, vous pouvez crer
cette plage en ordre inverse en passant 1 comme paramtre de pas range() :
$nombres = range(10, 1, -1);

Chargement de tableaux partir de fichiers


Nous avons vu au Chapitre 2 comment enregistrer les commandes client dans un
fichier. Chaque ligne se prsentait de la manire suivante :
15:42 le 20-04 4 pneus 1 bidons dhuiles 6 bougies 434.00 22 rue noire, Toulouse
Pour traiter cette commande, nous pouvons avoir besoin de recharger le contenu de ce
fichier dans un tableau. Le script prsent dans le Listing 3.2 permet dafficher le
contenu de ce fichier.
106 Partie I Utilisation de PHP

Listing 3.2 : vieworders.php Utilisation de PHP pour afficher le contenu du fichier


de commandes de lentreprise de Bob

<?php
// Cration dun nom abrg de variable
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];

$commandes = file("$DOCUMENT_ROOT/../orders/orders.txt");

$nbre_de_cdes = count($commandes);
if ($nbre_de_cdes == 0) {
echo "<p><strong>Aucune commande en attente.
Ressayez plus tard.</strong></p>";
}

for ($i = 0; $i < $nbre_de_cdes; $i++) {


echo $commandes[$i]."<br />";
}
?>

Ce script produit presque le mme affichage que le Listing 2.3, au Chapitre 2 (voir
Figure 2.4). Cette fois, cependant, on utilise la fonction file() pour charger lintgra-
lit du fichier dans un tableau. Chaque ligne du fichier devient alors un lment du
tableau ainsi produit.
Par ailleurs, le Listing 3.2 utilise la fonction count() pour dterminer le nombre
dlments contenus dans le tableau cr.
Nous pouvons aller plus loin et charger chacune des sections des lignes de commandes
dans des lments tableaux distincts, afin de traiter les sections sparment les unes des
autres ou de les mettre en forme de manire plus attractive. Cest ce que fait le code du
Listing 3.3.

Listing 3.3 : vieworders2.php Utilisation de PHP pour sparer, mettre en forme


et afficher les commandes reues par lentreprise de Bob

<?php
// Cration dun nom abrg de variable
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob - Commandes clients</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Commandes clients</h2>
<?php
// Lecture du fichier complet.
// Chaque commande devient un lment du tableau
$commandes = file("$DOCUMENT_ROOT/../orders/orders.txt");
Chapitre 3 Utilisation de tableaux 107

// Compte le nombre de commandes dans le tableau


$nbre_de_cdes = count($commandes);

if ($nbre_de_cdes == 0) {
echo "<p><strong>Aucune commande en attente.
Ressayez plus tard.</strong></p>";
}

echo "<table border=\"1\">\n";


echo "<tr><th bgcolor=\"#CCCCFF\">Date commande</th>
<th bgcolor=\"#CCCCFF\">Pneus</th>
<th bgcolor=\"#CCCCFF\">Huiles</th>
<th bgcolor=\"#CCCCFF\">Bougies</th>
<th bgcolor=\"#CCCCFF\">Total</th>
<th bgcolor=\"#CCCCFF\">Adresse</th>
<tr>";

for ($i = 0; $i < $nbre_de_cdes; $i++) {


// Dcoupage de chaque ligne
$ligne = explode("\t", $commandes[$i]);

// On ne conserve que le nombre darticles commands


$ligne[1] = intval($ligne[1]);
$ligne[2] = intval($ligne[2]);
$ligne[3] = intval($ligne[3]);

// Affiche chaque commande


echo "<tr>
<td>".$ligne[0]."</td>
<td align=\"right\">".$ligne[1]."</td>
<td align=\"right\">".$ligne[2]."</td>
<td align=\"right\">".$ligne[3]."</td>
<td align=\"right\">".$ligne[4]."</td>
<td>".$ligne[5]."</td>
</tr>";
}

echo "</table>";
?>
</body>
</html>

Le code du Listing 3.3 charge lintgralit du fichier dans un tableau. Contrairement au


Listing 3.2, cest ici la fonction explode() qui est employe pour dcouper chaque
ligne avant les oprations de traitement et de mise en forme avant affichage.
108 Partie I Utilisation de PHP

Le rsultat obtenu lexcution du Listing 3.3 est montr la Figure 3.6.

Figure 3.6
Aprs le dcoupage des lignes de commande avec explode(), les diffrentes sections de chaque
commande sont places dans des cellules spares dun tableau, de faon amliorer la prsentation
des rsultats.

Voici le prototype de la fonction explode() :


array explode(string sparateur, string chane [, int limite])

Au cours du Chapitre 2, nous avons utilis le caractre de tabulation en guise de dlimi-


teur lors de lenregistrement de ces donnes. Cest pourquoi lappel de la fonction
explode() est ici ralis de la manire suivante :
explode( "\t", $commandes[$i] )

Cette instruction a pour effet de dcouper la chane passe comme deuxime paramtre.
Chaque caractre de tabulation devient une sparation entre deux lments. Ainsi, la
chane :
"15:42 le 20-04 4 pneus 1 bidons dhuiles 6 bougies 434.00 22 rue noire, Toulouse"
est dcoupe en six parties, "15:42 le 20 04", "4pneus", "1bidons dhuiles",
"6bougies", "434.00" et "22rue noire, Toulouse".
Vous pouvez galement utiliser le paramtre facultatif limit pour limiter le nombre
maximal de parties renvoyes.
Dans le code du Listing 3.3, le traitement auquel sont soumises les donnes extraites du
fichier des commandes est minimal. Nous nous contentons dafficher les quantits de
chaque article et dajouter au tableau une ligne den-tte indiquant la signification
des nombres affichs.
Chapitre 3 Utilisation de tableaux 109

Nous aurions pu procder de plusieurs autres manires pour extraire les nombres conte-
nus dans ces chanes. Dans le Listing 3.3, nous avons utilis la fonction intval() qui
convertit une chane en nombre entier. Cette conversion ne pose pas de problme puis-
que les parties qui ne peuvent pas tre converties en nombres entiers sont ignores.
Nous tudierons diverses autres mthodes de traitement des chanes au cours du
prochain chapitre.

Autres manipulations de tableaux


Nous navons vu jusquici que la moiti environ des fonctions de traitement de tableaux
offertes par PHP. La plupart des autres ne servent que de manire occasionnelle.

Parcours dun tableau : each, current(), reset(), end(), next(), pos() et prev()
Nous avons vu plus haut que chaque tableau comprend un pointeur interne dirig sur
llment courant du tableau. Nous avons dj fait usage de manire indirecte de ce
pointeur lorsque nous nous sommes servis de la fonction each(), mais il est galement
possible de lutiliser et de le manipuler directement.
la cration dun nouveau tableau, le pointeur est initialis de sorte pointer sur
le premier lment du tableau. Cest ainsi que lappel de current($tableau) renvoie le
premier lment.
Les fonctions next() et each() permettent de faire avancer ce pointeur dun lment.
La fonction each($tableau) renvoie llment courant avant de dplacer le pointeur.
Le comportement de la fonction next($tableau) est lgrement diffrent puisquelle
fait avancer le pointeur puis renvoie le nouvel lment courant.
Comme nous lavons dj mentionn, la fonction reset() fait revenir le pointeur sur
le premier lment dun tableau. De la mme manire, la fonction end() le dplace sur le
dernier lment du tableau qui lui est fourni en paramtre. Les fonctions reset() et
end() renvoient, quant elles, respectivement le premier et le dernier lment dun
tableau.
Pour parcourir un tableau en sens inverse, vous pouvez employer les fonctions end() et
prev(). La fonction prev() est loppos de la fonction next() : elle fait reculer le pointeur
dun lment puis renvoie le nouvel lment courant.
Le code qui suit produit laffichage dun tableau dans lordre inverse :
$valeur = end ($tableau);
while ($valeur) {
echo "$valeur<br />";
$valeur = prev($tableau);
}
110 Partie I Utilisation de PHP

Si la variable $tableau a t dclare de la manire suivante :


$tableau = array(1, 2, 3);

le rsultat de lexcution du code prcdent sera :


3
2
1

Avec les fonctions each(), current(), reset(), end(), next(), pos() et prev(), vous
pouvez donc parcourir un tableau comme bon vous semble.

Application dune fonction donne chaque lment dun tableau :


array_walk()
Il est parfois ncessaire dappliquer le mme traitement tous les lments dun
tableau : cest l que la fonction array walk() entre en jeu.
Voici le prototype de la fonction array walk() :
bool array_walk(array tableau, string fonction, [mixed donnes_utilisateur])

Tout comme la fonction usort(), array walk() requiert comme second paramtre une
fonction dfinie par lutilisateur.
La fonction array walk() prend trois paramtres. Le premier, tableau, est le tableau
dont on veut traiter le contenu. Le second, fonction, est le nom de la fonction dfinie
par lutilisateur et qui sera applique chaque lment du tableau. Le troisime para-
mtre, donnes utilisateur, est facultatif. Sil est prsent, il est pass en paramtre
la fonction dfinie par lutilisateur. Nous allons voir un peu plus loin un exemple de
mise en uvre de la fonction array walk().
Il pourrait, par exemple, se rvler trs pratique dattribuer chaque lment dun
tableau une fonction qui applique une mise en forme particulire.
Le code qui suit affiche chaque lment du tableau $tableau sur une nouvelle ligne, en
appliquant chaque lment la fonction mon affichage() :
function mon_affichage($valeur) {
echo "$valeur<br />";
}
array_walk($tableau, mon_affichage);

La signature de la fonction personnalise est particulire. Pour chaque lment du


tableau trait, array walk prend la cl et la valeur enregistres dans le tableau, ainsi
que la valeur spcifie comme paramtre donnes utilisateur, puis appelle la fonction
personnalise de la manire suivante :
fonctionUtilisateur (valeur, cl, donnes_utilisateur)
Chapitre 3 Utilisation de tableaux 111

Dans la plupart des cas, le paramtre donnes utilisateur est inutile ; il ne sert que
lorsque la fonction que vous avez dfinie exige un paramtre.
Il peut galement arriver que la cl de chaque lment soit tout autant ncessaire la
manipulation effectue que la valeur de llment. Mais, comme dans le cas de
mon affichage(), votre fonction peut ignorer aussi bien la cl que le paramtre
donnes utilisateur.
Considrons prsent un exemple un peu plus complexe : nous allons crire une
fonction qui modifie les valeurs dun tableau et attend un paramtre. Notez que, dans
ce cas, nous devons indiquer la cl dans la liste des paramtres afin de pouvoir spci-
fier le troisime, mme si nous navons pas besoin de cette cl dans le corps de la
fonction :
function ma_multiplication(&$valeur, $cle, $facteur){
$valeur *= $facteur;
}
array_walk(&$tableau, ma_multiplication, 3);

La fonction ma multiplication() multiplie chaque lment du tableau par le facteur


pass en paramtre. Nous devons utiliser le troisime paramtre (facultatif) de la fonc-
tion array walk() afin que celle-ci passe ce dernier comme paramtre notre fonction
(laquelle sen sert ensuite comme facteur de la multiplication). Pour que notre fonc-
tion ma multiplication() rcupre ce facteur, il est impratif de la dfinir avec trois
arguments : une valeur dlment de tableau ($valeur), une cl dlment de tableau
($cle) et le facteur de multiplication ($facteur). Ici, la fonction ma multiplication()
ignore la cl qui lui est passe en second paramtre.
La manire dont $valeur est passe la fonction ma multiplication() mrite quel-
ques explications. Lesperluette (&) place avant le nom de la variable dans la dfinition
de ma multiplication() indique que $valeur doit tre passe par rfrence. Passer
une variable par rfrence permet la fonction de modifier le contenu de cette variable
et donc, ici, du tableau.
Cette manire de passer les variables aux fonctions est tudie en dtail au Chapi-
tre 5. Si cette notion vous est trangre, il vous suffit pour linstant de savoir que,
pour passer en paramtre une variable par rfrence, il faut placer une esperluette
devant son nom.

Comptage des lments dun tableau :


count(), sizeof() et array_count_values()
Dans un des exemples prcdents, nous avons employ la fonction count() pour
dterminer le nombre des lments dun tableau contenant les commandes des
clients. La fonction sizeof() accomplit la mme tche que la fonction count().
112 Partie I Utilisation de PHP

Toutes les deux renvoient le nombre dlments du tableau qui leur est pass en paramtres.
Elles renvoient la valeur 1 lorsquelles sont appliques une variable scalaire et 0
lorsquelles sappliquent un tableau vide ou une variable non dfinie.
La fonction array count values() est plus complexe : elle dtermine le nombre
doccurrences de chaque valeur unique dans le tableau qui lui est pass en paramtre
(cest ce que lon appelle la cardinalit du tableau). Cette fonction renvoie un
tableau associatif contenant une table des frquences. Ce tableau a pour cls toutes
les valeurs uniques du tableau pass array count values() et chacune de ces cls
est associe une valeur numrique reprsentant le nombre de ses occurrences dans
le paramtre.
Le code suivant :
$tableau = array(4, 5, 1, 2, 3, 1, 2, 1);
$ac = array_count_values($tableau);

cre un tableau $ac dont le contenu est le suivant :

Cl Valeur

4 1

5 1

1 3

2 2

3 1

Dans ce cas prcis, le tableau retourn par array count values() indique que le
tableau $tableau contient une seule fois les valeurs 4, 5 et 3, trois fois la valeur 1, et
deux fois la valeur 2.

Conversion de tableaux en variables scalaires : extract()


Vous pouvez transformer un tableau indices non numriques contenant des paires cl/
valeur en un ensemble de variables scalaires au moyen de la fonction extract().
Le prototype de la fonction extract() est le suivant :
extract(array tableau [, int type_extraction] [, string prfixe] );

La fonction extract() produit des variables scalaires partir du tableau qui lui est
pass en paramtre. Elle utilise les cls pour dfinir les noms de ces variables et les
valeurs des lments comme valeurs des variables.
Chapitre 3 Utilisation de tableaux 113

Voici un exemple simple dutilisation de la fonction extract() :


$tableau = array( cle1 => valeur1, cle2 => valeur2, cle3 => valeur3);
extract($tableau);
echo "$cle1 $cle2 $cle3";

Lexcution de ce code produit le rsultat suivant :


valeur1 valeur2 valeur3

Le tableau $tableau contenant trois lments dont les cls sont cle1, cle2 et cle3, la
fonction extract() applique $tableau cre donc les trois variables scalaires $cle1,
$cle2 et $cle3. Vous pouvez constater dans le rsultat obtenu que les valeurs
de $cle1, $cle2 et $cle3 sont respectivement valeur1, valeur2 et valeur3, qui
proviennent du tableau initial.
La fonction extract() accepte deux arguments facultatifs : type extraction et
prfixe. Le premier indique extract() la manire dont doivent tre gres les colli-
sions, cest--dire les situations o il existe dj une variable de mme nom quune cl.
Le comportement par dfaut consiste craser la variable existante. Le Tableau 3.2
dcrit les quatre valeurs autorises pour type extraction.

Tableau 3.2 : Valeurs possibles du paramtre type_extraction de la fonction extract()

Type Signification
EXTR OVERWRITE crase la variable existante en cas de collision.
EXTR SKIP Saute llment en cas de collision.
EXTR PREFIX SAME Cre une variable dnomme $prefixe cl en cas de collision.
Le paramtre prfixe doit alors tre prcis.
EXTR PREFIX ALL Prfixe tous les noms de variables avec la valeur indique dans
le paramtre prfixe, qui est alors obligatoire.
EXTR PREFIX INVALID Prfixe avec la valeur de prfixe les noms de variables qui
seraient sans cela invalides (par exemple les noms de variable
numriques). Vous devez fournir le prfixe.
EXTR IF EXISTS Nextrait que les variables dj existantes (autrement dit,
remplace les valeurs des variables existantes par les valeurs du
tableau). Cette fonctionnalit permet, par exemple, de convertir
$ REQUEST en un ensemble de variables valides.

EXTR PREFIX IF EXISTS Ne cre une version prfixe que si la version non prfixe
existe dj.
EXTR REFS Extrait les variables sous forme de rfrences.
114 Partie I Utilisation de PHP

Les deux valeurs les plus couramment utilises pour largument type extraction sont
la valeur par dfaut (EXTR OVERWRITE) et EXTR PREFIX ALL. Les deux valeurs suivantes
sont utiles de manire occasionnelle, lorsquune collision particulire est attendue et
que vous voulez "sauter" ou prfixer la cl posant problme. Le fragment de code qui
suit illustre lutilisation de la valeur EXTR PREFIX ALL. Observez la manire dont sont
forms les noms des variables cres : prfixe_cl.
$tableau = array( cle1 => valeur1, cle2 => valeur2, cle3 => valeur3);
extract($tableau, EXTR_PREFIX_ALL, mon_prefixe);
echo "$mon_prefixe_cle1 $mon_prefixe_cle2 $mon_prefixe_cle3";
L encore, le rsultat obtenu lexcution des lignes de codes prcdents est valeur1
valeur2 valeur3.
Pour que la fonction extract() puisse extraire un lment, il faut que la cl de
llment soit un nom de variable valide, ce qui signifie que les cls dont les noms
commencent par des chiffres ou qui contiennent des espaces ne peuvent pas tre extraites.

Pour aller plus loin


Ce troisime chapitre a prsent les fonctions PHP de manipulation de tableau qui nous
apparaissent les plus utiles. Certaines ne sont volontairement pas abordes. Vous trou-
verez dans le manuel en ligne PHP (http://www.manuelphp.com/php/ref.array.php)
une prsentation exhaustive de toutes les fonctions PHP disponibles.

Pour la suite
Le Chapitre 4 traite des fonctions de manipulation des chanes. Il couvre les fonctions
de recherche, de remplacement, de scission et de fusion de chanes. Il dcrit galement
les puissantes fonctions de traitement des expressions rgulires qui permettent de
raliser quasiment toutes les oprations envisageables sur les chanes.
4
Manipulation de chanes
et dexpressions rgulires

Dans ce chapitre, nous verrons comment utiliser les fonctions PHP de traitement des
chanes pour mettre en forme et manipuler du texte. Nous examinerons galement
lemploi des fonctions de traitement de chanes et dexpressions rgulires pour rechercher
et remplacer des mots, des phrases ou tout autre motif au sein dune chane.
Les fonctions dcrites dans ce chapitre sont utiles dans de nombreux contextes. Vous
vous trouverez sans aucun doute souvent en situation de devoir nettoyer ou mettre en
forme les donnes saisies par les utilisateurs avant de les enregistrer dans une base
de donnes, par exemple. Par ailleurs, les fonctions de recherche sont prcieuses lors de
llaboration dapplications de type moteur de recherche (entre autres).

Application modle : formulaire intelligent de saisie dun message


(Smart Form Mail)
Nous illustrerons notre tude des fonctions de manipulation de chanes et dexpressions
rgulires par le dveloppement dun formulaire intelligent de saisie dun message.
Nous utiliserons les scripts crits au cours de ce chapitre pour complter lapplication
du garage de Bob labore dans les chapitres prcdents.
Notre objectif est ici de dvelopper un formulaire simple, que les clients de Bob pour-
ront utiliser pour faire part de leurs rclamations et de leurs encouragements. Ce formu-
laire (voir Figure 4.1) est plus labor que la plupart des formulaires de ce type publis
sur le Web (et qui sont lgion). En effet, au lieu de transmettre le formulaire vers une
adresse de courrier lectronique gnrique, telle que commentaires@chezbob.com, nous
ferons appel un processus plus intelligent qui consiste rechercher des mots et des
phrases cls dans ce qui a t saisi par les clients, puis transmettre le message du client
116 Partie I Utilisation de PHP

lemploy appropri. Si, par exemple, le message transmis par le client contient le mot
"publicit", il sera dirig vers la bote aux lettres du dpartement de marketing. Si le
message mane dun client important, il pourra tre directement transmis Bob.

Figure 4.1
Le formulaire de saisie
dun message du site de Bob
permet aux clients de trans-
mettre leurs commentaires,
aprs avoir saisi leur nom
et leur adresse de courrier
lectronique.

Nous commencerons ce projet par le script simple du Listing 4.1. Nous complterons
ensuite ce script au fur et mesure de notre avance dans ce chapitre.

Listing 4.1 : processfeedback.php Script de base permettant la transmission


du contenu dun formulaire par courrier lectronique

<?php
// Cration de noms abrgs pour les variables
$nom = $_POST[nom];
$email = $_POST[email];
$commentaire = $_POST[commentaire];

// Initialisation de quelques informations statiques


$adresse_dest = "commentaires@exemple.com";
$sujet = "Message provenant du site web";
$contenu_message = "Nom client : " . $nom ."\n" .
"Email client : ". $email . "\n".
"Commentaires client :\n" . $commentaire. "\n";
$adresse_exp = "From: webserver@exemple.com";

// Appel de la fonction mail() pour envoyer le courrier


mail($adresse_dest, $sujet, $contenu_message, $adresse_exp);
?>
Chapitre 4 Manipulation de chanes et dexpressions rgulires 117

<html>
<head>
<title>Le garage de Bob -- Commentaire transmis</title>
</head>
<body>
<h1>Commentaire transmis</h1>
<p>Votre commentaire a t envoy.</p>
</body>
</html>

Notez quen situation relle il faudrait tester si lutilisateur a bien rempli tous les
champs obligatoires, par exemple en utilisant la fonction isset() avant dappeler la
fonction mail(). Ce test a t omis dans le Listing 4.1 et dans les autres exemples par
souci de simplification.
Dans ce script, on concatne les champs du formulaire et on utilise la fonction mail()
de PHP pour transmettre par courrier lectronique la chane rsultante ladresse
commentaires@exemple.com. Il sagit bien sr dune adresse e-mail dexemple : si vous
souhaitez tester le code de ce chapitre, remplacez-la par votre adresse e-mail. Comme
cest la premire fois que nous utilisons la fonction mail(), nous allons nous intresser
son fonctionnement.
Comme son nom le suggre, la fonction mail() transmet des courriers lectroniques
(des e-mails). Voici son prototype :
bool mail(string A, string Objet, string Message,
string [enttes_additionnels]);

Les trois premiers arguments de la fonction mail() sont obligatoires et reprsentent


respectivement ladresse laquelle doivent tre envoys le message, lobjet et le
contenu du message. Le quatrime paramtre permet denvoyer nimporte quel en-tte
supplmentaire valide de courrier lectronique. Vous trouverez une description des en-
ttes e-mails valides dans le document RFC822 qui peut tre consult en ligne (nombre
de standards Internet sont dfinis dans des RFC, Request For Comments, que nous
prsenterons au Chapitre 18). Ici, le quatrime paramtre que nous passons la fonc-
tion mail() sert ajouter un champ "From:" (ladresse de provenance) dans le courrier.
Nous aurions galement pu lemployer pour insrer des champs " Reply To:" et "Cc:",
entre autres. Pour ajouter plusieurs en-ttes additionnels, il suffit de les indiquer la
suite sous forme dune chane, en les sparant par des caractres de nouvelle ligne et de
retour chariot (\n\r), comme ici :
$entetes_additionnels ="From: webserver@exemple.com\r\n"
"Reply-To: bob@exemple.com";

Vous pouvez vous servir du cinquime paramtre facultatif pour passer un paramtre au
programme que vous avez configur pour lenvoi de-mails.
118 Partie I Utilisation de PHP

Pour pouvoir mettre en uvre la fonction mail(), vous devez configurer votre installa-
tion PHP pour lui indiquer lexistence de votre programme denvoi des courriers. Si
lexcution de votre script pose problme, relisez attentivement lAnnexe A et vrifiez
votre installation PHP.
Tout au long de ce chapitre, nous amliorerons le script de base du Listing 4.1 en nous
servant de fonctions PHP de manipulation des chanes et dexpressions rgulires.

Mise en forme de chanes


Les chanes saisies par les visiteurs des sites web (gnralement partir dun formu-
laire HTML) ncessitent souvent dtre nettoyes pour tre exploitables. Les sections
qui suivent prsentent certaines des fonctions permettant deffectuer cette opration.

lagage des chanes : chop(), Itrim() et trim()


La premire tape dans le nettoyage dune chane consiste souvent en liminer tout
espace superflu. Cet lagage nest pas indispensable, mais se rvle souvent trs utile
lorsque les chanes doivent tre enregistres dans un fichier ou dans une base de
donnes ou lorsquelles doivent tre compares avec dautres chanes.
Le langage PHP offre trois fonctions permettant deffectuer ce type de nettoyage. Dans
le cadre de notre application modle, nous utiliserons la fonction trim() pour laguer
les donnes entrantes au moment o lon cre les noms abrgs :
$nom = trim($_POST[nom]);
$email = trim($_POST[email]);
$commentaire = trim($_POST[commentaire]);

La fonction trim() limine les espaces existant en dbut et la fin de la chane qui lui
est fournie en paramtre et retourne la chane ainsi lague. Les caractres despace
supprims par la fonction trim() sont les nouvelles lignes et les retours chariot (\n, \r),
les tabulations horizontales et verticales (\t et \v), les caractres de fin de chane (\0) et
les caractres espaces. Vous pouvez galement passer cette fonction un second para-
mtre contenant une liste des caractres supprimer la place de cette liste par dfaut.
Selon le but recherch, les fonctions ltrim() ou rtrim() peuvent se rvler plus appro-
pries que la fonction trim(). Comme la fonction trim(), elles prennent toutes les
deux la chane traiter en paramtre et renvoient cette chane mise en forme. En
revanche, alors que la fonction trim() supprime tous les espaces qui encadrent la
chane, la fonction ltrim() limine uniquement les espaces en dbut de chane
(cest--dire la gauche de la chane) tandis que la fonction rtrim() les supprime
uniquement la fin de la chane (cest--dire droite).
Chapitre 4 Manipulation de chanes et dexpressions rgulires 119

Mise en forme des chanes en vue de leur prsentation


PHP offre tout un jeu de fonctions ddies la mise en forme des chanes.

Utilisation du format HTML : la fonction nl2br()


La fonction nl2br() remplace chaque caractre de nouvelle ligne de la chane qui lui
est passe en paramtre par la balise <br />. Cette fonction est prcieuse lorsque de
longues chanes doivent tre affiches dans la fentre du navigateur. Par exemple, nous
utiliserons la fonction nl2br() pour prsenter en retour au client le message quil a
transmis sous une forme acceptable :
<p>Votre commentaire (voir ci-aprs) a t envoy.</p>
<p><?php echo nl2br($contenu_message);?> </p>

Souvenez-vous que, dans le contexte dun codage HTML, lespace est ignore. Par
consquent, en labsence dun traitement par nl2br(), le message du client sera
imprim sous la forme dune seule ligne ( lexception des caractres de nouvelles
lignes imposs par le navigateur lui-mme). La Figure 4.2 illustre ces deux modes
daffichage, avec et sans traitement par nl2br().

Figure 4.2
La fonction PHP nl2br()
permet damliorer la
prsentation des longues
chanes dans du code
HTML.

Mise en forme dune chane pour lafficher


Jusquici, nous avons utilis la construction echo de PHP pour afficher des chanes dans
la fentre du navigateur web.
120 Partie I Utilisation de PHP

PHP offre galement la fonction print(), qui est analogue la construction echo, sauf
quelle renvoie une valeur (vrai ou faux, selon la russite ou lchec de laffichage).
echo, tout comme print(), affiche la chane "telle quelle". Vous pouvez toutefois appli-
quer une mise en forme plus sophistique au moyen des fonctions printf() et
sprintf(). Toutes les deux oprent pratiquement de la mme manire, sauf que
printf() affiche la chane mise en forme dans le navigateur, tandis que sprintf()
renvoie cette chane mise en forme.
Ces fonctions ont le mme comportement que leurs quivalents dans le langage C, bien
que leur syntaxe ne soit pas la mme. Si vous navez jamais programm en C, il vous
faudra peut-tre un peu de temps pour vous familiariser avec ces fonctions, mais le jeu
en vaut toutefois la chandelle, compte tenu de leur puissance et de leur utilit.
Les prototypes de ces fonctions sont les suivants :
string sprintf (string format [, mixed paramtres...])
int printf (string format [, mixed paramtres...])

Le premier paramtre requis par ces fonctions est une chane de format dcrivant la
forme de base de la sortie, avec des codes de mise en forme au lieu de variables. Les
autres paramtres sont des variables que PHP viendra insrer dans la chane, en lieu et
place des codes de mise en forme.
Par exemple, avec la fonction echo, nous pouvons afficher une chane en y insrant une
variable, comme suit :
echo "Le montant total de la commande est $total.";

Le mme rsultat peut tre obtenu au moyen de la fonction printf(), de la manire


suivante :
printf ("Le montant total de la commande est %s.", $total);

Le code %s dans la chane de format est une "spcification de conversion". Il indique


PHP quil doit tre remplac par une chane. Dans le cas prsent, il doit tre remplac
par la variable $total qui doit tre interprte comme une chane.
Si la valeur stocke dans $total est 12,4, ces deux approches conduiraient laffichage
de $total sous la forme 12,4.
Lintrt de la fonction printf() est quelle permet dutiliser une spcification de
conversion plus utile. En effet, nous pouvons utiliser printf() en prcisant que $total
est, en ralit, un nombre virgule flottante et que sa valeur doit tre affiche avec deux
dcimales, comme ceci :
printf ("Le montant total de la commande est %.2f", $total);

Avec ce formatage et la valeur 12.4 stocke dans $total, linstruction affichera 12.40.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 121

Une chane de format peut comprendre plusieurs spcifications de conversion. Si vous


avez n spcifications, il doit normalement y avoir n arguments aprs la chane de
format. Chaque spcification de conversion sera remplace par largument reformat
correspondant, dans lordre o ils sont indiqus. Par exemple :
printf ("Montant total: %.2f (dont %.2f de transport)",
$total, $total_transport);

Dans le cas prsent, la premire spcification de conversion utilisera la valeur de


$total et la seconde spcification se servira de la valeur de $total transport.
Chaque spcification de conversion se conforme au format suivant :
%[caractre_remplissage][-][largeur][.prcision]type

Toutes les spcifications de conversion commencent par le symbole %. Pour afficher un


symbole %, vous devrez par consquent utiliser %%.
Le spcificateur caractre remplissage est facultatif. Sil est prcis, il sert
complter la variable jusqu la largeur spcifie. Par exemple, un caractre de remplis-
sage sutilise pour ajouter des zros au dbut de nombres comme les compteurs. Le
caractre de remplissage par dfaut est une espace. Si vous spcifiez une espace ou
zro, vous navez pas besoin de le prfixer avec lapostrophe (). Tous les autres carac-
tres de remplissage doivent tre prfixs par une apostrophe.
Le symbole est facultatif. Il indique que les donnes doivent tre justifies gauche,
au lieu de ltre droite, comme cest le cas par dfaut.
Le spcificateur largeur indique la fonction printf() lespace (en nombre de carac-
tres) rserver pour la variable.
Le spcificateur prcision commence normalement par un point dcimal. Il indique le
nombre de dcimales afficher.
Le type constitue la dernire partie dune spcification de conversion ; il indique le type
des donnes passes en paramtre. Les valeurs possibles pour ce spcificateur sont
prsentes dans le Tableau 4.1.

Tableau 4.1 : Valeurs possibles pour le type dune spcification de conversion

Type Signification
b Largument est trait comme un entier et affich comme un nombre binaire.
c Largument est trait comme un entier et affich comme un caractre.
d Largument est trait comme un entier et affich comme un nombre dcimal.
122 Partie I Utilisation de PHP

Tableau 4.1 : Valeurs possibles pour le type dune spcification de conversion (suite)

Type Signification
f Largument est trait comme un double et affich comme un nombre virgule
flottante.
o Largument est trait comme un entier et affich comme un nombre octal.
s Largument est trait et affich comme une chane.
u Largument est trait comme un entier et affich comme un nombre dcimal non
sign.
x Largument est trait comme un entier et affich comme un nombre hexadcimal
(en minuscules sil sagit dune lettre).
X Largument est trait comme un entier et affich comme un nombre hexadcimal
(en majuscules sil sagit dune lettre).

Il est possible de numroter les paramtres, ce qui permet de passer les paramtres dans
un autre ordre que les spcifications de conversion. Par exemple :
printf ("Montant total : %2\$.2f (dont %1\$.2f de transport)",
$total_transport, $total);
Il suffit dajouter la position du paramtre dans la liste directement aprs le signe %,
suivi dun symbole $ protg par un antislash ; dans le cas prsent, 2\$ signifie donc
"remplacer par le deuxime paramtre de la liste". Ce procd peut aussi tre utilis
pour rpter des paramtres.
Il existe deux versions alternatives de ces fonctions, appeles vprintf() et
vsprintf(). Ces variantes acceptent deux paramtres : la chane de format et un
tableau des paramtres au lieu dun nombre variable de paramtres.

Modification de la casse dune chane


PHP offre la possibilit de modifier la casse dune chane. Dans le cas de lapplication
modle tudie dans ce chapitre, cette possibilit nest gure utile, mais nous examine-
rons nanmoins quelques exemples simples o elle est trs apprciable.
Considrons pour commencer la chane $sujet qui contient lobjet dun message.
Diverses fonctions sont notre disposition pour en changer la casse. Les effets de ces
diffrentes fonctions sont rsums dans le Tableau 4.2.
La premire colonne indique le nom de la fonction, la deuxime dcrit leffet de la
fonction considre, la troisime montre comment la fonction serait applique
la chane $sujet, tandis que la dernire colonne donne la valeur qui serait renvoye
par la fonction.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 123

Tableau 4.2 : Fonctions de modification de la casse dune chane, avec leurs effets

Fonction Description Usage Valeur retourne


$sujet Commentaire du site
web
strtoupper() Convertit la chane en strtoupper($sujet) COMMENTAIRE
majuscules. DU SITE WEB
strtolower() Convertit la chane en strtolower($sujet) commentaire du site
minuscules. web
ucfirst() Met en majuscule la premire ucfirst($sujet) Commentaire du site
lettre de la chane, si ce web
caractre est alphabtique.
ucwords() Met en majuscule la premire ucwords($sujet) Commentaire Du
lettre de chaque mot de la chane Site Web
qui commence par un caractre
alphabtique.

Mise en forme de chanes en vue de leur enregistrement :


addslashes() et stripslashes()
Si les fonctions de traitement de chane permettent de modifier la prsentation visuelle
des chanes, certaines dentre elles peuvent galement tre employes pour reformater
des chanes dans la perspective de leur enregistrement dans une base de donnes. Bien
que lcriture dans une base de donnes ne soit pas aborde dans cet ouvrage avant la
deuxime partie, nous traiterons ds maintenant de la mise en forme des chanes en vue
de leur stockage dans une base.
Certains caractres dont la prsence est autorise au sein dune chane peuvent se rv-
ler une source de problme, particulirement lors de linsertion des donnes dans une
base de donnes. Une base de donnes interprte en effet certains caractres comme des
caractres de contrle. Les caractres les plus problmatiques sont les apostrophes
(simples et doubles), les barres obliques inverses (\) et le caractre NULL.
Il est par consquent ncessaire de marquer, ou de "protger", ces caractres, de sorte
quune base de donnes telle que MySQL les traite en tant que caractres littraux et
non pas comme des squences de contrle. Pour protger ces caractres, il suffit de les
faire prcder dune barre oblique inverse. Par exemple, le caractre " (apostrophe
double) doit tre not sous la forme \" (barre oblique inverse apostrophe double) et le
caractre \ (barre oblique inverse) doit tre reprsent par \\ (deux barres obliques
inverses successives).
124 Partie I Utilisation de PHP

Notez que cette rgle sapplique tous les caractres spciaux. Par consquent, si votre
chane contient la squence \\, vous devez enregistrer celle-ci sous la forme \\\\.
PHP offre deux fonctions spcialement ddies la protection des caractres. Avant
dcrire une chane dans une base de donnes, vous devez reformater celle-ci avec la
fonction addslashes(), comme dans lexemple suivant, moins que votre configuration
ne le fasse par dfaut :
$commentaire = addslashes(trim($_POST[commentaire]));

Comme nombre dautres fonctions de traitement de chanes, la fonction addslashes()


prend une chane en paramtre et renvoie la chane reformate.
La Figure 4.3 illustre les transformations ralises par ces fonctions sur les chanes.
Vous pouvez tester ces fonctions sur votre serveur et obtenir un rsultat qui ressemble
plus celui de la Figure 4.4.

Figure 4.3
Aprs traitement par la fonction
addslashes(), toutes les apostrophes
sont prcdes dune barre oblique.
La fonction stripslashes() limine
toutes les barres obliques servant
de caractre dchappement.

Figure 4.4
Tous les caractres problmatiques
ont t protgs deux fois ; cela
signifie que la fonction des apostro-
phes magiques est active.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 125

Si vous voyez ce rsultat, cela signifie que votre configuration de PHP est dfinie de
manire ajouter et supprimer les barres obliques automatiquement. Cette capacit
est contrle par la directive de configuration magic quotes gpc, qui est active par
dfaut dans les nouvelles versions de PHP. Les lettres gpc correspondent GET, POST et
cookie. Cela signifie que les variables provenant de ces sources sont automatiquement
mises entre apostrophes. Vous pouvez vrifier si cette directive est active dans votre
systme en utilisant la fonction get magic quotes gpc(), qui renvoie true si les cha-
nes provenant de ces sources sont automatiquement places entre apostrophes. Si cette
directive est active sur votre systme, vous devez appeler stripslashes() avant
dafficher les donnes utilisateur ; sans cela, les barres obliques seront affiches.
Lutilisation des guillemets magiques vous permet dcrire du code plus portable. Pour
en apprendre plus sur cette fonction, consultez le Chapitre 22.

Fusion et scission de chanes au moyen des fonctions de traitement


de chane
Il apparat souvent ncessaire dexaminer et de traiter certaines parties dune chane
sparment du reste de la chane. Par exemple, on peut souhaiter examiner les mots
dune phrase (afin den vrifier lorthographe) ou scinder un nom de domaine ou une
adresse de courrier lectronique en ses diffrentes composantes. PHP met votre dispo-
sition plusieurs fonctions de traitement de chane (et une fonction de traitement
dexpression rgulire) permettant doprer ce type de manipulation.
Dans le cadre de notre application modle, supposez que Bob veuille recevoir person-
nellement tous les messages des clients provenant de grosclient.com. Pour exhaucer son
souhait, il suffit de dcomposer ladresse de courrier lectronique fournie par les clients
et dexaminer si elle contient la sous-chane grosclient.com.

Utilisation des fonctions explode(), implode() et join()


explode() est la premire fonction que nous pouvons mettre en uvre pour atteindre
notre objectif. Son prototype est le suivant :
array explode(string sparateur, string entre [, int limite]);
Cette fonction prend une chane comme deuxime paramtre (entre) et dcoupe celle-
ci en se servant du sparateur (de type chane) indiqu en premier paramtre. Les
diffrentes sous-chanes ainsi obtenues sont renvoyes dans un tableau. Vous pouvez
limiter le nombre dlments ainsi produits avec le paramtre facultatif limite.
Dans le cadre de notre application modle, nous pouvons extraire le nom de domaine de
ladresse de courrier lectronique du client grce au code suivant :
$tab_email = explode(@, $email);
126 Partie I Utilisation de PHP

Lexcution de cette ligne de code dcoupe ladresse de courrier lectronique du client


en deux parties : le nom dutilisateur, qui est enregistr dans $tab email[0], et le nom
de domaine, qui est enregistr dans $tab email[1].
Nous pouvons alors identifier lorigine du client en testant le nom de domaine. Ne reste
plus ensuite qu transmettre le message saisi par le client la personne approprie :
if ($tab_email[1] == "grosclient.com") {
$adresse_dest = "bob@exemple.com";
} else {
$adresse_dest = "commentaires@example.com";
}

Notez que, si le nom de domaine nest pas entirement dfini en lettres minuscules, le
code prcdent ne conduira pas au rsultat recherch. Pour viter ce problme, nous
devons dabord convertir le nom de domaine en majuscules, ou bien en minuscules,
avant deffectuer notre test :
if (strtolower($tab_email[1]) == "grosclient.com") {
$adresse_dest = "bob@exemple.com";
} else {
$adresse_dest = "commentaires@exemple.com";
}
Leffet produit par la fonction explode() peut tre annul avec les fonctions implode()
ou join(). Ces deux fonctions sont identiques (ce sont des alias lune de lautre). Par
exemple, la ligne de code :
$nouveau_email = implode(@, $tab_email);

rassemble tous les lments du tableau $tab email en les reliant par la chane passe
en premier paramtre. Cet appel de fonction est donc trs semblable celui de la fonction
explode() mais il produit le rsultat oppos.

Utilisation de la fonction strtok()


Contrairement la fonction explode(), qui dcompose en une seule fois une chane en
diffrentes parties, la fonction strtok() extrait une une les diffrentes parties dune
chane (lesquelles sont appeles des token, terme pouvant tre traduit par "lexme"). La
fonction strtok() est donc une alternative intressante la fonction explode()
lorsquil sagit de traiter un par un les mots dune chane de caractres.
Le prototype de la fonction strtok() est le suivant :
string strtok(string entre, string sparateur);

Le paramtre sparateur peut tre soit un caractre individuel, soit une chane de
caractres. La chane entre sera scinde au niveau de chacun des caractres spcifis
dans le sparateur et non pas au niveau des occurrences de la chane sparateur
complte (comme cest le cas avec explode).
Chapitre 4 Manipulation de chanes et dexpressions rgulires 127

Lappel de strtok() nest pas aussi simple que le laisse penser son prototype.
Pour obtenir le premier segment dune chane, appelez la fonction strtok() en lui
passant la chane dcomposer et le sparateur utiliser. Pour obtenir les maillons
suivants, il suffit de passer un seul paramtre : le sparateur. La fonction strtok()
conserve en effet un pointeur interne sur la chane qui lui a t passe en paramtre.
Pour rinitialiser le pointeur de strtok(), appelez strtok() en indiquant nouveau le
paramtre entre.
Voici un exemple typique dutilisation de la fonction strtok() :
$mot = strtok($commentaire, " ");
echo $mot . "<br />";
while ($mot!= "") {
$mot = strtok(" ");
echo $mot . "<br />";
};

Comme nous lavons dj mentionn, il serait fortement conseill, ici, de vrifier que le
client a bien rempli les champs du formulaire de message, par exemple au moyen de la
fonction empty(). Ce test nest pas implment dans les exemples de code donns dans
ce chapitre, par souci de concision.
Le code prcdent affiche chaque mot du message saisi par le client sur une ligne
distincte et poursuit le traitement jusqu ce quil ny ait plus de mot. Les chanes vides
sont automatiquement ignores.

Utilisation de la fonction substr()


La fonction substr() permet daccder une sous-chane dune chane en indiquant le
dbut et la fin de la sous-chane. Dans le cadre de lexemple considr ici, cette fonction
na gure dutilit, mais elle se rvle prcieuse lorsquil faut traiter des parties de chanes
ayant un format bien dtermin.
La fonction substr() sutilise avec le prototype suivant :
string substr(string chane, int dbut, int [longueur] );

La fonction substr() renvoie une sous-chane extraite de la chane chane passe en


paramtre.
Pour illustrer lusage de cette fonction, considrons lexemple de chane suivant :
$test = "Votre service client est parfait";

Si la fonction substr() est appele en spcifiant uniquement un nombre positif comme


argument dbut, vous obtiendrez la sous-chane comprise entre la position dbut et la
fin de la chane. Par exemple, lexcution de linstruction :
substr($test, 1);
128 Partie I Utilisation de PHP

renvoie "otre service client est parfait". Notez que les positions dans la chane
sont numrotes partir de 0, comme dans les tableaux.
Lorsque la fonction substr() est appele en spcifiant uniquement un nombre ngatif
comme argument dbut, vous obtenez la sous-chane comprise entre la fin de la chane
moins "longueur caractres" et la fin de la chane. Par exemple, lexcution de
linstruction :
substr($test, -7);

renvoie la sous-chane "parfait".


Le paramtre longueur permet dindiquer soit le nombre des caractres renvoyer (si
longueur est un nombre positif), soit le caractre final de la sous-chane (si longueur
est un nombre ngatif). Par exemple :
substr($test, 0, 5);

renvoie les cinq premiers caractres de la chane, cest--dire "Votre". La ligne de code
suivante :
echo substr($test, 6, -13);

retourne la sous-chane comprise entre le septime caractre et le treizime caractre


compt partir de la fin de la chane, cest--dire "service client". Le premier carac-
tre tant lemplacement 0, lemplacement 6 correspond donc au septime caractre.

Comparaison de chanes
Jusqu prsent, les seules comparaisons de chanes que nous avons faites se sont limi-
tes au test de lgalit entre deux chanes, au moyen de loprateur ==. PHP permet
deffectuer des comparaisons plus sophistiques que nous classerons en deux catgo-
ries : les correspondances partielles et les autres. Nous commencerons par tudier ces
dernires, puis nous examinerons dans un second temps les correspondances partielles,
dont nous aurons besoin pour poursuivre le dveloppement de notre application
modle.

Comparaison des chanes : strcmp(), strcasecmp() et strnatcmp()


Ces fonctions permettent dordonner des chanes les unes par rapport aux autres. Elles
sont prcieuses lors du tri de donnes.
Le prototype de la fonction strcmp() est le suivant :
int strcmp(string chane1, string chane2);

La fonction strcmp() compare les deux chanes qui lui sont passes en paramtre et renvoie
0 si elles sont gales, un nombre positif si chane1 vient aprs (ou est suprieure )
Chapitre 4 Manipulation de chanes et dexpressions rgulires 129

chane 2 dans lordre lexicographique et un nombre ngatif dans le cas contraire. Cette
fonction est sensible la casse.
La fonction strcasecmp() est identique strcmp(), sauf quelle nest pas sensible la
casse.
La fonction strnatcmp() et son homologue non sensible la casse strnatcasecmp()
comparent les chanes daprs lordre "naturel", plus proche du comportement humain.
Par exemple, la fonction strcmp() classerait la chane "2" aprs la chane "12", parce
que cette dernire est suprieure dun point de vue lexicographique. En revanche, la
fonction strnatcmp() effectuerait le classement inverse. Vous trouverez plus dinfor-
mations sur la notion dordre naturel sur le site http://www.naturalordersort.org/.

Longueur dune chane : la fonction strlen()


Nous pouvons tester la longueur dune chane en faisant appel la fonction strlen().
Celle-ci renvoie la longueur de la chane qui lui est passe en paramtre. Lappel
suivant, par exemple, affichera 7 :
echo strlen("bonjour");

strlen() permet de valider les donnes saisies par lutilisateur. Par exemple, consid-
rons le cas de ladresse de courrier lectronique entre dans notre exemple de formu-
laire et stocke dans la variable $email. Une des mthodes de base de validation des
adresses de courrier lectronique consiste tester leur longueur. Une adresse de cour-
rier lectronique valide doit compter au moins six caractres (a@a.fr, par exemple),
dans le cas minimaliste dune adresse se composant dun code de pays sans deuxime
niveau de domaine, dun nom de serveur dun seul caractre et dune adresse e-mail
dune seule lettre. On pourrait donc produire un message derreur si ladresse saisie na
pas au moins cette longueur :
if (strlen($email) < 6) {
echo "Cette adresse email est incorrecte.";
exit; // Fin de lexcution du script PHP
}

Il sagit bien sr dune mthode simpliste de validation de linformation. Nous en


verrons de meilleures dans la prochaine section.

Recherche et remplacement de sous-chanes avec les fonctions


de traitement de chanes
On a souvent besoin de vrifier la prsence dune sous-chane dtermine dans une
chane plus longue. Ce type de correspondance partielle est souvent plus utile quun
simple test dgalit.
130 Partie I Utilisation de PHP

Dans notre exemple de formulaire, nous devons dterminer si le message contient


certains mots-cls pour en dduire le service vers lequel il doit tre dirig. Si nous
souhaitons, par exemple, diriger tous les e-mails o il est question des boutiques de Bob
vers le responsable du rseau de distribution, nous pouvons rechercher les occurrences
du mot "boutique" (ou ses drivs) dans les messages.
Pour faire cette slection, nous disposons des fonctions explode() ou strtok() dj
tudies. Celles-ci permettent de rcuprer des mots dans les messages que nous pourrons
ensuite comparer laide de loprateur dgalit ou de la fonction strcmp().
PHP nous offre toutefois la possibilit daboutir au mme rsultat via un seul appel
dune des fonctions de recherche de chanes ou dexpressions rgulires. Ces fonctions
servent rechercher la prsence dun motif donn dans une chane de caractres. Nous
allons prsent passer en revue chacun de ces jeux de fonctions.

Recherche de sous-chanes dans des chanes : strstr(), strchr(), strrchr()


et stristr()
Pour tester la prsence dune chane dans une autre chane, vous pouvez utiliser lune
ou lautre des fonctions strstr(), strchr(), strrchr() ou stristr().
La fonction strstr() est la plus gnrique et peut tre utilise pour rechercher une
correspondance entre une sous-chane ou un caractre et une chane plus longue. En
PHP, la fonction strchr() est identique la fonction strstr(), bien que son nom
suggre quelle sert rechercher un caractre au sein dune chane (ce qui est bien le
cas en C). En ralit, la fonction strchr() de PHP permet tout autant de rechercher un
caractre quune chane de caractres au sein dune autre chane.
Le prototype de strstr() est le suivant :
string strstr(string botte_de_foin, string aiguille);

La fonction strstr() recherche dans la botte de foin qui lui est passe comme
premier paramtre sil existe l aiguille qui lui est fournie en deuxime paramtre.
Lorsque strstr() tablit une correspondance exacte entre l aiguille et la
botte de foin, elle renvoie la partie de la botte de foin partir de laiguille loca-
lise. Dans le cas contraire, strstr() renvoie false. Lorsque plusieurs occurrences de
la sous-chane recherche sont dtectes, strstr() renvoie la partie de la chane qui
commence la premire occurrence de laiguille.
Par exemple, dans le cadre de notre application modle, nous pouvons choisir le desti-
nataire vers lequel un message reu doit tre dirig laide du code suivant :
$adresse_dest = "commentaires@exemple.com"; // la valeur par dfaut

// Modifie $adresse_dest si le critre de slection est satisfait


if (strstr($commentaire, "boutique")) {
Chapitre 4 Manipulation de chanes et dexpressions rgulires 131

$adresse_dest = "distribution@exemple.com";
} else if (strstr($commentaire, "livraison")) {
$adresse_dest = "livraison@exemple.com";
} else if (strstr($commentaire, "facture")) {
$adresse_dest = "comptes@exemple.com";
}

Ce code examine si le message contient certains mots-cls et transmet le-mail la


personne approprie. Si, par exemple, le message dun client contient la phrase "Je nai
pas encore reu la facture de ma dernire commande", la chane "facture" sera dtecte et
le message sera transmis comptes@exemple.com.
Il existe deux variantes de la fonction strstr(). La premire, stristr(), est presque
identique strstr(), sauf quelle nest pas sensible la casse. Elle serait trs utile dans
lexemple considr ici, puisque le client est susceptible de saisir "facture", "Facture",
"FACTURE" ou tout autre mlange de minuscules et de majuscules pour ce mot.
La deuxime variante de la fonction strstr() est strrchr(), qui est elle aussi quasi-
ment identique strstr(), sauf quelle renvoie la botte de foin partir de la
dernire occurrence de laiguille.

Dtermination de la position dune sous-chane dans une chane :


strpos() et strrpos()
Les fonctions strpos() et strrpos() oprent de manire comparable strstr(), sauf
quelles renvoient la position numrique de laiguille dans la botte de foin au lieu
de renvoyer une sous-chane. Fait intressant, le manuel de PHP recommande prsent
dutiliser strpos() au lieu de strstr() pour vrifier la prsence dune sous-chane
dans une chane, car elle sexcute plus rapidement.
Le prototype de la fonction strpos() est le suivant :
int strpos(string botte_de_foin, string aiguille, int [offset] );

Le nombre entier renvoy par cette fonction donne la position de la premire occur-
rence de laiguille dans la botte de foin. Comme dhabitude, le premier caractre
occupe la position 0.
Le code qui suit affichera donc 1 dans la fentre du navigateur :
$test = "Bonjour tous";
echo strpos($test, o);

Dans ce cas, laiguille nest constitue que dun seul caractre, mais il pourrait sagir
dune chane de nimporte quelle longueur.
Le paramtre facultatif offset permet dindiquer la position partir de laquelle
commencera la recherche dans la botte de foin. La ligne de code suivante :
echo strpos($test, o, 5);
132 Partie I Utilisation de PHP

afficherait donc 11 dans le navigateur, car PHP commencerait la recherche du caractre


"o" partir de la position 5 et ne considrerait par consquent ceux qui sont situs aux
positions 1 et 4.

La fonction strrpos() est quasiment identique la fonction strpos(), sauf quelle


retourne la position de la dernire occurrence de laiguille dans la botte de foin.

Les fonctions strpos() et strrpos() renvoient false si elles ne trouvent aucune


occurrence de laiguille dans la botte de foin. Ce comportement peut se rvler
problmatique car, dans un langage faiblement typ comme PHP, false est quivalent
0, qui dsigne galement la position du premier caractre dans une chane.

Pour viter toute confusion, utilisez loprateur == pour tester les valeurs renvoyes :
$resultat = strpos($test, B);
if ($resultat === false) {
echo "Non trouv";
} else {
echo "Trouv la position 0";

Substitution de sous-chanes : str_replace() et substr_replace()


La fonctionnalit de recherche/remplacement peut se rvler extrmement utile dans le
traitement des chanes. Elle permet de personnaliser les documents produits par PHP
(on peut, par exemple, utiliser une procdure de recherche/remplacement pour
remplacer <nom> par un nom de personne et <adresse> par ladresse de la personne
considre). Elle permet galement de censurer certains termes, par exemple dans le
contexte dune application de forum de discussion, voire dune application de formu-
laire "intelligent".

L encore, PHP offre un jeu de fonctions spcifiques pour le traitement des chanes ou
des expressions rgulires.

str replace() est la fonction de traitement de chane la plus utilise pour le remplacement.
Son prototype est le suivant :
string str_replace(string aiguille, string nouvelle_aiguille,
string botte_de_foin[, int &nombre]));

La fonction str replace() remplace dans la chane botte de foin toutes les occur-
rences de la sous-chane aiguille par la sous-chane nouvelle aiguille et renvoie la
nouvelle version de la botte de foin.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 133

Le quatrime paramtre facultatif, nombre, contient le nombre de remplacements


effectus.

INFO
Vous pouvez passer tous les paramtres sous la forme dun tableau ; la fonction
str replace() agira de manire remarquablement intelligente. Vous pouvez passer un
tableau contenant les mots remplacer, un tableau des mots en remplacement (en corres-
pondance avec le premier) et un tableau des chanes auxquelles appliquer ces rgles. La
fonction renverra alors un tableau des chanes modifies.

Dans le cadre de notre formulaire de courrier lectronique, par exemple, les clients
pourraient glisser des termes injurieux dans leurs messages. Nous pouvons viter aux
divers services de lentreprise de Bob dtre importuns par de tels messages en utili-
sant un tableau $injures contenant les mots injurieux que vous souhaitez censurer.
Voici un exemple utilisant str replace() avec un tableau :
$commentaire = str_replace($injures, "%!@*", $commentaire);

La fonction substr replace() permet de rechercher et de remplacer une sous-chane


particulire dans une chane. Son prototype est le suivant :
string substr_replace(string chane, string remplacement, int dbut, int [longueur] );

Cette fonction remplace une partie de la chane chane par la chane remplacement. Les
valeurs des paramtres dbut et longueur dfinissent la partie remplacer.
La valeur de dbut reprsente un offset (ou dcalage) partir duquel entreprendre le
remplacement dans chane. Si la valeur de dbut est positive ou nulle, loffset est dfini
partir du dbut de la chane ; si elle est ngative, loffset est dfini partir de la fin de
la chane. Par exemple, la ligne de code qui suit remplace le dernier caractre de la
chane $test par un X :
$test = substr_replace($test, X, -1);

Le paramtre longueur est facultatif et indique la position dans la chane o PHP doit
stopper le remplacement. Lorsque cet argument nest pas fourni, la chane est remplace
partir de la position dbut jusqu la fin de la chane.
Si longueur vaut zro, la chane de remplacement est insre dans chane sans craser
la chane existante.
Si longueur a une valeur positive, il indique le nombre de caractres qui doivent tre
remplacs par nouvelle chane.
Si longueur a une valeur ngative, il indique la position partir de laquelle doit sinter-
rompre le remplacement, compte partir de la fin de chane.
134 Partie I Utilisation de PHP

Introduction aux expressions rgulires


PHP reconnat deux styles de syntaxe pour les expressions rgulires : POSIX et Perl.
Ces deux types sont intgrs par dfaut dans PHP et, partir de la version 5.3, les
expressions rgulires Perl (PCRE ou Perl-Compatible Regular Expression) ne peuvent
plus tre dsactives. Nous prsenterons ici le style POSIX car cest le plus simple ; si
vous connaissez dj Perl ou que vous vouliez en savoir plus sur PCRE, consultez le
manuel en ligne, publi lURL http://www.manuelphp.com/php/ref.pcre.php.

INFO
Les expressions rgulires POSIX sont dun apprentissage plus simple mais elles ne sont pas
compatibles avec les donnes binaires.

Toutes les oprations de correspondance de motifs ralises jusquici ont fait appel
aux fonctions sur les chanes, qui nous ont limits la recherche de correspondances
exactes sur des chanes ou des sous-chanes. Pour raliser des oprations de corres-
pondance plus sophistiques, vous devez employer les expressions rgulires. Leur
apprentissage nest pas ais, mais elles sont dun secours apprciable en certaines
circonstances.

Notions de base
Une expression rgulire est un moyen de dcrire un motif dans un morceau de texte.
Les correspondances exactes (ou littrales) ralises dans les sections prcdentes
taient une forme dexpressions rgulires. Par exemple, avec "boutique" et "livraison",
nous avons effectu une recherche laide dexpressions rgulires.
En PHP, la recherche de correspondances avec des expressions rgulires sapparente
plus une recherche de correspondances avec la fonction strstr() qu une comparai-
son dgalit, parce quil sagit de rechercher loccurrence dune sous-chane dans une
autre chane (la sous-chane pouvant se situer nimporte o dans la chane, moins den
dfinir plus prcisment lemplacement). Par exemple, la chane " boutique" corres-
pond lexpression rgulire "boutique", mais elle correspond galement aux expressions
rgulires "o", "ou", etc.
Outre les caractres qui se correspondent exactement, vous pouvez utiliser des caractres
spciaux pour ajouter une mtasignification un motif. Vous pouvez, par exemple, utiliser
des caractres spciaux pour indiquer que le motif recherch doit se trouver en dbut ou
la fin dune chane, quune partie du motif peut tre rpte, ou bien encore que
certains caractres du motif doivent tre dun type particulier. Vous pouvez galement
Chapitre 4 Manipulation de chanes et dexpressions rgulires 135

rechercher des occurrences littrales de caractres spciaux. Nous allons nous pencher
sur chacune de ces possibilits.

Ensembles et classes de caractres


La possibilit dutiliser des ensembles de caractres, au lieu de simples expressions
exactes, dans les expressions rgulires confre celles-ci plus de puissance pour les
oprations de recherche. Les ensembles de caractres permettent en effet de rechercher
des correspondances sur tous les caractres dun type particulier, un peu la manire
dun joker.
Tout dabord, le caractre point (.) peut servir de joker pour reprsenter nimporte quel
caractre unique, sauf le caractre de nouvelle ligne (\n). Lexpression rgulire :
.ou
permet de raliser des correspondances sur les chanes "cou", "pou" ou "sou" (entre
autres). Ce type de joker semploie souvent pour raliser des correspondances sur des
noms de fichiers dans les systmes dexploitation.
Avec les expressions rgulires, vous pouvez tre encore plus prcis sur le type du
caractre rechercher. Vous pouvez mme dfinir un ensemble de caractres auquel le
caractre recherch devra appartenir. Dans lexemple prcdent, lexpression rgulire
correspondait "cou" et "pou", mais elle pouvait galement capturer "#ou". Pour
prciser que le caractre capturer doit tre une lettre comprise entre a et z, vous
pouvez utiliser la formulation suivante :
[a-z]
La paire de crochets, [ et ], dfinit une classe de caractres, cest--dire un ensemble
de caractres auquel doit appartenir le caractre recherch. Notez que lexpression entre
les deux crochets ne permet de capturer quun seul caractre.
Vous pouvez dfinir un ensemble de caractres sous la forme dune liste, comme ici :
[aeiou]
Cette expression indique que le caractre recherch doit tre une voyelle.
Vous pouvez galement prciser une plage de caractres en utilisant des tirets, comme dans
lexpression [a z], ou un ensemble de plages de caractres, de la manire suivante :
[a-zA-Z]
Cette expression prcise que le caractre recherch doit tre une lettre majuscule ou
minuscule.
Les ensembles peuvent aussi servir indiquer que le caractre sur lequel raliser la
correspondance ne doit pas appartenir un ensemble. Par exemple :
[^a-z]
136 Partie I Utilisation de PHP

capture tout caractre qui nest pas compris entre a et z. Laccent circonflexe plac
entre les crochets est synonyme de ngation. En dehors des crochets, il prend une autre
signification sur laquelle nous reviendrons un peu plus loin.
Outre la possibilit de dfinir vos ensembles et classes de caractres sous forme de
listes, vous disposez de plusieurs classes de caractres prdfinies, qui sont dcrites
dans le Tableau 4.3.

Tableau 4.3 : Classes de caractres utilisables dans des expressions rgulires de style
POSIX

Classe Correspondance
[[:alnum:]] Caractres alphanumriques
[[:alpha:]] Caractres alphabtiques
[[:lower:]] Lettres en majuscules
[[:upper:]] Lettres en minuscules
[[:digit:]] Chiffres dcimaux
[[:xdigit:]] Chiffres hexadcimaux
[[:punct:]] Ponctuations
[[:blank:]] Tabulations et espaces
[[:space:]] Espaces
[[:cntrl:]] Caractres de contrle
[[:print:]] Tous les caractres affichables
[[:graph:]] Tous les caractres affichables, sauf le caractre espace

Rptition
Lors dune recherche, il arrive frquemment quil soit ncessaire dindiquer que le
motif recherch peut tre une chane particulire ou une classe de caractres rpte
plusieurs fois. Pour reprsenter une telle rptition, il suffit dutiliser deux caractres
spciaux dans lexpression rgulire. Le symbole * indique que le motif peut tre rpt
zro ou plusieurs fois, tandis que le symbole + indique que le motif peut tre rpt une
ou plusieurs fois. Le symbole doit tre spcifi directement aprs la partie de lexpression
laquelle il sapplique. Par exemple :
[[:alnum:]]+

signifie "au moins un caractre alphanumrique".


Chapitre 4 Manipulation de chanes et dexpressions rgulires 137

Sous-expressions
Il est souvent trs utile de pouvoir dcouper une expression en sous-expressions, pour,
par exemple, signifier "au moins une de ces chanes suivie par exactement une autre".
Lusage de parenthses permet de dcouper une expression rgulire, exactement
comme les expressions arithmtiques. Par exemple :
(trs )*grand

correspond "grand", "trs grand", trs trs grand", et ainsi de suite.

Dnombrement de sous-expressions
Vous pouvez indiquer le nombre de rptitions dune sous-expression au moyen dune
expression numrique place entre accolades ({}). Vous avez ainsi la possibilit dindi-
quer un nombre dtermin de rptitions ({3}), une plage de rptitions ({2, 4} signifie
de 2 4 rptitions), ou bien encore une plage de rptition ouverte ( {2,} signifie au
moins deux rptitions).
Par exemple :
(trs ){1, 3}

correspond "trs ", "trs trs " et "trs trs trs ".

Ancrage au dbut ou la fin dune chane


Le motif [a z] capturera nimporte quelle chane contenant un caractre alphabtique
en minuscule. Peu importe que la chane fasse un caractre de long ou contienne un
unique caractre correspondant dans une chane plus longue.
Vous pouvez prciser quune sous-expression particulire doit apparatre en dbut et/ou
la fin de la chane explore. Cette possibilit se rvle prcieuse pour sassurer que
seule lexpression recherche, et aucune autre, napparatra dans la chane trouve.
Le symbole accent circonflexe (^) sutilise en dbut dexpression rgulire pour indi-
quer que le motif recherch doit figurer au dbut de la chane explore. Inversement, le
symbole $ sutilise en fin dexpression rgulire pour indiquer que le motif recherch
doit figurer la fin de la chane explore.
Par exemple, lexpression rgulire :
^bob

capture bob en dbut dune chane, tandis que :


com$

capture com la fin dune chane.


138 Partie I Utilisation de PHP

Enfin, lexpression :
^[a-z]$

correspond nimporte quelle chane contenant uniquement un caractre compris entre


a et z.

Branchement
Pour reprsenter un choix dans une expression rgulire, utilisez une barre verticale ( |).
Pour, par exemple, rechercher com, edu ou net, nous pouvons utiliser lexpression :
(com)|(edu)|(net)

Recherche littrale de caractres spciaux


Pour rechercher un des caractres spciaux mentionns dans les prcdentes sections,
tels que ., {, ou $, vous devez le faire prcder dune barre oblique inverse (\). Pour
reprsenter littralement une barre oblique inverse, vous devez donc la doubler ( \\).
Veillez placer vos motifs dexpression rgulire dans des chanes entre apostro-
phes simples car lutilisation dapostrophes doubles entrane des complications
inutiles.
En effet, rappelez-vous que, pour reprsenter une barre oblique inverse dans une
chane entre apostrophes doubles, vous devez utiliser deux barres obliques inverses.
Une chane PHP entre apostrophes doubles qui reprsente une expression rgulire
contenant une barre oblique inverse littrale ncessitera donc quatre barres obliques
inverses. PHP analysera ces quatre barres obliques inverses comme sil sagissait de
deux barres obliques inverses. Puis linterprteur dexpressions rgulires analysera
son tour les deux barres obliques inverses comme sil sagissait dune seule barre oblique
inverse.
Le signe dollar est galement un caractre spcial la fois dans les chanes PHP entre
apostrophes doubles et dans les expressions rgulires. Pour capturer un $ littral avec
un motif, vous devez utiliser la squence "\\\$". Cette chane se trouvant entre guille-
mets, PHP lanalysera comme correspondant \$, que linterprteur dexpression rgu-
lire interprtera ensuite comme un simple signe dollar.

Rcapitulatif sur les caractres spciaux


Les Tableaux 4.4 et 4.5 prsentent un rcapitulatif des caractres spciaux. Le
Tableau 4.4 donne la signification des caractres spciaux, utiliss en dehors de paires
de crochets. Le Tableau 4.5 donne la signification des caractres spciaux lorsque ceux-
ci sont placs entre crochets.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 139

Tableau 4.4 : Rcapitulatif des caractres spciaux utiliss dans des expressions rgulires
POSIX, en dehors des crochets

Caractre Signification
\ Caractre de protection
^ Correspondance en dbut de chane
$ Correspondance en fin de chane
. Correspond tout caractre, sauf le caractre de nouvelle ligne (\n)
| Dbut dun autre choix (se lit comme OU)
( Dbut dun sous-motif
) Fin dun sous-motif
* Rptition 0 ou plusieurs fois
+ Rptition 1 ou plusieurs fois
{ Dbut dun quantificateur min/max
} Fin dun quantificateur min/max
? Marque un sous-motif comme tant facultatif

Tableau 4.5 : Rcapitulatif sur les caractres spciaux utiliss dans des expressions
rgulires POSIX, entre crochets

Caractre Signification
\ Caractre de protection
^ NON, seulement lorsquil est utilis en position initiale
Utilis pour spcifier des plages de caractres

Application au cas du formulaire "intelligent" de courrier lectronique


Dans le cadre de notre formulaire de courrier lectronique, nous pouvons envisager au
moins deux usages possibles des expressions rgulires. Nous pourrions tout dabord y
avoir recours pour amliorer le dispositif prcdemment propos pour la dtection de
termes particuliers dans les messages envoys par les clients. En utilisant une fonction
de traitement des chanes, comme nous lavons dj suggr, il nous faudrait effectuer
trois recherches diffrentes pour tester la prsence des expressions " boutique",
"service client" et "ventes" alors que toutes les trois peuvent tre captures par une
seule expression rgulire :
boutique|service client|ventes
140 Partie I Utilisation de PHP

La seconde utilisation envisageable est la validation des adresses de courrier lectroni-


que des clients. Il faut pour cela coder le format standard dune adresse de courrier lec-
tronique dans une expression rgulire. Le codage de ce format doit reprsenter la
squence suivante : des caractres alphanumriques et de ponctuation, suivis par un
symbole @, puis par des caractres alphanumriques et des tirets, suivis par un point,
puis par plusieurs caractres alphanumriques et des tirets et, ventuellement, plusieurs
points, jusqu la fin de la chane. Concrtement, ce format pourrait tre cod de la
manire suivante :
^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$
La sous-expression ^[a zA Z0 9 \ \.]+ signifie "la chane doit commencer par une
lettre, un nombre, un blanc soulign, un tiret, un point ou toute combinaison de ces
caractres". Notez que, lorsquun point est utilis au dbut ou la fin dune classe de
caractres, il perd sa signification spciale de caractre de remplacement et devient un
simple point littral.
Le symbole @ reprsente un caractre @ littral.
La sous-expression [a zA Z0 9\ ]+ dcrit la premire partie du nom dhte. Celle-ci
doit tre compose de caractres alphanumriques et de tirets. Notez que le tiret, qui est
un caractre spcial, est prcd ici dune barre oblique inverse parce quil est plac
entre crochets.
La combinaison \. reprsente un point littral (.). Nous utilisons un point en dehors des
classes de caractres, aussi devons-nous le protger pour ne dfinir de correspondance
quavec un point littral.
La sous-expression [a zA Z0 9\ \.]+$ reprsente le reste dun nom de domaine. Cette
partie peut tre compose de lettres, de nombres, de tirets et de plusieurs points si
ncessaire, jusqu la fin de la chane.
Une analyse un tant soit peu pousse montrerait que certaines adresses de courrier lec-
tronique non valides pourraient tre dcrites par cette expression rgulire. Il est pres-
que impossible de dresser la liste de toutes ces adresses mais notre code en limine
quand mme un bon nombre. Notre expression peut tre encore affine de nombreuses
manires. Il est par exemple possible de lister tous les TLD valides. Soyez tout de
mme prudent avant dtre trop restrictif, car une fonction de validation qui rejette 1 %
de donnes valides procure plus dennuis quune autre qui accepte 10 % de donnes
non valides.
Maintenant que nous avons dfini la notion dexpression rgulire, nous allons passer
en revue les fonctions PHP qui permettent de les utiliser.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 141

Recherche de sous-chanes au moyen dexpressions rgulires


La recherche de sous-chanes est la principale application des expressions rgulires
dcrites dans les sections prcdentes. Les deux fonctions de PHP pour rechercher des
expressions rgulires POSIX sappellent ereg() et eregi().
Le prototype de la fonction ereg() est le suivant :
int ereg(string motif, string chane, array [rsultat]);

La fonction ereg() parcourt chane afin dy rechercher des occurrences de lexpres-


sion rgulire motif. Les sous-chanes ainsi dtectes sont enregistres dans le tableau
rsultat raison dune sous-expression par lment du tableau.
La fonction eregi() est identique la fonction ereg(), sauf quelle nest pas sensible
la casse.
Notre formulaire de courrier lectronique peut tre modifi en y introduisant des
expressions rgulires :
if (!eregi(^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$, $email))
{
echo "<p>Ceci nest pas une adresse email correcte.</p>" .
"<p>Revenez la page prcdente et ressayez.</p>";
exit;
}
$adresse_dest = "commentaires@exemple.com; // Adresse par dfaut
if (eregi(boutique|service client|ventes, $commentaire)) {
$adresse_dest = "ventes@exemple.com";
} else if (eregi(livraison|traitement, $commentaire))
$adresse_dest = traitements@exemple.com";
} else if (eregi(facture|compte, $commentaire))
$adresse_dest = "comptes@exemple.com";
}
if (eregi(grosclient\.com, $email))
$adresse_dest = "bob@exemple.com";
}

Remplacement de sous-chanes au moyen dexpressions rgulires


Vous pouvez galement utiliser des expressions rgulires pour rechercher et remplacer
des sous-chanes, tout comme nous lavons dj fait au moyen de la fonction
str replace. Les deux fonctions PHP ddies ce type dopration de recherche/
remplacement sont ereg replace() et eregi replace(). Le prototype de la fonction
ereg replace() est le suivant :
string ereg_replace(string motif, string remplacement, string chane);

Cette fonction cherche dans chane les occurrences de lexpression rgulire motif et
les remplace par la chane remplacement.
142 Partie I Utilisation de PHP

La fonction eregi replace() est identique la fonction ereg replace(), sauf quelle
nest pas sensible la casse.

Dcoupage de chanes au moyen dexpressions rgulires


La fonction split() est une autre fonction de traitement dexpression rgulire trs
utile. Son prototype est le suivant :
array split(string motif, string chane, int [max]);

Cette fonction dcoupe chane en sous-chanes au niveau des sous-chanes correspon-


dant lexpression rgulire motif. Elle renvoie les sous-chanes obtenues sous la
forme dun tableau. Le paramtre entier max limite le nombre dlments qui peuvent
tre contenus dans le tableau.
Par exemple, la fonction split() pourrait tre mise en uvre pour dcomposer les
adresses e-mail, les noms de domaine ou les dates :
$adresse = "utilisateur@exemple.com";
$tab = split (\.|@, $adresse);
while (list($cle, $valeur) = each ($tab)) {
echo "<br />" . $valeur;
}

Ce code dcompose ladresse en ses cinq composantes et affiche chacune delles sur
une ligne spare :
utilisateur
@
exemple
.
com

INFO
En gnral, les fonctions des expressions rgulires sexcutent moins vite que les fonctions
quivalentes sur les chanes. Si votre traitement est suffisamment simple pour se contenter
dune fonction sur les chanes, nhsitez pas. Cela peut ne plus tre vrai si le traitement peut
tre ralis par une seule expression rgulire, mais par plusieurs fonctions sur les chanes.

Pour aller plus loin


PHP compte de nombreuses fonctions sur les chanes. Nous navons ici abord que les
plus utiles mais, si vous avez un besoin particulier (la conversion de caractres latins
dans lalphabet cyrillique, par exemple), consultez le manuel en ligne afin de voir si le
PHP dispose de la fonction recherche.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 143

La littrature et les ressources consacres aux expressions rgulires sont innombra-


bles. Si vous utilisez Unix, vous pouvez commencer par la page man intitule regexp.
Vous trouverez galement des articles prcieux sur les sites devshed.com et phpbuil-
der.com.
Le site web de Zend propose une fonction de validation des courriers lectroniques plus
complexe et plus puissante que celle dveloppe dans le cadre de notre exemple. Cette
fonction sappelle MailVal() ; elle est disponible lURL http://www.zend.com/
codex.php?id=88&single=1.
Vous aurez besoin dun peu de pratique pour bien exploiter les expressions rgulires.
Plus vous vous exercerez dans le domaine et mieux vous saurez les manier.

Pour la suite
Nous tudierons au prochain chapitre plusieurs manires dutiliser PHP pour conomi-
ser du temps et des efforts de programmation et empcher la redondance en rutilisant
du code prexistant.
5
Rutilisation de code
et criture de fonctions

Ce chapitre explique comment rutiliser du code pour dvelopper des applications plus
cohrentes, plus fiables et plus faciles grer, avec moins defforts. Nous examinerons
des techniques de modularisation et de rutilisation du code, en commenant par la
simple mise en uvre des fonctions require() et include() pour utiliser le mme
code dans plusieurs pages. Nous expliquerons pourquoi cette technique est meilleure
que les inclusions ct serveur. Lexemple donn expliquera comment utiliser des
fichiers include afin dobtenir une apparence cohrente sur tout un site web.
Nous montrerons galement comment crire et appeler ses propres fonctions en prenant
titre dexemple des fonctions gnrant des pages et des formulaires.

Avantages de la rutilisation du code


Lun des buts recherchs par les dveloppeurs consiste rutiliser du code au lieu den
crire du nouveau. Non pas quils soient particulirement paresseux, mais la rutilisa-
tion de code existant tend rduire les cots, augmenter la fiabilit des programmes et
amliorer leur cohrence. Dans lidal, un nouveau projet devrait tre conduit en
combinant des composants logiciels rutilisables existants, avec un minimum de nouveau
dveloppement.

Cot
Sur la dure de vie dun composant logiciel, le temps pass sa maintenance, sa
modification, son test et sa documentation excde largement le temps initialement
consacr son dveloppement. Concernant le code commercial, il est fortement recom-
mand de limiter le nombre de lignes de code en usage au sein dune entreprise.
146 Partie I Utilisation de PHP

Une des meilleures mthodes pour observer cette recommandation consiste rutiliser
du code dj existant au lieu dcrire une version lgrement diffrente dun morceau
de code existant pour accomplir une nouvelle tche. Une rduction du volume du code
se traduit directement par une rduction des cots. Sil existe sur le march un logiciel
rpondant aux objectifs dun nouveau projet, achetez-le. Le prix des logiciels existants
est presque toujours infrieur au cot de dveloppement dun projet quivalent. Si un
programme existant correspond "presque" vos besoins, vous devrez toutefois exami-
ner soigneusement les modifications qui devront lui tre apportes, car modifier du
code existant peut tre plus difficile qucrire du nouveau code.

Fiabilit
Lorsquun module de code est utilis au sein dune entreprise, cest gnralement aprs
avoir fait lobjet de tests srieux. Mme si un composant logiciel ne requiert que quel-
ques lignes de code, vous courez le risque, en le rcrivant, doublier un point pris en
compte par lauteur du composant existant ou de ngliger une correction apporte au
code dorigine aprs que les tests ont mis en vidence un dfaut. Le code mature, existant,
est gnralement plus fiable que le code encore "vert".

Cohrence
Les interfaces externes vers votre systme, y compris les interfaces utilisateur et les
interfaces vers des systmes externes, doivent tre cohrentes. Il faut de lopinitret et
des efforts dlibrs pour crire du nouveau code qui reste cohrent avec les autres
parties du systme. En revanche, si vous rutilisez du code dj en service dans une
autre partie du systme, vous avez toutes les chances pour que la fonctionnalit obtenue
soit automatiquement cohrente.
Un avantage essentiel de la rutilisation du code est quelle minimise la charge de
travail du dveloppeur, mais condition que le code dorigine soit modulaire et bien
crit. Lorsque vous programmez, faites en sorte didentifier les sections de votre code
susceptibles de servir ultrieurement dans dautres applications.

Utilisation des instructions require() et include()


PHP offre deux instructions trs simples et nanmoins trs utiles qui permettent de
rutiliser tout type de code. Par le biais dune instruction require() ou include(),
vous pouvez charger un fichier dans un script PHP. Le fichier ainsi charg peut contenir
tout ce qui pourrait normalement tre inclus dans un script, y compris des instructions
PHP, du texte, des balises HTML, des fonctions PHP ou des classes PHP.
Les instructions require() et include() fonctionnent la manire des inclusions ct
serveur offertes par de nombreux serveurs web et des instructions #include des langages C
et C++.
Chapitre 5 Rutilisation de code et criture de fonctions 147

Ces deux instructions sont quasiment identiques. La seule diffrence est que require()
provoque une erreur fatale lorsquelle choue, alors que include() ne produit quun
message davertissement.
require once() et include once() sont des variantes de require() et include().
Leur but consiste sassurer quun fichier inclus ne le sera quune seule fois, ce qui
devient particulirement utile lorsque lon utilise require() et include() pour inclure
des bibliothques de fonctions. Lutilisation de ces deux variantes vous empche alors
dinclure accidentellement la mme bibliothque deux fois, ce qui provoquerait la
redfinition de ses fonctions et donc une erreur. Si vous tes suffisamment rigoureux,
vous avez tout intrt prfrer require() ou include() car elles sexcutent plus
rapidement.

Extensions des noms de fichiers et require()


Supposons que le code suivant soit stock dans le fichier reutilisable.php :
<?
echo "Ceci est une instruction PHP trs simple.<br />";
?>

et que le fichier principal.php ait le contenu suivant :


<?
echo "Ceci est le fichier principal.<br />";
require( reutilisable.php );
echo "Fin du script.<br />";
?>

Si vous chargez directement reutilisable.php dans votre navigateur web, vous ne serez
pas surpris de le voir afficher la phrase Ceci est une instruction PHP trs simple. En
revanche, le chargement de principal.php a un effet un peu plus inattendu. Le rsultat
obtenu est montr la Figure 5.1.

Figure 5.1
Le chargement du fichier
principal.php fait apparatre
le rsultat de linstruction
require().

Une instruction require() exige un fichier. Dans lexemple prcdent, nous avons
utilis le fichier appel reutilisable.php. lexcution du script, linstruction
require() :
require( reutilisable.php );
148 Partie I Utilisation de PHP

est remplace par le contenu du fichier indiqu, puis le script contenu dans ce dernier
est alors excut. Lexcution qui sopre au chargement du fichier principal.php est
donc quivalente lexcution du script suivant :
<?
echo "Ceci est le fichier principal.<br />";
echo "Ceci est une instruction PHP trs simple.<br />";
echo "Fin du script.<br />";
?>
Pour bien utiliser linstruction require(), vous devez connatre la manire dont sont
traites les extensions des noms de fichier et les balises PHP.
PHP ignore lextension du nom du fichier qui est charg au moyen de la fonction
require(). Par consquent, vous pouvez donner ce fichier le nom qui vous convient
du moment que vous ne comptez pas lappeler directement. Lorsque le fichier est
charg par require(), celui-ci devient partie intgrante dun fichier PHP et est excut
en tant que tel.
Gnralement, des instructions PHP contenues dans un fichier appel, par exemple,
page.html ne seront pas traites. PHP ne traite normalement que les fichiers dont les
noms portent des extensions dfinies, comme .php (ce comportement peut tre modifi
dans le fichier de configuration de votre serveur web). Toutefois, si le fichier page.html
est charg via la fonction require(), toute instruction PHP contenue dans ce fichier
sera traite PHP. Par consquent, vous pouvez choisir nimporte quelle extension pour
les fichiers inclure via require(). Il est toutefois recommand de sen tenir une
convention logique pour le choix des noms de fichier (par exemple en adoptant syst-
matiquement lextension .inc ou .php pour tous les fichiers inclure).
Attention : lorsque des fichiers portant une extension non standard, telle que .inc, sont
stocks dans larborescence des documents du serveur, les utilisateurs qui les chargent
directement dans leur navigateur pourront visualiser leur contenu en texte clair, y
compris les mots de passe qui y sont ventuellement contenus ! Par consquent, il est
important de conserver ce type de fichier en dehors de larborescence des documents ou
bien alors demployer des extensions standard.

INFO
Dans lexemple considr plus haut, le fichier rutilisable reutilisable.php avait le contenu
suivant :
<?
echo "Ceci est une instruction PHP trs simple.<br />";
?>
Le code PHP de ce fichier est encadr par des balises PHP, ce qui est indispensable pour que
le code dun fichier charg via require() soit trait par linterprteur PHP. En labsence de
ces balises, le code sera considr comme du texte ou du code HTML et ne sera pas excut.
Chapitre 5 Rutilisation de code et criture de fonctions 149

Utilisation require() pour crer des modles de site web


Si les pages de votre site web doivent avoir une prsentation et un style cohrents, vous
pouvez utiliser require() pour ajouter un modle et des lments standard toutes les
pages.
Par exemple, considrons le cas dune entreprise fictive, appele TLA Consulting, dont
le site contient tout un jeu de pages ressemblant celle de la Figure 5.2. Lorsquune
nouvelle page doit tre ajoute au site, le dveloppeur peut ouvrir une page existante,
effacer le texte contenu dans le milieu du fichier, entrer un nouveau texte, puis enregistrer
le fichier sous un nouveau nom.

Figure 5.2
Lentreprise TLA utilise une prsentation homogne pour toutes les pages de son site web.

Considrez le scnario suivant : le site web est en service depuis un certain temps dj
et contient prsent des centaines, voire des milliers de pages, toutes construites sur le
mme style. Supposez quil soit dcid de procder une modification de lapparence
standard, mme mineure, comme lajout dune adresse de courrier lectronique en bas
de chaque page ou dune nouvelle entre dans le menu de navigation. Voulez-vous vous
trouver dans la situation de devoir modifier des centaines, voire des milliers de pages ?
La rutilisation des sections HTML communes toutes les pages est de loin prfrable
des oprations de couper/coller reproduire sur des centaines ou des milliers
de pages. Le code source de la page daccueil montre la Figure 5.2 est prsent dans
le Listing 5.1.
150 Partie I Utilisation de PHP

Listing 5.1 : accueil.html Le code HTML de la page daccueil du site TLA Consulting

<html>
<head>
<title>TLA Consulting</title>
<style type="text/css">
h1 {color:white; font-size:24pt; text-align:center;
font-family:arial,sans-serif}
.menu {color:white; font-size:12pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold}
td {background:black}
p {color:black; font-size:12pt; text-align:justify;
font-family:arial,sans-serif}
p.foot {color:white; font-size:9pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold}
a:link,a:visited,a:active {color:white}
</style>
</head>
<body>
<!-- Entte de page -->
<table width="100%" cellpadding="12" cellspacing="0" border="0">
<tr bgcolor="black">
<td align="left"><img src="logo.gif" alt="Logo TLA" height="70"
width="70"></td>
<td>
<h1>TLA Consulting</h1>
</td>
<td align="right"><img src="logo.gif" alt="Logo TLA" height="70"
width="70"></td>
</tr>
</table>

<!-- Menu -->


<table width="100%" bgcolor="white" cellpadding="4" cellspacing="4">
<tr >
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Accueil</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Contacts</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Services</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Carte du site</span></td>
</tr>
</table>

<!-- Contenu de la page -->


<p>Bienvenue sur le site de TLA Consulting.
Prenez le temps de nous connatre.</p>
<p>Nous sommes spcialiss dans laide aux dcisions et
nous esprons que vous ferez bientt appel nous.</p>
Chapitre 5 Rutilisation de code et criture de fonctions 151

<!-- Pied de page -->


<table width="100%" bgcolor="black" cellpadding="12" border="0">
<tr>
<td>
<p class="foot">&copy; TLA Consulting</p>
<p class="foot">Consultez la page sur nos
<a href="legal.php">informations lgales</a></p>
</td>
</tr>
</table>
</body>
</html>

Le Listing 5.1 se compose de plusieurs sections de code bien distinctes. Len-tte


HTML contient les dfinitions CSS (Cascading Style Sheet) utilises dans la page. La
section intitule "Entte de page" affiche le nom et le logo de lentreprise, la section
"Menu" cre la barre de navigation de la page, tandis que la section "Contenu de la
page" rassemble le texte spcifique cette page. Vient ensuite le pied de page. Nous
allons scinder ce fichier en trois parties que nous enregistrerons respectivement dans les
fichiers entete.php, accueil.php et pied.php. Les fichiers entete.php et pied.php
contiendront alors le code que nous rutiliserons pour produire dautres pages.
Le fichier accueil.php remplace le fichier accueil.html ; il renferme le contenu textuel
spcifique de la page ainsi que deux instructions require(). Le contenu de ce fichier
est prsent dans le Listing 5.2.

Listing 5.2 : accueil.php Le code PHP de la page daccueil du site web de TLA Consulting

<?php
require("entete.php");
?>
<!-- Contenu de la page -->
<p>Bienvenue sur le site de TLA Consulting.
Prenez le temps de nous connatre.</p>
<p>Nous sommes spcialiss dans laide aux dcisions et
nous esprons que vous ferez bientt appel nous.</p>

<?php
require(pied.php);
?>

Les instructions require() du Listing 5.2 provoquent le chargement des fichiers


entete.php et pied.php.
Comme nous lavons dj mentionn, les noms attribus ces fichiers nont pas dinci-
dence sur la manire dont les fichiers seront traits lorsque le chargement seffectue
via une instruction require(). Lextension .inc (pour "inclure", ou include) est trs
152 Partie I Utilisation de PHP

souvent adopte pour ces types de fichiers, qui sont appels tre inclus dans dautres
fichiers. Nous ne recommandons pas cette convention comme une stratgie gnrale car
les fichiers .inc ne seront pas interprts comme du code PHP, sauf si le serveur a t
spcifiquement configur pour cela.
Par ailleurs, lusage consiste gnralement rassembler les fichiers inclus dans un
rpertoire visible des scripts, mais qui ne permette pas leur chargement individuel via le
serveur web, cest--dire lextrieur de larborescence des documents du serveur.
Cette pratique est fortement recommande. En effet, le chargement individuel de ces
fichiers peut provoquer des erreurs si lextension des fichiers est .php et que les fichiers
ne contiennent que des pages ou des scripts partiels, ou il peut permettre des tiers de
lire le code source lorsquune extension autre que .php est employe.
Le fichier entete.php contient les dfinitions CSS utilises par la page ainsi que les
tableaux qui affichent le nom de lentreprise et les barres de navigation. Son contenu est
donn dans le Listing 5.3.

Listing 5.3 : entete.php Len-tte rutilisable par toutes les pages du site web de TLA
Consulting

<html>
<head>
<title>TLA Consulting</title>
<style type="text/css">
h1 {color:white; font-size:24pt; text-align:center;
font-family:arial,sans-serif}
.menu {color:white; font-size:12pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold}
td {background:black}
p {color:black; font-size:12pt; text-align:justify;
font-family:arial,sans-serif}
p.foot {color:white; font-size:9pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold}
a:link,a:visited,a:active {color:white}
</style>
</head>
<body>
<!-- Entte de page -->
<table width="100%" cellpadding="12" cellspacing="0" border="0">
<tr bgcolor="black">
<td align="left"><img src="logo.gif" alt="Logo TLA" height="70"
width="70"></td>
<td>
<h1>TLA Consulting</h1>
</td>
<td align="right"><img src="logo.gif" alt="Logo TLA" height="70"
width="70"></td>
</tr>
</table>

<!-- Menu -->


Chapitre 5 Rutilisation de code et criture de fonctions 153

<table width="100%" bgcolor="white" cellpadding="4" cellspacing="4">


<tr >
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Accueil</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Contacts</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Services</span></td>
<td width="25%">
<img src="s-logo.gif" alt="" height="20" width="20">
<span class="menu">Carte du site</span></td>
</tr>
</table>

Le fichier pied.php contient le tableau utilis pour afficher le pied de page en bas de
chaque page. Il est prsent dans le Listing 5.4.

Listing 5.4 : pied.php Le pied de page rutilisable par toutes les pages du site web
de TLA Consulting

<!-- Pied de page -->


<table width="100%" bgcolor="black" cellpadding="12" border="0">
<tr>
<td>
<p class="foot">&copy; TLA Consulting</p>
<p class="foot">Consultez la page sur nos
<a href="legal.php">informations lgales</a></p>
</td>
</tr>
</table>
</body>
</html>

Une telle approche permet dobtenir facilement une prsentation et une apparence
homognes sur tout un site. Une nouvelle page conue dans le mme style peut ainsi
tre aisment gnre en quelques lignes de code :
<?php require(entete.php);?>
Mettre ici le contenu de cette page
<?php require(pied.php);?>

Plus important encore, mme lorsque de nombreuses pages ont ainsi t produites
partir des mmes fichiers den-tte et de pied de page, vous pouvez facilement modifier
ces fichiers modles. Que la modification apporte soit mineure ou quelle vise
donner une apparence compltement nouvelle au site, elle ne devra tre apporte
quune seule fois. Cette technique vite davoir traiter chaque page sparment.
154 Partie I Utilisation de PHP

Dans lexemple considr ici, le corps, len-tte et le pied de page de chaque page ne
contiennent que du HTML pur. Des instructions PHP pourraient toutefois tre utilises
pour produire dynamiquement certaines parties des pages web du site.
Si vous souhaitez tre sr quun fichier sera trait comme du texte brut ou du HTML et
quaucun code PHP ne sera excut, vous pouvez utiliser readfile() la place de
require() car cette fonction affiche le contenu dun fichier sans lanalyser. Il peut
sagir dune mesure de prcaution importante si vous utilisez du texte fourni par lutili-
sateur.

Utilisation des options de configuration auto_prepend_file et


auto_append_file
Il existe une autre manire dutiliser linstruction require() ou include() pour ajouter
un en-tte et un pied de page chaque page. Le fichier de configuration php.ini contient
deux options de configuration, auto prepend file et auto append file, qui peuvent
tre initialises avec, respectivement, le nom de notre fichier den-tte et celui du pied
de page, de sorte que ces fichiers seront systmatiquement chargs au dbut et la fin
de chaque page. Les fichiers inclus par ces directives se comportent comme sils avaient
t ajouts en utilisant une instruction include() ; autrement dit, si le fichier est
manquant, cela produira un message davertissement.
Sur un systme Windows, le paramtrage de ces options seffectuerait de la manire
suivante :
auto_prepend_file = "c:/Program Files/Apache Group/Apache2//include/entete.php"
auto_append_file = "c:/Program Files/Apache Group/Apache2/include/pied.php"

Sur une plate-forme Unix, ces options se paramtrent de la faon suivante :


auto_prepend_file = /home/utilisateur/include/entete.php
auto_append_file = /home/utilisateur/include/pied.php

Lorsque ces directives sont indiques dans le fichier php.ini, il nest plus ncessaire de
faire appel aux instructions include(). En revanche, les en-ttes et les pieds de page ne
sont plus facultatifs dans les pages web.
Avec un serveur web Apache, vous pouvez dfinir des options de configuration comme
celles dcrites prcdemment pour chaque rpertoire individuel. Pour cela, vous devez
configurer votre serveur de sorte que ses principaux fichiers de configuration soient
"crasables". Pour configurer PHP afin quil charge automatiquement des fichiers au
dbut et la fin de chaque page pour un rpertoire spcifique, crez dans ce rpertoire
un fichier appel .htaccess et placez-y les deux lignes suivantes :
php_value auto_prepend_file /home/utilisateur/include/entete.php
php_value auto_append_file /home/utilisateur/include/pied.php
Chapitre 5 Rutilisation de code et criture de fonctions 155

Notez que la syntaxe diffre lgrement de celle utilise plus haut pour la mme option
dans le fichier php.ini ; outre la prsence de php value au dbut de la ligne, il ny a plus
de signe gal. Plusieurs autres paramtres de configuration de php.ini peuvent tre
modifis de la sorte.
La dfinition doptions dans le fichier .htaccess et non dans le fichier php.ini ou dans le
fichier de configuration du serveur web procure une grande souplesse. Vous pouvez
ainsi modifier le paramtrage sur une machine partage en naffectant que vos seuls
rpertoires. Il nest pas ncessaire de redmarrer le serveur web ni de bnficier dun
accs dadministrateur systme. Lapproche .htaccess a toutefois linconvnient que les
fichiers sont lus et analyss chaque fois quun fichier est sollicit dans le rpertoire
concern, au lieu dtre lus et analyss une seule fois au dmarrage. Elle a donc un cot
en terme de performances.

Utilisation de fonctions en PHP


Les fonctions existent dans la plupart des langages de programmation. Elles servent
sparer le code qui accomplit une tche unique et bien dfinie. Les fonctions rendent le
code plus lisible et permettent de le rutiliser chaque fois quune mme tche doit tre
accomplie.
Une fonction est un module de code autonome associ une interface dappel. Elle
accomplit un certain traitement et renvoie ventuellement un rsultat.
Nous avons dj tudi plusieurs fonctions. Dans les chapitres prcdents, nous avons
rgulirement appel des fonctions prdfinies de PHP. Par ailleurs, nous avons nous-
mmes crit quelques fonctions simples, sans toutefois entrer dans les dtails. Dans les
sections suivantes, nous allons nous pencher plus attentivement sur lappel et lcriture
de fonctions.

Appel de fonctions
Lappel de fonction le plus simple qui soit est le suivant :
nom_fonction();

Cette ligne de code appelle la fonction nom fonction, qui ne prend pas de paramtre.
Elle ignore toute valeur ventuellement renvoye par la fonction.
Un certain nombre de fonctions sont appeles exactement de cette manire. Par exem-
ple, cest le cas de la fonction phpinfo(), qui est trs utile lors des tests puisquelle affi-
che la version installe de PHP, les informations relatives PHP, la configuration du
serveur web et les valeurs des diverses variables de PHP et du serveur. Cette fonction ne
prend aucun paramtre et la valeur quelle renvoie est le plus souvent ignore.
156 Partie I Utilisation de PHP

Lappel de la fonction phpinfo() scrit donc de la manire suivante :


phpinfo();

La plupart des fonctions requirent cependant un ou plusieurs paramtres qui fournis-


sent les informations ncessaires laccomplissement de la tche et qui influencent le
rsultat de lexcution de la fonction. Les paramtres sont passs une fonction sous la
forme de donnes ou de noms de variables contenant ces donnes. Ils sont placs dans
une liste entre parenthses, la suite du nom de la fonction. Lappel dune fonction
prenant un seul paramtre seffectue donc de la faon suivante :
nom_fonction(paramtre);

Ici, le paramtre est une chane contenant seulement le mot paramtre. Les appels de
fonction qui suivent sont galement valides, selon la fonction appele :
nom_fonction (2);
nom_fonction (7.993);
nom_fonction ($variable);

Dans la dernire de ces trois lignes de code, $variable peut tre une variable PHP de
tout type, y compris un tableau ou un objet.
Les paramtres peuvent tre de nimporte quel type, mais certaines fonctions exigent
gnralement des types de donnes spcifiques.
Le prototype dune fonction dcrit le nombre de paramtres requis ainsi que la signifi-
cation et le type de chacun deux. Cet ouvrage donne gnralement le prototype de
chaque fonction dcrite.
Le prototype de la fonction fopen(), par exemple, est le suivant :
resource fopen( string nomFichier, string mode,
[, bool utiliser_include_path [, resource contexte]] )

Le prototype dune fonction fournit de prcieuses indications sur la fonction, quil est
important de savoir interprter. Dans le prototype de la fonction fopen(), le terme
resource plac avant le nom de la fonction indique quelle renvoie une ressource
(un descripteur de fichier ouvert). Les paramtres de la fonction sont indiqus entre
parenthses. Comme le montre ce prototype, fopen() attend donc quatre param-
tres. Les paramtres nomFichier et mode sont des chanes, tandis que le paramtre
utiliser include path est un boolen et que le paramtre contexte est une
ressource. La prsence de crochets de part et dautre des paramtres
utiliser include path et contexte indique que ces paramtres sont facultatifs : vous
pouvez leur fournir une valeur ou les ignorer, auquel cas PHP utilisera une valeur par
dfaut. Notez toutefois que, lorsquune fonction a plusieurs paramtres facultatifs, vous
ne pouvez ignorer que les paramtres placs droite. Lorsque vous appelez fopen(),
par exemple, vous pouvez ignorer simplement contexte ou utiliser include path et
Chapitre 5 Rutilisation de code et criture de fonctions 157

contexte, mais vous ne pouvez pas ignorer utiliser include path tout en fournissant
contexte.
Daprs le prototype de fopen(), nous pouvons affirmer que lappel de cette fonction
est correct dans le fragment de code qui suit :
$nom = monfichier.txt;
$mode_ouverture = r;
$fp = fopen($nom, $mode_ouverture);
Ce code appelle la fonction fopen(). La valeur renvoye par cette dernire sera stocke
dans la variable $fp. On passe la variable $name comme premier paramtre de fopen().
Celle-ci contient une chane reprsentant le nom du fichier ouvrir. Le deuxime para-
mtre pass est une variable appele $mode ouverture, qui contient une chane repr-
sentant le mode douverture du fichier. Dans cet exemple, nous navons pas fourni les
troisime et quatrime paramtres facultatifs.

Appel dune fonction indfinie


Lappel dune fonction qui nexiste pas provoque la production dun message derreur
comme celui de la Figure 5.3.

Figure 5.3
Ce message derreur
rsulte de lappel
dune fonction qui
nexiste pas.

Les messages derreur affichs par linterprteur PHP sont gnralement trs utiles.
Celui de la Figure 5.3 nous indique exactement le contexte dans lequel sest produite
lerreur, cest--dire le nom du fichier, le numro de la ligne du script et le nom de la
fonction qui a t appele et qui nexiste pas. Ces indications permettent en principe de
corriger facilement et rapidement lerreur survenue.
laffichage dun tel message derreur, vous devez vous poser deux questions :
1. Le nom de la fonction est-il correctement orthographi dans le script ?
2. La fonction appele existe-t-elle dans la version de PHP utilise ?
Les noms des fonctions sont parfois difficiles mmoriser. Par exemple, certaines fonc-
tions prdfinies de PHP ont des noms composs de deux mots spars par un caractre
de soulignement (comme strip tags()), tandis que dautres ont des noms forms de
deux mots accols (comme stripslashes()). La prsence dune faute dorthographe
dans le nom dune fonction provoque lerreur montre la Figure 5.3.
158 Partie I Utilisation de PHP

Certaines fonctions dcrites dans cet ouvrage nexistent pas dans la version 4.0 de
PHP car nous partons du principe que vous tes au moins quip de la version 5.0.
Chaque nouvelle version de PHP apporte son lot de nouveauts qui enrichissent les
fonctionnalits et les performances du langage et justifient donc une mise jour.
Vous pouvez consulter dans le manuel en ligne de PHP (http://no.php.net/manual/
fr/) la date dajout de chaque fonction disponible. Lappel dune fonction non dcla-
re dans la version de PHP utilise provoque lerreur dont le message est montr la
Figure 5.3.
Lune des autres raisons qui peuvent conduire ce message derreur peut tre que la
fonction que vous appelez fait partie dune extension de PHP qui nest pas charge. Par
exemple, si vous essayez dutiliser des fonctions de la bibliothque gd (manipulation
dimages) alors que vous ne lavez pas installe, vous obtiendrez ce message.

Casse et noms des fonctions


Les appels de fonctions ne sont pas sensibles la casse. Les appels de fonction nom(),
Fonction Nom() et FONCTION NOM sont donc tous valides et conduisent au mme rsul-
tat. Vous tes libre de choisir la casse qui vous convient et que vous jugez plus facile
lire mais essayez de rester cohrent. Dans cet ouvrage, comme dans la plupart des
ouvrages de programmation, la convention adopte consiste crire tous les noms de
fonctions en minuscules.
Les noms de fonctions se comportent diffremment des noms de variables puisque ces
derniers sont, eux, sensibles la casse: $Nom et $nom dsignent donc deux variables
diffrentes, alors que Nom() et nom() dsignent la mme fonction.

Dfinir ses propres fonctions ?


Au cours des chapitres prcdents, nous avons t amens tudier et utiliser
un certain nombre de fonctions prdfinies de PHP. Toutefois, la relle puissance dun
langage de programmation tient dans la possibilit de crer des fonctions person-
nalises.
Grce aux fonctions prdfinies dans PHP, vous pouvez interagir avec des fichiers,
manipuler une base de donnes, crer des images et vous connecter dautres serveurs.
Malgr toute la richesse de ces possibilits, vous devrez souvent raliser des traitements
que les crateurs du langage nont pas prvus.
Vous ntes heureusement pas limit aux fonctions prdfinies de PHP : vous pouvez
crer des fonctions personnalises qui accompliront les traitements que vous souhaitez.
Votre code consistera certainement en une combinaison de fonctions existantes et de
logique personnelle ; lensemble tant destin raliser des tches particulires.
Chapitre 5 Rutilisation de code et criture de fonctions 159

Lorsque vous crivez un bloc de code pour effectuer une tche que vous serez vraisem-
blablement amen rutiliser plusieurs autres endroits dans votre script, voire dans
dautres scripts, vous avez tout intrt dclarer ce bloc de code comme une fonction.
Dclarer une fonction permet dutiliser du code personnalis la manire des fonctions
prdfinies de PHP : il suffit dappeler la fonction utilisateur et de lui fournir les para-
mtres requis. Vous pouvez ainsi appeler et rutiliser la mme fonction plusieurs fois
dans un mme script.

Structure de base dune fonction


Une dclaration de fonction cre, ou dclare, une nouvelle fonction. Une dclaration
commence par le mot-cl function, suivi du nom de la fonction, de ses paramtres et
du code excuter chaque appel de la fonction.
La dclaration dune fonction triviale seffectue de la manire suivante :
function ma_fonction(){
echo ma_fonction a t appele.;
}

Cette dclaration de fonction commence par function pour que le lecteur et linterpr-
teur PHP sachent que le code qui suit est celui dune fonction personnalise. Le nom de
la fonction tant ma fonction, nous pouvons appeler notre nouvelle fonction au moyen
de linstruction suivante :
ma_fonction();

Vous lavez probablement devin, lappel de cette fonction se traduit par laffichage
dans la fentre du navigateur du texte "ma fonction a t appele.".
Alors que les fonctions prdfinies dans PHP sont utilisables dans tous les scripts PHP,
les fonctions personnalises ne le sont que par les scripts dans lesquels elles ont t
dclares. Il est conseill de placer dans un mme fichier, ou dans un ensemble de
fichiers, toutes les fonctions personnalises couramment utilises. Cette astuce permet
en effet au programmeur daccder toutes ses fonctions par une simple instruction
require() insre dans chacun des scripts.
Dans une dclaration de fonction, le code accomplissant la tche requise doit tre plac
entre accolades. Ce code peut contenir tout ce qui est autoris dans un script PHP, y
compris des appels dautres fonctions, des dclarations de nouvelles variables ou fonc-
tions, des instructions require() ou include(), des dclarations de classe et du code
HTML. Lorsque, au sein dune fonction, il est ncessaire de quitter PHP et dafficher
du code HTML brut, il suffit de procder comme en tout autre endroit dun script : en
plaant une balise PHP de fermeture avant le code HTML.
160 Partie I Utilisation de PHP

Le code qui suit est une variante possible de lexemple prcdent et il produit le mme
rsultat :
<?php
function ma_fonction() {
?>
ma_fonction a t appele.
<?php
}
?>

Vous remarquerez que le code PHP est encadr par des balises PHP douverture/ferme-
ture. Dans la plupart des fragments de code donns en exemple dans cet ouvrage, ces
balises ne sont pas montres. Nous les avons montres dans cet exemple car elles y sont
indispensables.

Attribution dun nom une fonction


Votre souci principal, lors du choix dun nom pour une fonction personnalise, devrait
tre dadopter un nom court mais explicite. Par exemple, pour une fonction crant un
en-tte de page web, les noms entete page() ou entetePage() seraient appropris.
Les quelques restrictions prendre en compte lors du choix des noms de fonctions sont
les suivantes :
m Ne donnez pas une fonction un nom dj attribu une autre fonction.
m Un nom de fonction ne peut contenir que des lettres, des chiffres et des blancs souligns.
m Un nom de fonction ne doit pas commencer par un chiffre.
De nombreux langages de programmation autorisent la rutilisation des noms de fonc-
tions. On parle alors de "surcharge de fonction" (overloading). PHP interdit la
surcharge des fonctions, cest--dire quil ne permet pas de donner une fonction
personnalise le mme nom quune fonction prdfinie ou quune autre fonction
personnalise. Notez galement que, si chaque script PHP "connat" toutes les fonc-
tions PHP prdfinies, les fonctions personnalises ne sont connues que dans les scripts
o elles sont dclares. Par consquent, rien ne vous empche de rutiliser le nom dune
de vos fonctions personnalises pour lattribuer une autre fonction contenue dans un
autre fichier. Cette pratique est toutefois source de confusion et devrait tre vite.
Les diffrents noms qui suivent sont tous corrects :
nom()
nom2()
nom_trois()
_nomquatre()
Chapitre 5 Rutilisation de code et criture de fonctions 161

tandis que ceux-ci sont incorrects :


5nom()
nom-six()
fopen()

(Le dernier de ces noms aurait t autoris sil ntait pas dj attribu une fonction
prdfinie.)
Bien que $nom ne soit pas un nom correct pour une fonction, un appel de fonction comme :
$nom();

peut sexcuter correctement, selon la valeur de $nom. En effet, PHP prend la valeur
stocke dans $nom, recherche une fonction portant ce nom et essaie de lappeler pour
vous. Ces fonctions sont appeles des fonctions variables. Elles peuvent tre utiles
loccasion.

Paramtres
Pour accomplir la tche pour laquelle elles ont t conues, la plupart des fonctions
requirent que un ou plusieurs paramtres leur soient fournis. Un paramtre permet de
passer des donnes une fonction. Voici lexemple dune fonction qui prend un tableau
unidimensionnel comme paramtre et laffiche sous la forme dune table :
function crer_table($donnees) {
echo <table border ="1">;
reset($donnees); // Revient pointer sur le dbut des donnes
$valeur = current($donnees);
while ($value) {
echo "<tr><td>" . $valeur . "</td></tr>\n";
$valeur = next($donnees);
}
echo "</table>";
}

Si la fonction creer table() est appele de la manire suivante :


$mon_tableau = array(Ligne un.,Ligne deux.,Ligne trois.);
creer_table($mon_tableau);

le rsultat obtenu sera celui de la Figure 5.4.

Figure 5.4
Lappel de la fonction
creer_table() produit
laffichage de ce
tableau HTML.
162 Partie I Utilisation de PHP

En passant un paramtre creer table(), nous avons pu manipuler au sein de cette


dernire des donnes cres en dehors de la fonction sous le nom $donnees.
Tout comme les fonctions prdfinies, les fonctions dfinies par lutilisateur peuvent
prendre plusieurs paramtres et peuvent galement prendre des paramtres facultatifs.
La fonction creer table() peut tre amliore de diverses manires, par exemple en
permettant celui qui lappelle de prciser la bordure ou dautres attributs du tableau.
Voici une version amliore de cette fonction, qui est trs semblable la prcdente, si
ce nest quelle permet de dfinir (de manire facultative) la largeur de la bordure,
lespacement entre les cellules et celui entre le contenu des cellules et la bordure :
function creer_table2( $donnees, $contour =1, $remplissage = 4,
$espacement = 4 ) {
echo "<table border = $contour cellpadding = $remplissage"
." cellspacing = $espacement>";
reset($donnees);
$valeur = current($donnees);
while ($valeur) {
echo "<tr><td>" . $valeur . "</td></tr>\n";
$valeur = next($donnees);
}
echo </table>;
}

Le premier paramtre de la fonction creer table2() est obligatoire, comme dans


creer table(). Les trois paramtres suivants sont facultatifs, parce que des valeurs par
dfaut sont indiques pour ces paramtres dans la dclaration de la fonction. Cet appel de la
fonction creer table2() produit donc un rsultat trs comparable celui de la Figure 5.4 :
creer_table2($mon_tableau);

Pour une prsentation plus are des donnes du tableau, nous pouvons appeler
creer table2() de la manire suivante :
creer_table2($mon_tableau, 3, 8, 8);

Lorsque des paramtres sont facultatifs, il nest pas indispensable de leur fournir des
valeurs. Linterprteur PHP assigne les paramtres de la gauche vers la droite.
Noubliez pas quil nest pas possible domettre un paramtre facultatif lors de lappel
dune fonction et de passer un autre paramtre facultatif plac sa droite dans la dfi-
nition de la fonction. Dans lexemple prcdent, il faut passer une valeur pour le
paramtre remplissage pour pouvoir passer une valeur pour le paramtre espace
ment. Le non-respect de cette rgle est lorigine de nombreuses erreurs de program-
mation. Par ailleurs, cette rgle est la raison pour laquelle les paramtres facultatifs
doivent toujours apparatre en dernier dans la liste des paramtres.
Lappel de fonction suivant :
creer_table2($mon_tableau, 3);
Chapitre 5 Rutilisation de code et criture de fonctions 163

est tout fait correct et cre une bordure large de 3 pixels ; les espacements entre les
cellules et lintrieur de celles-ci sont dfinis par leurs valeurs par dfaut.
Vous pouvez galement dclarer des fonctions qui acceptent un nombre variable de
paramtres. Le nombre de paramtres passs et leurs valeurs peuvent tre retrouvs
laide de trois fonctions auxiliaires : func num args(), func get arg() et
func get args().
tudiez par exemple la fonction suivante :
function params_variables() {
echo "Nombre de paramtres: ";
echo func_num_args();

echo "<br />";


$params = func_get_args();
foreach ($params as $param) {
echo $param . "<br />";
}

Cette fonction indique le nombre de paramtres qui lui sont passs et affiche chacun
deux. La fonction func num args() renvoie le nombre darguments passs et
func get args() renvoie un tableau des paramtres. Vous pouvez galement accder
un paramtre particulier en utilisant la fonction func get arg(), laquelle il faut
passer le numro du paramtre souhait (les paramtres sont numrots en commenant
zro).

Porte
Vous avez peut-tre not que, lorsque nous avons besoin dutiliser des variables dans un
fichier charg via une instruction require() ou include(), nous les dclarons simple-
ment dans le script avant linstruction require() ou include(). En revanche, avec une
fonction, les variables requises au sein de la fonction doivent tre explicitement passes
la fonction sous forme de paramtres. Cette diffrence sexplique en partie par le fait
quil nexiste pas de mcanisme permettant de passer explicitement des variables des
fichiers inclus, et en partie parce que la porte dune variable est diffrente pour les
fonctions.
La porte dune variable dfinit les parties du code o cette variable est visible et utili-
sable. Chaque langage de programmation a ses propres rgles en la matire et celles de
PHP sont relativement simples :
m La porte dune variable dclare au sein dune fonction stend de linstruction
partir de laquelle elle est dclare jusqu laccolade de fermeture de la fonction. La
porte est alors dite "limite la fonction" et les variables portent le nom de variables
locales.
164 Partie I Utilisation de PHP

m La porte dune variable dclare en dehors dune fonction stend de linstruction


dans laquelle elle est dclare jusqu la fin du fichier, exception faite des fonctions.
La porte est alors globale et les variables elles-mmes sont qualifies de variables
globales.
m Les variables superglobales sont visibles aussi bien lintrieur qu lextrieur des
fonctions (reportez-vous au Chapitre 1 pour plus dinformations sur ces variables).
m Lutilisation des instructions require() et include() naffecte pas la porte des
variables. Sil est fait appel lune de ces instructions lintrieur dune fonction, la
porte est limite la fonction. Si cet appel est ralis lextrieur dune fonction,
la porte est globale.
m Le mot-cl global peut tre employ pour indiquer explicitement quune variable
dfinie ou utilise au sein dune fonction a une porte globale.
m Une variable peut tre supprime explicitement via un appel unset
($nom variable). Lorsquune variable a t traite par la fonction unset(), elle
nexiste plus dans la porte.
Les quelques exemples qui suivent vous aideront mieux saisir les implications de ces
rgles.
Lexcution du code ci-aprs ne produit aucun rsultat. Ici, on dclare une variable
appele $var sans une fonction appele fn(). Cette variable tant dclare dans une
fonction, sa porte est limite la fonction et elle nexiste donc quentre le point o elle
a t dclare et la fin de la fonction. Lorsque $var est utilise en dehors de la fonction
fn(), PHP cre une nouvelle variable appele $var. Cette nouvelle variable est de
porte globale et reste visible jusqu la fin du fichier. $var tant uniquement utilise
dans une instruction echo, elle ne recevra jamais de valeur.
function fn() {
$var = "contenu";
}
fn();
echo $var;

Voici la situation inverse, o une variable est dclare en dehors de la fonction fn() et
o nous tentons de lutiliser lintrieur de celle-ci.
function fn() {
echo Dans la fonction, $var = . $var . <br />;
$var = "contenu 2";
echo Dans la fonction, $var = . $var . <br />;
}
$var = "contenu 1";
fn();
echo En dehors de la fonction, $var = . $var . <br />;
Chapitre 5 Rutilisation de code et criture de fonctions 165

Lexcution de ce fragment de code conduit au rsultat suivant :


Dans la fonction, $var =
Dans la fonction, $var = contenu 2
En dehors de la fonction, $var = contenu 1

Les fonctions ntant excutes que lorsquelles sont appeles, la premire instruction
excute dans ce code est $var = "contenu 1";. Une variable appele $var est alors
cre, dont la porte est globale et qui contient la chane "contenu 1". PHP excute
ensuite lappel la fonction fn() en excutant dans lordre les lignes qui constituent la
dclaration de la fonction. La premire de ces lignes fait rfrence une variable appe-
le $var. Au moment de lexcution de cette ligne, linterprteur PHP ne peut pas voir
la variable $var dj cre et cre une nouvelle variable dont la porte se limite la
fonction fn(). Cest laffichage du contenu de cette nouvelle variable au moyen de
linstruction echo qui produit la premire ligne de la sortie.
La ligne qui vient ensuite dans la dclaration de la fonction donne $var le contenu
"contenu 2". Cette ligne de code appartenant la fonction, elle modifie la valeur de la
variable $var locale, pas celle de la variable globale. La deuxime ligne de la sortie met
en vidence ce fonctionnement.
Lorsque lexcution de la fonction sachve, la dernire ligne de notre script est excute.
Cette instruction echo finale montre que la valeur de la variable globale $var na pas t
affecte par lexcution de la fonction fn().
Pour quune variable cre au sein dune fonction soit de porte globale, nous devons
utiliser le mot-cl global, comme ici :
function fn() {
global $var;
$var = "contenu";
echo Dans la fonction, $var = . $var . <br />;
}

fn();
echo En dehors de la fonction, $var = . $var. <br />;

Dans cet exemple, la variable $var est explicitement dfinie comme globale. Aprs
lappel de la fonction fn(), la variable continue donc dexister en dehors de la fonction.
Lexcution de ce fragment de code produit laffichage suivant :
Dans la fonction, $var = contenu
En dehors de la fonction, $var = contenu

Notez que la porte de la variable commence au point o la ligne global $var; est
excute. Nous aurions aussi bien pu placer la dclaration de la fonction aprs quavant
la ligne contenant lappel de la fonction. Une dclaration de fonction peut tre indiff-
remment place en nimporte quel point dun script. En revanche, la position de lappel
166 Partie I Utilisation de PHP

de la fonction est importante, puisquelle dfinit lendroit du script o est excute la


fonction.
Le mot-cl global peut galement tre utilis en dbut de script, la premire utilisa-
tion dune variable, afin dindiquer PHP que la variable doit tre de porte globale.
Cet usage du mot-cl global est probablement le plus courant.
Les exemples prcdents montrent bien quil est parfaitement possible dutiliser le
mme nom pour des variables dclares en dehors et lintrieur dune fonction, sans
quil y ait dinterfrence. Cette pratique est toutefois dconseille car elle est source de
confusion.

Passer des paramtres par rfrence et par valeur


Pour crire une fonction appele incrementer() qui nous permette dincrmenter une
valeur, nous pourrions tre tents dcrire le code suivant :
function incrementer($valeur, $montant = 1) {
$valeur = $valeur +$montant;
}
Ce code ne produit pourtant pas le rsultat escompt : lexcution des lignes suivantes
affichera "10" :
$valeur = 10;
incrementer($valeur);
echo $valeur;
cause des rgles de porte, le contenu de la variable $valeur na pas t modifi. En
effet, ce code cre une variable appele $valeur qui contient la valeur 10, puis appelle
la fonction incrementer(). La variable $valeur utilise dans la fonction incremen
ter() est cre au moment de lappel de la fonction. Linterprteur PHP ajoute 1 cette
variable, qui prend par consquent la valeur 11 dans la fonction et jusqu la fin de
celle-ci. Linterprteur revient ensuite au code qui a appel incrementer(). Dans ce
code, $valeur est une variable diffrente, de porte globale, dont le contenu na donc
pas chang.
Nous pourrions rsoudre ce problme en dclarant $valeur dans la fonction en tant que
variable globale. Mais, pour utiliser la fonction incrementer(), nous serions alors dans
lobligation de donner le nom $valeur la variable incrmenter.
Les paramtres dune fonction sont normalement passs la fonction par valeur.
Lorsquun paramtre est pass une fonction, PHP cre une nouvelle variable conte-
nant la valeur transmise. Il sagit donc dune copie de la variable originale. Cette valeur
copie peut ainsi tre modifie loisir, sans que la valeur de la variable dorigine nen
soit affecte (notre explication simplifie lgrement le mcanisme interne vritablement
mis en uvre).
Chapitre 5 Rutilisation de code et criture de fonctions 167

Ici, la meilleure approche consiste utiliser le passage de paramtre par rfrence.


Dans ce cas, au lieu de crer une nouvelle variable pour le paramtre pass la fonc-
tion, linterprteur passe une rfrence sur la variable dorigine. Cette rfrence est
associe un nom de variable qui commence par un signe dollar et elle peut tre utilise
comme nimporte quelle variable. Cependant, au lieu de possder sa propre valeur, une
rfrence pointe sur la valeur dorigine. Toute modification apporte la rfrence sera
donc rpercute sur la variable originale.
Pour indiquer quun paramtre est pass par rfrence, il suffit de le faire prcder
dune esperluette (&) dans la dfinition de la fonction. Lappel de la fonction, en revanche,
ne ncessite aucune modification.
Dans lexemple prcdent, nous pouvons modifier la fonction incrementer() pour
aboutir au rsultat recherch, en passant la fonction le premier paramtre par rf-
rence.
function incrementer(&$valeur, $montant = 1) {
$valeur = $valeur +$montant;
}

Ainsi formule, notre fonction effectue le traitement attendu et nous avons toute libert
pour le choix du nom de la variable incrmenter. Comme nous lavons dj
mentionn, lutilisation dun mme nom de variable lintrieur et lextrieur dune
fonction est source de confusion, si bien que nous attribuerons un nouveau nom la
variable utilise dans le script principal. Le code de test qui suit conduit laffichage du
nombre 10 dans la fentre du navigateur avant lappel de la fonction incrementer() et
du nombre 11 aprs lappel de la fonction.
$a = 10;
echo $a . <br />;
incrementer($a);
echo $a . <br />;

Utilisation du mot-cl return


Le mot-cl return interrompt lexcution dune fonction. Lorsque lexcution dune
fonction prend fin, soit parce que toutes ses instructions ont t excutes, soit parce
que le mot-cl return a t atteint, lexcution se poursuit par linstruction qui suit
lappel de la fonction.
lappel de la fonction suivante, seule la premire instruction echo est excute :
function test_return() {
echo Cette instruction sera excute.;
return;
echo Cette instruction ne sera jamais excute.;
}
168 Partie I Utilisation de PHP

Cette utilisation du mot-cl return nest videmment pas des plus utiles. Normale-
ment, le mot-cl return semploie pour sortir dune fonction, au milieu de celle-ci,
lorsquune certaine condition a t vrifie.
Une condition derreur est une raison typique dutiliser une instruction return pour
interrompre lexcution dune fonction avant sa fin. Par exemple, supposez quil nous
faille crire une fonction dterminant quel est le plus grand de deux nombres. Il faudrait
que lexcution de la fonction puisse tre interrompue si lun des deux nombres na pas
t fourni.
function superieur( $x, $y ) {
if (!isset($x) ||!isset($y) ) {
echo "Cette fonction attend deux nombres.";
return;
}
if ($x >= $y) {
echo $x;
} else {
echo $y;
}
}

La fonction prdfinie isset() permet de dterminer si une variable a bien t cre et


si elle contient une valeur. Dans le code prcdent, un message derreur sera produit et
lexcution de la fonction se terminera si lun des paramtres na pas t fourni avec
une valeur. Pour cela, on utilise un test !isset(), qui signifie "NON isset()" ; linstruc-
tion if de ce fragment de code peut donc se lire "si x nest pas dfini ou si y nest pas
dfini". Lexcution sinterrompt si lune de ces conditions est vraie.
Lorsque linterprteur PHP atteint une instruction return dans une fonction, il
nexcute pas les lignes qui suivent linstruction return dans la fonction. Lexcution
du programme revient lendroit o la fonction a t appele. Si les deux paramtres
sont bien dfinis, la fonction affiche dans la fentre du navigateur la valeur du plus
grand des deux paramtres.
Lexcution du code suivant :
$a = 1;
$b = 2.5;
$c = 1.9;
superieur($a, $b);
superieur($c, $a);
superieur($d, $a);

produit le rsultat suivant :


2.5
1.9
Cette fonction attend deux nombres.
Chapitre 5 Rutilisation de code et criture de fonctions 169

Retour de valeurs des fonctions


Lutilisation du mot-cl return ne se limite pas linterruption de lexcution dune
fonction. Dans nombre de fonctions, une instruction return sert communiquer
avec le code qui a appel la fonction. Ainsi, superieur() pourrait se rvler plus utile
si le rsultat de la comparaison tait renvoy par la fonction au lieu dtre affich dans
le navigateur. Cest alors dans le code du script principal que se dciderait laffichage
ou lutilisation de ce rsultat. La fonction max() prdfinie dans PHP a exactement ce
comportement.
La fonction superieur() pourrait ainsi tre modifie de la manire suivante :
function superieur($x, $y) {
if (!isset($x) ||!isset($y) ) {
return false;
} else if ( $x >= $y ) {
return $x;
} else {
return $y;
}
}

La fonction superieur() renvoie prsent la plus grande des deux valeurs qui lui sont
passes en paramtres. Elle renverra une valeur qui sera de toute vidence fausse en
cas derreur : si lun des nombres comparer nest pas fourni, la fonction retourne
false. La seule difficult avec cette approche est que les programmeurs appelant cette
fonction doivent tester le type du retour avec == pour sassurer de ne pas confondre
false avec 0.
titre de comparaison, la fonction max() ne renvoie rien si les deux variables nont pas
t dfinies. Si une seule a t dfinie, cest elle qui est renvoye.
Le code qui suit :
$a = 1; $b = 2.5; $c = 1.9;
echo superieur($a, $b) . "<br />";
echo superieur($c, $a) . "<br />";
echo superieur($d, $a) . "<br />";
produit le rsultat suivant parce que $d nexiste pas et que false nest pas visible :
2.5
1.9
Souvent, les fonctions qui effectuent certains traitements, mais qui nont pas besoin de
renvoyer de valeur, renvoient les valeurs true ou false pour signaler si elles ont russi
ou chou. Les valeurs boolennes true et false peuvent tre respectivement reprsentes
par 0 et 1, bien quil sagisse de types diffrents.
170 Partie I Utilisation de PHP

Rcursivit
Une fonction rcursive est une fonction qui sappelle elle-mme. Ce type de fonction se
rvle particulirement utile pour naviguer dans des structures de donnes dynamiques,
comme les listes chanes et les arborescences.
Toutefois, les applications web qui requirent des structures de donnes dune telle
complexit sont assez rares, si bien que la rcursivit nest que rarement exploite en
PHP. Dans nombre de cas, elle peut tre utilise la place dune structure itrative,
parce quelle consiste galement effectuer des rptitions du code. Cependant, les
fonctions rcursives tant plus lentes et consommant plus de mmoire que leurs homo-
logues itratives, vous avez tout intrt prfrer les itrations aux rcursions lorsque
cest possible.
Pour que cette tude soit complte, nous allons quand mme examiner lexemple
simple prsent dans le Listing 5.5.

Listing 5.5 : recursion.php Une chane peut tre facilement inverse au moyen
dune fonction rcursive. La version itrative est galement donne.

function inverser_recursive($chaine) {
if (strlen($chaine) > 0) {
inverser_recursive(substr($chaine, 1));
}
echo substr($chaine, 0, 1);
return;
}

function inverser_iterative($chaine) {
for ($i=1; $i<=strlen($chaine); $i++) {
echo substr($str, -$i, 1);
}
return;
}

Le Listing 5.5 contient deux fonctions qui affichent toutes deux lenvers la chane qui
leur est fournie en paramtre. La fonction inverser recursive () est rcursive, tandis
que la fonction inverser iterative () est itrative.
inverser recursive () prend une chane en paramtre. Lorsquelle est appele, elle
opre en sappelant elle-mme et en se passant chaque fois la sous-chane comprise
entre le deuxime et le dernier caractre de la chane. Cet appel, par exemple :
inverser_recursive(Bonjour);
se traduit par la srie dappels suivante :
inverser_recursive (onjour);
inverser_recursive (njour);
inverser_recursive (jour);
Chapitre 5 Rutilisation de code et criture de fonctions 171

inverser_recursive (our);
inverser_recursive (ur);
inverser_recursive (r);
inverser_recursive ();
chaque fois que la fonction sappelle elle-mme, une nouvelle copie du code de la
fonction est effectue dans la mmoire du serveur, mais avec un paramtre diffrent.
Tout se passe comme si une fonction diffrente tait appele chaque fois. Ce fonction-
nement permet dviter la confusion entre les diffrentes instances de la fonction.
chaque appel, la longueur de la chane est value. Lorsque linterprteur PHP atteint
la fin de la chane (strlen()==0), la condition nest plus satisfaite. Linstance de la
fonction la plus rcente (inverser recursive ()) se poursuit par lexcution de
la prochaine ligne de code, laquelle commande dafficher le premier caractre de la
chane passe en paramtre. ce stade, il ny a pas de caractre, parce que la chane est
vide.
Ensuite, cette instance de la fonction redonne le contrle linstance qui la appele,
cest--dire inverser recursive (r). Celle-ci affiche le premier caractre de sa
chane, en loccurrence r, et redonne le contrle linstance qui la appele.
Le processus se poursuit ainsi, affichant un caractre puis redonnant le contrle
linstance prcdente de la fonction selon lordre dappel, jusqu ce que le contrle soit
redonn au programme principal.
Les solutions rcursives sont lgantes et ont un aspect mathmatique indniable mais,
le plus souvent, la solution itrative leur est prfrable. Le Listing 5.5 donne galement
lquivalent itratif de la fonction inverser recursive : vous pouvez remarquer que
cette variante nest pas plus longue (ce qui nest pas toujours vrai de toutes les fonctions
itratives) et quelle produit exactement le mme rsultat.
La fonction rcursive se distingue principalement de la fonction itrative par le fait
quelle effectue des copies delle-mme dans la mmoire et gnre plusieurs appels de
fonction, ce qui est coteux en termes de mmoire et de temps dexcution.
Peut-tre choisirez-vous des solutions rcursives lorsquelles permettent dcrire un
code plus court et plus lgant que la version itrative, mais cela ne se produit pas
souvent dans le domaine des applications web.
Bien que la rcursion apparaisse plus lgante, les programmeurs oublient souvent de
fournir une condition de terminaison dans leurs fonctions rcursives. Dans ce cas,
lexcution rcursive de la fonction se poursuit jusqu ce que le serveur soit court de
mmoire ou que le temps dexcution maximal ait t dpass.
172 Partie I Utilisation de PHP

Pour aller plus loin


Lusage des instructions include(), require(), function et return est galement
expliqu dans le manuel en ligne de PHP. Pour en savoir plus sur des concepts comme
la rcursivit, le passage de paramtres par valeur/rfrence et la porte des variables
(sujets que lon retrouve dans plusieurs langages de programmation), consultez un
manuel gnral dinformatique comme C++ How to Program, de Deitel et Deitel.

Pour la suite
Vous savez prsent amliorer la maintenabilit et la rutilisabilit de votre code par le
recours des fichiers de type "include" et "require" et des fonctions. Nous allons
donc pouvoir poursuivre notre tude par laspect orient objet du langage PHP. Lutili-
sation dobjets rpond aux mmes objectifs que ceux des concepts dcrits dans ce
chapitre, mais avec plus davantages encore lorsque les projets sont complexes.
6
PHP orient objet

Ce chapitre prsente les concepts de la programmation oriente objet (POO) et montre


comment ils peuvent tre implments en PHP.
Limplmentation de la POO en PHP possde toutes les fonctionnalits que vous seriez
en droit dattendre dun langage orient objet complet. Nous signalerons chacune de
ces fonctionnalits mesure que nous avancerons dans ce chapitre.

Concepts de la programmation oriente objet


Les langages de programmation modernes supportent gnralement, voire requirent,
une approche oriente objet du dveloppement logiciel. Le dveloppement orient objet
(DOO) consiste exploiter les classifications, les relations et les proprits des objets
dun systme pour faciliter le dveloppement des programmes et la rutilisation du
code.

Classes et objets
Dans le contexte de la POO, un objet peut tre quasiment tout lment ou concept,
cest--dire un objet physique comme un bureau ou un client, ou un objet conceptuel
qui nexiste que dans le programme lui-mme, comme un champ de saisie ou un fichier.
Le plus souvent, le dveloppeur sintresse aux objets du monde rel et aux objets
conceptuels qui doivent tre reprsents dans le programme.
Un logiciel orient objet est conu et construit sous la forme dun ensemble dobjets
indpendants dots la fois dattributs et doprations qui interagissent pour rpondre
nos besoins. Les attributs sont des proprits ou des variables qui se rapportent
lobjet. Les oprations sont des mthodes, des actions ou des fonctions que lobjet peut
accomplir, soit pour se modifier lui-mme, soit pour produire un effet externe (le terme
attribut est utilis de manire interchangeable avec les termes variable membre et
174 Partie I Utilisation de PHP

proprit, tandis que le terme opration est utilis de manire interchangeable avec le
terme mthode).
Le principal avantage dun logiciel orient objet rside dans sa capacit prendre en
charge et encourager lencapsulation, galement appele masquage de donnes. Pour
lessentiel, les donnes contenues dans un objet ne sont accessibles que par le biais des
oprations de celui-ci, qui forment linterface de lobjet.
La fonctionnalit dun objet est lie aux donnes quil utilise. Les dtails de limpl-
mentation dun objet peuvent tre facilement modifis pour amliorer les performances,
ajouter de nouvelles caractristiques ou corriger des bogues, sans quil soit ncessaire
de changer linterface. Le fait de modifier cette interface peut, en effet, avoir des rper-
cussions en cascade dans le projet, alors que lencapsulation vous permet deffectuer
des modifications et de raliser des corrections de bogues sans que vos actions ne se
rpercutent dans les autres parties du projet.
Dans les autres secteurs du dveloppement logiciel, la POO sest impose comme la norme
et le dveloppement orient fonctions est dsormais considr comme dmod. Cepen-
dant, pour diverses raisons, la plupart des scripts web restent malheureusement conus et
crits avec une approche ad hoc, utilisant une mthodologie oriente fonctions.
Ce "retard" a plusieurs causes. Une majorit de projets web sont de petite taille et rela-
tivement simples. Nul besoin dlaborer un plan dtaill pour construire une tagre
avec une scie. De la mme manire, la plupart des projets logiciels pour le Web peuvent
tre raliss de cette faon parce quils sont de petite taille. En revanche, si vous prenez
votre scie pour construire une maison sans avoir formellement planifi vos travaux,
vous ne pourrez pas obtenir des rsultats de qualit, si tant est que vous obteniez des
rsultats. Il en va exactement de mme pour les projets logiciels importants.
Nombre de projets web voluent dun ensemble de pages relies entre elles par des
hyperliens vers des applications complexes. Ces applications complexes, quelles
soient prsentes via des botes de dialogue et des fentres ou via des pages HTML
dynamiques, requirent une mthodologie de dveloppement mrement rflchie.
Lorientation objet peut aider grer la complexit des projets logiciels, augmenter la
rutilisabilit du code et, par consquent, rduire les cots de maintenance.
En POO, un objet est une collection unique et identifiable de donnes et doprations
agissant sur ces donnes. Par exemple, considrons le cas de deux objets reprsentant
des boutons. Mme si ces boutons portent tous deux lintitul "OK", ont une largeur de
60 pixels, une hauteur de 20 pixels et divers autres attributs identiques, nous devons
pouvoir les distinguer et les manipuler sparment lun de lautre. Dun point de vue
logiciel, cette distinction seffectue via des variables spares, qui servent de descripteurs
(didentificateurs uniques) pour les objets.
Chapitre 6 PHP orient objet 175

Les objets peuvent tre regroups en "classes". Une classe est un ensemble dobjets qui
peuvent tre diffrents les uns des autres, mais qui ont certains points communs. Une
classe contient des objets qui prsentent tous des oprations se comportant de la mme
manire et des attributs identiques reprsentant les mmes choses, bien que les valeurs
de ces attributs puissent varier dun objet lautre au sein de la classe.
Vous pouvez ainsi considrer le nom bicyclette comme celui dune classe dobjets qui
dcrit les nombreuses bicyclettes distinctes qui prsentent toutes des caractristiques ou
attributs communs, comme deux roues, une couleur et une taille, et des oprations,
comme le dplacement.
Ma propre bicyclette pourrait ainsi tre considre comme un objet appartenant la
classe bicyclette. Elle a des caractristiques identiques toutes les bicyclettes, y
compris lopration de dplacement, qui est tout fait comparable lopration de
dplacement des autres bicyclettes, mme si elle nest utilise que trs rarement. Les
attributs de ma bicyclette ont toutefois des valeurs qui leur sont propres ; par exemple,
sa couleur est verte, ce qui nest pas le cas de toutes les bicyclettes.

Polymorphisme
Un langage de programmation orient objet doit prendre en charge le polymorphisme,
qui signifie que diffrentes classes peuvent avoir des comportements diffrents pour la
mme opration. Par exemple, supposez que nous ayons dfini une classe voiture et une
classe bicyclette. Ces deux classes peuvent avoir des oprations de dplacement diff-
rentes. Dans lunivers des objets rels, cette diffrentiation pose rarement problme : il
est peu probable en effet quune bicyclette soit confondue avec une voiture et dmarre
avec une opration de dplacement de voiture au lieu dune opration de dplacement
de bicyclette. En revanche, un langage de programmation ne possde pas le sens
commun du monde rel : il doit par consquent disposer du polymorphisme pour quil
soit possible de distinguer lopration de dplacement approprie un objet particulier.
Le polymorphisme est plus une caractristique des comportements que des objets eux-
mmes. En PHP, seules les fonctions membres dune classe peuvent tre polymor-
phiques. Les verbes des langages naturels sont un peu lquivalent dans le monde rel
des fonctions membres dune classe. Considrez la manire dont peut tre utilise une
bicyclette dans la vie relle. Vous pouvez la nettoyer, la dplacer, la dmonter, la rparer
ou la peindre, entre autres choses.
Les verbes de cette dernire phrase dcrivent des actions gnriques parce que le type
dobjet auquel ils peuvent tre appliqus nest pas prcis (ce type dabstraction concer-
nant les objets et les actions est, du reste, lune des caractristiques distinctives de
lintelligence humaine).
176 Partie I Utilisation de PHP

Le dplacement dune bicyclette, par exemple, exige des actions totalement diffrentes
de celles requises pour dplacer une voiture, mme si les concepts sont similaires. Le
verbe "dplacer" peut donc tre associ un ensemble particulier dactions, mais
uniquement aprs que lobjet auquel il sapplique a t dfini.

Hritage
Lhritage permet de crer une relation hirarchique entre les classes au moyen de sous-
classes. Une sous-classe hrite des attributs et des oprations de sa superclasse. Les
voitures et les bicyclettes ont, par exemple, des points communs et nous pourrions donc
dfinir une classe vhicule contenant des attributs comme la couleur et des oprations
comme le dplacement qui sont communs tous les vhicules. Il suffirait ensuite de
laisser les classes voiture et bicyclette hriter de la classe vhicule.
Les termes sous-classe, classe drive et classe fille sont utiliss de manire interchan-
geable. Il en va de mme des termes superclasse, classe de base et classe parente.
Grce au concept dhritage, nous pouvons laborer et enrichir lensemble des classes
existantes. partir dune simple classe de base, des classes plus complexes et plus
spcialises peuvent tre cres au fur et mesure des besoins. Cette approche rend le
code plus rutilisable et constitue lun des atouts indniables de la programmation
oriente objet.
Exploiter la notion dhritage peut permettre dconomiser du temps et des efforts de
dveloppement lorsque des oprations peuvent tre implmentes une seule fois dans
une superclasse, au lieu de ltre chaque fois dans des sous-classes spares. Cette
approche favorise galement une modlisation plus prcise des relations du monde rel.
Lorsque la phrase dcrivant la relation entre deux classes peut contenir les mots "est un"
ou "est une", alors, le concept dhritage peut tre exploit. La phrase "une voiture est
un vhicule", par exemple, est tout fait sense, tandis que la phrase "un vhicule est
une voiture" nest pas vraie dans le monde rel. Par consquent, les voitures peuvent
hriter de la classe vhicule.

Cration de classes, dattributs et doprations en PHP


Jusquici, la description que nous avons donne des classes est plutt abstraite. Plus
concrtement, la cration dune classe en PHP seffectue au moyen du mot-cl class.

Structure dune classe


La dfinition minimale dune classe se formule de la manire suivante :
class nomclass {
}
Chapitre 6 PHP orient objet 177

Pour quune classe ait une quelconque utilit, elle doit tre dote dattributs et dopra-
tions. Pour crer des attributs, il faut dclarer des variables au sein dune dfinition de
classe en les prcdant de mots-cls indiquant leur visibilit : public, private ou
protected (ces mots-cls seront prsents plus loin dans ce chapitre). Le code qui suit
cre une classe nomclasse dote des deux attributs publics, $attribut1 et $attribut2 :
class classname {
public $attribut1;
public $attribut2;
}

La cration doprations dans une classe seffectue en dclarant des fonctions dans la
dfinition de la classe. Le code suivant cre une classe nomclasse dote de deux opra-
tions qui neffectuent rien de particulier. Lopration operation1() ne prend aucun
paramtre, tandis que operation2() attend deux paramtres.
class nomclasse {
function operation1() {}
function operation2($param1, $param2) {}
}

Constructeurs
La plupart des classes disposent dun type spcial dopration appel constructeur. Un
constructeur est appel lors de la cration dun objet et effectue gnralement des tches
dinitialisation comme lassignation de valeurs initiales aux attributs ou la cration
dautres objets ncessaires lobjet concern.
Un constructeur se dclare de la mme manire que les autres oprations, sauf quil
porte le nom spcial construct().
Bien quun constructeur puisse tre appel manuellement, son rle principal est dtre
appel automatiquement la cration dun objet. Le code qui suit dclare une classe
dote dun constructeur :
class nomclasse {
function _ _construct($param) {
echo "Constructeur appel avec le paramtre " . $param . "<br />";
}
}

Destructeurs
Loppos dun constructeur est un destructeur. Les destructeurs permettent dexcuter
un traitement particulier juste avant quun objet ne soit dtruit, ce qui aura lieu automa-
tiquement lorsque toutes les rfrences cet objet ont t indfinies ou hors de porte.
Le destructeur dune classe doit sappeler destruct() et ne peut prendre aucun para-
mtre.
178 Partie I Utilisation de PHP

Instanciation des classes


Une fois que nous avons dclar une classe, nous devons crer un objet (cest--dire un
individu particulier appartenant la classe) avec lequel nous pourrons ensuite travailler.
Cette tape sappelle galement cration dune instance ou instanciation dune classe.
On cre un objet laide du mot-cl new. Il faut galement prciser la classe dont lobjet
sera linstance et fournir les paramtres ventuellement requis par le constructeur de la
classe.
Le code qui suit dclare une classe nomclasse avec un constructeur, puis cre trois
objets de type nomclasse :
class nomclasse {
function _ _construct($param) {
echo "Constructeur appel avec le paramtre " . $param ."<br />";
}
}

$a = new nomclasse("Premier");
$b = new nomclasse("Second");
$c = new nomclasse();

Le constructeur tant invoqu chaque cration dobjet, ce code produit le rsultat


suivant :
Constructeur appel avec le paramtre Premier
Constructeur appel avec le paramtre Second
Constructeur appel avec le paramtre

Utilisation des attributs de classe


lintrieur dune classe, vous avez accs un pointeur spcial appel $this. Si un
attribut de la classe courante porte le nom $attribut, vous pouvez le dsigner par
$this >attribut lorsque vous linitialisez ou que vous y accdez partir dune opration
situe dans la classe.
Le code qui suit illustre la dfinition et laccs un attribut lintrieur dune classe :
class nomclasse {
public $attribut;
function operation($param) {
$this->attribut = $param
echo $this->attribut;
}
}

La possibilit daccder un attribut depuis lextrieur de la classe est dtermine par


des modificateurs daccs, comme vous le verrez dans la suite de ce chapitre. Cet exem-
ple ne restreignant pas laccs lattribut, vous pouvez y accder depuis lextrieur de
la classe :
Chapitre 6 PHP orient objet 179

class nomclasse {
public $attribut;
}
$a = new nomclasse();
$a->attribut = "valeur";
echo $a->attribut;

Il est toutefois dconseill daccder directement aux attributs depuis lextrieur dune
classe. Lun des intrts de lapproche oriente objet rside justement dans le fait que
lencapsulation y est encourage.
Vous pouvez garantir cette encapsulation laide des fonctions _ _get et _ _set. Au lieu
daccder directement aux attributs dune classe, vous pouvez crire des fonctions
accesseurs de sorte effectuer tous vos accs par le biais dune seule section de code.
Une fonction accesseur peut se formuler de la manire suivante :
class nomclasse {
public $attribut;
function _ _get($nom) {
return $this->$nom;
}
function _ _set ($nom, $valeur) {
$this->$nom = $valeur;
}
}

Ce code se contente de fournir des fonctions minimales permettant daccder lattri-


but $attribut. La fonction _ _get() renvoie simplement la valeur de $attribut, tandis
que la fonction set() affecte une nouvelle valeur $attribut.
Notez que _ _get() ne prend quun seul paramtre le nom dun attribut et renvoie la
valeur de cet attribut. De manire similaire, la fonction _ _set() prend deux paramtres :
le nom dun attribut et la valeur que vous souhaitez lui donner.
Ces fonctions ne sappellent pas directement. Le double blanc soulign devant le nom
indique que ces fonctions possdent une signification spciale en PHP, tout comme les
fonctions _ _construct() et _ _destruct().
Si vous instanciez la classe :
$a = new nomclasse();

vous pouvez utiliser les fonctions _ _get() et _ _set() pour tester et modifier la valeur
de nimporte quel attribut.
Si vous tapez :
$a->$attribut = 5;

cette instruction appellera implicitement la fonction _ _set() avec la valeur $nom posi-
tionne "attribut" et la valeur $valeur initialise 5. Si vous souhaitez effectuer
180 Partie I Utilisation de PHP

des contrles sur les valeurs affectes lattribut, vous devez crire la fonction _ _set()
en consquence.
La fonction _ _get() fonctionne de manire similaire. Dans votre code, si vous crivez :
$a->attribut
lexpression appellera implicitement la fonction _ _get() avec le paramtre $nom posi-
tionn "attribut". Cest vous dcrire la fonction _ _get() pour retourner la valeur
de lattribut.
Au premier coup dil, ce code peut sembler navoir que peu ou pas dintrt. Sous sa
forme actuelle, cest probablement le cas, mais il existe une raison simple de proposer
des fonctions daccs : vous naurez alors quune unique section de code qui accde
cet attribut particulier.
Avec un seul point daccs, vous pouvez implmenter des contrles de validit afin de
vous assurer que les donnes stockes sont cohrentes. Si vous jugez par la suite que la
valeur de $attribut doit tre comprise entre 0 et 100, vous pouvez ajouter quelques
lignes de code et oprer la vrification avant dautoriser les modifications. Vous pourriez
ainsi modifier la fonction _ _set() de la manire suivante :
function _ _set ($nom, $valeur) {
if( $nom == "attribut" && $valeur >= 0 && $valeur <= 100 ) {
$this->attribut = $valeur;
}
}
Avec un unique point daccs, vous tes libre de modifier limplmentation sous-jacente.
Si, pour une raison ou pour une autre, vous deviez modifier la manire dont $attribut
est stock, les fonctions accesseurs vous permettraient de le faire en ne modifiant le
code qu un seul emplacement.
Il se peut que vous dcidiez, au lieu de stocker $attribut sous forme de variable, de le
rcuprer partir dune base de donnes selon les besoins, de calculer une nouvelle
valeur chaque fois quelle est requise, de dduire une valeur partir de valeurs
dautres attributs ou dencoder les donnes sous un type de donnes plus compact.
Quelle que soit la modification que vous souhaitiez oprer, il suffit de modifier les fonc-
tions accesseurs. Les autres sections du code ne seront pas affectes, pour autant que
vous faites en sorte que les fonctions accesseurs continuent daccepter ou de renvoyer
les donnes que les autres parties du programme sattendent pouvoir utiliser.

Contrler laccs avec private et public


PHP utilise des modificateurs daccs qui contrlent la visibilit des attributs et des
mthodes et qui sont placs devant les dclarations dattribut et de mthode.
PHP dispose des trois modificateurs daccs suivants :
Chapitre 6 PHP orient objet 181

m Loption par dfaut est public. Cela signifie que, si vous navez pas spcifi de
modificateur daccs pour un attribut ou une mthode, ceux-ci seront publics.
Laccs aux lments publics peut se faire depuis lintrieur ou lextrieur de la
classe.
m Le modificateur daccs private signifie quil nest possible daccder llment
marqu que depuis lintrieur de la classe. Vous pouvez lutiliser sur tous les attri-
buts si vous nutilisez pas _ _get() et _ _set(). Vous pouvez galement choisir de
rendre certaines mthodes prives, par exemple sil sagit de fonctions utilitaires
utiliser lintrieur de la classe uniquement. Les lments privs ne sont pas hrits
(nous y reviendrons dans la suite de ce chapitre).
m Le modificateur daccs protected signifie que lon ne peut accder llment
marqu que depuis lintrieur de la classe. Il existe galement dans toutes les sous-
classes. Nous reviendrons aussi sur cette question lorsque nous traiterons de lhri-
tage dans la suite de ce chapitre. Pour linstant, considrez que protected est mi-
distance entre private et public.
Le code suivant montre lutilisation du modificateur public :
class nomclasse {
public $attribut;
public function _ _get($nom) {
return $this->$nom;
}
public function _ _set ($nom, $valeur) {
$this->$nom = $valeur;
}
}

Ici, chaque membre de classe est prcd dun modificateur daccs qui indique sil est
priv ou public. Le mot-cl public peut tre omis car il sagit du rglage par dfaut,
mais le code est plus simple comprendre lorsque vous lincluez, notamment si vous
utilisez dautres modificateurs.

Appel des oprations dune classe


Nous pouvons appeler une opration de classe en procdant de la mme manire que
pour un attribut de classe. Si nous dclarons la classe suivante :
class nomclasse {
public function operation1() { }
public function operation2($param1, $param2) { }
}

et que nous crons un objet de type nomclasse, comme ici :


$a = new nomclasse();
182 Partie I Utilisation de PHP

nous pouvons appeler des oprations en procdant de la mme faon que pour lappel
dautres fonctions : en spcifiant leur nom, suivi des paramtres requis, placs entre
parenthses. Ces oprations appartenant un objet, la diffrence des fonctions norma-
les, il est ncessaire de prciser lobjet concern. Le nom de cet objet est indiqu de la
mme manire que pour ses attributs :
$a->operation1();
$a->operation2(12, "test");

Si les oprations renvoient des valeurs, elles peuvent tre rcupres de la manire
suivante :
$x = $a->operation1();
$y = $a->operation2(12, "test");

Implmentation de lhritage en PHP


Une classe peut tre dclare comme tant une sous-classe dune autre classe en utili-
sant le mot-cl extends. Le code qui suit cre une classe B qui hrite dune classe A
prcdemment dfinie :
class B extends A {
public $attribut2;
public function operation2() { }
}

En admettant que la classe A ait t dclare comme suit :


class A {
public $attribut1;
public function operation1() { }
}

tous les accs suivants aux attributs et oprations dun objet de la classe B seraient
corrects :
$b = new B();
$b->operation1();
$b->attribut1 = 10;
$b->operation2();
$b->attribut2 = 10;

Notez que, la classe B hritant de la classe A, nous pouvons faire rfrence


operation1() et $attribut1 bien que ceux-ci soient dclars dans la classe A. En tant
que sous-classe de A, la classe B en possde les caractristiques et les donnes. En outre,
B a dclar un attribut et une opration qui lui sont propres.
Lhritage ne fonctionne que dans un sens. La sous-classe (la fille) hrite de sa super-
classe (le parent) mais le parent nhrite pas de son enfant. Il sensuit que les deux
dernires lignes du code suivant sont incorrectes :
Chapitre 6 PHP orient objet 183

$a = new A();
$a->operation1();
$a->attribut1 = 10;
$a->operation2();
$a->attribut2 = 10;

En effet, la classe A ne possde pas dopration operation2() ni dattribut attribut2.

Contrler la visibilit via lhritage avec private et protected


Les modificateurs daccs private et protected permettent de contrler lhritage. Un
attribut ou une mthode dclar private ne sera pas hrit, alors quun attribut ou une
mthode dclar protected ne sera pas visible en dehors de la classe (comme un lment
priv) mais sera hrit.
Considrez lexemple suivant :
<?php
class A {
private function operation1() {
echo "Appel de operation1";
}
protected function operation2() {
echo "Appel de operation2";
}
public function operation3() {
echo "Appel de operation3";
}
}

class B extends A {
function _ _construct() {
$this->operation1();
$this->operation2();
$this->operation3();
}
}

$b = new B;

?>

Ce code cre une opration de chaque type dans la classe A : public, protected et
private. B hrite de A. Dans le constructeur de B, vous essayez donc dappeler des
oprations du parent.
La ligne suivante :
$this->operation1();

produit une erreur fatale :


Fatal error: Call to private method A::operation1() from context B
184 Partie I Utilisation de PHP

Cet exemple montre que les oprations prives ne peuvent pas tre appeles depuis une
classe fille.
Si vous mettez cette ligne en commentaire, vous remarquerez que les deux autres appels
de fonction marchent bien. La fonction protected est hrite mais elle ne peut tre
utilise que depuis lintrieur de la classe fille, comme nous le faisons ici. Si vous
essayez dajouter la ligne suivante :
$b->operation2();

en bas du fichier, vous obtenez lerreur suivante :


Fatal error: Call to protected method A::operation2() from context

En revanche, vous pouvez appeler operation3() depuis lextrieur de la classe :


$b->operation3();

Cet appel est possible car la fonction est dclare public.

Redfinition (overriding)
Nous venons de voir le cas dune sous-classe dans laquelle sont dclars de nouveaux
attributs et oprations. Il est galement permis et parfois utile de redclarer les mmes
attributs et oprations. Une telle redclaration, qualifie de "redfinition" (overriding),
permet en effet de donner un attribut dune sous-classe une valeur par dfaut diff-
rente de celle du mme attribut dans la superclasse, ou bien encore de donner une
opration dune sous-classe une fonctionnalit diffrente de la mme opration dans la
superclasse.
Par exemple, si nous disposons de la classe A suivante :
class A {
public $attribut = "Valeur par dfaut";
public function operation() {
echo "Quelque chose<br />";
echo La valeur de $attribut est . $this->attribut . "<br />";
}
}

et quil nous apparaisse ncessaire de modifier la valeur par dfaut de $attribut et de


fournir une nouvelle fonctionnalit operation(), nous pourrions crer la classe B en
redfinissant $attribut et operation() de la faon suivante :
class B extends {
public $attribut = "Valeur diffrente";
public function operation() {
echo "Autre chose<br />";
echo La valeur de $attribut est . $this->attribut . "<br />";
}
}
Chapitre 6 PHP orient objet 185

Dclarer B naffecte en rien la dfinition originale de A. Considrez les deux lignes de


code suivantes :
$a = new A();
$a -> operation();

Elles crent un objet de type A et appellent sa fonction operation(). Le rsultat obtenu


lexcution de ces lignes est le suivant :
Quelque chose
La valeur de $attribut est Valeur par dfaut

Ce rsultat montre bien que la cration de B na pas affect A. Si nous crons un objet de
type B, nous obtiendrons un rsultat diffrent.
Les lignes suivantes :
$b = new B();
$b -> operation();

produiront :
Autre chose
La valeur de $attribut est Valeur diffrente

De la mme manire que fournir de nouveaux attributs ou oprations dans une sous-
classe naffecte pas la superclasse, la redfinition dattributs ou doprations dans une
sous-classe naffecte pas la superclasse.
Une sous-classe hrite de tous les attributs et oprations non privs de sa superclasse,
moins que vous effectuiez des remplacements. Si vous fournissez une dfinition de
remplacement, celle-ci devient prpondrante et remplace la dfinition dorigine.
Le mot-cl parent vous permet dappeler la version originale de lopration dans la
classe parente. Par exemple, pour appeler lopration A::operation depuis lintrieur
de la classe B, vous utiliseriez :
parent::operation();

La sortie produite est cependant diffrente. Bien que vous appeliez lopration depuis la
classe parente, PHP utilise les valeurs dattribut de la classe courante. Vous obtiendrez
donc la sortie suivante :
Quelque chose
La valeur de $attribut est Valeur diffrente

Lhritage peut tre implment sur plusieurs niveaux. Par exemple, nous pourrions
dclarer une classe appele C qui hrite de B, cest--dire qui hrite la fois des
proprits de B et de celles du parent de B, cest--dire de A. Tout comme pour la classe B,
nous serions libres de redfinir et de remplacer dans la classe C des attributs et oprations
des parents.
186 Partie I Utilisation de PHP

Empcher lhritage et les redfinitions avec final


PHP dispose du mot-cl final. Lorsque vous utilisez ce mot-cl devant une dclaration
de fonction, la fonction ne pourra plus tre redfinie dans aucune sous-classe. Vous
pouvez par exemple lajouter la classe A de lexemple prcdent :
class A {
public $attribut = "Valeur par dfaut";
final function operation() {
echo "Quelque chose<br />";
echo La valeur de $attribut est . $this->attribut . "<br />";
}
}

Cette approche vous empche de redfinir operation() dans la classe B. Si vous


essayez de le faire, vous obtenez lerreur suivante :
Fatal error: Cannot override final method A::operation()

Vous pouvez galement utiliser le mot-cl final pour empcher la cration de sous-
classes partir dune classe. Pour empcher la cration de sous-classes partir de la
classe A, ajoutez le mot-cl de la manire suivante :
final class A {...}

Si vous essayez ensuite dhriter de A, vous obtiendrez une erreur comme celle-ci :
Fatal error: Class B may not inherit from final class (A)

Hritage multiple
Quelques langages OO (dont C++ et Smalltalk) prennent en charge lhritage multiple
mais, comme la plupart des autres, ce nest pas le cas de PHP. Il sensuit que chaque
classe ne peut hriter que dun seul parent. En revanche, aucune restriction nimpose
une limite sur le nombre denfants que peut engendrer un mme parent.
Les implications de cet tat de fait ne sont pas ncessairement videntes premire vue.
La Figure 6.1 montre trois modes dhritage diffrents.

Figure 6.1
A
PHP ne prend pas
en charge lhritage A A B
multiple.
B

B C C
Hritage simple Hritage multiple
C
Hritage simple
Chapitre 6 PHP orient objet 187

Dans le mode le plus gauche, la classe C hrite de la classe B, qui hrite son tour de
la classe A. Chaque classe possde au plus un parent : ce mode dhritage unique est
parfaitement valide en PHP.
Dans le mode du centre, les classes B et C hritent toutes deux de la classe A. L encore,
chaque classe possde au plus un parent : ce mode dhritage unique est galement valide
en PHP.
Dans le mode le plus droite, la classe C hrite la fois des classes A et B. Dans ce cas,
la classe C possde deux parents : il sagit l dune situation dhritage multiple, non
supporte par PHP.

Implmentation dinterfaces
Si vous devez implmenter une fonctionnalit analogue lhritage multiple, vous
pouvez le faire grce aux interfaces, qui sont un moyen de contourner labsence de
lhritage multiple. Leur implmentation est semblable celle des autres langages
orients objet, dont Java.
Le principe dune interface consiste prciser un ensemble de fonctions qui devront tre
implmentes dans les classes qui implmentent linterface. Par exemple, vous pourriez
souhaiter quun ensemble de classes soient capables de safficher. Au lieu de crer une
classe parente avec une fonction Afficher() dont hriteraient toutes les sous-classes et
quelles redfiniraient, vous pouvez utiliser une interface de la manire suivante :
interface Affichable {
function Afficher(){
}

class pageWeb implements Affichable {


function Afficher() {
// ...
}
}

Cet exemple prsente une alternative lhritage multiple car la classe pageWeb peut
hriter dune seule classe et implmenter une ou plusieurs interfaces.
Si vous nimplmentez pas les mthodes spcifies dans linterface (dans le cas prsent,
Afficher()), vous obtiendrez une erreur fatale.

Conception de classes
Maintenant que nous avons pass en revue les principaux concepts de lapproche orien-
te objet concernant les objets et les classes, ainsi que la syntaxe de leur implmen-
tation en PHP, nous pouvons nous intresser la conception de classes qui nous seront
utiles.
188 Partie I Utilisation de PHP

Souvent, les classes implmentes dans le code reprsentent des classes ou des catgo-
ries dobjets rels. Dans le cadre dun dveloppement web, les classes peuvent notam-
ment servir reprsenter des pages web, des composants dinterface utilisateur, des
paniers virtuels, des gestionnaires derreur, des catgories de produits ou des clients.
Les objets de votre code peuvent galement reprsenter des instances spcifiques des
classes numres plus haut, comme une page daccueil, un bouton particulier ou le
panier dachat de Jean Dupont un moment donn. Jean Dupont lui-mme pourrait
dailleurs tre reprsent par un objet de type client. Chaque article achet par Jean peut
tre reprsent sous la forme dun objet, appartenant une catgorie ou une classe.
Dans le chapitre prcdent, nous nous sommes servis de fichiers inclus pour donner une
apparence cohrente toutes les pages du site de lentreprise fictive TLA Consulting.
Une version plus labore de ce site pourrait tre obtenue en utilisant des classes et en
exploitant le concept puissant dhritage.
Nous voulons maintenant pouvoir ajouter rapidement de nouvelles pages web au site de
TLA, qui aient la mme prsentation et un comportement similaire. Nous voulons
toutefois tre en mesure de modifier ces pages pour les adapter aux diffrentes parties
du site.
Pour les besoins de cet exemple, nous allons crer une classe Page dont le rle principal
est de limiter la quantit de code HTML ncessaire la cration dune nouvelle page.
Cette classe devra nous permettre de modifier les sections qui changent dune page
lautre, tout en produisant automatiquement les lments communs toutes les pages.
La classe Page devra donc fournir un cadre flexible pour la cration de nouvelles
pages, sans compromettre notre libert.
Comme les pages seront produites partir dun script et non avec du code HTML statique,
nous pouvons implmenter diverses possibilits astucieuses :
m Nautoriser la modification dlments de la page quen un emplacement seulement.
Par exemple, sil apparat ncessaire de changer la dclaration de copyright ou
dajouter un bouton supplmentaire, nous ne devrions avoir apporter la modification
quen un seul point du code.
m Disposer dun contenu par dfaut pour la plupart des sections de la page, tout en
gardant la possibilit de modifier chaque lment si ncessaire, de dfinir des
valeurs personnalises pour des lments tels que le titre et les mtabalises.
m Identifier la page en cours daffichage dans le navigateur et modifier en consquence
les lments de navigation (par exemple, un bouton permettant de retourner la
page de dmarrage na pas lieu dtre sur la page de dmarrage).
Chapitre 6 PHP orient objet 189

m Autoriser le remplacement dlments standard dans des pages particulires. Par


exemple, pour implmenter diffrents jeux de boutons dans diffrentes parties du
site, nous devons tre en mesure de remplacer les boutons standard.

Implmentation dune classe


Une fois que le rsultat vis et la fonctionnalit recherche ont t soigneusement dfinis,
nous pouvons nous attaquer limplmentation.
La conception et la gestion de projets denvergure sont traites un peu plus loin dans cet
ouvrage. Pour lheure, nous nous limiterons aux aspects spcifiques de lcriture dun
code orient objet en PHP.
Nous devons attribuer notre classe un nom logique et explicite. La classe reprsentant
une page web, nous lappellerons simplement Page. Pour dclarer une classe nomme
Page, il suffit dcrire :
class Page {
}

Notre classe doit contenir des attributs. Nous dfinirons comme attributs de la classe
Page les lments appels changer dune page lautre. Nous appellerons $contenu le
contenu principal de la page, qui sera une combinaison de balises HTML et de texte.
$contenu peut tre dclar dans la dfinition de la classe par la ligne de code suivante :
public $contenu;

Nous pouvons galement dfinir des attributs pour stocker le titre de la page. Pour que
les visiteurs du site identifient clairement la page consulte, ce titre changera dune
page lautre. Pour viter laffichage de titres vides, nous dfinirons un titre par dfaut :
public $titre = "TLA Consulting Pty Ltd";

La plupart des pages web des sites commerciaux contiennent des mtabalises destines
aider les moteurs de recherche dans leur indexation. Pour que ces mtabalises soient
utiles, elles doivent changer dune page lautre. L encore, nous fournirons une valeur
par dfaut:
public $mots_cles = "TLA Consulting, Three Letter Abbreviation,
les moteurs de recherche sont mes amis";

Les boutons de navigation montrs sur la page modle de la Figure 5.2 (voir le chapitre
prcdent) resteront probablement identiques dune page lautre afin de ne pas semer
la confusion dans lesprit du visiteur. Toutefois, pour faciliter la modification de ces
boutons, nous les implmenterons galement sous la forme dattributs. Le nombre de
boutons pouvant tre appel changer, nous utiliserons un tableau dans lequel nous
stockerons la fois lintitul du bouton et lURL pointe.
190 Partie I Utilisation de PHP

public $boutons = array( "Accueil" => "acceuil.php",


"Contacts" => "contacts.php",
"Services" => "services.php",
"Carte du site" => "carte.php"
);

Pour que la classe Page fournisse des fonctionnalits, nous devons la munir dopra-
tions. Pour commencer, nous pouvons lui ajouter des fonctions accesseurs qui nous
permettront de dfinir et de rcuprer la valeur des attributs que nous venons de crer :
public function _ _set($nom, $valeur)
{
$this->$nom = $valeur;
}

La fonction _ _set() ne contient pas de vrification derreur (par souci de concision),


mais cette fonctionnalit peut aisment tre ajoute par la suite, en fonction des
besoins. Comme il est peu probable que vous ayez besoin de rcuprer lune de ces
valeurs depuis lextrieur de la classe, vous pouvez dlibrment ne pas fournir de
fonction _ _get() ; cest ce que nous faisons ici. La classe Page visant principalement
afficher une page HTML, nous devons implmenter une fonction cette fin, que nous
appelons Afficher() :
public function Afficher() {
echo "<html>\n<head>\n";
$this -> AfficherTitre();
$this -> AfficherMotsCles();
$this -> AfficherStyles();
echo "</head>\n<body>\n";
$this -> AfficherEntete();
$this -> AfficherMenu($this->boutons);
echo $this->contenu;
$this -> AfficherPied();
echo "</body>\n</html>\n";
}

Outre quelques instructions echo simple qui affichent le texte HTML, cette fonction
comprend essentiellement des appels dautres fonctions de la classe. Comme le lais-
sent deviner leurs noms, ces autres fonctions affichent des parties distinctes de la page.
Un tel dcoupage en fonctions nest pas indispensable et nous aurions trs bien pu
combiner ces diffrentes fonctions en une seule. Nous avons toutefois choisi ce dcou-
page pour diverses raisons.
Chaque fonction doit, en principe, accomplir une tche bien dfinie. Plus la tche est
simple, plus la fonction est facile tester. Ne poussez toutefois pas cette modularisation
trop loin : un programme morcel en trop dunits risque dtre difficile lire.
Grce au concept dhritage, nous avons la possibilit de redfinir des oprations. Nous
pouvons redfinir une fonction Afficher() volumineuse, mais il est peu probable que
nous soyons amens changer la manire dont toute la page est affiche. Il est par
Chapitre 6 PHP orient objet 191

consquent prfrable de diviser la fonctionnalit daffichage en quelques tches auto-


nomes, de sorte pouvoir redfinir les seules parties qui doivent tre modifiables.
La fonction Afficher() invoque AfficherTitre(), AfficherMotsCles(), AfficherS
tyles(), AfficherEntete(), AfficherMenu() et AfficherPied(). Nous devons donc
dfinir ces oprations. En PHP, nous pouvons crire les oprations ou fonctions dans cet
ordre logique, en appelant lopration ou la fonction avant que son code nait t crit,
alors que dans de nombreux autres langages de programmation la fonction ou lopration
doivent tre crites avant dtre appeles.
La plupart des oprations sont relativement simples et se contentent dafficher du code
HTML et, ventuellement, le contenu des attributs.
Le Listing 6.1 donne lintgralit du code de la classe Page. Ce script est enregistr
dans le fichier page.inc, pour tre inclus dans dautres fichiers.

Listing 6.1 : page.inc La classe Page constitue un moyen facile et flexible de cration
de pages pour le site TLA Consulting

<?php
class Page {
// Attributs de la classe Page
public $contenu;
public $titre = "TLA Consulting Pty Ltd";
public $mots_cles = "TLA Consulting, Three Letter Abbreviation,
les moteurs de recherche sont mes amis";
public $boutons = array( "Accueil" => "acceuil.php",
"Contacts" => "contacts.php",
"Services" => "services.php",
"Carte du site" => "carte.php"
);

// Oprations de la classe Page


public function _ _set($nom, $valeur) {
$this->$nom = $valeur;
}

public function Afficher() {


echo "<html>\n<head>\n";
$this -> AfficherTitre();
$this -> AfficherMotsCles();
$this -> AfficherStyles();
echo "</head>\n<body>\n";
$this -> AfficherEntete();
$this -> AfficherMenu($this->boutons);
echo $this->contenu;
$this -> AfficherPied();
echo "</body>\n</html>\n";
}

public function AfficherTitre() {


echo "<title>" . $this->titre . "</title>";
}
192 Partie I Utilisation de PHP

public function AfficherMotsCles() {


echo <meta name="keywords" content=" . $this->mots_cls . "/>;
}

public function AfficherStyles() {


?>
<style>
h1 {
color:white; font-size:24pt; text-align:center;
font-family:arial,sans-serif
}
.menu {
color:white; font-size:12pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold
}
td {
background:black
}
p {
color:black; font-size:12pt; text-align:justify;
font-family:arial,sans-serif
}
p.foot {
color:white; font-size:9pt; text-align:center;
font-family:arial,sans-serif; font-weight:bold
}
a:link,a:visited,a:active {
color:white
}
</style>
<?php
}

public function AfficherEntete() {


?>
<table width="100%" cellpadding="12" cellspacing="0" border="0">
<tr bgcolor="black">
<td align="left"><img src="logo.gif" /></td>
<td>
<h1>TLA Consulting</h1>
</td>
<td align="right"><img src="logo.gif" /></td>
</tr>
</table>
<?php
}

public function AfficherMenu($boutons) {


echo <table width="100%" bgcolor="white"
cellpadding="4" cellspacing="4">;
echo "\n<tr>\n";

// Calcul de la taille des bouton


$largeur = 100 / count($boutons);

while (list($nom, $url) = each($boutons)) {


Chapitre 6 PHP orient objet 193

$this->AfficherBouton($largeur, $nom, $url,


!$this->EstPageCourante($url));
}
echo "</tr>\n";
echo "</table>\n";
}

public function EstPageCourante($url) {


if(strpos($_SERVER[PHP_SELF], $url ) == false) {
return false;
} else {
return true;
}
}

public function AfficherBouton($largeur, $nom, $url, $active = true) {


if ($active) {
echo "<td width = \"" . $largeur . "%\">
<a href=\"" . $url . "\">
<img src=\"s-logo.gif\" alt=\"" . $name . "\" border=\"0\" /></a>
<a href=\"" . $url . "\"><span class=\"menu\">" . $nom . "</span></a>
</td>";
} else {
echo "<td width=\"" . $largeur . "%\">
<img src=\"side-logo.gif\">
<span class=\"menu\">". $nom . "</span>
</td>";
}
}

public function AfficherPied()


{
?>
<table width="100%" bgcolor="black" cellpadding="12" border="0">
<tr>
<td>
<p class="foot">&copy; TLA Consulting.</p>
<p class="foot">Consultez notre <a href ="">page dinformations
lgales</a></p>
</td>
</tr>
</table>
<?php
}
}
?>

la lecture du Listing 6.1, vous remarquerez que AfficherStyles(), Afficher


Entete() et AfficherPied() doivent afficher beaucoup de HTML statique, sans traite-
ment PHP. Cest la raison pour laquelle ces oprations sont implmentes sous la forme
dune simple balise de fermeture PHP (?>), suivie du code HTML, puis dune balise
douverture PHP (<?php).
194 Partie I Utilisation de PHP

La classe Page comprend deux autres oprations que celles cites dans le paragraphe
prcdent. Lopration AfficherBouton() produit un simple bouton de menu. Si ce
bouton doit pointer sur la page courante, il est remplac par un bouton inactif, dappa-
rence lgrement diffrente et ne pointant sur aucune page. Cette astuce permet de
conserver une prsentation cohrente des pages du site et donne aux visiteurs une indi-
cation sur leur localisation dans le site.
Lopration EstPageCourante() dtermine si lURL qui lui a t passe en paramtre
pointe sur la page courante. Il existe de nombreuses techniques pour crire ce type de
test ; ici, nous faisons appel la fonction strpos() pour dterminer si lURL est contenue
dans lune des variables de serveur. Linstruction strpos( $ SERVER[PHP SELF],
$url ) renvoie un nombre si la chane stocke dans $url est contenue dans la variable
superglobale $ SERVER[PHP SELF] ou renvoie la valeur false dans le cas contraire.
Pour utiliser la classe Page, nous devons inclure le fichier page.inc dans un script et
appeler Afficher().
Le code du Listing 6.2 cre la page daccueil du site de lentreprise fictive TLA Consulting
et donne un rsultat trs semblable celui montr la Figure 6.2.
Le code du Listing 6.2 fonctionne de la manire suivante :
1. Il utilise linstruction require pour inclure le contenu de page.inc qui contient la
dfinition de la classe Page.
2. Il cre une instance de la classe Page. Cette instance est appele $page accueil.
3. Il dfinit le contenu, constitu de texte et de balises HTML qui doivent figurer dans
la page (ce qui appelle implicitement la mthode _ _set()).
4. Il appelle lopration Afficher() sur lobjet $page accueil pour provoquer laffi-
chage de la page dans le navigateur web du visiteur.

Listing 6.2 : accueil.php Cette page daccueil est obtenue en utilisant la classe Page
pour accomplir lessentiel du travail ncessaire la gnration de la page

<?php
require("page.inc");

$page_accueil = new Page();

$page_accueil->contenu = "<p>Bienvenue sur le site de TLA Consulting.


Prenez le temps de nous connatre.</p>
<p>Nous sommes spcialiss dans laide aux dcisions et
nous esprons que vous ferez bientt appel nous.</p>";
$page_accueil->Afficher();
?>
Chapitre 6 PHP orient objet 195

Le Listing 6.2 montre la facilit avec laquelle de nouvelles pages web peuvent tre
ajoutes au site grce la classe Page. En outre, cette approche permet dobtenir des
pages dapparence trs similaire sur lensemble du site.
Pour utiliser une variante de la page standard dans une certaine partie du site, il suffit de
copier page.inc dans un nouveau fichier appel page2.inc et dy apporter les modifications
voulues. Toutefois, aprs avoir opr une telle "scission" de notre modle, nous devrons
reproduire dans le fichier page2.inc les ventuelles mises jour effectues dans page.inc.
Le concept dhritage nous offre une solution bien meilleure : nous pouvons crer une
nouvelle classe qui hrite de lessentiel de la fonctionnalit de la classe Page, mais qui
redfinit les parties que nous voulons prsenter diffremment.
Dans le cas du site TLA, par exemple, nous pourrions vouloir insrer une seconde barre
de navigation dans la page des services.
Le script du Listing 6.3 ralise cette modification en crant une nouvelle classe appele
PageServices qui hrite de la classe Page. Les boutons et les liens que nous voulons
voir figurer sur une seconde ligne sont enregistrs dans un nouveau tableau, appel
$boutonsLigne2. Cette classe devant avoir un comportement trs semblable celui de
la classe Page, nous ne redfinissons que les parties modifier, cest--dire lopration
Afficher().

Listing 6.3 : services.php La classe PageServices hrite de la classe Page mais


redfinit lopration Afficher() de sorte produire une barre de navigation diffrente

<?php
require ("page.inc");

class PageServices extends Page {


private $boutonsLigne2 = array(
"Re-engineering" => "reengineering.php",
"Conformit aux standards" => "standards.php",
"Respect du Buzz" => "buzzword.php",
"Missions" => "mission.php"
);

public function Afficher() {


echo "<html>\n<head>\n";
$this->AfficherTitre();
$this->AfficherMotsCles();
$this->AfficherStyles();
echo "</head>\n<body>\n";
$this->AfficherEntete();
$this->AfficherMenu($this->boutons);
$this->AfficherMenu($this->boutonsLigne2);
echo $this->contenu;
$this->AfficherPied();
echo "</body>\n</html>\n";
}
}
196 Partie I Utilisation de PHP

$services = new PageServices();

$services->contenu ="<p>TLA Consulting offre un grand nombre de


services. La productivit de vos employs samliorerait
srement si nous rorganisions votre entreprise. Votre socit
ncessite peut-tre une redfinition de sa mission ou dun
nouveau lot de mots la mode.</p>";

$services -> Afficher();


?>

Lopration Afficher() redfinie est analogue lopration Afficher() de la classe


Page, sauf quelle contient la ligne supplmentaire suivante :
$this->AfficherMenu($this->boutonsLigne2);

Cette ligne appelle AfficherMenu() une seconde fois, de sorte crer la seconde barre
de menus.
En dehors de la dfinition de la classe, nous crons une instance de la classe Page
Services, nous dfinissons les valeurs qui requirent des valeurs diffrentes de celles
par dfaut, puis nous appelons Afficher().
Comme le montre la Figure 6.2, nous produisons bien ainsi une variante de la page
standard. Pour cela, nous nous sommes contents dcrire du nouveau code pour les
seules parties rellement diffrentes.

Figure 6.2
La page des services est produite sur le principe de lhritage, de sorte rutiliser lessentiel
du contenu de la page standard.
Chapitre 6 PHP orient objet 197

La cration de pages via des classes PHP prsente des avantages indniables. Comme
nous disposons dune classe capable de faire lessentiel du travail notre place, la cra-
tion dune nouvelle page ne ncessite que trs peu defforts. De plus, nous pouvons
facilement mettre jour toutes les pages du site en une seule fois, en travaillant directe-
ment la source, cest--dire sur la classe. Grce au principe de lhritage, il est facile
dobtenir diffrentes variantes dune mme classe tout en conservant les avantages de la
classe dorigine.
Comme cest hlas gnralement le cas, les avantages de cette approche ont un cot.
La gnration de pages partir dun script requiert plus deffort de la part du processeur
de lordinateur que le simple chargement dune page HTML statique partir dun
disque dur ou la transmission dune page un navigateur. Sur un site trs frquent, ce
dtail peut tre important et vous devrez alors faire en sorte dutiliser des pages HTML
statiques ou de mettre en cache la sortie de vos scripts chaque fois que cela est possible
afin de rduire la charge pesant sur le serveur.

Comprendre les fonctionnalits orientes objet avances de PHP


Dans les sections suivantes, nous traiterons des fonctionnalits orientes objet avances
de PHP.

Constantes de classe
PHP permet de crer des constantes de classe, qui peuvent tre utilises sans quil soit
ncessaire dinstancier la classe :
<?php
class Math {
const pi = 3.14159;
}
echo "Math::pi = " . Math::pi. "\n";
?>
Vous pouvez accder la constante de classe en utilisant loprateur : : pour indiquer la
classe laquelle la constante appartient, comme dans lexemple prcdent.

Mthodes statiques
PHP 5 dispose du mot-cl static, qui peut tre appliqu aux mthodes afin de leur
permettre dtre appeles sans instancier la classe. Il sagit dune notion quivalente de
celle de constante de classe. Par exemple, vous pourriez ajouter une mthode carre()
la classe Math de la section prcdente et invoquer cette mthode sans instancier la
classe :
class Math {
static function carre($valeur) {
198 Partie I Utilisation de PHP

return $valeur * $valeur;


}
}
echo Math::carre(8);

Notez que vous ne pouvez pas utiliser le mot-cl this lintrieur dune mthode stati-
que, car il ny a aucune instance laquelle se rfrer.

Vrification du type de classe et indication de type


Le mot-cl instanceof permet de vrifier le type dun objet. Avec lui, vous pouvez
vrifier si un objet est une instance dune classe particulire, sil hrite dune classe ou
sil implmente une interface. Le mot-cl instanceof est, en ralit, un oprateur
conditionnel. Par exemple, avec les exemples prcdents, dans lesquels la classe B est
une sous-classe de la classe A :

($b instanceof B) serait vrai.


($b instanceof A) serait vrai.
($b instanceof Affichable) serait faux.

Tous ces exemples prsupposent que A, B et Affichable se trouvent dans la porte


courante. Sinon une erreur est dclenche.
Vous pouvez galement utiliser lindication de type de classe. Normalement, lorsque
vous passez un paramtre une fonction dans PHP, vous ne passez pas le type de ce
paramtre. Avec lindication de type de classe, vous pouvez prciser le type de classe
qui doit tre pass ; sil ne sagit pas du type effectivement pass, une erreur sera
dclenche. La vrification de type est lquivalent de instanceof.
Voici un exemple :
function verif_type(B $uneClasse) {
//...
}

Cet exemple suggre que $uneClasse doit tre une instance de la classe B. Si vous
passez ensuite une instance de la classe A de la manire suivante :
verif_type($a);

vous obtiendrez cette erreur fatale :


Fatal error: Argument 1 must be an instance of B

Notez que, si vous aviez indiqu A et pass une instance de B, aucune erreur ne serait
survenue, car B hrite de A.
Chapitre 6 PHP orient objet 199

Clonage dobjets
Le mot-cl clone permet de copier un objet existant. Linstruction suivante, par exemple :
$c = clone $b;

cre une copie de lobjet $b de la mme classe, avec les mmes valeurs dattributs.
Vous pouvez galement modifier ce comportement. Si vous souhaitez que le clonage
nadopte pas le comportement par dfaut, vous devez crer une mthode _ _clone()
dans la classe de base. Cette mthode est semblable un constructeur ou un destruc-
teur car on ne lappelle pas directement : elle est invoque lorsque lon utilise le mot-cl
clone comme ici. Dans cette mthode _ _clone(), vous pouvez ensuite dfinir exactement
le comportement de copie que vous souhaitez.
Le fait intressant concernant la fonction _ _clone() tient ce quelle est appele aprs
quune copie exacte eut t effectue en utilisant le comportement par dfaut, ce qui
permet ce stade de ne modifier que ce que vous souhaitez changer.
Le plus souvent, on ajoute _ _clone() du code pour garantir que les attributs de la
classe qui sont grs comme des rfrences seront correctement copis. Si vous vous
prparez cloner une classe qui contient une rfrence un objet, vous souhaiterez sans
doute obtenir une seconde copie de cet objet au lieu dune seconde rfrence au mme
objet. Il est alors judicieux dajouter cette fonctionnalit _ _clone().
Il est galement possible que vous choisissiez de ne rien changer mais de raliser
dautres actions, par exemple en mettant jour un enregistrement dune base de
donnes sous-jacente lie la classe.

Classes abstraites
PHP permet dcrire des classes abstraites qui ne peuvent pas tre instancies, ainsi que
des mthodes abstraites qui fournissent la signature dune mthode mais nen proposent
pas dimplmentation. Voici un exemple dune telle mthode :
abstract operationX($param1, $param2);

Toute classe qui contient des mthodes abstraites doit elle-mme tre abstraite, comme
le montre cet exemple :
abstract class A {
abstract function operationX($param1, $param2);
}

Lusage principal des mthodes et des classes abstraites concerne le cas des hirarchies
de classes complexes o vous souhaitez vous assurer que chaque sous-classe contient et
redfinit certaines mthodes particulires. Ce but peut galement tre atteint avec une
interface.
200 Partie I Utilisation de PHP

Surcharge de mthodes avec _ _call()


Nous avons prcdemment examin un certain nombre de mthodes ayant des signifi-
cations spciales et dont les noms commencent par un double blanc soulign ( _ _),
comme _ _get(), _ _set(), _ _construct() et _ _destruct(). La mthode _ _call(),
qui est utilise dans PHP pour implmenter la surcharge de mthodes, en est un autre
exemple.
La surcharge de mthode est courante dans de nombreux langages orients objet mais
elle nest pas aussi utile en PHP parce que lon a tendance plutt employer des types
flexibles et des paramtres facultatifs de fonction (simples implmenter).
Pour lutiliser, vous devez implmenter une mthode _ _call(), comme dans cet
exemple :
public function _ _call($methode, $p) {
if ($methode == "Afficher") {
if (is_object($p[0])) {
$this->AfficherObjet($p[0]);
} else if (is_array($p[0])) {
$this->AfficherTableau($p[0]);
} else {
$this->AfficherScalaire($p[0]);
}
}
}

La mthode _ _call() attend deux paramtres. Le premier contient le nom de la


mthode invoque et le second, un tableau des paramtres passs cette mthode. Vous
pouvez ensuite dcider par vous-mme de la mthode sous-jacente appeler. Dans ce
cas, si un objet est pass la mthode Afficher(), vous appelez la mthode Affiche
rObjet() sous-jacente ; si un tableau est pass, vous appelez AfficherTableau() ;
dans tous les autres cas, vous appelez AfficherScalaire().
Pour appeler ce code, vous devez dabord instancier la classe contenant cette mthode
_ _call() (supposons quelle sappelle Surcharge) puis invoquer la mthode Affi
cher(), comme dans cet exemple :
$obj = new Surcharge;
$obj->Afficher(array(1, 2, 3));
$obj->Afficher("chat");

Le premier appel Afficher() invoquera AfficherTableau() et le second, Afficher


Scalaire().
Notez que vous navez besoin daucune implmentation sous-jacente de la mthode
Afficher() pour que ce code fonctionne.
Chapitre 6 PHP orient objet 201

Utiliser _ _autoload()
La fonction _ _autoload() est une autre fonction spciale de PHP. Il sagit non pas
dune mthode de classe mais dune fonction autonome. Autrement dit, il faut la dcla-
rer en dehors de toute classe. Si vous limplmentez, elle sera automatiquement appele
lorsque vous tenterez dinstancier une classe qui na pas t dclare.
Lutilisation principale de _ _autoload() consiste inclure tous les fichiers requis pour
instancier une classe. Considrez lexemple suivant :
function _ _autoload($nom) {
include_once $nom . ".php";
}

Cette implmentation tente dinclure un fichier possdant le mme nom que la classe.

Implmentation des itrateurs et itrations


Lune des fonctionnalits astucieuses du moteur orient objet de PHP tient ce que
vous pouvez utiliser une boucle foreach() pour parcourir les attributs dun objet
comme vous le feriez avec un tableau. Voici un exemple :
class MaClasse {
public $a = 5;
public $b = 7;
public $c = 9;
}
$x = new MaClasse;
foreach ($x as $attribut) {
echo $attribut . "<br />";
}
lheure o nous crivons ces lignes, le manuel PHP suggre quil faut implmenter
linterface vide Traversable pour que linterface foreach fonctionne mais, si vous le
faites, une erreur fatale se produit. Inversement, tout semble fonctionner si vous ne
limplmentez pas.
Si vous avez besoin dun comportement plus sophistiqu, vous pouvez implmenter un
itrateur. Pour cela, il faut que la classe sur laquelle vous souhaitez oprer litration
implmente linterface IteratorAggregate et vous devez lui crire une mthode appele
getIterator qui renvoie une instance de la classe ditrateur. Cette classe ditrateur doit
implmenter linterface Iterator, qui possde une srie de mthodes que vous devrez
donc galement implmenter. Le Listing 6.4 montre un exemple de classe et ditrateur.

Listing 6.4 : iterator.php Exemple de classe de base et de classe ditrateur

<?php
class IterateurObjet implements Iterator {

private $obj;
202 Partie I Utilisation de PHP

private $cpteur;
private $indiceCourant;

function _ _construct($obj) {
$this->obj = $obj;
$this->cpteur = count($this->obj->donnees);
}
function rewind() {
$this->indiceCourant = 0;
}
function valid() {
return $this->indiceCourant < $this->cpteur;
}
function key() {
return $this->indiceCourant;
}
function current() {
return $this->obj->donnees[$this->indiceCourant];
}
function next() {
$this->indiceCourant++;
}
}

class Objet implements IteratorAggregate {


public $donnees = array();

function _ _construct($in)
{
$this->donnees = $in;
}

function getIterator() {
return new ObjectIterator($this);
}
}

$monObjet = new Objet(array(2, 4, 6, 8, 10));

$monIter = $monObjet->getIterator();
for($monIter->rewind(); $monIter->valid(); $monIter->next()) {
$cle = $monIter->key();
$valeur = $monIter->current();
echo $cle . "=> " . $valeur . "<br />";
}
?>

La classe IterateurObjet possde un jeu de fonctions requis par linterface Iterator :


m Le constructeur nest pas obligatoire, mais il sagit videmment dun bon emplace-
ment pour dfinir les valeurs pour le nombre dlments que vous prvoyez de
parcourir et un lien vers llment courant.
m La fonction rewind() doit repositionner le pointeur de donnes interne au dbut des
donnes.
Chapitre 6 PHP orient objet 203

m La fonction valid() doit vous indiquer si dautres donnes existent encore


lemplacement courant du pointeur de donnes.
m La fonction key() doit renvoyer la valeur du pointeur de donnes.
m La fonction value() doit renvoyer la valeur stocke au niveau du pointeur de
donnes courant.
m La fonction next() doit faire avancer le pointeur de donnes.
La raison pour laquelle on utilise une classe ditrateur comme celle-ci est que linter-
face vers les donnes ne changera pas mme si limplmentation sous-jacente devait
tre modifie par la suite. Dans cet exemple, la classe IteratorAggregate est un simple
tableau ; si vous dcidiez de la modifier en la remplaant par un tableau de hachages ou
une liste chane, vous pourrez toujours utiliser un Iterator standard pour la traverser,
mme si le code de la classe Iterator devrait tre modifi.

Conversion de classes en chanes


Si vous implmentez une mthode _ _toString() dans votre classe, elle sera appele
lorsque vous essayez dafficher un objet de cette classe, comme dans cet exemple :
$p = new Affichable;
echo $p;

echo affichera alors ce que renvoie la mthode _ _toString(). Vous pourriez par exemple
limplmenter de la faon suivante :
class Affichable {
public $testUn;
public $testDeux;
public function _ _toString() {
return(var_export($this, TRUE));
}
}

La fonction var export() affiche toutes les valeurs dattribut de la classe.

Utiliser lAPI dintrospection


Lintrospection est la possibilit dinterroger des classes et des objets existants afin de
connatre leur structure et leur contenu. Cette capacit peut tre utile lorsque vous effec-
tuez un interfaage avec des classes inconnues ou non documentes, par exemple avec
des scripts PHP encods.
LAPI est extrmement complexe, mais nous examinerons un exemple simple afin de
vous donner un avant-got de lintrt quelle peut avoir. Par exemple, considrez la
classe Page dfinie dans ce chapitre. Vous pouvez obtenir toutes les informations
204 Partie I Utilisation de PHP

concernant cette classe partir de lAPI dinstrospection, comme le montre le


Listing 6.5.

Listing 6.5 : introspection.php Affichage dinformations concernant la classe Page

<?php
require_once("page.inc");
$classe = new ReflectionClass("Page");
echo <pre>;
echo $classe;
echo </pre>;
?>

Ici, vous utilisez la mthode _ _toString() de la classe Reflection pour imprimer ces
donnes. Notez que les balises <pre> se trouvent sur des lignes spares afin de ne pas
perturber la mthode _ _toString().
Le premier cran de sortie de ce code est prsent la Figure 6.3.

Figure 6.3
La sortie de lAPI dintro-
spection est tonnamment
dtaille.

Pour la suite
Le chapitre suivant prsente le traitement des exceptions en PHP, qui constituent un
mcanisme lgant pour la gestion des erreurs dexcution.
7
Gestion des exceptions

Dans ce chapitre, nous prsenterons la gestion des exceptions et son implmentation


dans PHP. Les exceptions offrent un mcanisme unifi pour grer les erreurs de manire
volutive, adapte la maintenance et oriente objet.

Notions relatives la gestion des exceptions


Lide fondamentale de la gestion des exceptions tient ce que le code est excut
lintrieur de ce que lon appelle un bloc try. Il sagit dune section de code qui ressemble
ceci :
try {
// Le code vient ici
}
Si quelque chose se passe mal lintrieur du bloc try, vous pouvez lever une
exception. Certains langages, comme Java, lvent automatiquement des exceptions
dans certains cas. En PHP, les exceptions doivent tre leves manuellement, comme
ici :
throw new Exception(message, code);
Le mot-cl throw dclenche le mcanisme de gestion des exceptions. Il sagit dune
structure du langage plutt que dune fonction, mais vous devez lui passer une valeur.
Elle sattend recevoir un objet. Dans le cas de figure le plus simple, vous pouvez
instancier la classe prdfinie Exception, comme dans lexemple prcdent.
Le constructeur de cette classe attend deux paramtres : un message et un code qui
reprsentent, respectivement, le message de lerreur et son numro de code. Ils sont
tous deux facultatifs.
206 Partie I Utilisation de PHP

Enfin, sous le bloc try, vous avez besoin au minimum dun bloc catch, qui doit ressembler
ceci :
catch (indication du type de lexception {
// gestion de lexception
}

Plusieurs blocs catch peuvent tre associs un mme bloc try. Cest notamment
cohrent si chaque bloc catch capture un type dexception diffrent. Si, par exemple,
vous souhaitez capturer des exceptions de la classe Exception, votre bloc catch pourrait
ressembler ceci :
catch (Exception $e) {
// gestion de lexception
}

Lobjet pass dans (et captur par) le bloc catch est celui qui est transmis (et lanc
par) linstruction throw qui a lev lexception. Lexception peut tre de nimporte quel
type, mais il est prfrable dutiliser des instances de la classe Exception ou des exceptions
que vous avez dfinies vous-mme et qui hritent de la classe Exception (vous verrez
comment dfinir vos propres exceptions plus loin dans ce chapitre).
Lorsquune exception est leve, PHP recherche un bloc catch correspondant. Sil
existe plusieurs blocs catch, les objets passs chacun dentre eux doivent tre de
types diffrents afin que PHP puisse dterminer sur quel bloc catch il convient de
retomber.
Notez par ailleurs que vous pouvez lever dautres exceptions lintrieur dun bloc
catch.
Pour rendre ces explications plus claires, considrez lexemple simple de gestion
dexception prsent dans le Listing 7.1.

Listing 7.1 : basic_exception.php Lever et capturer une exception

<?php

try {
throw new Exception("Une terrible erreur sest produite", 42);
}
catch (Exception $e) {
echo "Exception " . $e->getCode() . ": " . $e->getMessage() .
" dans " . $e->getFile(). " en ligne ". $e->getLine() . "<br />";
}
?>

Dans le Listing 7.1, vous pouvez remarquer que nous avons utilis un certain nombre
de mthodes de la classe Exception, sur lesquelles nous reviendrons dans un instant.
Le rsultat de ce code est prsent la Figure 7.1.
Chapitre 7 Gestion des exceptions 207

Figure 7.1
Ce bloc catch signale le message derreur de lexception et lendroit o lexception est survenue.

Dans cet exemple, vous pouvez remarquer que nous levons une exception de la classe
Exception. Cette classe prdfinie possde des mthodes que vous pouvez utiliser dans
le bloc catch afin de produire un message derreur utile.

La classe Exception
PHP dispose dune classe prdfinie appele Exception. Son constructeur prend deux
paramtres, comme indiqu prcdemment : un message et un code derreur.
Outre ce constructeur, cette classe propose les mthodes suivantes :
m getCode(). Rennvoie le code tel quil a t pass au constructeur.
m getMessage(). Renvoie le message tel quil a t pass au constructeur.
m getFile(). Renvoie le chemin daccs complet au fichier dans lequel lexception a
t leve.
m getLine(). Renvoie le numro de ligne du fichier dans lequel lexception a t
leve.
m getTrace(). Renvoie un tableau contenant une trace dexcution de lendroit o
lexception a t leve.
m getTraceAsString(). Renvoie les mmes informations que getTrace, formates
sous forme de chane.
m _ _toString(). Permet deffectuer un simple echo dun objet Exception, en four-
nissant toutes les informations des mthodes prcdentes.
Comme vous le voyez, nous avons utilis les quatre premires mthodes dans le
Listing 7.1. Vous pouvez obtenir les mmes informations (ainsi que la trace dexcution)
laide de linstruction suivante :
echo $e;

La trace dexcution indique quelles fonctions sexcutaient au moment o lexception


a t leve.
208 Partie I Utilisation de PHP

Exceptions dfinies par lutilisateur


Au lieu dinstancier et de passer une instance de la classe de base Exception, vous
pouvez passer lobjet que vous souhaitez. Dans la plupart des cas, vous tendrez la
classe Exception afin de crer vos propres classes dexception.
Vous pouvez passer nimporte quel autre objet avec votre clause throw. Il se peut que
vous souhaitiez occasionnellement le faire si vous avez des problmes avec un objet
particulier et que vous souhaitiez le passer pour des besoins de dbogage.
La plupart du temps, cependant, vous tendrez la classe Exception. Le manuel PHP
fournit du code qui prsente le squelette de la classe Exception. Ce code, qui peut tre
tlcharg ladresse http://www.php.net/zend-engine-2.php, est reproduit dans le
Listing 7.2. Notez quil sagit non pas du code lui-mme mais de ce que vous pouvez
vous attendre hriter.

Listing 7.2 : classe Exception Ce que vous pouvez vous attendre hriter

<?php
class Exception {
function _ _construct(string $message = NULL, int $code = 0) {
if (func_num_args()) {
$this->message = $message;
}
$this->code = $code;
$this->file = _ _FILE_ _; // de la clause throw
$this->line = _ _LINE_ _; // de la clause throw
$this->trace = debug_backtrace();
$this->string = StringFormat($this);
}

protected $message = "Unknown exception"; // message de lexception


protected $code = 0; // code dexception dfini par lutilisateur
protected $file; // nom du fichier source de lexception
protected $line; // ligne source de lexception

private $trace; // trace dexcution de lexception


private $string; // usage interne uniquement!!

final function getMessage(){


return $this->message;
}
final function getCode() {
return $this->code;
}
final function getFile() {
return $this->file;
}
final function getTrace() {
return $this->trace;
}
final function getTraceAsString() {
Chapitre 7 Gestion des exceptions 209

return self::TraceFormat($this);
}
function _toString() {
return $this->string;
}
static private function StringFormat(Exception $exception) {
// ... fonction non disponible dans les scripts PHP
// qui renvoie toutes les infos pertinentes sous forme de chane
}
static private function TraceFormat(Exception $exception) {
// ... fonction non disponible dans les scripts PHP
// qui renvoie la trace dexcution sous forme de chane
}
}
? >

La raison principale qui nous amne examiner cette dfinition de classe consiste
noter que la plupart des mthodes publiques sont finales : vous ne pouvez donc pas les
redfinir. Vous pouvez crer vos propres sous-classes Exceptions, mais vous ne pouvez
pas modifier le comportement des mthodes de base. Notez que vous pouvez redfinir
la fonction _ _toString(), ce qui vous permet de modifier la manire dont lexception
sera affiche. Vous pouvez galement ajouter vos propres mthodes.
Le Listing 7.3 prsente un exemple de classe Exception dfinie par lutilisateur.

Listing 7.3 : exception_utilisateur.php Exemple de classe Exception dfinie


par lutilisateur

<?php

class MonException extends Exception {


function _ _toString() {
return "<table border=\"1\">
<tr>
<td><strong>Exception " . $this->getCode()
. "</strong>: " . $this->getMessage() ."<br />" . " dans "
. $this->getFile() . " en ligne " . $this->getLine()
. "</td>
</tr>
</table><br />";
}
}

try {
throw new MonException("Une erreur terrible sest produite", 42);
}
catch (MonException $m) {
echo $m;
}

?>
210 Partie I Utilisation de PHP

Dans ce code, vous dclarez une nouvelle classe dexception appele MonException qui
tend la classe de base Exception. La diffrence entre cette classe et la classe Excep
tion tient ce que vous redfinissez la mthode _ _toString() afin de proposer une
sortie amliore de lexception. La sortie rsultant de lexcution de ce code est prsente
la Figure 7.2.

Figure 7.2
La classe myException
fournit un affichage
amlior des exceptions.

Cet exemple est plutt simple. Dans la section suivante, nous allons examiner des
moyens de crer diffrentes exceptions pour grer diffrentes catgories derreur.

Exceptions dans le garage de Bob


Le Chapitre 2 vous a montr comment les donnes des commandes du garage de Bob
pouvaient tre stockes dans un fichier plat. Vous savez que les E/S sur fichier (en fait,
tout type dE/S) sont un secteur des programmes o des erreurs interviennent souvent.
Il sagit ainsi dun bon domaine pour mettre en application la gestion des exceptions.
En revenant au code dorigine, vous pouvez voir que trois choses peuvent mal se passer
avec lcriture dans le fichier : le fichier ne peut pas tre ouvert, un verrou ne peut pas
tre obtenu ou le fichier nest pas accessible en criture. Nous avons donc cr une
classe dexception pour chacune de ces possibilits, comme le montre le Listing 7.4.

Listing 7.4 : exceptions_fichiers.php Exceptions lies aux E/S de fichier

<?php

class ExceptionOuvertureFichier extends Exception {


public function _ _toString() {
return " ExceptionOuvertureFichier " . $this->getCode()
. ": " . $this->getMessage() . "<br />" . " dans "
. $this->getFile() . " en ligne " . $this->getLine()
. "<br />";
}
}

class ExceptionEcritureFichier extends Exception {


public function _ _toString() {
return "ExceptionEcritureFichier " . $this->getCode()
. ": " . $this->getMessage() . "<br />" . " dans "
Chapitre 7 Gestion des exceptions 211

. $this->getFile() . " en ligne " . $this->getLine()


. "<br />";
}
}

class ExceptionVerrouillageFichier extends Exception {


public function _ _toString() {
return "ExceptionVerrouillageFichier " . $this->getCode()
. ": " . $this->getMessage() . "<br />" . " dans "
. $this->getFile() . " en ligne " . $this->getLine()
. "<br />";
}
}
?>

Ces sous-classes de Exception ne font rien de particulirement intressant. En fait,


pour le besoin de cette application, vous pourriez les conserver vides ou utiliser la
classe Exception fournie. Nous avons cependant fourni pour chacune des sous-classes
une mthode _ _toString() qui indique le type dexception survenu.
Nous avons galement rcrit le fichier processorder.php du Chapitre 2 afin dy inclure
lutilisation des exceptions. La nouvelle version est prsente dans le Listing 7.5.

Listing 7.5 : processorder.php Script de traitement des commandes du garage


de Bob incluant la gestion des exceptions

<?php

require_once("exceptions_fichiers.php");

// Cre des noms de variables abrges


$qte_pneus = $_POST[qte_pneus];
$qte_huiles = $_POST[qte_huiles];
$qte_bougies = $_POST[qte_bougies];
$adresse = $_POST[adresse];

$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob R&eacute;sultats de la commande</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>R&eacute;sultats de la commande</h2>
<?php
$date = date(H:i, \l\e j-m-Y);
echo <p>Commmande trait&eacute;e &agrave; ;
echo $date;
echo </p>;

echo <p>Rcapitulatif de votre commande:</p>;


212 Partie I Utilisation de PHP

$qte_totale = 0;
$qte_totale = $qte_pneus + $qte_huiles + $qte_bougies;
echo Articles command&eacute;s: . $qte_totale . <br />;

if( $qte_totale == 0)
{
echo "Vous navez rien command&eacute;!<br />";
}
else
{
if ( $qte_pneus > 0 )
echo $qte_pneus . pneus<br />;
if ( $qte_huiles > 0 )
echo $qte_huiles . " bidons dhuile<br />";
if ( $qte_bougies > 0 )
echo $qte_bougies . bougies<br />;
}

$montant_total = 0.00;

define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(PRIX_BOUGIES, 4);

$montant_total = $qte_pneus * PRIX_PNEUS


+ $qte_huiles * PRIX_HUILES
+ $qte_bougies * PRIX_BOUGIES;

$montant_total = number_format($montant_total, 2, ., );

echo <p>Total de la commande: . $montant_total . </p>;


echo <p>Adresse de livraison: . $adresse . </p>;

$chaine_sortie = "$date\t$qte_pneus pneus\t$qte_huiles bidons " .


"dhuile\t$qte_bougies bougies\t$montant_total \t" .
"$adresse\n";

// Ouverture du fichier en mode ajout


try {
if (!($fp = @fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab))) {
throw new ExceptionOuvertureFichier();
}
if (!flock($fp, LOCK_EX)) {
throw new ExceptionVerrouillageFichier();
}
if (!fwrite($fp, $chaine_sortie, strlen($chaine_sortie))) {
throw new ExceptionEcritureFichier();
}
flock($fp, LOCK_UN);
flclose($fp);
echo <p>Commande sauvegard&eacute;e.</p>;
}
catch (ExceptionOuvertureFichier $ex_of) {
echo "<p><strong>Impossible douvrir le fichier des commandes.
Contactez le webmaster pour plus de renseignements.</strong></p>";
}
Chapitre 7 Gestion des exceptions 213

catch (Exception $ex) {


echo "<p><strong>Nous ne pouvons pas traiter votre commande
pour le moment. Ressayez plus tard.</strong></p>";
}

?>
</body>
</html>

Comme vous pouvez le constater, la section des E/S de fichier de ce script est encapsu-
le dans un bloc try. En gnral, le bon usage en matire de programmation consiste
utiliser des blocs try de petite taille et capturer les exceptions appropries la fin de
chacun dentre eux. Le code de gestion des exceptions est ainsi plus facile crire et
maintenir car vous pouvez voir ce que vous grez.
Si vous ne pouvez pas ouvrir le fichier, vous levez une ExceptionOuvertureFichier;
si vous ne pouvez pas verrouiller le fichier, vous levez une ExceptionVerrouillage
Fichier; enfin, si vous ne pouvez pas crire dans le fichier, vous levez une Exception
EcritureFichier.
Examinez les blocs catch. des fins illustratives, nous nen utilisons que deux : lun
pour grer les ExceptionOuvertureFichier, lautre pour grer les Exception. Les
autres exceptions hritant de Exception, elles seront donc captures par le second bloc
catch. Les blocs catch sont mis en correspondance selon le mme principe que
loprateur instanceof. Il sagit dune bonne raison dtendre vos propres classes
dexception partir dune seule classe.
Attention : si vous levez une exception pour laquelle vous navez pas crit de bloc
catch correspondant, PHP signalera une erreur fatale !

Exceptions et autres mcanismes de gestion des erreurs en PHP


Outre le mcanisme de gestion des exceptions trait dans ce chapitre, PHP dispose dun
support de gestion des erreurs complexe, que nous tudierons au Chapitre 24. Le
processus de leve et de gestion des exceptions ninterfre pas avec ce mcanisme de
gestion des erreurs et ne lempche pas de fonctionner.
Dans le Listing 7.5, vous remarquerez que lappel fopen() est toujours prfix de
loprateur de suppression derreur @. Si cet appel choue, PHP met un avertissement
qui peut tre signal ou non, ou journalis ou non selon les rglages dfinis dans
php.ini. Ces paramtres sont traits en dtail dans le Chapitre 24, mais vous devez
savoir que cet avertissement sera toujours mis, indpendamment du fait que vous
leviez ou non une exception.
214 Partie I Utilisation de PHP

Lectures complmentaires
La gestion des exceptions tant rcente en PHP, il ny a que peu dcrits sur ce sujet. En
revanche, on trouve dabondantes informations sur la gestion des exceptions. Sun,
notamment, propose un excellent didacticiel qui explique ce que sont les exceptions et
les raisons qui pourraient vous amener les utiliser (dans loptique dune programma-
tion en Java, videmment). Ce didacticiel est disponible ladresse http://
java.sun.com/docs/books/tutorial/essential/exceptions/handling.html.

Prochaine tape
La prochaine tape de ce livre concerne MySQL. Nous montrerons comment crer et
remplir une base de donnes MySQ, puis nous mettrons en uvre ce que vous avez
appris sur PHP afin de pouvoir accder votre base de donnes depuis le Web.
II
Utilisation de MySQL

8 Conception dune base de donnes web


9 Cration dune base de donnes web
10 Travailler avec une base de donnes MySQL
11 Accs une base de donnes MySQL partir du Web
avec PHP
12 Administration MySQL avance
13 Programmation MySQL avance
8
Conception dune base
de donnes web

Maintenant que vous connaissez les lments essentiels de PHP, nous allons nous int-
resser lintgration dune base de donnes dans vos scripts. Au Chapitre 2, nous avons
prsent les avantages de lutilisation dune base de donnes relationnelle la place
dun fichier plat. Voici un rsum des atouts des SGBDR (systmes de base de donnes
relationnelles) :
m Ils permettent daccder aux donnes plus rapidement quavec des fichiers plats.
m On peut les interroger trs facilement pour rcuprer des ensembles de donnes
satisfaisant certains critres.
m Ils possdent des mcanismes intgrs permettant de grer les accs simultans,
pour que le programmeur, cest--dire vous-mme, nait pas besoin de sen
occuper.
m Ils permettent daccder directement aux donnes.
m Ils disposent dun systme de privilges intgr.
Concrtement, lutilisation dune base de donnes relationnelle permet de rpondre
rapidement et simplement des questions comme les suivantes : quelle est lorigine de
vos clients, quels sont les produits qui se vendent le mieux ou quelle catgorie de clients
dpense le plus dargent ? Ces informations pourront vous aider amliorer votre site
pour attirer un plus grand nombre dutilisateurs et les fidliser, et il serait bien plus diffi-
cile de les obtenir partir de fichiers plats.
218 Partie II Utilisation de MySQL

Dans cette partie du livre, nous utiliserons le SGBDR MySQL mais, avant dtudier ses
caractristiques spcifiques, nous devons prsenter :
m les concepts et la terminologie des bases de donnes relationnelles ;
m la conception dune base de donnes web ;
m larchitecture dune base de donnes web.
Voici un rsum des prochains chapitres :
m Le Chapitre 9 prsente la configuration de base dont vous aurez besoin pour connec-
ter votre base de donnes MySQL sur le Web. Vous apprendrez crer des utilisa-
teurs, des bases de donnes, des tables et des index. Vous dcouvrirez galement les
diffrents moteurs de stockage de MySQL.
m Le Chapitre 10 explique comment interroger la base de donnes, ajouter, supprimer
et modifier des enregistrements partir de la ligne de commande.
m Le Chapitre 11 explique comment connecter PHP et MySQL pour pouvoir adminis-
trer votre base de donnes partir dune interface web. Nous prsenterons deux
mthodes : lextension mysqli de PHP et la couche dabstraction PEAR:DB.
m Le Chapitre 12 couvre en dtail ladministration de MySQL, notamment le systme
des privilges, la scurit et loptimisation.
m Le Chapitre 13 dcrit les moteurs de stockage et traite notamment des transactions,
des recherches textuelles et des procdures stockes.

Concepts des bases de donnes relationnelles


Les bases de donnes relationnelles sont, de loin, les bases de donnes les plus utilises.
Elles font appel de solides bases thoriques en algbre relationnelle. Si vous navez
heureusement pas besoin de comprendre cette thorie relationnelle pour pouvoir utiliser
une base de donnes relationnelle, vous devez en revanche connatre quelques concepts
essentiels des bases de donnes.

Tables
Les bases de donnes relationnelles sont composes de relations, que lon appelle plus
couramment des tables. Une table est, comme son nom lindique, un ensemble de
donnes organises de faon tabulaire. Si vous avez dj utilis une feuille de calcul
dans un tableur, vous avez dj utilis une table.
la Figure 8.1, vous trouverez un exemple de table qui contient les noms et les adresses
des clients dune librairie, Book-O-Rama.
Chapitre 8 Conception dune base de donnes web 219

CLIENTS

IDClient Nom Adresse Ville

1 Julie Dupont 25 rue neuve Toulouse


2 Alain Wong 147 avenue Foch Paris
3 Michelle Arthur 19 rue blanche Bordeaux

Figure 8.1
Les informations concernant les clients de Book-O-Rama sont enregistres dans une table.

Cette table possde un nom (Clients), un certain nombre de colonnes (correspondant


chacune un type dinformation) et plusieurs lignes correspondant aux diffrents
clients.

Colonnes
Chaque colonne possde un nom unique et contient diffrentes donnes. En outre,
chaque colonne est associe un type de donnes particulier. Par exemple, dans la table
Clients de la Figure 8.1, vous pouvez constater que la colonne IDClient contient des
entiers, alors que les trois autres contiennent des chanes de caractres. Les colonnes
sont parfois appeles champs ou attributs.

Lignes
Chaque ligne de cette table reprsente un client particulier. Grce au format tabulaire,
toutes ces lignes possdent les mmes attributs. Les lignes peuvent galement tre
appeles enregistrements ou tuples.

Valeurs
Chaque ligne est forme dun ensemble de valeurs particulires correspondant chaque
colonne. Le type de chaque valeur doit correspondre au type de la colonne dans laquelle
elle se trouve.

Cls
Il nous faut ensuite un moyen didentifier chaque client. Gnralement, les noms des
clients ne sont pas trs adapts : si vous possdez un nom assez rpandu, vous avez
probablement dj compris pourquoi. Prenons, par exemple, le nom Julie Dupont dans
la table Clients. En ouvrant un annuaire tlphonique, on se rend aussitt compte quil
existe un grand nombre de personnes possdant ce nom.
220 Partie II Utilisation de MySQL

Nous pouvons identifier Julie de plusieurs manires. On peut supposer quil sagit de la
seule Julie Dupont habitant son adresse. Cependant, le fait de dsigner ce client par
"Julie Dupont, 25 rue neuve, Toulouse" est assez pnible et un peu trop administratif.
Cela implique galement dutiliser plusieurs colonnes dans la table.
Ici, nous avons choisi une approche que vous reprendrez probablement dans vos appli-
cations : nous utilisons un identificateur unique (IDClient) pour chaque client. Ce prin-
cipe est assez courant puisque vous possdez dj un numro de compte bancaire ou un
numro de scurit sociale qui sont uniques. Ces numros permettent denregistrer les
dtails qui vous concernent dans une base de donnes de faon plus efficace et plus
simple. De plus, ce numro tant artificiel et cr de toutes pices, nous pouvons garan-
tir quil sera unique. Dans la pratique, il existe peu dinformations qui possdent cette
proprit, mme si lon en utilise plusieurs conjointement.
La colonne didentification dune table est appele cl, ou cl primaire. Une cl peut
galement tre rpartie sur plusieurs colonnes. Si, par exemple, nous avions choisi
didentifier Julie par "Julie Dupont, 25 rue neuve, Toulouse", la cl serait forme des
colonnes Nom, Adresse et Ville ; dans ce cas, il serait impossible de garantir son
unicit.

CLIENTS

IDClient Nom Adresse Ville

1 Julie Dupont 25 rue neuve Toulouse


2 Alain Wong 147 avenue Foch Paris
3 Michelle Arthur 19 rue blanche Bordeaux

COMMANDES

IDCommande IDClient Montant Date

1 3 27.50 02 Avr 2007


2 1 12.99 15 Avr 2007
3 2 74.00 19 Avr 2007
4 3 6.99 01 Mai 2007

Figure 8.2
Chaque commande de la table Commandes fait rfrence un client dans la table Clients.
Chapitre 8 Conception dune base de donnes web 221

Les bases de donnes contiennent gnralement plusieurs tables et se servent des cls
comme dune rfrence dune table une autre. Dans la Figure 8.2, nous avons ajout
une seconde table dans la base de donnes, afin de stocker les commandes effectues
par les clients. Chaque ligne de la table Commandes reprsente une seule commande,
effectue par un seul client, identifi par son IDClient. Si, par exemple, nous exami-
nons la commande dont lIDCommande est 2, nous pouvons voir quelle a t effectue
par le client dont lIDClient est 1. Si nous nous reportons ensuite la table Clients,
nous pouvons constater que cet identifiant dsigne Julie Dupont.
Dans la terminologie des bases de donnes relationnelles, cette relation est appele une
cl trangre. IDClient est la cl primaire dans Clients mais, lorsquelle apparat dans
une autre table comme Commandes, elle devient une cl trangre dans cette table.
Vous vous demandez peut-tre pourquoi nous avons choisi davoir deux tables diffren-
tes et pourquoi nous ne nous sommes pas contents denregistrer ladresse de Julie dans
Commandes ? Nous expliquerons ce choix dans la prochaine section.

Schmas
Lensemble des structures des tables dune base de donnes est appel schma de la
base de donnes. Il sagit dune sorte de plan. Un schma doit reprsenter les tables
ainsi que leurs colonnes, la cl primaire de chaque table et toutes les cls trangres. Il
ne contient aucune donne, mais vous pouvez choisir de prsenter quelques donnes
typiques avec votre schma pour expliquer son fonctionnement. Un schma peut tre
reprsent par un diagramme informel comme celui des figures prcdentes, par un
diagramme entits-relations (que nous ne prsenterons pas dans ce livre) ou, plus
simplement, sous forme textuelle, comme ici :
Clients(IDClient, Nom, Adresse, Ville)
Commandes(IDCommande, IDClient, Montant, Date)

Les termes souligns dans ce schma sont les cls primaires de la relation dans laquelle
ils apparaissent, tandis que les termes en italique sont les cls trangres de la relation
dans laquelle ils apparaissent en italique.

Relations
Les cls trangres reprsentent une relation entre des donnes de deux tables. Par
exemple, le lien de la table Commandes vers la table Clients reprsente une relation
entre une ligne de Commandes et une ligne de Clients.
Il existe trois principaux types de relations dans une base de donnes relationnelle. Ces
relations peuvent tre classes en fonction du nombre dlments intervenant dans
chaque membre de la relation : un-vers-un, un-vers-plusieurs, ou plusieurs-vers-
plusieurs.
222 Partie II Utilisation de MySQL

Une relation un-vers-un signifie que la relation fait intervenir un seul lment de chaque
ct. Par exemple, si nous avions plac les adresses dans une autre table que Clients, il
existerait une relation un-vers-un entre elles. Vous pourriez alors avoir une cl trangre
de Addresses vers Clients ou dans lautre sens (cette rciprocit nest pas ncessaire).
Dans une relation un-vers-plusieurs, une ligne dune table est associe plusieurs
lignes dune autre table. Dans notre exemple, un client de la table Clients peut effec-
tuer plusieurs commandes, qui apparatront alors dans la table Commandes. Dans ce type
de relation, la table dont plusieurs lignes participent la relation possde une cl tran-
gre vers lautre table. Ici, nous avons plac IDClient dans la table Commandes pour
illustrer cette relation.
Dans une relation plusieurs-vers-plusieurs, plusieurs lignes dune table sont associes
plusieurs lignes dune autre table. Par exemple, si nous prenons lexemple de deux
tables, Livres et Auteurs, il se peut quun livre ait t crit par deux auteurs, chacun
dentre eux ayant crit dautres livres, soit indpendamment, soit avec dautres auteurs.
Ce type de relation est gnralement assez complexe, cest pourquoi il peut tre intres-
sant de possder les tables Livres, Auteurs et Livres Auteurs. Cette dernire table ne
contiendra que les cls des autres tables sous forme de cls trangres, afin de connatre
les auteurs associs chaque livre.

Conception dune base de donnes web


Dterminer quand vous avez besoin dune nouvelle table et choisir ses cls peut tre
considr comme un art. Vous trouverez dans dautres livres beaucoup dinformations
sur les diagrammes entits-relations et sur la normalisation des bases de donnes, qui
dpassent le cadre de cet ouvrage. Cependant, la plupart du temps, il suffit de respecter
quelques principes de conception assez simples. Nous allons les prsenter dans le
contexte de la librairie Book-O-Rama.

Penser aux objets rels que vous modlisez


Lorsque vous crez une base de donnes, vous modlisez gnralement des objets du
monde rel, les relations qui existent entre eux et vous enregistrez des informations sur
ces objets et ces relations.
Gnralement, chaque type dobjet rel que vous modlisez a besoin de sa propre table.
En effet, dans notre exemple, il faut enregistrer les mmes informations pour tous les
clients. Si un ensemble de donnes possde les mmes proprits, vous pouvez
commencer par crer une table correspondant ces donnes.
Dans lexemple de la librairie Book-O-Rama, nous devons enregistrer des informations
sur les clients, les livres vendre et les dtails de chaque commande. Tous les clients
Chapitre 8 Conception dune base de donnes web 223

possdent un nom et une adresse. Les commandes sont caractrises par une date, un
montant total et un ensemble de livres achets. Chaque livre possde un code ISBN,
un auteur, un titre et un prix.
Daprs ces caractristiques, nous pouvons crer au moins trois tables dans cette base
de donnes : Clients, Commandes et Livres. Ce schma initial est reprsent par la
Figure 8.3.

CLIENTS

IDClient Nom Adresse Ville

1 Julie Dupont 25 rue neuve Toulouse


2 Alain Wong 147 avenue Foch Paris
3 Michelle Arthur 19 rue blanche Bordeaux

COMMANDES

IDCommande IDClient Montant Date

1 3 27.50 02 Avr 2007


2 1 12.99 15 Avr 2007
3 2 74.00 19 Avr 2007
4 3 6.99 01 Mai 2007

LIVRES

ISBN Auteur Titre Prix

0 672 31697 8 Michael Morgan Java 2 for Professional Developers 34.99


0 672 31745 1 Thomas Down Installing GNU/Linux 24.99
0 672 31509 2 Pruitt.et al. Teach Yourself GIMP in 24 Hours 24.99

Figure 8.3
Le schma initial contient les tables Clients, Commandes et Livres.

Pour linstant, il est impossible de deviner, partir du modle, les livres qui correspondent
chaque commande. Nous allons nous en occuper maintenant.
224 Partie II Utilisation de MySQL

viter denregistrer des informations redondantes


Plus haut, nous nous sommes demand pourquoi ne pas enregistrer ladresse de Julie
Smith dans la table Commandes.
Si Julie achte plusieurs livres chez Book-O-Rama, cela reviendrait enregistrer
plusieurs fois les informations qui la concernent. Au cours du temps, la table Commandes
pourrait alors ressembler celui de la Figure 8.4.

IDCommande Montant Date IDClient Nom Adresse Ville

12 199.50 25 Avr 2007 1 Julie Dupont 25 rue neuve Toulouse


13 43.00 29 Avr 2007 1 Julie Dupont 25 rue neuve Toulouse
14 15.99 30 Avr 2007 1 Julie Dupont 25 rue neuve Toulouse
15 23.75 01 Mai 2007 1 Julie Dupont 25 rue neuve Toulouse

Figure 8.4
Une conception de base de donnes qui enregistre des informations redondantes gaspille
de lespace disque et peut entraner des anomalies dans les donnes.

Cette conception pose essentiellement deux problmes.


m Elle gaspille de lespace. Pourquoi enregistrer trois fois les donnes concernant
Julie, alors quil suffit de ne les enregistrer quune seule fois ?
m Cette approche peut entraner des anomalies dans les mises jour des informations,
cest--dire des situations dans lesquelles certaines informations de la base de
donnes sont modifies avec, pour consquence, une base de donnes dans un tat
incohrent. Lintgrit des donnes est viole et il est alors impossible de distinguer
les donnes correctes des donnes incorrectes. Cette situation implique gnralement
des pertes dinformations.
Il convient dviter trois types danomalies : les anomalies de modifications, dinsertions
et de suppressions.
m Si Julie dmnage pendant quelle a une commande en cours, il faut mettre jour
son adresse trois endroits au lieu dun seul, ce qui reprsente trois fois plus de
travail. Il est assez facile doublier cette tche et de ne changer son adresse qu un
seul endroit, ce qui entranera des incohrences dans la base de donnes (une
situation quil faut viter tout prix). Ce type de problme est appel anomalie de
modification, puisquil a lieu pendant une modification de la base de donnes.
m Nous devons saisir les dtails concernant Julie chaque fois quelle effectue
une commande et vrifier que ces dtails sont cohrents avec les donnes exis-
tant dj dans la table. Si nous omettons cette vrification, il se peut que nous
Chapitre 8 Conception dune base de donnes web 225

nous retrouvions avec deux lignes contenant des informations diffrentes sur
Julie. Par exemple, lune de ces lignes peut indiquer que Julie habite Toulouse
et une autre, quelle habite Blagnac. Ce type derreur est appel anomalie
dinsertion, puisquelle a lieu lorsque de nouvelles donnes sont insres dans
les tables.
m Le troisime type danomalie est appel anomalie de suppression, puisque ces
anomalies surviennent lorsque des donnes sont supprimes de la base de donnes.
Par exemple, imaginons que lorsquune commande est termine nous la supprimons
de la base de donnes. Lorsque toutes les commandes de Julie ont t traites, elles
sont toutes supprimes du tableau Commandes. Cela signifie donc que ladresse de
Julie nexiste plus dans notre base de donnes. Il est alors impossible de lui envoyer
des publicits et, la prochaine fois quelle souhaitera passer une commande, il
faudra rassembler nouveau toutes les informations qui la concernent.
Les bases de donnes sont normalement conues pour quaucune de ces anomalies ne
puisse avoir lieu.

Utiliser des valeurs de colonne atomiques


Utiliser des valeurs de colonne atomiques signifie que, dans chaque attribut de chaque
ligne, vous ne stockez quun seul lment. Par exemple, si nous devons connatre tous
les livres associs chaque commande, il existe plusieurs approches diffrentes.
Nous pouvons ajouter une colonne dans la table Commandes qui fournira la liste de tous
les livres commands (voir la Figure 8.5).

COMMANDES
IDCommande IDClient Montant Date Livres Commandes

1 3 27.50 02 Avr 2007 0 672 31697 8


2 1 12.99 15 Avr 2007 0 672 31745 1. 0 672 31509 2
3 2 74.00 19 Avr 2007 0 672 31697 8
4 3 6.99 01 Mai 2007 0 672 31745 1. 0 672 31509 2. 0 672 31697 8

Figure 8.5
Avec cette architecture, lattribut Livres commands de chaque ligne contient plusieurs valeurs.

Cette organisation nest pas trs judicieuse pour plusieurs raisons. Elle revient imbri-
quer une table complte dans une colonne, une table qui associe les commandes aux
livres. Il est alors plus difficile de rpondre des questions comme : "Combien dexem-
plaires du livre Java 2 pour les professionnels ont t commands ?" Le systme ne
peut plus se contenter de compter les champs qui correspondent cette requte ; il doit
226 Partie II Utilisation de MySQL

analyser la valeur de chaque attribut pour vrifier si elle contient la chane de caractres
recherche.
Au lieu dinsrer une table lintrieur dune autre table, il suffit en fait de crer un
nouvelle table, Livres Commandes, comme celle de la Figure 8.6.

Figure 8.6 LIVRES COMMANDES


Cette architecture
simplifie la recherche IDCommande ISBN Quantit
des livres qui ont t
1 0 672 31697 8 1
commands.
2 0 672 31745 1 2
2 0 672 31509 2 1
3 0 672 31697 8 1
4 0 672 31745 1 1
4 0 672 31509 2 2
4 0 672 31697 8 1

Cette table permet de crer une association entre la table Commandes et la table Livres.
Ce type de table est assez rpandu lorsquil existe une relation plusieurs-vers-plusieurs
entre deux objets comme ici : une commande peut concerner plusieurs livres et un livre
peut tre command par plusieurs personnes.

Choisir des cls pertinentes


Assurez-vous que les cls que vous choisissez sont uniques. Dans notre cas, nous avons
cr des cls spciales pour les clients (IDClient) et pour les commandes (IDCommande)
puisque ces objets du monde rel ne possdent pas ncessairement un identificateur
unique. En revanche, nous navons pas besoin de crer un identificateur unique pour les
livres puisquil en existe dj un : le numro ISBN. Pour la table Livre Commandes,
vous pourriez ajouter une cl supplmentaire, mais la combinaison des deux attributs
IDCommande et ISBN est unique tant que plusieurs exemplaires dun mme livre dans la
mme commande sont traits sur une seule ligne. Cest pour cela que Livre Commandes
possde une colonne Quantite.

Penser aux questions que vous poserez votre base de donnes


Il est essentiel de connatre les questions auxquelles la base de donnes doit pouvoir
rpondre ("Quelles sont les meilleures ventes ?", par exemple). Assurez-vous que votre
base contient toutes les donnes ncessaires et que les liens appropris existent entre les
diffrentes tables pour rpondre correctement vos questions.
Chapitre 8 Conception dune base de donnes web 227

viter les architectures ayant beaucoup dattributs vides


Si nous souhaitons ajouter des commentaires aux livres de la base de donnes, nous
pouvons choisir entre deux approches diffrentes, prsentes la Figure 8.7.

LIVRES

ISBN Auteur Titre Prix Commentaire

0 672 31697 8 Michael Morgan Java 2 for Professional Developers 34.99


0 672 31745 1 Thomas Down Installing GNU/Linux 24.99
0 672 31509 2 Pruitt.et al. Teach Yourself GIMP in 24 Hours 24.99

COMMENTAIRES LIVRES

ISBN Commentaire

Figure 8.7
Pour fournir des commentaires, nous pouvons ajouter une colonne Commentaire dans la table
Livres ou ajouter une autre table, consacre aux commentaires.

La premire mthode consiste ajouter une colonne Commentaire dans la table Livres.
De cette manire, il existe un champ Commentaire pour chaque livre. Si la base de
donnes contient beaucoup de livres, et si la personne qui rdige les commentaires na
pas lintention de le faire pour chaque livre, il se peut que plusieurs lignes ne possdent
aucune valeur associe cet attribut. On parle dans ce cas de valeurs null.
La prsence de nombreuses valeurs null dans une base de donnes doit tre vite car
elles gaspillent lespace de stockage et peuvent entraner divers problmes lorsque vous
calculez des totaux ou dautres fonctions sur des colonnes numriques. En outre,
lorsquun utilisateur voit une valeur null dans une table, il ne peut pas savoir si la valeur
de cet attribut na aucune signification, sil sagit dune erreur dans la base de donnes
ou sil sagit dune donne qui na pas encore t saisie.
Vous pouvez viter tous ces problmes en utilisant la seconde architecture prsente
la Figure 8.7. Dans cette organisation, seuls les livres qui possdent un commentaire
apparaissent dans la table Commentaires Livres, accompagns de leur commentaire.
Vous remarquerez que la premire architecture implique quil ne peut y avoir quun
commentaire par livre. Si vous souhaitiez pouvoir ajouter plusieurs commentaires pour
le mme livre, il faut utiliser une relation un--plusieurs que seule la seconde architec-
ture est capable de vous apporter. Cette dernire permet galement de reprsenter une
228 Partie II Utilisation de MySQL

relation un-vers-un puisquil suffit dutiliser lISBN comme cl primaire dans la table
Commentaires Livres. Pour reprsenter une relation un--plusieurs, vous devez en
revanche dfinir un identificateur unique pour chaque ligne de cette table.

Rcapitulatif sur les types de tables


Les bases de donnes sont gnralement composes de deux types de tables :
m Des tables simples qui dcrivent des objets du monde rel. Ces tables peuvent gale-
ment contenir des cls vers dautres objets simples, pour lesquels il existe une relation
un-vers-un ou un-vers-plusieurs. Un client peut, par exemple, passer plusieurs
commandes, mais chaque commande est effectue par un seul client. Par cons-
quent, nous pouvons placer dans chaque commande une rfrence au client qui a
effectu cette commande.
m Des tables de liaison qui dcrivent des relations plusieurs-vers-plusieurs entre deux
objets rels, comme la relation qui existe entre Commandes et Livres. Ces tables sont
souvent associes des transactions du monde rel.

Architecture dune base de donnes web


Maintenant que nous avons prsent larchitecture interne dune base de donnes, nous
pouvons nous intresser larchitecture externe des systmes de bases de donnes web
et prsenter la mthodologie permettant de dvelopper ces systmes.

Architecture
Le fonctionnement fondamental dun serveur web est prsent la Figure 8.8. Ce
systme est compos de deux objets : un navigateur web et un serveur web. Un lien
de communication doit exister entre ces deux objets. Le navigateur effectue des
requtes auprs du serveur, qui lui renvoie des rponses. Cette architecture est parfai-
tement adapte un serveur qui fournit des pages statiques, mais celle qui permet de
mettre en place des sites web faisant intervenir des bases de donnes est un peu plus
complexe.

Requte
Navigateur Serveur web
Rponse

Figure 8.8
La relation client/serveur entre un navigateur web et un serveur web ncessite un lien
de communication.
Chapitre 8 Conception dune base de donnes web 229

Les applications de bases de donnes web que nous allons mettre en uvre dans ce livre
respectent une structure de base de donnes web gnrale, prsente la Figure 8.9.
Lessentiel de cette structure devrait dj vous sembler familier.

1 2 3
Navigateur Serveur web Moteur PHP Serveur MySQL

6 5 4

Figure 8.9
Larchitecture fondamentale des bases de donnes web est compose dun navigateur web,
dun serveur web, dun moteur de scripts et dun serveur de bases de donnes.

Une transaction de base de donnes web classique est compose des tapes numrotes
la Figure 8.9. Examinons ces tapes dans le contexte de la librairie Book-O-Rama.
1. Le navigateur web dun utilisateur envoie une requte HTTP pour une page web
particulire. Cette requte peut, par exemple, concerner tous les livres de Book-O-
Rama crits par Laura Thomson et tre envoye partir dun formulaire HTML. La
page de recherche des rsultats est appele resultats.php.
2. Le serveur web reoit une requte pour resultats.php, rcupre le fichier et le passe
au moteur PHP afin quil soit trait.
3. Le moteur PHP commence analyser le script. Dans celui-ci se trouve une commande
permettant de se connecter la base de donnes et dexcuter une requte (pour
rechercher les livres). PHP ouvre une connexion vers le serveur MySQL et transmet
la requte approprie.
4. Le serveur MySQL reoit la requte de base de donnes et la traite, puis renvoie les
rsultats (cest--dire une liste de livres) au moteur PHP.
5. Le moteur PHP termine lexcution du script, ce qui consiste gnralement forma-
ter les rsultats de la requte en HTML. Il envoie ensuite le fichier HTML obtenu au
serveur web.
6. Le serveur web transmet la page HTML au navigateur, pour que lutilisateur puisse
voir la liste des livres quil a demands.
Ce processus reste relativement identique, quels que soient le moteur de scripts et le serveur
de bases de donnes que vous utilisez. Le plus souvent, le serveur web, le moteur PHP
et le serveur de bases de donnes tournent tous sur le mme ordinateur. Cependant, il
arrive que le serveur de bases de donnes se trouve sur un autre ordinateur. Cette
dernire approche rpond des problmes de scurit, daugmentation des capacits
et de rpartition de la charge. Au niveau du dveloppement, cela ne change pas
230 Partie II Utilisation de MySQL

grand-chose, bien que cette approche fournisse des avantages significatifs en terme de
performances.
mesure quaugmenteront la taille et la complexit de vos applications, vous commen-
cerez les diviser en niveaux, ou couches. Cest ce que lon appelle une architecture
trois tiers car lapplication est alors forme dune couche de base de donnes qui se
charge de linterfaage avec MySQL, dune couche mtier qui contient le systme
central de lapplication et dune couche de prsentation qui gre la sortie HTML.
Larchitecture lmentaire prsente la Figure 8.9 vaut cependant toujours : vous
ajoutez simplement dautres lments de structure la section PHP.

Pour aller plus loin


Dans ce chapitre, nous avons prsent quelques conseils gnraux pour larchitecture
des bases de donnes relationnelles. Si vous souhaitez vous attaquer plus profondment
la thorie des SGBR, vous pouvez consulter plusieurs livres crits par des auteurs
faisant rfrence en la matire, comme C. J. Date. Cependant, vous devez savoir que ces
livres sont trs thoriques et nont pas ncessairement dintrt immdiat pour un dve-
loppeur web. Gnralement, les bases de donnes web classiques ne sont pas trs
compliques.

Pour la suite
Au prochain chapitre, nous nous intresserons la construction dune base de donnes
MySQL. Nous commencerons par voir comment configurer une base de donnes MySQL
pour le Web, comment effectuer des requtes dans cette base de donnes et comment
linterroger partir de PHP.
9
Cration dune base
de donnes web

Dans ce chapitre, nous verrons comment configurer une base de donnes MySQL pour
pouvoir lutiliser sur un site web.
Nous reprendrons lexemple de la librairie virtuelle Book-O-Rama, prsente au chapi-
tre prcdent et dont nous rappelons ici le schma :
Clients(IDClient, Nom, Adresse, Ville)
Commandes(IDCommande, IDClient, Montant, Date)
Livres(ISBN, Auteur, Titre, Prix)
Livres_Commandes(IDCommande, ISBN, Quantite)
Commentaires_Livres(ISBN, Commentaire)

Noubliez pas que les cls primaires sont soulignes et que les cls trangres sont en
italique.
Pour pouvoir tirer profit des lments de cette section, vous devez avoir accs
MySQL. Cela signifie normalement que :
1. Vous avez effectu linstallation de base de MySQL sur votre serveur web. Pour
cela, il faut notamment :
installer les fichiers ;
crer un utilisateur sous le nom duquel MySQL sera excut ;
configurer votre chemin daccs ;
excuter mysql install db, si ncessaire ;
dfinir le mot de passe root de MySQL ;
supprimer lutilisateur anonymous et la base de donnes test ;
dmarrer le serveur MySQL pour la premire fois et le configurer pour quil se lance
automatiquement.
232 Partie II Utilisation de MySQL

Si vous avez bien fait tout cela, vous pouvez commencer lire ce chapitre. Dans le
cas contraire, vous trouverez lAnnexe A des instructions qui vous aideront.
Si, nimporte quel moment dans ce chapitre, vous avez des problmes, ce peut tre
d la configuration de votre systme MySQL. Dans ce cas, vrifiez nouveau
cette liste et consultez lAnnexe A pour vous assurer que votre configuration est
correcte.
2. Vous devriez galement avoir accs MySQL sur un ordinateur dont vous ntes
pas ladministrateur, comme un service dhbergement web, un ordinateur de votre
socit, etc.
Dans ce cas, pour que vous puissiez utiliser les exemples ou crer votre propre base
de donnes, votre administrateur doit configurer un utilisateur et une base de
donnes et vous fournir le nom dutilisateur, le mot de passe et le nom de la base de
donnes quil vous a affects.
Vous pouvez choisir de sauter les sections de ce chapitre qui expliquent comment
configurer les utilisateurs et les bases de donnes, ou les lire pour expliquer plus
prcisment votre administrateur ce dont vous avez besoin. En tant quutilisateur
normal, vous navez pas le droit dexcuter les commandes permettant de crer des
utilisateurs et des bases de donnes.
Tous les exemples de ce chapitre ont t dvelopps et tests avec la dernire version de
MySQL 5. Certaines versions antrieures de MySQL possdent moins de fonctionnali-
ts : il est donc prfrable dinstaller la version stable la plus rcente lorsque vous confi-
gurez votre systme. Vous pouvez charger la dernire version sur le site de MySQL,
http://mysql.com.
Dans ce livre, nous interagirons avec MySQL au moyen dun client en ligne de
commande, le moniteur MySQL fourni avec chaque installation de MySQL, mais vous
pouvez utiliser dautres clients. Par exemple, si vous utilisez MySQL dans un environ-
nement web, les administrateurs systme proposent souvent linterface phpMyAdmin
que vous pouvez utiliser dans votre navigateur. Les diffrents clients graphiques propo-
sent videmment des procdures lgrement diffrentes de celles dcrites ici, mais vous
devriez pouvoir adapter les instructions fournies assez facilement.

Note sur lutilisation du moniteur MySQL


Dans les exemples MySQL de ce chapitre et du chapitre suivant, vous remarquerez
que toutes les commandes se terminent par un point-virgule ( ;). Celui-ci demande
MySQL dexcuter les commandes. Si vous oubliez ce point-virgule, il ne se
Chapitre 9 Cration dune base de donnes web 233

passera rien du tout. Il sagit dun problme trs frquent chez les nouveaux utilisa-
teurs.
Cela signifie galement que vous pouvez insrer des retours la ligne au milieu dune
commande. Nous nous sommes dailleurs servis de cette caractristique pour amliorer
la lisibilit de nos exemples. Cette situation se remarque facilement puisque MySQL
affiche un symbole indiquant quil attend la suite de la commande. Il sagit dune petite
flche qui ressemble ceci :
mysql> grant select
->

Vous obtiendrez cette invite jusqu ce que vous saisissiez un point-virgule, chaque
fois que vous appuyez sur la touche Entre.
Un autre point important est que les instructions SQL ne tiennent pas compte de la
diffrence majuscules/minuscules, mais ce nest pas forcment le cas pour les noms des
bases de donnes et des tables. Nous reviendrons sur ce point un peu plus loin.

Comment ouvrir une session MySQL


Pour dmarrer une session MySQL, lancez un interprteur de commandes sur votre
ordinateur et saisissez la ligne suivante :
> mysql -h hte -u utilisateur -p

La commande mysql lance le moniteur MySQL. Il sagit dun client en ligne de


commande qui vous connecte au serveur MySQL.
Loption h sert indiquer lhte auquel vous souhaitez vous connecter, cest--dire
lordinateur sur lequel le serveur MySQL sexcute. Si vous lancez cette commande sur
le mme ordinateur que le serveur MySQL, vous pouvez ignorer cette option, ainsi que
le paramtre hte. Dans le cas contraire, il faut remplacer le paramtre hte par le nom
de lordinateur sur lequel le serveur MySQL sexcute.
Loption u sert indiquer le nom de lutilisateur sous lequel vous souhaitez vous
connecter. Si vous nen spcifiez aucun, le client choisira par dfaut le nom de lutili-
sateur sous lequel vous avez ouvert une session dans le systme dexploitation.
Si vous avez install MySQL sur votre propre ordinateur ou sur votre serveur, vous
devez ouvrir une session sous le compte root et crer la base de donnes que nous utili-
serons dans cette section. Si vous venez dinstaller MySQL, root est le seul utilisateur
qui existe et vous devez donc vous connecter sous son compte. Si vous utilisez MySQL
sur un ordinateur administr par quelquun dautre, servez-vous du nom dutilisateur
que lon vous a fourni.
234 Partie II Utilisation de MySQL

Loption p indique au serveur que vous souhaitez vous connecter en utilisant un mot de
passe. Vous navez pas besoin de la spcifier si aucun mot de passe na t dfini pour
lutilisateur sous lequel vous voulez ouvrir une session.
Si vous avez ouvert votre session sous le nom root et quaucun mot de passe na t
dfini pour root, nous vous recommandons fortement de consulter sans tarder
lAnnexe A et de le dfinir tout de suite. Sans mot de passe root, votre systme nest
pas du tout scuris.
Vous navez pas besoin de donner le mot de passe sur cette ligne, puisque le serveur
MySQL vous le demandera. En fait, il vaut mieux ne pas le donner car, si vous le saisis-
sez sur la ligne de commande, il apparatra clairement lcran et pourra donc tre
intercept trs facilement.
Aprs avoir saisi la commande prcdente, vous devriez obtenir une rponse comme
celle-ci :
Enter password:

Si vous nobtenez pas cette ligne, vrifiez que le serveur MySQL fonctionne correcte-
ment et que la commande mysql se trouve dans votre PATH.
Il faut ensuite saisir votre mot de passe. Si tout se passe bien, vous devriez ensuite obte-
nir une rponse ressemblant ceci :
Welcome to the MySQL monitor. Commands end with; or \g.
Your MySQL connection id is 1 to server version: 5.0.0-alpha-max-debug

Type help; or \h for help. Type \c to clear the buffer.

mysql>

Si vous nobtenez pas une rponse similaire avec une installation sur votre propre
machine, assurez-vous que vous avez bien excut mysql install db, que vous avez
dfini le mot de passe root et que vous lavez saisi correctement. Si vous ntes pas
responsable de linstallation de MySQL, assurez-vous que vous avez saisi le mot de
passe correctement.
Vous devriez maintenant obtenir linvite de commande de MySQL et tre prt crer la
base de donnes.
Si vous utilisez votre propre ordinateur, suivez les indications de la section suivante.
Si vous utilisez lordinateur de quelquun dautre, la base de donnes devrait dj tre
cre. Vous pouvez alors passer directement la section "Utiliser la bonne base de
donnes" ou lire les sections qui suivent titre dinformations gnrales, mais vous ne
serez pas capable dexcuter les commandes indiques dans ces sections ou, tout du
moins, vous ne devriez pas tre autoris le faire !
Chapitre 9 Cration dune base de donnes web 235

Cration des bases de donnes et des utilisateurs


Le systme de base de donnes MySQL peut grer de nombreuses bases de donnes.
Gnralement, il existe une base de donnes par application. Dans notre exemple de la
librairie Book-O-Rama, la base de donnes sappellera livres.
La cration de la base de donnes est la partie la plus simple. Sur la ligne de commande
de MySQL, saisissez la commande suivante :
mysql> create database livres;
Cest tout. Vous devriez obtenir une rponse comme celle-ci (au temps dexcution prs) :
Query OK, 1 row affected (0.06 sec)
Cette rponse signifie que tout sest bien pass. Si vous obtenez une autre rponse,
assurez-vous que vous navez pas oubli de saisir le point-virgule la fin de la ligne. Un
point-virgule indique MySQL que vous avez termin de saisir votre commande et
quil doit lexcuter.

Configuration des utilisateurs et des privilges


Un systme MySQL peut compter plusieurs utilisateurs. Pour des raisons de scurit,
lutilisateur root ne devrait servir quaux tches dadministration. Vous devez dfinir
un nom et un mot de passe pour chaque utilisateur devant avoir accs MySQL. Ces
noms dutilisateurs ne correspondent pas forcment aux noms dutilisateurs ou aux
mots de passe existant en dehors de MySQL (les noms dutilisateurs et les mots de
passe Unix ou Windows, par exemple). Ce principe est galement valable pour le
compte root. Il est gnralement conseill de choisir un mot de passe diffrent pour les
comptes du systme et pour les comptes de MySQL, en particulier pour le compte root.
Bien quil ne soit pas obligatoire de crer des mots de passe pour les utilisateurs, nous
vous conseillons fortement de choisir un mot de passe pour tous les utilisateurs que
vous crez. Dans le cadre de la configuration dune base de donnes web, il est gnra-
lement intressant de crer au moins un utilisateur par application web. Vous pouvez
vous demander pourquoi ; la rponse se trouve dans les privilges.

Introduction au systme de privilges de MySQL


Lune des caractristiques les plus intressantes de MySQL est quil dispose dun
systme de privilges volu. Un privilge est le droit deffectuer une action particu-
lire sur un objet spcifique, sous un compte utilisateur donn. Ce concept ressemble
beaucoup aux droits daccs des fichiers.
Lorsque vous crez un utilisateur dans MySQL, vous lui accordez un ensemble de
privilges pour indiquer ce quil peut faire et ne peut pas faire dans le systme.
236 Partie II Utilisation de MySQL

Principe des privilges minimaux


Ce principe permet damliorer la scurit de nimporte quel systme informatique. Il
sagit dun principe la fois trs simple et trs important, que lon oublie un peu trop
souvent et qui peut se rsumer de la manire suivante :
Un utilisateur (ou un processus) doit possder le niveau de privilge le plus bas
possible pour pouvoir effectuer correctement sa tche.
Ce principe sapplique galement MySQL. Pour, par exemple, excuter des requtes
partir du Web, un utilisateur na pas besoin de possder tous les privilges auxquels
root a accs. Il convient par consquent de crer un autre utilisateur qui possde
uniquement les privilges ncessaires pour accder la base de donnes que vous venez
de crer.

Configuration des utilisateurs : la commande GRANT


Les commandes GRANT et REVOKE servent accorder ou retirer des droits daccs aux
utilisateurs de MySQL, selon quatre niveaux de privilges :

m global ;

m base de donnes ;

m table ;

m colonne.

Nous verrons bientt comment les utiliser.

La commande GRANT cre des utilisateurs et leur octroie des privilges. Voici son format
gnral :
GRANT privilges [colonnes]
ON lment
TO nom_utilisateur [IDENTIFIED BY mot de passe]
[REQUIRE options ssl]
[WITH GRANT OPTION | limites ] ]

Les clauses entre crochets sont facultatives. Cette syntaxe comprend plusieurs paramtres
en italique que nous allons passer en revue.
Le premier, privilges, est une liste de privilges spars par des virgules. Ces privi-
lges doivent tre choisis dans une liste prdfinie de MySQL, que nous prsenterons
dans la prochaine section.
Chapitre 9 Cration dune base de donnes web 237

Le paramtre colonnes est facultatif. Vous pouvez lutiliser pour prciser les privilges
associs certaines colonnes. Il peut correspondre au nom dune seule colonne ou une
liste de noms de colonnes spars par des virgules.

Le paramtre lment correspond la base de donnes ou la table laquelle sappli-


quent les privilges.

Vous pouvez octroyer des privilges sur toutes les bases de donnes en indiquant *.* la
place de lment. On accorde alors des privilges globaux. Vous pouvez aussi indiquer * si
vous nutilisez aucune base de donnes particulire.

Le plus souvent, vous dsignerez toutes les tables dune base de donnes avec
nom base.*, une table particulire avec nom base.nom table, ou des colonnes spcifi-
ques avec nom base.nom table et les colonnes en question la place de colonnes. Ces
trois approches reprsentent respectivement les trois autres niveaux de privilges dispo-
nibles : sur une base de donnes, une table et une colonne. Si vous utilisez une base de
donnes spcifique lorsque vous excutez cette commande, nom table sera interprt
comme une table de la base de donnes courante.

nom utilisateur doit correspondre au nom de lutilisateur sous lequel vous souhai-
tez ouvrir une session dans MySQL. Noubliez pas que ce nom ne doit pas forcment
correspondre votre nom dutilisateur sur votre systme dexploitation. Avec
MySQL, nom utilisateur peut galement correspondre un nom dhte. Vous
pouvez utiliser cette particularit pour diffrencier, par exemple, laura (qui sera
interprt comme laura@localhost) et laura@autre part.com. Cette particularit
est trs intressante puisquil arrive souvent que des utilisateurs de diffrents domai-
nes aient le mme nom en local. En outre, cette caractristique amliore la scurit du
systme, puisque vous pouvez spcifier lendroit partir duquel les utilisateurs se
connectent, et mme les tables et les bases de donnes auxquelles ils ont accs partir
dun emplacement particulier.

mot de passe dsigne le mot de passe que vous avez choisi pour lutilisateur indiqu.
Les rgles gnrales pour choisir les mots de passe doivent toujours tre respectes.
Nous reviendrons un peu plus loin sur les problmes de scurit, mais, dune manire
gnrale, un mot de passe ne doit pas pouvoir tre devin facilement. Cela signifie quil
ne doit figurer dans aucun dictionnaire et quil doit tre diffrent du nom de lutilisa-
teur. Idalement, il doit contenir des lettres majuscules, des lettres minuscules et des
caractres non alphabtiques.

La clause REQUIRE vous permet de prciser que lutilisateur doit se connecter via SSL
(Secure Sockets Layer) et dindiquer dautres options SSL. Pour plus dinformations
238 Partie II Utilisation de MySQL

concernant les connexions SSL MySQL, reportez-vous au manuel MySQL. Loption


WITH GRANT OPTION, lorsquelle est indique, permet lutilisateur slectionn de
transmettre ses privilges dautres utilisateurs.

la place de WITH GRANT OPTION, vous pouvez galement utiliser les limites suivantes :
MAX_QUERIES_PER_HOUR n

ou
MAX_UPDATES_PER_HOUR n

ou
MAX_CONNECTIONS_PER_HOUR n

Ces clauses vous permettent de limiter le nombre de requtes, de mises jour ou de


connexions par heure quun utilisateur est autoris effectuer. Elles peuvent tre
utiles lorsquil importe de limiter la charge des utilisateurs individuels sur des systmes
partags.
Les privilges sont enregistrs dans cinq tables systme appartenant la base de
donnes mysql. Ces cinq tables sappellent mysql.user, mysql.db, mysql.host,
mysql.tables priv et mysql.columns priv et correspondent directement aux
niveaux de privilges que nous avons dj mentionns. Si vous ne souhaitez pas
passer par GRANT, vous pouvez modifier directement ces tables. Nous y reviendrons
en dtail au Chapitre 12.

Types et niveaux des privilges


Il existe trois principaux types de privilges dans MySQL : les privilges des utilisa-
teurs classiques, les privilges des administrateurs et deux privilges particuliers.
Nimporte quel utilisateur peut obtenir ces privilges, mais il est gnralement prfra-
ble de rserver les privilges dadministration aux administrateurs, conformment au
principe des privilges minimaux.
Les privilges ne devraient tre octroys aux utilisateurs que pour les bases de
donnes et les tables quils ont besoin dutiliser. La base de donnes mysql ne doit
tre accessible quaux administrateurs car elle stocke les informations sur les utilisa-
teurs, les mots de passe, etc. (nous reviendrons sur cette base de donnes au Chapi-
tre 12).
Les privilges des utilisateurs normaux sont directement associs des types spcifi-
ques de commandes SQL et indiquent si un utilisateur a le droit dexcuter ces
commandes. Nous reviendrons sur ces commandes SQL au chapitre suivant. Pour
linstant, nous tudierons une description conceptuelle de leurs actions. Les privilges
Chapitre 9 Cration dune base de donnes web 239

dun utilisateur normal sont prsents dans le Tableau 9.1. La deuxime colonne indique
les objets auxquels chaque privilge peut tre appliqu.

Tableau 9.1 : Privilges des utilisateurs normaux

Privilge Applicable Description


SELECT Tables, colonnes Permet aux utilisateurs de slectionner des lignes (des
enregistrements) dans des tables.
INSERT Tables, colonnes Permet aux utilisateurs dinsrer de nouvelles lignes dans des
tables.
UPDATE Tables, colonnes Permet aux utilisateurs de modifier les valeurs existantes dans
les lignes des tables.
DELETE Tables Permet aux utilisateurs de supprimer des lignes existantes dans
des tables.
INDEX Tables Permet aux utilisateurs de crer et de supprimer des index dans
des tables.
ALTER Tables Permet aux utilisateurs de modifier la structure de tables
existantes, par exemple en ajoutant des colonnes, en renommant
des colonnes ou des tables ou en modifiant le type des donnes
de certaines colonnes.
CREATE Bases de donnes, Permet aux utilisateurs de crer de nouvelles bases de donnes
tables ou de nouvelles tables. Si une table ou une base de donnes
particulires sont indiques dans la commande GRANT, le
privilge CREATE est limit la base de donnes ou la table
indique, ce qui signifie quil faudra au pralable la supprimer
(avec DROP).
DROP Bases de donnes, Permet aux utilisateurs de supprimer des bases de donnes ou
tables des tables.

La plupart des privilges des utilisateurs normaux sont relativement inoffensifs en


termes de scurit. Le privilge ALTER peut permettre de contourner les privilges
systme en renommant des tables, mais les utilisateurs en ont souvent besoin. La scu-
rit est toujours un compromis entre la sret et la simplicit dutilisation. Vous devrez
donc prendre vos propres dcisions quant ALTER, mais il faut savoir que ce privilge
est souvent accord aux utilisateurs normaux.
Outre ceux du Tableau 9.1, les privilges appels REFERENCES et EXECUTE existent mais
ne sont pas encore utiliss et le privilge GRANT nest octroy que par la clause WITH
GRANT OPTION ; il ne peut pas apparatre dans la liste privilges.
240 Partie II Utilisation de MySQL

Le Tableau 9.2 prsente les privilges rservs aux administrateurs.

Tableau 9.2 : Privilges des administrateurs

Privilge Description
CREATE TEMPORARY TABLES Permet un administrateur dutiliser le mot-cl TEMPORARY
dans une instruction CREATE TABLE.
FILE Autorise les donnes tre lues dans des tables depuis des
fichiers et vice versa.
LOCK TABLES Autorise lutilisation explicite dune instruction LOCK TABLES.
PROCESS Permet un administrateur de visualiser les processus serveur
qui appartiennent tous les utilisateurs.
RELOAD Permet un administrateur de recharger les tables de
privilges et de rinitialiser les privilges, les htes, les
journaux et les tables.
REPLICATION CLIENT Autorise lutilisation de SHOW STATUS sur les matres et les
esclaves de rplication. La rplication est traite au
Chapitre 12.
REPLICATION SLAVE Autorise les serveurs esclaves de rplication se connecter au
serveur matre. La rplication est traite au Chapitre 12.
SHOW DATABASES Autorise la consultation de la liste de toutes les bases de
donnes avec une instruction SHOW DATABASES. Sans ce
privilge, les utilisateurs ne voient que les bases de donnes
pour lesquelles ils possdent dautres privilges.
SHUTDOWN Autorise un administrateur arrter le serveur MySQL.
SUPERT Autorise un administrateur tuer des threads appartenant
nimporte quel utilisateur.

Vous pouvez attribuer ces privilges des utilisateurs normaux, mais nous vous
conseillons de ne le faire quaprs avoir trs soigneusement estim toutes les cons-
quences.
Le cas est un peu diffrent pour le privilge FILE car il peut tre intressant pour les
utilisateurs puisquil permet de charger des donnes partir de simples fichiers, ce qui
peut leur faire gagner beaucoup de temps en leur vitant davoir saisir leurs donnes
dans leurs bases. Cependant, le mcanisme de chargement de fichiers peut servir
charger nimporte quel fichier visible par le serveur MySQL, y compris des bases de
donnes appartenant dautres utilisateurs et, ventuellement, des fichiers de mots
Chapitre 9 Cration dune base de donnes web 241

de passe. Ce privilge ne doit donc tre accord quavec beaucoup de prcautions et


vous pouvez prfrer charger les donnes des utilisateurs leur place.
Il existe galement deux privilges particuliers, prsents dans le Tableau 9.3.

Tableau 9.3 : Privilges particuliers

Privilge Description
ALL Accorde tous les privilges prsents dans les Tableaux 9.1 et 9.2. Vous pouvez
galement crire ALL PRIVILEGES la place de ALL.
USAGE Naccorde aucun privilge. Cela permet de crer un utilisateur et de ne lautoriser
qu ouvrir une session, sans pouvoir faire autre chose. Gnralement, il sagit
simplement dune premire tape avant dajouter dautres privilges.

La commande REVOKE
Linverse de GRANT sappelle REVOKE. Cette commande supprime des privilges aux
utilisateurs. Sa syntaxe ressemble beaucoup celle de GRANT :
REVOKE privilges [(colonnes)]
ON lment
FROM nom_utilisateur

Si vous avez octroy le privilge GRANT avec la clause WITH GRANT OPTION, vous pouvez
le supprimer de cette faon (avec tous les autres privilges) :
REVOKE All PRIVILEGES, GRANT
FROM nom_utilisateur

Exemples dutilisation de GRANT et de REVOKE


Pour configurer le compte dun administrateur, vous pouvez saisir la commande
suivante :
mysql> grant all
-> on *
-> to fred identified by mnb123
-> with grant option;

Cette commande accorde tous les privilges sur toutes les bases de donnes un utilisateur
appel fred, avec le mot de passe mnb123, et lautorise transmettre ces privilges.
Si vous vous ravisez et que vous ne vouliez pas de cet utilisateur dans votre systme,
vous pouvez le supprimer avec la commande suivante :
mysql> revoke all privileges, grant
-> on *
-> from fred;
242 Partie II Utilisation de MySQL

Voyons maintenant comment configurer le compte dun utilisateur normal, sans aucun
privilge :
mysql> grant usage
-> on livres.*
-> to martine identified by magic123;
Aprs avoir discut un peu avec Martine, et aprs avoir appris ce quelle souhaite rel-
lement faire, vous pouvez lui fournir les privilges appropris :
mysql> grant select, insert, update, delete, index, alter, create, drop
-> on livres.*
-> to martine;
Vous remarquerez quil ny a pas besoin de spcifier le mot de passe de Martine pour
effectuer cette opration.
Si vous vous rendez compte que Martine abuse de ses privilges, vous pouvez les
rduire :
mysql> revoke alter, create, drop
-> on livres.*
-> from martine;
Et, pour terminer, lorsquelle na plus besoin dutiliser la base de donnes, vous pouvez
supprimer tous ses droits :
mysql> revoke all
-> on livres.*
-> from martine;

Configurer un utilisateur pour le Web


Vous devrez configurer un utilisateur pour que vos scripts PHP puissent se connecter
MySQL. Une fois encore, nous pouvons appliquer le principe de privilges minimaux
pour dterminer ce que les scripts doivent pouvoir faire.
Dans la plupart des cas, il leur suffit de slectionner, dinsrer, de supprimer et de
mettre jour des lignes dans des tables, grce SELECT, INSERT, DELETE et UPDATE. Vous
pouvez octroyer ces privilges grce la commande suivante :
mysql> grant select, insert, delete, update
-> on livres.*
-> to bookorama identified by bookorama123;
Pour des raisons de scurit videntes, vous devez choisir un meilleur mot de passe que
celui-ci.
Si vous passez par un service dhbergement web, vous avez en gnral accs aux
autres privilges utilisateur sur une base de donnes que ce service cre pour vous. Les
services dhbergement web donnent souvent les mmes noms utilisateurs et mots de
passe pour laccs en ligne de commande (la dfinition des tables, etc.) et pour les
Chapitre 9 Cration dune base de donnes web 243

connexions des scripts web (les requtes sur la base de donnes). Cette pratique est
juste un peu moins scurise. Vous pouvez configurer un utilisateur avec ce niveau de
privilges de la manire suivante :
mysql> grant select, insert, update, delete, index, alter, create, drop
-> on livres.*
-> to bookorama identified by bookorama123;

Utilisez cette seconde version de lutilisateur, car vous en aurez besoin dans la
prochaine section.
Vous pouvez quitter le moniteur MySQL en tapant la commande quit. Essayez ensuite
douvrir une nouvelle session sous le nom de votre utilisateur web, afin de vrifier que
tout fonctionne correctement. Si linstruction GRANT que vous avez lance a t excute
mais que laccs vous soit refus lorsque vous tentez de vous connecter, cela signifie
gnralement que vous navez pas supprim les utilisateurs anonymes au cours du
processus dinstallation. Reconnectez-vous en tant que root et consultez lAnnexe A
pour plus dinformations concernant la manire de supprimer les comptes anonymes.
Vous devriez alors pouvoir vous connecter en tant quutilisateur web.

Utiliser la bonne base de donnes


Si vous navez eu aucun problme particulier, vous devriez avoir ouvert une session
sous un compte dutilisateur MySQL pour tester les exemples de code, soit parce que
vous venez de configurer cet utilisateur, soit parce que ladministrateur du serveur web
la fait pour vous.
La premire chose faire aprs avoir ouvert une session consiste indiquer la base de
donnes avec laquelle vous souhaitez travailler. Pour cela, saisissez la commande
suivante :
mysql> use nom_base;

o nom base correspond au nom de votre base de donnes.


Vous pouvez vous passer de cette commande si vous indiquez directement le nom de la
base de donnes lorsque vous ouvrez votre session, comme ici :
mysql -D nom_base -h hte -u utilisateur -p

Dans cet exemple, nous utiliserons la base de donnes livres :


mysql> use livres;

Lorsque vous tapez cette commande, MySQL devrait vous rpondre par une ligne
comme celle-ci :
Database changed
244 Partie II Utilisation de MySQL

Si vous ne slectionnez aucune base de donnes avant de commencer votre travail,


MySQL affichera un message derreur :
ERROR 1046 (3D000): No Database Selected

Cration des tables de la base de donnes


Ltape suivante dans la configuration de la base de donnes consiste crer les tables.
Pour cela, vous pouvez vous servir de la commande SQL CREATE TABLE. Voici le format
gnral de cette instruction :
CREATE TABLE nom_table(colonnes)

INFO
MySQL propose plusieurs types de tables ou moteurs de stockage, dont certains permettent
deffectuer des transactions sres. Nous prsenterons ces types de tables au Chapitre 13.
Pour le moment, toutes les tables de la base de donnes utiliseront le moteur de stockage
par dfaut, MyISAM.

Il faut videmment remplacer le paramtre nom table par le nom de la table que vous
souhaitez crer et le paramtre colonnes par la liste des colonnes de votre table, spares
par des virgules.
Chaque colonne possde un nom, suivi dun type de donnes.
Voici nouveau le schma de Book-O-Rama :
Clients(IDClient, Nom, Adresse, Ville)
Commandes(IDCommande, IDClient, Montant, Date)
Livres(ISBN, Auteur, Titre, Prix)
Livres_Commandes(IDCommande, ISBN, Quantite)
Commentaires_Livres(ISBN, Commentaire)

Le Listing 9.1 prsente le code SQL permettant de crer ces tables, en supposant que
vous avez dj cr la base de donnes livres. Vous trouverez ce programme SQL sur
le site Pearson, dans le fichier chapitre09/bookorama.sql.
Vous pouvez demander MySQL dexcuter un fichier SQL existant, du site Pearson,
en saisissant une commande comme celle-ci :
> mysql -h hte -u bookorama -D livres -p < bookorama.sql

(Noubliez pas de remplacer hte par le nom de votre hte.)


La redirection de lentre standard est trs pratique puisquelle permet de modifier votre
programme SQL dans lditeur de texte de votre choix avant de lexcuter.
Chapitre 9 Cration dune base de donnes web 245

Listing 9.1 : bookorama.sql Le programme SQL permettant de crer les tables


de Book-O-Rama

create table clients


( idclient int unsigned not null auto_increment primary key,
nom char(50) not null,
adresse char(100) not null,
ville char(30) not null
);

create table commandes


( idcommande int unsigned not null auto_increment primary key,
idclient int unsigned not null,
montant float(6,2),
date date not null
);

create table livres


( isbn char(13) not null primary key,
auteur char(50),
titre char(100),
prix float(4,2)
);

create table livres_commandes


( idcommande int unsigned not null,
isbn char(13) not null,
quantite tinyint unsigned,
primary key (idcommande, isbn)
);

create table commentaires_livres


(
isbn char(13) not null primary key,
commentaire text
);

Chaque table cre sa propre instruction CREATE TABLE. Vous remarquerez que nous
avons cr chaque table de ce schma avec les colonnes que nous avons mises en place
au chapitre prcdent. Le type de donnes de chaque colonne est indiqu directement
aprs son nom. En outre, certaines colonnes possdent dautres particularits.

Signification des autres mots-cls


NOT NULL signifie que toutes les lignes de la table doivent possder une valeur associe
cet attribut. Sil nest pas indiqu, le champ peut tre vide (NULL).
AUTO INCREMENT est une fonctionnalit particulire de MySQL que vous pouvez utiliser
sur des colonnes contenant des nombres entiers. Ce mot-cl signifie que si nous laissons
ce champ vide lorsque nous insrons de nouvelles lignes dans la table, MySQL gnre
automatiquement une valeur didentification unique. Cette valeur correspond la valeur
246 Partie II Utilisation de MySQL

maximale existant dans la colonne, incrmente de 1. Cette caractristique ne peut tre


utilise quune fois dans chaque table. Les colonnes qui spcifient AUTO INCREMENT
doivent tre indexes.
Le mot-cl PRIMARY KEY, lorsquil est indiqu aprs un nom de colonne, indique que
cette colonne est la cl primaire de la table. Les entres de cette colonne doivent tre
uniques. MySQL indexe automatiquement cette colonne. Vous remarquerez que, lors-
que nous nous en sommes servis avec idclient dans la table clients, nous lavons
utilis avec AUTO INCREMENT. Lindexage automatique des cls primaires soccupe des
index ncessaires pour AUTO INCREMENT.
PRIMARY KEY ne peut apparatre quune seule fois dans la dfinition dune table. La
clause PRIMARY KEY la fin de linstruction commandes livres utilise donc une autre
forme puisque la cl primaire de cette table est forme de deux colonnes pour lesquelles
nous naurions pas eu le droit de rpter PRIMARY KEY. Notons que cette cl de deux
colonnes cre galement un index reposant sur les deux colonnes la fois.
UNSIGNED aprs un type entier signifie quil ne peut pas prendre une valeur ngative.

Analyse des types de colonnes


Prenons comme exemple la premire table :
create table clients
( idclient int unsigned not null auto_increment primary key,
nom char(50) not null,
adresse char(100) not null,
ville char(30) not null
);

Lorsquune table est cre, il faut choisir le type de chaque colonne.


Pour la table clients, nous avons bien quatre colonnes, comme lindiquait notre
schma. La premire colonne, idclient, correspond la cl primaire, que nous avons
indique directement. Nous avons choisi quelle contiendrait des nombres entiers (cest-
-dire des donnes de type int) et que ces identifiants seraient non signs (de type unsi
gned). Nous nous sommes galement servis de auto increment, pour que MySQL
puisse grer ces informations notre place : cela fait toujours une chose de moins faire.
Toutes les autres colonnes contiennent des chanes de caractres, cest pourquoi nous
avons choisi le type char. Ce type indique des champs de largeur fixe. Cette taille est
donne entre crochets, donc, par exemple, nom peut contenir jusqu cinquante caractres.
Ce type de donnes alloue cinquante caractres pour chaque entre, mme si tous les
caractres ne sont pas utiliss. MySQL compltera alors les donnes avec des espaces
pour les justifier sur cinquante caractres. Nous aurions pu choisir le type varchar, qui
permet dallouer uniquement la mmoire ncessaire pour chaque champ (plus un octet).
Chapitre 9 Cration dune base de donnes web 247

Une fois encore, il sagit dun petit compromis : varchar utilise moins de place, mais
char est plus rapide.
Vous remarquerez que toutes les colonnes sont dclares comme tant NOT NULL. Il
sagit dune petite optimisation quil ne faut pas hsiter mettre en uvre lorsque cest
possible.
Nous reviendrons sur les questions doptimisation au Chapitre 12.
La syntaxe de certaines instructions CREATE est lgrement diffrente. Examinons main-
tenant la table commandes:
create table commandes
( idcommande int unsigned not null auto_increment primary key,
idclient int unsigned not null,
montant float(6,2),
date date not null
);

La colonne montant est indique comme un nombre virgule flottante de type float.
Avec la plupart des types de donnes flottantes, il est possible de prciser la largeur de
laffichage et le nombre de chiffres aprs la virgule. Dans ce cas, le montant des
commandes sera en euros, cest pourquoi nous avons choisi une largeur assez impor-
tante (6) et deux chiffres dcimaux, pour les centimes.
La colonne date possde le type de donnes date.
Dans cette table particulire, toutes les colonnes (sauf montant) sont marques avec NOT
NULL. En effet, lorsquune commande est entre dans la base de donnes, nous devons
lajouter dans la table des commandes, puis ajouter les lments correspondants dans
commandes livres avant de traiter la commande. Il est donc tout fait possible que
nous ne connaissions pas le montant de la commande lorsque celle-ci est effectue,
cest pourquoi nous lautorisons tre NULL.
La table livres possde des caractristiques similaires :
create table livres
( isbn char(13) not null primary key,
auteur char(50),
titre char(100),
prix float(4,2)
);

Ici, nous navons pas besoin de produire une cl primaire parce que les numros ISBN
sont crs un autre endroit. Les autres champs peuvent tre NULL, puisquune librairie
peut connatre le code ISBN dun livre avant de connatre ses autres caractristiques
(titre, auteur ou prix).
248 Partie II Utilisation de MySQL

La table livres commandes montre comment crer une cl primaire sur plusieurs colonnes :
create table livres_commandes
( idcommande int unsigned not null,
isbn char(13) not null,
quantite tinyint unsigned,
primary key (idcommande, isbn)
);
Nous avons indiqu les quantits de livres avec TINYINT UNSIGNED, qui peut contenir
des nombres entiers positifs compris entre 0 et 255.
Comme nous lavons dj mentionn, les cls primaires rparties sur plusieurs colonnes
doivent tre spcifies avec une clause de cl primaire particulire. Cest ce que nous
utilisons ici.
Pour terminer, voici la table commentaires livres :
create table commentaires_livres
(
isbn char(13) not null primary key,
commentaire text
);
Cette table utilise un nouveau type de donnes, text, que nous navons pas encore
mentionn. Ce type est intressant pour les chanes de caractres plus longues, comme
un commentaire ou un article. Il en existe plusieurs variantes, que nous examinerons un
peu plus loin dans ce chapitre.
Pour comprendre plus finement la cration des tables, intressons-nous aux noms des
colonnes et aux identificateurs en gnral, puis aux types de donnes que nous pouvons
choisir pour les colonnes. Mais, pour linstant, examinons dabord la base de donnes
que nous venons de crer.

Examiner la base de donnes avec SHOW et DESCRIBE


Ouvrez une session avec le moniteur MySQL et slectionnez la base de donnes
livres. Vous pouvez afficher les tables de cette base de donnes en saisissant la
commande suivante :
mysql> show tables;
MySQL affiche alors la liste de toutes les tables de cette base de donnes :
+---------------------+
| Tables in livres |
+---------------------+
| clients |
| commandes |
| commentaires_livres |
| livres |
| livres_commandes |
+---------------------+
5 rows in set (0.06 sec)
Chapitre 9 Cration dune base de donnes web 249

Vous pouvez galement vous servir de la commande show pour afficher la liste des
bases de donnes, par exemple avec la commande suivante :
mysql> show databases;

Si vous ne possdez pas le privilge SHOW DATABASES, vous ne verrez que la liste des
bases de donnes pour lesquelles vous possdez des privilges.
Pour afficher plus dinformations sur une table particulire, par exemple la table
livres, servez-vous de DESCRIBE :
mysql> describe livres;

MySQL affiche alors les informations que vous avez fournies lors de la cration de la
base de donnes :
+--------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+-------+
| isbn | char(13) | NO | PRI | NULL | |
| auteur | char(50) | YES | | NULL | |
| titre | char(100) | YES | | NULL | |
| prix | float(4,2) | YES | | NULL | |
+--------+------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
Ces commandes sont utiles pour vous rappeler le type de donnes dune colonne ou
pour parcourir une base de donnes que vous navez pas cre vous-mme.

Cration dindex
Nous avons dj rapidement fait mention des index car la dsignation de cls primaires
cre automatiquement des index sur les colonnes concernes.
Lun des problmes courants auxquels sont confronts les nouveaux utilisateurs MySQL
concerne le regret que ces derniers expriment au sujet des mauvaises performances de
cette base de donnes quon leur a pourtant annonce tre rapide comme lclair. Ce
problme de performances survient parce quils nont pas cr dindex sur leur base de
donnes (il est en effet possible de crer des tables sans cl primaire et sans index).
Pour commencer, les index qui ont t automatiquement crs pour vous feront
laffaire. Si vous constatez que vous devez excuter un grand nombre de requtes sur
une colonne qui nest pas une cl, il peut tre souhaitable dajouter un index sur cette
colonne afin damliorer les performances. Vous pouvez le faire avec linstruction
CREATE INDEX, dont la syntaxe est la suivante :
CREATE [UNIQUE|FULLTEXT] INDEX nom_index
ON nom_table (nom_colonne_index [(longueur)] [ASC|DESC], ...])

Les index FULLTEXT sont utiliss pour indexer des champs texte. Nous reviendrons sur
ce sujet au Chapitre 13.
250 Partie II Utilisation de MySQL

Le champ facultatif longueur permet de prciser que seuls les longueur premiers
caractres du champ doivent tre indexs. Vous pouvez galement indiquer si lindex
doit tre croissant (ASC) ou dcroissant (DESC) ; par dfaut, les index sont croissants.

Identificateurs MySQL
Il existe cinq types didentificateurs dans MySQL : les bases de donnes, les tables, les
colonnes, les index, que nous connaissons dj, et les alias, que nous tudierons au
prochain chapitre.
Avec MySQL, les bases de donnes correspondent des rpertoires et les tables, des
fichiers du systme de fichiers sous-jacent. Cette correspondance a un effet direct sur les
noms que vous pouvez leur donner. Elle influe galement sur la casse de ces noms : si votre
systme dexploitation tient compte de la diffrence entre les majuscules et les minuscules
dans les noms des rpertoires et des fichiers, les noms des bases de donnes et des tables
seront galement sensibles cette diffrence. Unix, par exemple, fait la distinction entre
les majuscules et les minuscules, ce qui nest pas le cas de Windows. Quel que soit le
systme dexploitation sous-jacent, les noms des colonnes et des alias ne tiennent en
revanche jamais compte des majuscules et des minuscules, bien que vous ne puissiez
pas utiliser diffrentes casses du mme nom dans une mme instruction SQL.
En outre, lemplacement des rpertoires et des fichiers contenant vos donnes dpend
de votre configuration. Vous pouvez connatre cet emplacement grce lutilitaire
mysqladmin :
> mysqladmin -h hte -u root -p variables

Recherchez la variable datadir dans le rsultat de la commande prcdente.


Le Tableau 9.4 prsente un rsum des diffrents identificateurs. Il faut galement
savoir quil est impossible dutiliser les caractres ASCII 0 et 255 ni lapostrophe dans
les identificateurs.

Tableau 9.4 : Identificateurs MySQL

Type Longueur Majuscules/ Caractres autoriss


maximale minuscules
Bases 64 Comme le SE Nimporte quel caractre autoris dans les noms des
de donnes rpertoires de votre systme dexploitation (SE),
sauf les caractres /, \ et .
Table 64 Comme le SE Nimporte quel caractre autoris dans les noms des
fichiers de votre systme dexploitation, sauf les
caractres / et .
Chapitre 9 Cration dune base de donnes web 251

Tableau 9.4 : Identificateurs MySQL (suite)

Type Longueur Majuscules/ Caractres autoriss


maximale minuscules
Colonne 64 Non Nimporte lesquels
Index 64 Non Nimporte lesquels
Alias 255 Non Nimporte lesquels

Ces rgles sont extrmement souples. Vous pouvez mme utiliser des mots rservs, ou
des caractres spciaux, la seule limitation tant que si vous utilisez cette caractristique il
faudra placer vos identificateurs entre apostrophes inverses (Alt Gr+ sur les claviers
franais pour PC, la touche gauche de Entre sur les claviers franais pour Mac) :
create database `create database`;

Naturellement, cette libert supplmentaire ne doit tre utilise qu bon escient. Ce


nest pas parce que vous pouvez appeler une base de donnes `create database` quil
faut le faire. Ce principe reste valable dans nimporte quel type de programmation : il
faut toujours utiliser des identificateurs vocateurs.

Types des colonnes


Les colonnes des tables MySQL peuvent tre des nombres, des dates et des heures, ou
des chanes de caractres. Chacune de ces catgories compte plusieurs types diffrents
que nous allons rsumer ici. Au Chapitre 12, nous tudierons leurs avantages et leurs
inconvnients.
Il existe plusieurs variantes de ces trois catgories en fonction de leur taille de stockage.
Lorsque lon choisit un type de colonne, il faut gnralement choisir le type le plus petit
dans lequel vos donnes peuvent entrer.
Pour de nombreux types, vous pouvez spcifier la longueur maximale daffichage (qui
correspond au paramtre M dans les tableaux suivants) lorsque vous crez une colonne. Si
ce paramtre est facultatif, il est indiqu entre crochets. La valeur maximale de M est 255.
Dans les descriptions qui suivent, les autres valeurs facultatives sont prsentes entre
crochets.

Types numriques
Les types numriques sont des nombres entiers ou des nombres virgule flottante. Pour
les nombres virgule flottante, vous pouvez prciser le nombre de chiffres aprs la
virgule (paramtre D). La valeur maximale de D est la plus petite valeur entre 30 et M 2
252 Partie II Utilisation de MySQL

(cest--dire la longueur maximale daffichage moins deux : un caractre pour le point


et un pour la partie entire du nombre).
Pour les types entiers, vous pouvez utiliser lattribut UNSIGNED pour naccepter que des
nombres positifs, comme le montre le Listing 9.1.
Pour tous les types numriques, vous pouvez utiliser lattribut ZEROFILL. Lorsque les
valeurs dune colonne ZEROFILL sont affiches, elles sont justifies gauche avec des 0.
Une colonne avec lattribut ZEROFILL est automatiquement considre comme UNSIGNED.
Les types entiers sont prsents dans le Tableau 9.5, qui donne la fois les intervalles
signs et non signs pour les valeurs possibles.

Tableau 9.5 : Types de donnes entiers

Type Intervalle Taille (octets) Description


TINYINT[(M)] 127..128, ou 0..255 1 Entiers trs courts
BIT Synonyme de TINYINT
BOOL Synonyme de TINYINT
SMALLINT[(M)] 32 768..32 767, ou 0..65 535 2 Entiers courts
MEDIUMINT[(M)] 8 388 608.. 8 388 607, ou 3 Entiers de taille moyenne
0..16 777 215
INT[(M)] 231..231 1, ou 0..232 1 4 Entiers classiques
INTEGER[(M)] Synonyme de INT
BIGINT[(M)] 263..263 1, ou 0..264 1 8 Entiers larges

Les types virgule flottante sont prsents dans le Tableau 9.6.

Tableau 9.6 : Types de donnes virgule flottante

Type Intervalle Taille Description


(octets)
FLOAT Dpend de la prcision Variable Peut tre utilis pour reprsenter
(prcision) des nombres virgule flottante
en simple ou double prcision.
FLOAT[(M,D)] 1.175494351E-38, 4 Nombres virgule flottante en
3.402823466E+38 simple prcision. quivalent
FLOAT(4), mais avec une largeur
daffichage et un nombre de
chiffres aprs la virgule.
Chapitre 9 Cration dune base de donnes web 253

Tableau 9.6 : Types de donnes virgule flottante (suite)

Type Intervalle Taille Description


(octets)
DOUBLE[(M,D)] 1.7976931348623157E+308, 8 Nombres virgule flottante en
2.2250738585072014E-308 double prcision. quivalent
FLOAT(8), mais avec une largeur
daffichage et un nombre de
chiffres aprs la virgule.
DOUBLE PRECISION Comme ci-dessus Synonyme de DOUBLE[(M, D)].
[(M,D)]
REAL[(M,D)] Comme ci-dessus Synonyme de DOUBLE[(M, D)].
DECIMAL Variable M+2 Nombres virgule flottante
[(M[,D])] enregistr comme un type char.
Lintervalle dpend de M, la
largeur daffichage.
NUMERIC [(M,D)] Comme ci-dessus Synonyme de DECIMAL.
DEC[(M,D)] Comme ci-dessus Synonyme de DECIMAL.
FIXED[(M,D)] Comme ci-dessus Synonyme de DECIMAL.

Types de dates et dheures


MySQL prend en charge plusieurs types de dates et dheures, prsents dans le
Tableau 9.7. Grce tous ces types, vous pouvez saisir vos donnes sous la forme dune
chane de caractres ou sous un format numrique. Une colonne TIMESTAMP dune ligne
particulire prend automatiquement la date et lheure de la dernire opration sur cette
ligne, moins que vous ne la dfinissiez manuellement. Cette caractristique est trs
utile pour le suivi des transactions.

Tableau 9.7 : Types de dates et dheures

Type Intervalle Description


DATE 1000-01-01, 9999-12-31 Une date, affiche au format YYYY MM DD.
TIME -838:59:59, 838:59:59 Une heure, affiche au format HH:MM:SS.
Vous remarquerez que cet intervalle est
beaucoup plus grand que ce que lon utilise
ordinairement.
DATETIME 1000-01-01 00:00:00, Une date et une heure, affiches au format
9999-12-31 23:59:59 YYYY MM DDHH:MM:SS.
254 Partie II Utilisation de MySQL

Tableau 9.7 : Types de dates et dheures (suite)

Type Intervalle Description


TIMESTAMP[(M)] 1970-01-01 00:00:00 Une date complte (ou tiquette temporelle),
utile pour identifier les transactions. Le format
daffichage dpend de la valeur de M (voir le
Tableau 9.8). La valeur maximale dpend de
la limite dUnix, qui se situe parfois en 2037.
YEAR[(2|4)] 70-69 (1970-2069), Une anne, au format 2 ou 4 chiffres. Chacun
1901-2155 de ces formats correspond un intervalle.

Le Tableau 9.8 prsente les diffrents types daffichages de TIMESTAMP.

Tableau 9.8 : Les types daffichages de TIMESTAMP

Type spcifi Affichage


TIMESTAMP YYYYMMDDHHMMSS
TIMESTAMP(14) YYYYMMDDHHMMSS
TIMESTAMP(12) YYMMDDHHMMSS
TIMESTAMP(10) YYMMDDHHMM
TIMESTAMP(8) YYYYMMDD
TIMESTAMP(6) YYMMDD
TIMESTAMP(4) YYMM
TIMESTAMP(2) YY

Types de chanes
Il existe trois types de chanes. Tout dabord les chanes classiques, cest--dire des
chanes de texte courtes. Ces chanes correspondent aux types CHAR (longueur fixe) et
VARCHAR (longueur variable). Vous pouvez spcifier la largeur de ces chanes. Les
colonnes de type CHAR sont justifies avec des espaces pour atteindre la taille indique,
alors que la taille de stockage des colonnes VARCHAR varie automatiquement en fonction
de leur contenu. MySQL supprime les espaces placs la fin des CHAR lorsquils sont
lus et ceux des VARCHAR lorsquils sont stocks. Le choix entre ces deux types revient
faire un compromis entre lespace de stockage et la vitesse. Nous y reviendrons au
Chapitre 12.
Chapitre 9 Cration dune base de donnes web 255

Il existe galement les types TEXT et BLOB, dans diffrentes tailles. Ces types correspon-
dent des donnes texte ou binaires plus longues. Les BLOB sont des "objets binaires de
grande taille" (Binary Large OBjects). Ils peuvent contenir ce que vous voulez, comme
des images ou du son.
Dans la pratique, les colonnes BLOB et TEXT sont identiques, sauf que les colonnes BLOB
tiennent compte de la diffrence majuscules/minuscules, contrairement aux colonnes TEXT.
Comme ces types de colonnes peuvent contenir des donnes trs volumineuses, leur
emploi ncessite certaines prcautions. Nous voquerons ce problme au Chapitre 12.
Le troisime groupe contient deux types spciaux, SET et ENUM. Le type SET permet de
prciser que les valeurs dune colonne doivent faire partie dun certain ensemble de
valeurs. Les valeurs de la colonne peuvent contenir plusieurs valeurs provenant de cet
ensemble. Vous pouvez avoir au maximum 64 lments provenant de lensemble spcifi.
ENUM ressemble beaucoup SET, sauf que les colonnes de ce type ne peuvent contenir
quune seule des valeurs indiques, ou NULL. Par ailleurs, une numration ne peut pas
contenir plus de 65 535 lments.
Les types de chanes sont rsums dans les Tableaux 9.9, 9.10 et 9.11. Le Tableau 9.9
prsente les types de chanes classiques.

Tableau 9.9 : Types de chanes classiques

Type Intervalle Description


[NATIONAL] CHAR(M) 0 255 Chane de taille fixe, de longueur M, o M est compris
[BINARY | ASCII | entre 0 et 255. Le mot-cl NATIONAL prcise quon doit
UNICODE] utiliser le jeu de caractres par dfaut. Cela correspond
au comportement par dfaut de MySQL, mais il peut
galement tre prcis parce quil fait partie du standard
SQL ANSI. Le mot-cl BINARY indique que les donnes
doivent tre traites en respectant les majuscules et les
minuscules (le comportement par dfaut consiste
ignorer la casse). Le mot-cl ASCII prcise que la
colonne utilisera le jeu de caractres latin1. Le mot-cl
UNICODE indique que le jeu de caractres sera ucs.
CHAR [NATIONAL] Synonyme de CHAR(1).
[NATIONAL] VARCHAR(M) 1 255 Comme ci-dessus, sauf que la longueur est variable.
[BINARY]

Le Tableau 9.10 rsume les types TEXT et BLOB. La longueur maximale dun champ
TEXT (en caractres) correspond la taille maximale en octets des fichiers qui doivent
tre enregistrs dans ce champ.
256 Partie II Utilisation de MySQL

Tableau 9.10 : Types TEXT et BLOB

Type Longueur maximale (caractres) Description


TINYBLOB 28 1 (cest--dire 255) Un petit champ BLOB
TINYTEXT 28 1 (cest--dire 255) Un petit champ TEXT
BLOB 216 1 (cest--dire 65 535) Un champ BLOB de taille normale
TEXT 216 1 (cest--dire 65 535) Un champ TEXT de taille normale
MEDIUMBLOB 224 1 (cest--dire 16 777 215) Un champ BLOB de taille moyenne
MEDIUMTEXT 224 1 (cest--dire 16 777 215) Un champ TEXT de taille moyenne
LONGBLOB 232 1 (cest--dire 4 294 967 295) Un champ BLOB de grande taille
LONGTEXT 232 1 (cest--dire 4 294 967 295) Un champ TEXT de grande taille

Le Tableau 9.11 prsente les types ENUM et SET.

Tableau 9.11 : Types SET et ENUM

Type Maximum de valeurs Description


dans lensemble
ENUM(valeur1, valeur2,...) 65 535 Les colonnes de ce type ne
peuvent contenir quune seule
des valeurs numres, ou NULL.
SET(valeur1, valeur2,...) 64 Les colonnes de ce type peuvent
contenir un ensemble de valeurs
parmi celles de la liste, ou NULL.

Pour aller plus loin


Pour plus dinformations, reportez-vous au chapitre du manuel en ligne qui concerne la
configuration dune base de donnes, sur le site http://www.mysql.com/.

Pour la suite
Maintenant que vous savez comment crer des utilisateurs, des bases de donnes et des
tables, vous pouvez vous intresser linteraction avec la base de donnes. Nous
verrons au prochain chapitre comment insrer des donnes dans des tables, comment
les mettre jour, les supprimer et comment interroger la base.
10
Travailler avec une base
de donnes MySQL

Dans ce chapitre, nous prsenterons SQL (Structured Query Language) et nous verrons
comment lutiliser pour interroger des bases de donnes. Nous continuerons le dvelop-
pement de la base de donnes Book-O-Rama en apprenant insrer, supprimer et
mettre jour des donnes. Nous verrons galement comment interroger la base de
donnes.
Nous commencerons par prsenter SQL et verrons en quoi cet outil peut nous tre utile.
Si vous navez pas encore configur la base de donnes de Book-O-Rama, vous devez
le faire avant dexcuter les requtes SQL de ce chapitre. Vous trouverez tous les dtails
de cette procdure au Chapitre 9.

Quest-ce que SQL ?


SQL signifie Structured Query Language, ou "langage de requtes structur". Cest le
langage le plus employ par les systmes de gestion de bases de donnes relationnelles
(SGBDR) pour stocker et rcuprer les donnes. Il est utilis par des systmes de bases
de donnes comme MySQL, Oracle, PostgreSQL, Sybase et Microsoft SQL Server,
pour ne citer queux.
Bien quil y ait pour SQL un standard ANSI que les systmes de bases de donnes
comme MySQL sefforcent de respecter, il existe toutefois quelques diffrences subti-
les entre ce SQL standard et le SQL de MySQL. Il est prvu que certaines dentre elles
soient rsorbes dans les versions futures afin de se rapprocher du standard, mais
dautres sont dlibres. Nous signalerons les plus importantes mesure de notre
expos. Pour une liste exhaustive des diffrences entre le SQL version ANSI et celui de
MySQL, consultez le manuel en ligne de MySQL. Vous trouverez cette page lURL
258 Partie II Utilisation de MySQL

suivante, ainsi qu plusieurs autres endroits : http://dev.mysql.com/doc/refman/5.1/


en/compatibility.html.
Vous avez peut-tre dj entendu employer les termes langage de dfinition des donnes
(LDD) pour la dfinition des bases de donnes et langage de manipulation des
donnes (LMD) pour linterrogation des bases de donnes. SQL comprend les deux.
Au Chapitre 9, nous avons prsent la dfinition des donnes (LDD) en SQL et nous
nous en sommes donc dj un peu servis. Le LDD permet de mettre en place une base
de donnes.
La partie LMD de SQL sert bien plus souvent, puisquon lutilise chaque fois que lon
enregistre ou que lon lit des donnes dans une base de donnes.

Insertion de donnes dans une base de donnes


Avant de pouvoir travailler avec une base de donnes, vous devez y enregistrer des
informations. La plupart du temps, vous vous servirez de linstruction INSERT.
Rappelez-vous que les SGBDR contiennent des tables qui renferment leur tour des
lignes de donnes, organises en colonnes. Chaque ligne dune table dcrit normale-
ment un objet du mode rel ou une relation, et les valeurs dune colonne pour une ligne
donne correspondent aux informations relatives un objet rel particulier. Nous
pouvons nous servir de linstruction INSERT pour ajouter des lignes de donnes dans la
base de donnes.
La syntaxe de INSERT est la suivante :
INSERT [INTO] table [(colonne1, colonne2, colonne3,...)] VALUES
(valeur1, valeur2, valeur3,...);

Pour, par exemple, insrer une ligne dans la table Clients de Book-O-Rama, vous
pouvez saisir la commande suivante :
insert into clients values
(NULL, Julie Dupont, 25 rue noire, Toulouse);

Vous remarquerez que nous avons remplac table par le nom de la table dans laquelle
nous souhaitions placer nos donnes et que nous avons plac les valeurs insrer dans
la liste qui suit la clause values. Toutes les valeurs de cet exemple ont t mises entre
apostrophes simples. Avec MySQL, les chanes de caractres doivent toujours tre
mises entre apostrophes simples ou doubles (dans ce livre, nous utiliserons ces deux
types dapostrophes). Les nombres et les dates nen ont pas besoin.
Linstruction INSERT mrite quelques commentaires.
Les valeurs indiques sont utilises pour remplir la table, dans lordre o elles sont
fournies. Cependant, si vous souhaitez remplir uniquement certaines colonnes ou si
Chapitre 10 Travailler avec une base de donnes MySQL 259

vous voulez donner les valeurs dans un ordre diffrent, vous pouvez prciser le nom des
colonnes dans linstruction. Par exemple :
insert into clients (nom, ville) values
(Melissa Martin, Albi);

Cette approche nest intressante que si vous possdez des donnes partielles pour un
enregistrement particulier ou si certains champs de lenregistrement sont facultatifs.
Voici une autre syntaxe similaire :
insert into clients
set nom = Michel Archer,
adresse = "12 Avenue plate ,
ville = Montauban;

Vous remarquerez galement que nous avons donn la valeur NULL la colonne
idclient lorsque nous avons ajout Julie Dupont et que nous avons ignor cette
colonne lorsque nous avons ajout les autres clients. Vous vous rappelez peut-tre que,
lorsque nous avons configur la base de donnes, nous avons indiqu que idclient
tait la cl primaire de la table clients : cette procdure peut donc vous sembler
trange. Cependant, nous avions galement attribu lattribut AUTO INCREMENT ce
champ, ce qui signifie que si nous insrons une ligne avec la valeur NULL (ou aucune
valeur) dans ce champ, MySQL produira le nombre suivant dans la squence dauto-
incrmentation et linsrera automatiquement notre place. Cette fonctionnalit est
particulirement apprciable.
Il est galement possible dinsrer plusieurs lignes dun seul coup dans une table.
Chaque ligne doit tre mise entre parenthses et les ensembles de parenthses doivent
tre spars par des virgules.
Linstruction INSERT na que peu de variantes. Aprs le mot INSERT, vous pouvez ajou-
ter les mots-cls LOW PRIORITY ou DELAYED. Le premier indique que le systme peut
attendre et effectuer linsertion plus tard, lorsquil ny aura plus de lecture dans la table.
Le second, que les donnes insres seront mises en tampon. Si le serveur est occup,
vous pouvez donc continuer excuter des requtes au lieu davoir attendre que
lopration INSERT soit termine.
Immdiatement aprs ces mots-cls, vous pouvez ventuellement ajouter IGNORE pour
quune tentative dinsertion de lignes produisant une cl duplique supprime ces lignes
sans prvenir. Lautre solution consiste utiliser ON DUPLICATE KEY UPDATE expression
la fin de linstruction INSERT. Cette clause permet de modifier la valeur duplique en
utilisant une instruction UPDATE classique (voir plus loin dans ce chapitre).
Nous avons runi quelques donnes pour remplir la base de donnes grce quelques
instructions INSERT qui se servent de lapproche multiligne que nous venons dvoquer.
260 Partie II Utilisation de MySQL

Le script correspondant se trouve sur le site Pearson, dans le fichier


\chapitre10\insertion_livres.sql. Vous le trouverez galement dans le Listing 10.1.

Listing 10.1 : insertions_livres.sql Script SQL de remplissage des tables de Book-O-Rama

use livres;

insert into clients values


(3, Julie Dupont, 25 rue noire, Toulouse),
(4, Alain Wong, 147 Avenue Haines, Bordeaux),
(5, Michelle Arthur, 357 rue de Paris, Ramonville);

insert into commandes values


(NULL, 3, 69.98, 2007-04-02),
(NULL, 1, 49.99, 2007-04-15),
(NULL, 2, 74.98, 2007-04-19),
(NULL, 3, 24.99, 2007-05-01);

insert into livres values


(0-672-31697-8, Michael Morgan,
Java 2 for Professional Developers, 34.99),
(0-672-31745-1, Thomas Down, Installing Debian GNU/Linux, 24.99),
(0-672-31509-2, Pruitt, et al., Teach Yourself GIMP in 24 Hours,
24.99),
(0-672-31769-9, Thomas Schenk,
Caldera OpenLinux System Administration Unleashed, 49.99);

insert into livres_commandes values


(1, 0-672-31697-8, 2),
(2, 0-672-31769-9, 1),
(3, 0-672-31769-9, 1),
(3, 0-672-31509-2, 1),
(4, 0-672-31745-1, 3);

insert into commentaires_livres values


(0-672-31697-8, Le livre de Morgan est bien crit et va bien
au-del de la plupart des livres sur Java.);

Vous pouvez excuter ce script en ligne de commande en lenvoyant MySQL via un


pipeline, comme ici:
> mysql -h hte -u bookorama -p livres < path/vers/insertions_livres.sql

Rcupration des donnes dans la base de donnes


Linstruction principale de SQL est SELECT. Elle permet de rcuprer des donnes dans
une base de donnes en slectionnant les lignes qui correspondent certains critres.
Linstruction SELECT reconnat beaucoup doptions et peut tre utilise de plusieurs
manires trs diffrentes.
Chapitre 10 Travailler avec une base de donnes MySQL 261

Voici la syntaxe dune instruction SELECT :


SELECT [options] lments
[INTO fichier]
FROM tables
[ WHERE conditions ]
[ GROUP BY regroupement ]
[ HAVING proprits ]
[ ORDER BY liste_tri]
[LIMIT limite ]
[PROCEDURE nom_proc(paramtres)]
[options de verrouillage]
;

Nous reviendrons un peu plus loin sur toutes les clauses de cette instruction. Pour
linstant, examinons une requte sans aucune clause facultative, cest--dire une
requte simple qui slectionne des lments dans une table particulire. Typiquement,
ces lments sont des colonnes de la table, mais il peut galement sagir des rsultats de
nimporte quelle expression MySQL. Nous reviendrons sur les plus utiles un peu plus
loin dans cette section. Cette requte renvoie le contenu des colonnes nom et ville de la
table clients :
select nom, ville
from clients;

Cette requte renvoie le rsultat suivant, en supposant que vous ayez saisi les donnes
du Listing 10.1 et que vous ayez excut les deux autres instructions INSERT cites
titre dexemple :
+-----------------+--------------------+
| nom | ville |
+-----------------+--------------------+
| Julie Dupont | Toulouse |
| Alain Wong | Bordeaux |
| Michelle Arthur | Ramonville |
| Melissa Martin | Albi |
| Michal Archer | Montauban |
+-----------------+--------------------+

Comme vous pouvez le constater, nous obtenons une table qui contient les lments
slectionns (nom et ville), partir de la table que nous avons spcifie, clients. Ces
donnes sont issues de toutes les lignes de la table clients.
Vous pouvez indiquer autant de colonnes que vous le souhaitez, en les mentionnant
aprs le mot-cl select. Vous pouvez aussi spcifier dautres lments, comme le joker
(*), qui symbolise toutes les colonnes de la table concerne. Pour, par exemple, afficher
toutes les colonnes et toutes les lignes de la table livres commandes, nous pouvons
utiliser linstruction suivante :
select *
from livres_commandes;
262 Partie II Utilisation de MySQL

Cette commande renvoie la sortie suivante :


+------------+---------------+----------+
| idcommande | isbn | quantite |
+------------+---------------+----------+
| 1 | 0-672-31697-8 | 2 |
| 2 | 0-672-31769-9 | 1 |
| 3 | 0-672-31769-9 | 1 |
| 3 | 0-672-31509-2 | 1 |
| 4 | 0-672-31745-1 | 3 |
+------------+---------------+----------+

Rcuprer des donnes ayant des critres spcifiques


Pour accder un sous-ensemble de lignes dune table, nous devons indiquer plusieurs
critres de slection laide de la clause WHERE. Par exemple :
select *
from commandes
where idclient = 3;
slectionne toutes les colonnes de la table commandes, mais uniquement pour les lignes
dont le idclient vaut 3. Voici le rsultat obtenu :
+------------+----------+---------+------------+
| idcommande | idclient | montant | date |
+------------+----------+---------+------------+
| 1 | 3 | 69.98 | 2007-04-02 |
| 4 | 3 | 24.99 | 2007-05-01 |
+------------+----------+---------+------------+

La clause WHERE prcise les critres utiliss pour slectionner les lignes. Dans notre
exemple, nous avons slectionn les lignes dont le idclient vaut 3. En SQL, cest le
signe gal qui permet de tester lgalit : cest donc diffrent de PHP et cest une source
derreur frquente lorsquon utilise conjointement ces deux langages.
Outre le test dgalit, MySQL dispose de plusieurs oprateurs de comparaison et
dexpressions rgulires, dont les plus courants sont prsents dans le Tableau 10.1.
Notez bien quil ne sagit pas dune liste complte ; en cas de besoin, reportez-vous au
manuel de MySQL.

Tableau 10.1 : Les oprateurs de comparaison utiles dans les clauses WHERE

Oprateur Nom (si possible) Exemple Description


= galit idclient = 3 Teste si deux valeurs sont gales.
> Suprieur montant > 60.00 Teste si une valeur est suprieure
une autre.
< Infrieur montant < 60.00 Teste si une valeur est infrieure
une autre.
Chapitre 10 Travailler avec une base de donnes MySQL 263

Tableau 10.1 : Les oprateurs de comparaison utiles dans les clauses WHERE (suite)

Oprateur Nom (si possible) Exemple Description


>= Suprieur ou gal montant >= 60.00 Teste si une valeur est suprieure
ou gale une autre.
<= Infrieur ou gal montant <= 60.00 Teste si une valeur est infrieure
ou gale une autre.
!= ou <> Diffrent de quantit != 0 Teste si deux valeurs sont
diffrentes.
IS NOT NULL adresse is not null Teste si un champ contient une
valeur.
IS NULL adresse is null Teste si un champ ne contient
aucune valeur.
BETWEEN montant between 0 Teste si une valeur se trouve dans
and 60.00 un intervalle spcifi.
IN ville in ("Carlton", Teste si une valeur se trouve dans
"Moe") un ensemble spcifi.
NOT IN ville not in Teste si une valeur ne se trouve
("Carlton","Moe") pas dans un ensemble spcifi.
LIKE Concordance de motif nom like ("Fred%") Teste si une valeur correspond
un motif spcifi.
NOT LIKE Concordance de motif nom not like Teste si une valeur ne correspond
("Fred%") pas un motif spcifi.
REGEXP Expression rgulire nom regexp Teste si une valeur correspond
une expression rgulire.

Les trois dernires lignes de ce tableau font rfrence LIKE et REGEXP, qui effectuent
des comparaisons de motifs.
LIKE utilise la concordance de motif de SQL. Les motifs peuvent contenir du texte classi-
que, plus les caractres % et . Le caractre % sert de joker pour indiquer une correspon-
dance sur un nombre quelconque (ventuellement nul) de caractres, et correspond
nimporte quel caractre unique.
Le mot-cl REGEXP est utilis pour les recherches de correspondances ralises avec
des expressions rgulires. MySQL utilise les expressions rgulires POSIX. Vous
pouvez aussi vous servir de RLIKE la place de REGEXP, car ce sont deux synonymes.
Les expressions rgulires POSIX sont celles que nous avons prsentes au Chapi-
tre 4).
264 Partie II Utilisation de MySQL

Vous pouvez tester plusieurs critres en les associant avec AND et OR. Par exemple :
select *
from clients
where idclient = 3 or idclient = 4;

Rcuprer des donnes dans plusieurs tables


Pour rpondre une question pose la base de donnes, il faut souvent rcuprer des
donnes dans plusieurs tables. Si, par exemple, vous souhaitez connatre les clients qui
ont pass des commandes au cours du mois courant, vous devez examiner la table
clients et la table commandes. En outre, si vous souhaitez savoir prcisment ce quils
ont command, vous devez galement examiner la table livres commandes.
Ces lments se trouvent dans diffrentes tables puisquils correspondent des objets
rels diffrents. Cest lun des principes de conception que nous avons vus au Chapitre 8.
Pour rassembler ces informations avec SQL, vous devez effectuer une opration appe-
le jointure. Cette opration revient simplement runir plusieurs tables en fonction
des relations qui existent entre leurs donnes. Par exemple, si nous souhaitons afficher
les commandes effectues par Julie Dupont, nous devons commencer par rechercher
lidclient de Julie dans la table clients, puis rechercher les commandes correspondant
cet idclient dans la table commandes.
Bien que les oprations de jointure soient conceptuellement assez simples, il sagit en
fait dune des parties les plus subtiles et les plus complexes de SQL. MySQL impl-
mente plusieurs types de jointures, adapts diffrentes situations.

Jointure simple de deux tables


Commenons par tudier le code SQL pour la requte dont nous venons de parler,
propos de Julie Dupont :
select commandes.idcommande, commandes.montant, commandes.date
from clients, commande
where clients.nom = Julie Dupont
and clients.idclient = commandes.idclient;

Le rsultat de cette requte est le suivant :


+------------+---------+------------+
| idcommande | montant | date |
+------------+---------+------------+
| 1 | 69.99 | 2007-04-02 |
| 4 | 24.99 | 2007-05-01 |
+------------+---------+------------+

Nous pouvons remarquer plusieurs choses intressantes.


Tout dabord, comme il faut runir les informations des deux tables pour rpondre
cette requte, nous avons indiqu ces deux tables dans la requte.
Chapitre 10 Travailler avec une base de donnes MySQL 265

Ce faisant, nous avons prcis un type de jointure sans le savoir. En effet, la virgule qui
spare les noms des tables est quivalente INNER JOIN ou CROSS JOIN. Il sagit dun
type de jointure parfois appel jointure complte ou produit cartsien de deux tables.
Ce type de jointure signifie littralement : " partir des tables indiques, crer une seule
grande table qui doit contenir une ligne pour chaque combinaison possible des
lignes de ces tables, que cela ait un sens ou non." En dautres termes, nous obtenons
une table contenant toutes les lignes de la table clients associes toutes les lignes de
la table commandes, quelles que soient les commandes effectues par les clients.
Cette opration brutale na pas beaucoup de sens dans la plupart des cas. En effet, on
souhaite le plus souvent ne retenir que les lignes qui ont un sens, cest--dire ici les
commandes passes par un client qui correspondent ce client.
Pour obtenir ce rsultat, il suffit dajouter une condition de jointure dans la clause
WHERE. Ce type dinstruction conditionnelle spciale exprime la relation qui doit exister
entre les deux tables. Ici, notre condition de jointure est la suivante :
clients.idclient = commandes.idclient
Elle demande MySQL de ne placer dans la table finale que les lignes dont le idclient
de la table clients correspond au idclient de la table commandes.
En ajoutant cette condition de jointure notre requte, nous avons cr un autre type de
jointure, appel qui-jointure.
Vous avez galement remarqu la notation avec le point, qui permet de prciser sans
ambigut la table dont proviennent les colonnes : clients.idclient fait rfrence la
colonne idclient de la table clients et commandes.idclient fait rfrence la colonne
idclient de la table commandes.
Cette notation est ncessaire lorsque le nom dune colonne est ambigu, cest--dire sil
apparat dans plusieurs tables.
En outre, cette notation pointe peut galement tre utilise pour lever les ambiguts
sur des noms de colonnes de bases de donnes diffrentes. Dans cet exemple, nous nous
sommes servis de la notation table.colonne, mais il est galement possible dy ajouter
le nom dune base de donnes (base de donnes.table.colonne), par exemple pour
tester une condition comme celle-ci :
livres.commandes.idclient = autre_bd.commandes.idclient

Enfin, vous pouvez vous servir de cette notation pour toutes les rfrences de colonnes dans
une requte. Cest gnralement conseill, surtout lorsque vos requtes deviennent un peu
plus complexes car, mme si ce nest pas impos par MySQL, cela facilite beaucoup la lisi-
bilit et la maintenance des requtes. Vous remarquerez dailleurs que nous avons respect
cette convention dans le reste de la requte prcdente, par exemple dans la condition :
clients.nom = Julie Dupont
266 Partie II Utilisation de MySQL

La colonne nom nexistant que dans la table clients, nous navions pas rellement
besoin de prciser la table dont elle provient. Pour les utilisateurs qui relisent le code,
en revanche, la rfrence nom seule reste vague et elle devient plus claire sous la forme
clients.nom.

Jointures de plus de deux tables


Cette opration nest pas plus complexe que la jointure de deux tables. Dune manire
gnrale, les tables doivent tre jointes deux deux avec des conditions de jointure.
Vous pouvez considrer que cela revient respecter les relations qui existent entre les
donnes des tables.
Par exemple, si nous souhaitons connatre les clients qui ont command des livres sur
Java (ventuellement pour pouvoir leur envoyer des informations sur un nouveau livre
sur ce langage), nous devons suivre ces relations dans plusieurs tables.
Nous devons commencer par reprer les clients qui ont pass au moins une commande
contenant un Livres Commandes correspondant un livre sur Java. Pour passer de la table
clients la table commandes, nous pouvons nous servir de la colonne idclient, comme
nous lavons dj fait. Pour passer de la table commandes la table Livres Commandes,
nous pouvons utiliser idcommande. Pour obtenir dans la table Livres Commandes un livre
spcifique de la table livres, nous pouvons nous servir du numro ISBN. Aprs avoir
tabli toutes ces relations, nous pouvons chercher les livres dont le titre contient "Java" et
renvoyer les noms des clients qui ont achet lun de ces livres.
Voyons maintenant le code de cette requte :
select clients.nom
from clients, commandes, livres_commandes, livres
where clients.idclient = commandes.idclient
and commandes.idcommande = livres_commandes.idcommande
and livres_commandes.isbn = livres.isbn
and livres.titre like %Java%;

Cette requte renvoie le rsultat suivant :


+-----------------+
| nom |
+-----------------+
| Julie Dupont |
+-----------------+

Vous remarquerez que nous avons suivi les donnes dans quatre tables diffrentes. Pour
faire cela avec une qui-jointure, nous avons besoin de trois conditions de jointure
diffrentes. Comme il faut gnralement une condition de jointure pour chaque paire de
tables que vous souhaitez runir, il y a au total une jointure de moins que le nombre
de tables joindre. Cette rgle est assez utile pour dboguer les requtes qui ne fonc-
tionnent pas. Vrifiez vos conditions de jointure et assurez-vous que vous respectez
Chapitre 10 Travailler avec une base de donnes MySQL 267

bien les enchanements ncessaires pour obtenir ce que vous vouliez partir des infor-
mations que vous avez donnes.

Trouver les lignes qui ne correspondent pas


Lautre type de jointure principal dont vous aurez besoin est la jointure gauche.
Dans les exemples prcdents, seules les lignes vrifiant les conditions dans toutes les
tables taient retenues. Il arrive cependant que lon ait besoin des lignes qui ne corres-
pondent pas ces conditions, par exemple pour rechercher les clients qui nont pass
aucune commande ou les livres qui nont jamais t achets.
La mthode la plus simple pour rpondre ce type de question avec MySQL consiste
utiliser une jointure gauche. Ce type de jointure renvoie en effet les lignes qui satis-
font la condition de jointure entre deux tables. Sil ny a aucune ligne correspondante
dans la table de droite, une ligne est ajoute dans la table des rsultats, contenant des
valeurs NULL dans les colonnes de droite.
Prenons un exemple :
select clients.idclient, clients.nom, commandes.idcommande
from clients left join commandes
on clients.idclient = commandes.idclient;

Cette requte SQL se sert dune jointure gauche pour regrouper les tables clients et
commandes. Vous remarquerez que la jointure gauche utilise une syntaxe lgrement
diffrente pour sa condition de jointure : elle se trouve ici dans une clause ON spciale
de linstruction SQL.
Voici le rsultat de cette requte :
+-----------+-----------------+------------+
| idclient | nom | idcommande |
+-----------+-----------------+------------+
| 3 | Julie Smith | 1 |
| 3 | Julie Smith | 4 |
| 4 | Alain Wong | NULL |
| 5 | Michelle Arthur | 1 |
+-----------+-----------------+------------+

Ce rsultat ne montre que les clients qui ont des idclient non NULL.
Si vous ne voulez connatre que les clients qui nont pass aucune commande, il suffit de
rechercher ces valeurs NULL dans la cl primaire de la table correspondante (idcommande,
ici), puisque ce champ ne devrait tre NULL dans aucune des lignes :
select clients.idclient, clients.nom
from clients left join commandes
using (idclient)
where commandes.idcommande is null;
268 Partie II Utilisation de MySQL

Voici le rsultat obtenu :


+----------+-----------------+
| idclient | nom |
+----------+-----------------+
| 4 | Alain Wong |
| 5 | Michelle Arthur |
+----------+-----------------+

Vous remarquerez que nous nous sommes galement servis dune syntaxe diffrente
pour la condition de jointure de cet exemple. Les jointures gauche acceptent en effet
soit la syntaxe ON que nous avons utilise dans le premier exemple, soit la syntaxe USING
du second exemple. La syntaxe USING ne prcisant pas la table do provient lattribut
de jointure, les colonnes des deux tables doivent porter le mme nom lorsque vous
voulez utiliser cette clause.
Vous pouvez galement rpondre ce type de question en utilisant des sous-requtes,
que nous prsenterons plus loin dans ce chapitre.

Utiliser dautres noms pour les tables : les alias


Il est souvent pratique, et parfois indispensable, de pouvoir faire rfrence aux tables
avec dautres noms, que lon appelle des alias. Vous pouvez les crer au dbut dune
requte et les utiliser dans tout le reste de cette requte. Ils servent souvent de raccour-
cis pour les noms des tables, comme dans cet exemple qui nest quune rcriture dune
requte que nous avons dj prsente :
select cli.nom
from clients as cli, commandes as cde, livres_commandes as lc,
livres as l
where cli.idclient = cde.idclient
and cde.idcommande = lc.idcommande
and lc.isbn = l.isbn
and l.titre like %Java%;

Lorsque nous dclarons les tables que nous allons utiliser, nous ajoutons une clause
AS pour dclarer lalias dune table. Il est galement possible de dfinir des alias
pour des colonnes, mais nous y reviendrons lorsque nous verrons les fonctions
dagrgation.
Il faut passer par les alias pour raliser une jointure dune table avec elle-mme. Cela a
lair plus difficile et plus trange que cela ne lest en ralit. Cette approche peut tre
utile, si, par exemple, nous voulons trouver dans une table les lignes qui possdent des
valeurs en commun. Ainsi, pour trouver les clients qui habitent dans la mme ville
(ventuellement pour diffuser des publicits), nous pouvons affecter deux alias la
mme table (clients) :
select c1.nom, c2.com, c1.ville
from clients as c1, clients as c2
Chapitre 10 Travailler avec une base de donnes MySQL 269

where c1.ville = c2.ville


and c1.nom!= c2.nom;

Dans cette requte, nous faisons comme si la table clients reprsentait en fait deux
tables diffrentes, c1 et c2, et nous effectuons une jointure sur la colonne ville. Vous
remarquerez que nous avons galement besoin de la deuxime condition, c1.nom!=
c2.nom, pour viter que chaque client ne vrifie la condition (puisque chaque client
habite videmment dans la mme ville que lui).

Rcapitulatif sur les jointures


Les diffrents types de jointures sont prsents dans le Tableau 10.2. Il en existe
dautres, mais ce tableau rassemble celles que vous utiliserez le plus souvent.

Tableau 10.2 : Les types de jointures dans MySQL

Nom Description

Produit cartsien Toutes les combinaisons de toutes les lignes des tables de la jointure.
Ce type de jointure est choisi en plaant une virgule entre les noms des
tables et en ne spcifiant aucune clause WHERE.

Jointure complte Comme ci-dessus.

Jointure croise Comme ci-dessus. Peut galement tre utilise en utilisant la clause
CROSS JOIN entre les noms des tables de la jointure.

Jointure interne Smantiquement quivalente la virgule. Elle peut galement tre


indique laide de la clause INNER JOIN. Sans condition WHERE, elle est
quivalente produit cartsien. Gnralement, on utilise galement une
condition WHERE pour en faire une vritable jointure interne.

qui-jointure Utilise un test dgalit pour associer les lignes des diffrentes tables de
la jointure. En SQL, cest une jointure avec une clause WHERE.

Jointure gauche Tente dassocier des lignes provenant des tables indiques et remplit les
lignes ne correspondant pas avec la valeur NULL. Utilise dans SQL
avec les clauses LEFT JOIN. Elle permet de trouver des valeurs
manquantes. Vous pouvez utiliser de la mme manire RIGHT JOIN pour
faire une jointure droite.

Rcuprer les donnes dans un ordre particulier


Si vous souhaitez afficher les lignes renvoyes par une requte dans un ordre particulier,
vous pouvez vous servir de la clause ORDER BY de linstruction SELECT. Celle-ci permet
de prsenter la sortie obtenue dans un format plus lisible.
270 Partie II Utilisation de MySQL

La clause ORDER BY trie les lignes dune ou de plusieurs colonnes de la clause SELECT.
Par exemple :
select nom, adresse
from clients
order by nom;

Cette requte renvoie les noms et les adresses des clients, en les triant par ordre alphab-
tique des noms :
+-----------------+--------------------+
| nom | adresse |
+-----------------+--------------------+
| Alain Wong | 147 Avenue Haines |
| Julie Dupont | 25 rue noire |
| Melissa Jones | |
| Michel Archer | 12 Avenue plate |
| Michelle Arthur | 357 rue de Paris |
+-----------------+--------------------+

Vous remarquerez que, dans ce cas, les noms tant au format prnom nom de famille, ils
sont tris en fait daprs le prnom. Si vous souhaitez les trier daprs le nom de famille, il
faut sparer les prnoms et les noms de famille, et les mettre dans deux champs diffrents.
Par dfaut, lordre de tri est croissant. Vous pouvez le prciser explicitement laide du
mot-cl ASC :
select nom, adresse
from clients
order by nom asc;

Mais il est galement possible de trier par ordre dcroissant, en spcifiant le mot-cl DESC :
select nom, adresse
from clients
order by nom desc;

Vous pouvez aussi trier sur plusieurs colonnes, ou vous servir des alias des colonnes, ou
mme de leur position dans la table (par exemple, 3 correspond la troisime colonne
de la table) au lieu de leur nom.

Groupement et agrgation des donnes


Il faut souvent dterminer le nombre de lignes qui appartiennent un ensemble particu-
lier ou la valeur moyenne dune colonne (par exemple le montant moyen des comman-
des). MySQL possde plusieurs fonctions dagrgation qui se rvlent trs utiles pour
rpondre ce type de requte.
Ces fonctions dagrgation peuvent tre appliques une table prise comme un ensemble
ou un groupe de donnes dans une table.
Chapitre 10 Travailler avec une base de donnes MySQL 271

Les fonctions dagrgation les plus utilises sont prsentes dans le Tableau 10.3.

Tableau 10.3 : Les fonctions dagrgation de MySQL

Nom Description
AVG (colonne) Moyenne des valeurs de la colonne indique.
COUNT (lment) Si vous indiquez une colonne, cette fonction renvoie le nombre de
valeurs non NULL de cette colonne. Si vous ajoutez le mot DISTINCT
devant le nom de la colonne, vous obtiendrez le nombre de valeurs
distinctes dans cette colonne uniquement. Si vous utilisez COUNT(*),
vous obtiendrez un compte global, indpendamment des valeurs
NULL.
MIN (colonne) Plus petite valeur de la colonne indique.
MAX(colonne) Plus grande valeur de la colonne indique.
STD (colonne) cart-type des valeurs de la colonne indique.
STDDEV (colonne) Identique STD(colonne).
SUM (colonne) Somme des valeurs de la colonne indique.

Voyons maintenant quelques exemples, en commenant par celui que nous avons
mentionn plus haut. Nous pouvons calculer la moyenne des commandes comme ceci :
select avg(montant)
from commandes;

Ce qui fournit la sortie suivante :


+--------------+
| avg(montant) |
+--------------+
| 54.985002 |
+--------------+

Pour obtenir des informations plus dtailles, nous pouvons nous servir de la clause
GROUP BY. Celle-ci va nous permettre, par exemple, dafficher la moyenne des comman-
des de chaque client. Grce ce mcanisme, nous pouvons connatre le client qui a
dpens le plus dargent :
select idclient, avg(montant)
from commandes
group by idclient;

Lorsque vous utilisez la clause GROUP BY avec une fonction dagrgation, cette clause
modifie le comportement de la fonction. Au lieu de fournir la moyenne des montants
272 Partie II Utilisation de MySQL

des commandes de toute la table, cette requte fournit la moyenne des montants des
commandes pour chaque client (ou, plus prcisment, pour chaque idclient) :
+----------+--------------+
| idclient | avg(montant) |
+----------+--------------+
| 1 | 49.990002 |
| 2 | 74.980003 |
| 3 | 47.485002 |
+----------+--------------+

En SQL ANSI, si vous utilisez une clause GROUP BY, les seuls lments qui peuvent
apparatre dans la clause SELECT sont les fonctions dagrgation et les colonnes indi-
ques dans la clause GROUP BY. En outre, si vous voulez utiliser une colonne dans une
clause GROUP BY, celle-ci doit apparatre dans la clause SELECT.
MySQL accorde en fait un peu plus de libert. Il accepte une syntaxe tendue qui permet
de ne pas spcifier des lments dans la clause SELECT si vous ne souhaitez pas les y mettre.
Nous pouvons galement tester le rsultat dune agrgation laide dune clause HAVING.
Celle-ci doit tre indique immdiatement aprs la clause GROUP BY et elle fonctionne
comme une clause WHERE qui ne sappliquerait quaux groupes et aux agrgats.
Pour poursuivre notre exemple prcdent, nous pouvons nous servir de la requte
suivante pour connatre les clients dont la moyenne des commandes est suprieure
50 euros :
select idclient, avg(montant)
from commandes
group by idclient
having avg(montant) > 50;

La clause HAVING sapplique aux groupes. Cette requte renvoie donc le rsultat suivant :
+----------+--------------+
| idclient | avg(montant) |
+----------+--------------+
| 2 | 74.980003 |
+----------+--------------+

Choisir les lignes renvoyer


La clause LIMIT de linstruction SELECT peut tre particulirement utile dans les applica-
tions web. Elle permet dindiquer les lignes du rsultat qui seront renvoyes. Cette clause
prend deux paramtres : le numro de ligne de dpart et le nombre de lignes renvoyer.
La requte suivante met en uvre la clause LIMIT :
select nom
from clients
limit 2, 3;
Chapitre 10 Travailler avec une base de donnes MySQL 273

Cette requte peut tre interprte comme : "Slectionne les noms des clients et renvoie
3 lignes partir de la deuxime ligne du rsultat." Vous remarquerez que les lignes sont
numrotes partir de 0, cest--dire que la premire ligne du rsultat est la ligne 0.
Ceci est trs utile pour les applications web, car on peut ainsi nafficher, par exemple,
que 10 articles par page lorsque lon prsente un catalogue aux clients.
Notez cependant que LIMIT ne fait pas partie du standard ANSI SQL. Il sagit dune
extension MySQL : en lutilisant, vous rendez votre code SQL incompatible avec la
plupart des autres SGBDR.

Utiliser des sous-requtes


Une sous-requte est une requte imbrique dans une autre requte. Si la plupart des fonc-
tionnalits des sous-requtes peuvent tre obtenues en utilisant attentivement des jointures
et des tables temporaires, les sous-requtes sont gnralement plus simples lire et
crire.

Sous-requtes lmentaires
Lusage le plus courant des sous-requtes consiste utiliser le rsultat dune requte
dans une comparaison dune autre requte. Vous pouvez, par exemple, utiliser la requte
suivante pour retrouver la plus grosse commande :
select idclient, montant
from commandes
where montant = (select max(montant) from commandes);
Cette requte donne le rsultat suivant :
+----------+---------+
| idclient | montant |
+----------+---------+
| 2 | 74.98 |
+----------+---------+
Dans ce cas, la sous-requte renvoie une seule valeur (le montant maximal) qui est utili-
se ensuite pour la comparaison dans la requte externe. Il sagit dun bon exemple
dusage de sous-requte, car cette requte particulire ne peut pas tre reproduite de
manire lgante en utilisant des jointures en ANSI SQL.
Vous obtiendrez toutefois le mme rsultat avec la jointure suivante :
select idclient, montant
from commandes
order by montant desc
limit 1;
Mais, parce quelle sappuie sur LIMIT, cette requte nest pas compatible avec la plupart
des SGBDR. Cependant, elle sexcutera plus efficacement sur MySQL que la version
avec une sous-requte.
274 Partie II Utilisation de MySQL

Lune des principales raisons pour lesquelles MySQL a tant tard proposer des sous-
requtes tient au nombre trs rduit doprations quelles vous permettent de raliser.
Techniquement, vous pouvez crer une seule requte ANSI SQL ayant le mme effet,
mais qui sappuie sur un hack inefficace appel MAX-CONCAT.
Vous pouvez utiliser des valeurs de sous-requte de cette manire avec tous les opra-
teurs de comparaison classiques et il existe galement certains oprateurs de comparai-
son spcifiques aux sous-requtes que nous dcrirons dans la section suivante.

Sous-requtes et oprateurs
Il existe cinq oprateurs spcifiques aux sous-requtes. Quatre dentre eux sont utiliss
avec les sous-requtes standard et un (EXISTS) nest gnralement utilis quavec des
sous-requtes corrles. Nous en traiterons dans la prochaine section. Les quatre opra-
teurs de sous-requte standard sont prsents dans le Tableau 10.4.

Tableau 10.4 : Oprateurs de sous-requte

Nom Syntaxe dexemple Description


ANY SELECT c1 FROM t1 WHERE c1 > ANY (SELECT c1 FROM t2); Renvoie true si la
comparaison est vraie
pour lune des lignes
de la sous-requte.
IN SELECT c1 FROM t1 WHERE c1 IN SELECT c1 from t2); quivalent de =ANY.
SOME SELECT c1 FROM t1 WHERE c1 > SOME (SELECT c1 FROM t2); Alias de ANY.
ALL SELECT c1 FROM t1 WHERE c1 > ALL (SELECT c1 from t2); Renvoie true si la
comparaison est vraie
pour toutes les lignes
de la sous-requte.

Chacun de ces oprateurs ne peut apparatre quaprs un oprateur de comparaison,


lexception de IN, o loprateur de comparaison (=) est en quelque sorte "intgr".

Sous-requtes corrles
Dans les sous-requtes corrles, les choses se compliquent un peu, car vous pouvez
utiliser des lments de la requte externe dans la requte interne. Par exemple :
select isbn, titre
from livres
where not exists
(select *
from livres_commandes
where livres_commandes.isbn = livres.isbn);
Chapitre 10 Travailler avec une base de donnes MySQL 275

Cette requte illustre lutilisation des sous-requtes corrles et du dernier oprateur de


sous-requte spcifique, EXISTS. Elle rcupre tous les livres qui nont jamais t
commands (ces informations sont identiques celles retrouves prcdemment
laide dune jointure gauche). Notez que la clause FROM de requte interne ninclut que
la table livres commandes mais que cette sous-requte fait galement rfrence
livres.isbn. En dautres termes, la requte interne fait rfrence aux donnes de la
requte externe, ce qui est la dfinition mme dune sous-requte corrle. Vous recher-
chez en fait les lignes internes qui correspondent (ou, dans le cas prsent, ne correspondent
pas) aux lignes externes.
Loprateur EXISTS renvoie true sil existe des lignes correspondantes dans la sous-
requte. Inversement, NOT EXISTS renvoie true sil nexiste pas de ligne correspondante
dans la sous-requte.

Sous-requtes de ligne
Toutes les sous-requtes que nous avons tudies jusqu prsent retournaient une seule
valeur, correspondant gnralement true ou false (comme dans lexemple prc-
dent avec EXISTS). Les sous-requtes de ligne renvoient une ligne entire, qui peut
ensuite tre compare des lignes entires dans la requte externe. Cette mthode est
gnralement adopte pour rechercher des lignes dans une table qui existent galement
dans une autre table. Aucun exemple intressant ne peut tre trouv dans la base de
donnes livres, mais on peut fournir un exemple dutilisation de la syntaxe de la
manire suivante :
select c1, c2, c3
from t1
where (c1, c2, c3) in (select c1, c2, c3 from t2);

Utiliser une sous-requte comme table temporaire


Vous pouvez utiliser une sous-requte dans la clause FROM dune requte externe. Cette
approche vous permet dinterroger le rsultat de la sous-requte en la traitant comme
une table temporaire.
Sous sa forme la plus simple, ce type de sous-requte se prsente comme suit :
select * from
(select idclient, nom from clients where ville = Bordeaux)
as clients_bordeaux;

Notez quici nous plaons la sous-requte dans la clause FROM. Juste aprs la parenthse
fermante de la sous-requte, vous devez donner le rsultat de la sous-requte sous
forme dalias que vous pourrez ensuite traiter comme nimporte quelle autre table dans
la requte externe.
276 Partie II Utilisation de MySQL

Mise jour des enregistrements de la base de donnes


Outre la rcupration des donnes dans la base de donnes, une autre opration classi-
que consiste les modifier. Par exemple, nous pouvons avoir besoin daugmenter le
prix des livres dans la base de donnes. Pour cela, il existe linstruction UPDATE.
La syntaxe de UPDATE est la suivante :
UPDATE [LOW_PRIORITY] [IGNORE] nom_table
SET colonne1=expression1,colonne2=expression2,...
[WHERE condition]
[ORDER BY critres_tri]
[LIMIT nombre]

Cette instruction met jour la table nom table en modifiant toutes les colonnes indi-
ques avec les expressions fournies. Vous pouvez restreindre une instruction UPDATE
certaines lignes avec une clause WHERE et limiter le nombre total de lignes affectes avec
une clause LIMIT. ORDER BY nest gnralement utilis quen conjonction avec une
clause LIMIT ; par exemple, si vous devez ne mettre jour que les dix premires lignes,
vous devez pralablement les placer dans un ordre particulier. Si les clauses
LOW PRIORITY et IGNORE sont utilises, elles fonctionnent de la mme manire que dans
une instruction INSERT.
Passons maintenant quelques exemples.
Si nous souhaitons augmenter tous les prix de 10 %, nous pouvons utiliser une instruction
UPDATE sans clause WHERE :
update livres
set prix = prix * 1.1;

Si, en revanche, nous ne souhaitons modifier quune seule ligne (par exemple pour
changer ladresse dun client), nous pouvons nous servir de la requte suivante :
update clients
set adresse = 250 rue Olsens
where idclient = 4;

Modification des tables aprs leur cration


Non seulement nous pouvons modifier le contenu dune table, mais nous pouvons
galement modifier sa structure. Pour cela, on utilise linstruction ALTER TABLE, dont la
syntaxe est la suivante :
ALTER TABLE [IGNORE] nom_table modification [, modification ...]

En SQL ANSI, il nest possible dapporter quune seule modification par instruction
ALTER TABLE mais, avec MySQLn vous pouvez en faire autant que vous le souhaitez.
Chaque clause de modification peut servir modifier diffrents aspects de la table.
Chapitre 10 Travailler avec une base de donnes MySQL 277

Si la clause IGNORE est utilise et que vous essayiez deffectuer une modification qui
duplique des cls primaires, la premire ira dans la table modifie et les autres seront
supprimes. Si cette clause nest pas indique (par dfaut), la modification chouera et
sera annule. Les diffrents types de modifications que vous pouvez apporter avec cette
instruction sont prsents dans le Tableau 10.5.

Tableau 10.5 : Les modifications possibles avec linstruction ALTER TABLE

Syntaxe Description
ADD [COLUMN] description colonne Ajoute une nouvelle colonne lemplacement
[FIRST | AFTER colonne ] indiqu (sil nest pas indiqu, la colonne est
ajoute la fin). Notez que description colonne
ncessite un nom et un type, tout comme une
instruction CREATE.
ADD [COLUMN] (description colonne, Ajoute une ou plusieurs colonnes la fin de la table.
description colonne,...)
ADD INDEX [index] (colonne,...) Ajoute un index dans la table, sur les colonnes
indiques.
ADD [CONSTRAINT [symbole]] PRIMARY Transforme les colonnes indiques en cl primaire
KEY (colonne,...) de la table. La notation CONSTRAINT ne concerne
que les tables utilisant des cls trangres. Pour
plus dinformations ce sujet, consultez le
Chapitre 13.
ADD UNIQUE [CONSTRAINT [symbole]] Ajoute un index unique dans la table, sur les
[index] (colonne,...) colonnes indiques. La notation CONSTRAINT ne
concerne que les tables InnoDB utilisant des cls
trangres. Pour plus dinformations ce sujet,
consultez le Chapitre 13.
ADD [CONSTRAINT] [symbole]] FOREIGN Ajoute une cl trangre une table InnoDB.
KEY [index] (index col, )
[dfinition rfrence]
ALTER [COLUMN] colonne {SET DEFAULT Ajoute ou supprime une valeur par dfaut pour une
valeur | DROP DEFAULT} colonne particulire.
CHANGE [COLUMN] colonne Modifie la colonne indique en lui affectant la
description nlle colonne nouvelle description. Vous pouvez vous en servir
pour modifier le nom dune colonne, puisque la
description dune colonne contient son nom.
MODIFY [COLUMN] description colonne Comme CHANGE. Permet de modifier le type dune
colonne, pas son nom.
DROP [COLUMN] colonne Supprime la colonne indique.
278 Partie II Utilisation de MySQL

Tableau 10.5 : Les modifications possibles avec linstruction ALTER TABLE (suite)

Syntaxe Description
DROP PRIMARY KEY Supprime lindex principal (mais pas la colonne).
DROP INDEX index Supprime lindex indiqu.
DROP FOREIGN KEY cl Supprime la cl trangre (mais pas la colonne).
DISABLE KEYS Dsactive la mise jour de lindex.
ENABLE KEYS Active la mise jour de lindex.
RENAME [AS] nom nlle table Renomme une table.
ORDER BY nom col Recre la table avec les lignes dans un ordre
particulier (notez quaprs avoir modifi la table les
lignes ne seront plus dans lordre).
CONVERT TO CHARACTER SET jdc COLLATE Convertit toutes les colonnes texte avec le jeu de
odc caractres et lordre de classement indiqus.
[DEFAULT] CHARACTER SET cs COLLATE c Dfinit le jeu de caractres et lordre de classement
par dfaut.
DISCARD TABLESPACE Supprime le fichier despace de tables sous-jacent
pour une table InnoDB (pour plus dinformations
sur les tables InnoDB, voir le Chapitre 13).
IMPORT TABLESPACE Recre le fichier despace de tables sous-jacent
pour une table InnoDB (pour plus dinformations
sur les tables InnoDB, voir le Chapitre 13).
options table Permet de rinitialiser les options de table. Utilise
la mme syntaxe que CREATE TABLE.

Voyons maintenant quelques utilisations courantes de ALTER TABLE.


Il arrive assez souvent que lon se rende compte quune colonne nest pas assez grande
pour les donnes quelle contient. Par exemple, dans notre table clients, nous avons
choisi des noms de 50 caractres au maximum. Aprs avoir ajout quelques donnes, il
se peut que nous nous rendions compte que certains noms font plus de 50 caractres et
quils sont tronqus. Pour corriger ce problme, il suffit de modifier le type de la
colonne et de choisir une largeur de 75 caractres :
alter table clients
modify nom char(70) not null;

Il arrive aussi que lon ait besoin dajouter une colonne. Imaginons par exemple quune
taxe sur les livres soit ajoute et que Book-O-Rama ait besoin dajouter le montant de
Chapitre 10 Travailler avec une base de donnes MySQL 279

cette taxe au total des commandes. Nous pouvons ajouter une colonne taxe dans la
table commandes, comme ceci :
alter table commandes
add taxe float(6,2) after montant;
Pour supprimer une colonne, servez-vous de la requte suivante :
alter table commandes
drop taxe;

Supprimer des enregistrements de la base de donnes


La suppression des lignes est trs simple. Vous pouvez vous servir de linstruction
DELETE, dont la syntaxe est la suivante :
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM nom_table
[WHERE condition]
[ORDER BY cols_tri]
[LIMIT nombre]
Si vous crivez uniquement :
delete from nom_table;
toutes les lignes de la table seront supprimes ! En gnral, on prfre ne supprimer que
certaines lignes, indiques dans la clause WHERE. Par exemple, il faut supprimer une
ligne si un livre nest plus disponible ou si un client na pass aucune commande depuis
un certain temps :
delete from clients
where idclient = 5;
La clause LIMIT permet de limiter le nombre maximal de lignes supprimer.

Supprimer des tables


Il peut galement arriver que vous souhaitiez supprimer une table de votre base de donnes.
Vous pouvez le faire laide de linstruction DROP TABLE. Sa syntaxe est trs simple :
DROP TABLE nom_table;
Elle supprime toutes les lignes de la table et la table elle-mme. Il convient donc de
faire attention lorsque vous lutilisez. ORDER BY est gnralement utilise en conjonction
avec LIMIT.

Supprimer une base de donnes entire


Vous pouvez mme supprimer lintgralit dune base de donnes avec linstruction
DROP DATABASE, dont la syntaxe est la suivante :
DROP DATABASE base_de_donnes;
280 Partie II Utilisation de MySQL

Elle supprime toutes les lignes, toutes les tables, tous les index et la base de donnes
elle-mme. Il va donc sans dire quelle doit tre utilise avec prcaution !

Pour aller plus loin


Dans ce chapitre, nous avons prsent les oprations les plus courantes de SQL, celles
que vous utiliserez pour interagir avec une base de donnes MySQL. Au cours des deux
prochains chapitres, nous verrons comment connecter MySQL et PHP pour que vous
puissiez accder votre base de donnes partir du Web. Nous explorerons galement
quelques techniques avances de MySQL.
Si vous souhaitez vous documenter plus prcisment sur SQL, vous pouvez vous reporter
au standard SQL ANSI, disponible sur le site http://www.ansi.org/.
Pour plus de dtails sur les extensions de MySQL par rapport SQL ANSI, consultez le
site web de MySQL, http://www.mysql.com.

Pour la suite
Au Chapitre 11, nous verrons comment rendre la base de donnes Book-O-Rama
disponible sur le Web.
11
Accs une base de donnes
MySQL partir du Web avec PHP

Auparavant, lorsque nous travaillions avec PHP, nous nous servions dun fichier plat
pour enregistrer et rcuprer nos donnes. Lorsque nous avons mentionn cette appro-
che (voir Chapitre 2), nous avons galement dit que les systmes de bases de donnes
relationnelles rendent ces deux tches (enregistrement et rcupration des donnes) la
fois plus simples, plus sres et plus efficaces dans le cadre dune application web.
Maintenant que nous sommes capables de nous servir de MySQL pour crer des bases
de donnes, nous pouvons commencer connecter cette base de donnes une inter-
face web.
Dans ce chapitre, nous verrons comment accder la base de donnes de Book-O-
Rama partir du Web, en utilisant PHP. Nous expliquerons comment lire et crire dans
cette base de donnes et comment filtrer les donnes dentre susceptibles de poser
problme.

Fonctionnement des architectures de bases de donnes web


Au Chapitre 8, nous avons prsent le fonctionnement des architectures de bases de
donnes web. titre de rappel, voici les principales tapes de ce processus :
1. Le navigateur web dun utilisateur envoie une requte HTTP demandant une page
particulire. Par exemple, lutilisateur peut avoir demand de chercher tous les
livres crits par Michael Morgan laide dun formulaire HTML. La page de
recherche des rsultats sappelle resultats.php.
2. Le serveur web reoit la requte concernant resultats.php, rcupre le fichier corres-
pondant et le passe au moteur PHP afin quil y soit trait.
282 Partie II Utilisation de MySQL

3. Le moteur PHP commence analyser le script. lintrieur de celui-ci se trouve


une commande permettant de se connecter la base de donnes et dexcuter une
requte (cest--dire de rechercher les livres). PHP ouvre ensuite une connexion
vers le serveur MySQL et envoie la requte approprie.
4. Le serveur MySQL reoit la requte de base de donnes, la traite et renvoie les
rsultats obtenus (une liste de livres) au moteur PHP.
5. Le moteur PHP finit lexcution du script, consistant gnralement formater en
HTML les rsultats de la requte. Le fichier HTML obtenu est alors renvoy au
serveur web.
6. Le serveur web renvoie son tour le fichier HTML au navigateur, qui laffiche pour
que lutilisateur puisse voir la liste des livres quil a demande.
Maintenant que nous possdons une base de donnes MySQL, nous pouvons crire le code
PHP permettant dexcuter les tapes prcdentes. Nous commencerons par le formu-
laire de recherche. Il sagit dun formulaire en HTML classique, comme celui du
Listing 11.1.

Listing 11.1 : recherche.html La page de recherche dans la base de donnes


de Book-O-Rama

<html>
<head>
<title>Recherche dans le catalogue de Book-O-Rama</title>
</head>

<body>
<h1>Recherche dans le catalogue de Book-O-Rama</h1>

<form action="resultats.php" method="post">


Choisissez un type de recherche&nbsp;:<br />
<select name="type_recherche">
<option value="auteur">Par auteur</option>
<option value="titre">Par titre</option>
<option value="isbn">Par ISBN</option>
</select>
<br />
Entrez le terme recherch&nbsp;:<br />
<input name="terme_recherche" type="text" size="40" />
<br />
<input type="submit" value="Rechercher" />
</form>

</body>
</html>
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 283

Ce formulaire HTML est trs simple. Sa sortie est prsente la Figure 11.1.

Figure 11.1
Le formulaire de recherche
est trs gnral puisquil
permet de chercher un
livre partir de son titre,
de son auteur ou de son
code ISBN.

Le script appel lorsque lutilisateur clique sur le bouton Rechercher sappelle resul-
tats.php ; son code est celui du Listing 11.2. Tout au long de ce chapitre, nous allons
expliquer le but et le fonctionnement de ce script.

Listing 11.2 : resultats.php Le script qui rcupre les rsultats de notre base de donnes
MySQL et qui les formate pour les afficher correctement

<html>
<head>
<title>Rsultats de la recherche dans Book-O-Rama</title>
</head>
<body>
<h1>Rsultats de la recherche dans Book-O-Rama</h1>
<?php
// Cration de variables aux noms abrgs
$type_recherche = $_POST[type_recherche];
$terme_recherche = trim($_POST[terme_recherche]);

if (!$type_recherche ||!$terme_recherche) {
echo "Vous navez pas saisi les dtails de la recherche";
exit;
}

if (!get_magic_quotes_gpc()) {
$type_recherche = addslashes($type_recherche);
$terme_recherche = addslashes($terme_recherche);
}

@$db = new mysqli(localhost, bookorama, bookorama123, livres);

if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}
284 Partie II Utilisation de MySQL

$requete = "select * from livres where " . $type_recherche .


" like %" . $terme_recherche . "%";
$resultat = $db->query($requete);

$nb_lig_resultat = $resultat->num_rows;

echo "<p>Nombre de livres trouvs&nbsp;: " . $nb_lig_resultat . "</p>";

for ($i = 0; $i < $nb_lig_resultat; $i++) {


$ligne = $resultat->fetch_assoc();
echo "<p><strong>" . ($i+1) . ". Titre&nbsp;: ";
echo htmlspecialchars(stripslashes($ligne[titre]));
echo "</strong><br />Auteur&nbsp;: ";
echo stripslashes($ligne[auteur]);
echo "<br />ISBN&nbsp;: ";
echo stripslashes($ligne[isbn]);
echo "<br />Prix&nbsp;: ";
echo stripslashes($ligne[prix]);
echo </p>;
}

$resultat->free();
$db->close();

?>
</body></html>

Vous remarquerez que ce script vous permet dentrer les caractres joker de MySQL %
et (blanc soulign), ce qui peut tre utile pour lutilisateur. Si cela pose problme,
vous pouvez protger ces caractres.
La Figure 11.2 illustre les rsultats de ce script.

Figure 11.2
Les rsultats de la recherche
des livres sur Java dans
la base de donnes sont
prsents dans une page web
grce au script resultats.php.
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 285

Principales tapes dans linterrogation dune base de donnes partir


du Web
Dans tous les scripts utiliss pour accder une base de donnes partir du Web, il faut
respecter les tapes suivantes :
1. Vrifier et filtrer les donnes fournies par lutilisateur.
2. tablir une connexion vers la base de donnes approprie.
3. Interroger la base de donnes.
4. Rcuprer les rsultats.
5. Prsenter les rsultats lutilisateur.
Ce sont ces tapes que nous avons suivies dans le script resultats.php et nous allons
maintenant les tudier une par une.

Vrifier et filtrer les donnes saisies par lutilisateur


Nous commenons le script en supprimant tous les espaces que lutilisateur peut avoir
saisis par inadvertance au dbut ou la fin de ses donnes. Pour cela, nous appliquons la
fonction trim() $ POST[terme recherche] avant de lui associer un nom plus court :
$terme_recherche = trim($_POST[terme_recherche]);

Ltape suivante consiste vrifier que lutilisateur a bien entr une expression
rechercher et quil a slectionn un type de recherche. Vous remarquerez que nous
effectuons cette vrification aprs avoir supprim les espaces aux deux extrmits du
terme recherch : si nous inversions ces deux oprations, nous ne pourrions pas dtecter
le cas o lutilisateur a saisi uniquement des espaces et nous ne pourrions donc pas afficher
un message derreur puisque ces espaces nauraient pas t supprims par trim() :
if (!$type_recherche ||!$terme_recherche) {
echo "Vous navez pas saisi les dtails de la recherche."
exit;
}

Vous remarquerez que nous vrifions aussi la variable $type recherche, bien quelle
provienne dans notre cas dune instruction SELECT de HTML. Vous vous demandez
peut-tre pourquoi nous prenons la peine de vrifier des variables qui doivent tre
remplies automatiquement. Il est trs important de se rappeler quil peut exister
plusieurs interfaces votre base de donnes. Amazon, par exemple, possde plusieurs
filiales qui se servent de leur interface de recherche. En outre, il est important de filtrer
les donnes pour viter tout problme de scurit provenant des diffrentes interfaces
mises la disposition des utilisateurs pour saisir leurs donnes.
286 Partie II Utilisation de MySQL

Si vous comptez utiliser des donnes saisies par les utilisateurs, il faut les filtrer pour en
supprimer tous les caractres de contrle. Pour cela, utilisez les fonctions addslashes(),
stripslashes() et get magic quotes gpc() que nous avons vues au Chapitre 4. Vous
devez protger les donnes lorsque vous soumettez une entre utilisateur dans une base de
donnes comme MySQL.
Ici, il faut tester le rsultat de la fonction get magic quotes gpc(), qui vous indique si
la mise entre apostrophes est automatique. Si ce nest pas le cas, protgez les donnes
avec addslashes() :
if (!get_magic_quotes_gpc()) {
$type_recherche = addslashes($type_recherche);
$terme_recherche = addslashes($terme_recherche);
}

Vous devez galement utiliser stripslashes() sur les donnes qui proviennent de la base
de donnes. Si la fonctionnalit des apostrophes automatiques est active, les donnes
provenant de la base contiennent en effet des barres obliques que vous devez retirer.
Nous utilisons galement la fonction htmlspecialchars() pour encoder les caractres
qui ont une signification particulire en HTML. Nos donnes de test actuelles ne contien-
nent aucun de ces caractres (&, <, >, ou "), mais il existe plusieurs titres de livres qui
contiennent le symbole &. Grce cette fonction, nous pouvons liminer de futures
erreurs.

tablissement de la connexion
La bibliothque PHP pour se connecter MySQL sappelle mysqli (le i signifie improved,
cest--dire amlior). Vous avez le choix entre une syntaxe oriente objet ou une
syntaxe procdurale.
Dans le script, cest la ligne suivante qui nous permet de nous connecter au serveur
MySQL :
@$db = new mysqli(localhost, bookorama, bookorama123, livres);

Celle-ci cre une instance de la classe mysqli et une connexion lhte localhost
avec le nom dutilisateur bookorama et le mot de passe bookorama123. Cette
connexion est configure de manire utiliser la base de donnes appele livres.
Avec cette approche oriente objet, vous pouvez maintenant invoquer des mthodes sur
cet objet afin daccder la base de donnes. Si vous prfrez lapproche procdurale,
utilisez la ligne suivante pour crer la mme connexion :
@$db = mysqli_connect(localhost, bookorama, bookorama123,
livres);
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 287

Au lieu dun objet, cet appel renvoie alors une ressource qui reprsente la connexion
la base de donnes. Si vous utilisez lapproche procdurale, vous devrez passer cette
ressource tous les autres appels des fonctions mysqli. Ce mcanisme est trs semblable
celui des fonctions sur les fichiers comme fopen().
La plupart des fonctions mysqli ont une interface oriente objet et une interface procdu-
rale. En gnral, les diffrences tiennent ce que les noms de fonction de la version proc-
durale commencent par mysqli et exigent que vous passiez le descripteur que vous avez
obtenu de mysqli connect(). Les connexions de la base de donnes font exception cette
rgle car elles peuvent tre effectues par le constructeur de lobjet mysqli.
Il est prfrable de vrifier le rsultat de votre tentative de connexion, car rien dans le
reste du code ne fonctionnera si la connexion la base de donnes na pas fonctionn.
Pour cela, vous pouvez utiliser le code suivant :
if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}

Ce code est identique pour la version oriente objet et la version procdurale. La fonc-
tion mysqli connect errno() renvoie un numro derreur en cas derreur et zro en
cas de succs.
Lorsque vous vous connectez la base de donnes, commencez la ligne de code avec
loprateur de suppression derreur, @. Cette approche vous permettra de grer les
erreurs avec lgance (cela peut galement tre ralis avec des exceptions, que nous
navons pas utilises dans cet exemple simple).
Noubliez pas que le nombre de connexions MySQL simultanes est limit par le param-
tre MySQL max connections. Lintrt de ce paramtre et du paramtre Apache
MaxClients associ est de permettre au serveur de rejeter les nouvelles demandes de
connexion lorsquun ordinateur commence tre surcharg ou lors dun problme logiciel.
Vous pouvez modifier la valeur par dfaut de ces deux paramtres en modifiant les
fichiers de configuration. Pour modifier MaxClients dans Apache, ditez le fichier
httpd.conf de votre systme. Pour changer le paramtre max connections de MySQL,
modifiez le fichier my.conf.

Choisir une base de donnes utiliser


Vous vous rappelez que, lorsque nous utilisons MySQL partir de la ligne de
commande, nous devons lui indiquer la base de donnes que nous avons lintention
dutiliser, avec une commande comme celle-ci :
use livres;
288 Partie II Utilisation de MySQL

Cette tape est aussi ncessaire lorsque nous nous connectons partir du Web.
La base de donnes utiliser est indique en paramtre du constructeur mysqli ou de la
fonction mysqli connect(). Si vous souhaitez modifier la base de donnes par dfaut,
vous pouvez le faire avec la fonction mysqli select db() :
$db->select_db(nom_base)
ou comme ceci :
mysqli_select_db(descripteur, nom_base)
Vous pouvez remarquer ici la similarit avec les fonctions que nous avons dcrites
auparavant : la version procdurale commence avec mysqli et requiert le descripteur
de la connexion en paramtre.

Interroger la base de donnes


Pour raliser la requte, vous pouvez utiliser mysql query(). Cependant, avant dappeler
cette fonction, il vaut mieux construire la requte que vous voulez excuter :
$requete = "select * from livres where " .
$type_recherche . "like %$terme_recherche%";
Ici, nous recherchons les donnes saisies par lutilisateur ($terme recherche) dans le
champ quil a indiqu ($type recherche). Vous remarquerez que nous avons utilis
loprateur like au lieu de lgalit : il est gnralement prfrable dtre assez tolrant
pour les recherches dans les bases de donnes.

ASTUCE
Il est important de bien comprendre que les requtes que vous envoyez MySQL nont pas
besoin de se terminer par un point-virgule, contrairement aux requtes que vous saisissez
dans le moniteur de MySQL.

Nous pouvons maintenant excuter la requte :


$resultat = $db->query($requte);
Si vous souhaitez utiliser linterface procdurale, utilisez cette syntaxe :
$resultat = mysqli_query($db, $requte);
Ici, vous passez la requte que vous souhaitez excuter et, dans linterface procdurale,
le descripteur de la base de donnes ($db).
La version oriente objet renvoie un objet rsultat, tandis que la version procdurale
renvoie un descripteur de rsultat (ce systme est semblable au fonctionnement de la
connexion). Dans les deux cas, vous stockez ce rsultat dans une variable ( $resultat)
pour pouvoir lutiliser plus tard. Cette fonction renvoie false en cas dchec.
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 289

Rcuprer les rsultats de la requte


Il existe plusieurs fonctions permettant de rcuprer les rsultats partir de lobjet ou
du descripteur de rsultat. Cet objet ou ce descripteur sont essentiels pour accder aux
lignes renvoyes par la requte.
Dans cet exemple, vous avez compt le nombre de lignes et utilis galement la fonction
mysqli fetch assoc().
Lorsque vous utilisez lapproche oriente objet, le nombre de lignes est stock dans le
membre num rows de lobjet rsultat. Vous pouvez y accder de la manire suivante :
$nb_lig_resultat = $resultat->num_rows;

Lorsque vous utilisez lapproche procdurale, la fonction mysqli num rows() donne le
nombre de lignes retournes par la requte. Il faut lui passer lidentificateur de rsultat,
comme ceci :
$nb_lig_resultat = mysql_num_rows($result);

Cette information est intressante : si nous avons lintention de traiter ou dafficher les
rsultats, nous pouvons ainsi savoir combien il y en a et les traiter dans une boucle :
for ($i = 0; $i < $nb_lig_resultat; $i++) {
// Traitement du rsultat
}

chaque itration de cette boucle, nous appelons $resultat >fetch assoc() (ou
mysqli fetch assoc()). Cette boucle ne sera donc pas excute le rsultat de la
requte ne contenait aucune ligne. La fonction fetch assoc() prend chaque ligne du
rsultat et la renvoie sous la forme dun tableau associatif o les cls correspondent aux
noms de colonnes et les valeurs sont les valeurs de ces colonnes :
$ligne = $resultat->fetch_assoc();

Vous pouvez aussi utiliser une approche procdurale :


$ligne = mysqli_fetch_assoc($resultat);

partir du tableau associatif $ligne, nous pouvons parcourir chaque champ et lafficher
de manire approprie, comme ici :
echo "<br />ISBN&nbsp;: ;
echo stripslashes($ligne[isbn]);

Comme nous lavons dj vu, nous nous servons de stripslashes() pour filtrer les
valeurs avant de les afficher.
Il existe plusieurs manires de rcuprer les lignes partir de lobjet ou du descripteur
de rsultat. Au lieu de passer par un tableau associatif, nous pouvons placer chaque
ligne dans un tableau classique avec mysql fetch row(), comme ici :
$ligne = $resultat->fetch_row();
290 Partie II Utilisation de MySQL

ou
$ligne = mysqli_fetch_row($resultat);
Les valeurs des colonnes seront alors les valeurs $ligne[0], $ligne[1], etc. La fonc-
tion mysqli fetch array() permet dextraire une ligne comme lun ou lautre de ces
deux types de tableaux.
Vous pouvez galement rcuprer une ligne sous la forme dun objet avec la fonction
mysql fetch object() :
$ligne = $result->fetch_object();
ou
$ligne = mysqli_fetch_object($resultat);
Vous pouvez ensuite accder chacun des champs avec $ligne >titre, $ligne
>auteur, etc.

Dconnexion de la base de donnes


Vous pouvez librer lespace occup par le rsultat en appelant :
$resultat->free();
ou
mysqli_free_result($resultat);
Vous pouvez ensuite utiliser :
$db->close();
ou
mysqli_close($db);
pour fermer la connexion la base de donnes. Lutilisation de cette commande nest
pas strictement ncessaire, car la connexion est de toute faon ferme lorsquun script
termine son excution.

Ajouter des informations dans la base de donnes


Linsertion de nouveaux lments dans la base de donnes ressemble beaucoup leur
rcupration. Il faut en effet suivre les mmes tapes : tablir une connexion, envoyer
une requte et vrifier les rsultats. Ici, vous devrez envoyer une requte INSERT au lieu
dune requte SELECT.
Bien que le code soit relativement similaire, il peut tre utile de consulter un exemple
de rfrence. La Figure 11.3 montre un petit formulaire HTML qui permet dajouter de
nouveaux livres dans la base de donnes.
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 291

Figure 11.3
Linterface permettant
dajouter de nouveaux
livres dans la base de
donnes.

Le code HTML de cette page est prsent dans le Listing 11.3.

Listing 11.3 : nouveau_livre.html Le code HTML de la page dajout de livres

<html>
<head>
<title>Book-O-Rama - Ajout dun nouveau livre</title>
</head>

<body>
<h1>Book-O-Rama - Ajout dun nouveau livre</h1>

<form action="insertion_livre.php" method="post">


<table border="0">
<tr>
<td>ISBN</td>
<td><input type="text" name="isbn" maxlength="13"
size="13"><br /></td>
</tr>
<tr>
<td>Auteur</td>
<td> <input type="text" name="auteur" maxlength="30"
size="30"><br /></td>
</tr>
<tr>
<td>Titre</td>
<td> <input type="text" name="titre" maxlength="60"
size="30"><br></td>
</tr>
<tr>
<td>Prix</td>
<td><input type="text" name="prix" maxlength="7"
size="7"><br /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Enregistrer"></td>
</tr>
</table>
</form>
</body>
</html>
292 Partie II Utilisation de MySQL

Les donnes de ce formulaire sont transmises au script insertion_livre.php, qui


soccupe des dtails, effectue quelques validations mineures et tente dcrire les infor-
mations dans la base de donnes. Le code de ce script se trouve dans le Listing 11.4.

Listing 11.4 : insertion_livre.php Le script qui crit les nouveaux livres dans la base
de donnes

<html>
<head>
<title>Book-O-Rama Rsultat de lajout dun livre</title>
</head>
<body>
<h1>Book-O-Rama Rsultat de lajout dun livre</h1>
<?php
// Cration de variables aux noms abrgs
$isbn = $_POST[isbn];
$auteur = $_POST[auteur];
$titre = $_POST[titre];
$prix = $_POST[prix];

if (!$isbn ||!$auteur ||!$titre ||!$prix) {


echo "Vous navez pas indiqu tous les dtails requis.<br />";
exit;
}

if (!get_magic_quotes_gpc())
{
$isbn = addslashes($isbn);
$auteur = addslashes($auteur);
$titre = addslashes($titre);
$prix = doubleval($prix);
}

@$db = mysql_pconnect(localhost, bookorama, bookorama123,


livres);

if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}

$requete = "insert into livres values


(".$isbn., ".$auteur., ".$titre., ".$prix.);
$resultat = $db->query($requete);

if ($resultat) {
echo $db->affected_rows. " livre insr dans la base de donnes.";
} else {
echo "Une erreur sest produite. Le livre na pas t ajout.";
}

$db->close();
?>
</body></html>
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 293

Le rsultat dune insertion russie est prsent la Figure 11.4.

Figure 11.4
Le script se termine correctement et indique que le livre a t ajout la base de donnes.

Si vous examinez le code de insertion_livre.php, vous constaterez quil ressemble beau-


coup au script que nous avons crit pour rcuprer des informations de la base de
donnes. Nous vrifions que tous les champs du formulaire sont correctement remplis
et nous les formatons (si ncessaire) avec addslashes() pour quils puissent tre ajouts
dans la base de donnes :
if (!get_magic_quotes_gpc()) {
$isbn = addslashes($isbn);
$auteur = addslashes($auteur);
$titre = addslashes($titre);
$prix = doubleval($prix);
}

Comme le prix de chaque livre est enregistr dans la base de donnes sous la forme
dun nombre virgule flottante, il ne doit contenir aucune barre oblique. Nous pouvons
filtrer ce caractre et tous les autres caractres gnants avec doubleval(), que nous
avons dj vue au Chapitre 1. Cela permet en outre de supprimer tous les symboles
montaires que lutilisateur aurait pu saisir dans le formulaire.
Une fois encore, nous nous sommes connects la base de donnes en instanciant
lobjet mysqli et en configurant une requte envoyer cette base. Ici, il sagit dune
requte SQL INSERT :
$requete = "insert into livres values
(".$isbn., ".$auteur., ".$titre., ".$prix.);
$resultat = $db->query($requete);
Cette requte est excute sur la base de donnes en appelant $db >query() (ou
mysqli query() si vous adoptez lapproche procdurale).
Une diffrence importante entre lutilisation de INSERT et de SELECT rside dans lutili-
sation de mysqli affected rows(). Il sagit dune fonction dans la version procdurale
ou dune variable de classe dans la version oriente objet :
echo $db->affected_rows . " livre ajout la base de donnes.";
294 Partie II Utilisation de MySQL

Dans le script prcdent, nous nous tions servis de mysqli num rows() pour dtermi-
ner le nombre de lignes renvoyes par SELECT. Lorsque vous crivez des requtes qui
modifient la base de donnes, comme INSERT, DELETE ou UPDATE, vous devez vous
servir de mysql affected rows().

Utiliser des instructions prpares


La bibliothque mysqli reconnat les instructions prpares, qui permettent dacclrer
les excutions rptes dune mme requte avec des donnes diffrentes. Elles offrent
en outre une protection contre les attaques par injection SQL.
Lide fondamentale dune instruction prpare est que vous envoyez un modle de la
requte que vous souhaitez excuter MySQL, puis que vous transmettez les donnes
sparment. Vous pouvez envoyer plusieurs lots de donnes la mme instruction
prpare ; cette capacit est particulirement utile pour les insertions en masse.
Voici comment utiliser des instructions prpares dans le script insertion livre.php :
$requete = "insert into livres values(?,?,?,?)";
$instr = $db->prepare($requete);
$instr->bind_param("sssd", $isbn, $auteur, $titre, $prix);
$instr->execute();
echo $instr->affected_rows. livre insr dans la base de donnes.";
$instr->close();

tudions ce code ligne par ligne.


Au lieu de mettre les variables dans la requte comme prcdemment, on place des
points dinterrogation pour chaque lment de donnes. Il ne faut mettre aucune apos-
trophe ni aucun autre dlimiteur autour de ces points dinterrogation.
La seconde ligne est un appel $db >prepare(), qui sappelle mysqli stmt prepare()
dans sa version procdurale. Cette ligne construit un objet ou un descripteur dinstruction
que vous utiliserez pour raliser le traitement lui-mme.
Lobjet instruction possde une mthode appele bind param() (dans la version proc-
durale, il sagit de mysqli stmt bind param()). Son rle consiste indiquer PHP
quelles variables doivent venir remplacer les points dinterrogation. Le premier para-
mtre est une chane de format qui fonctionne un peu la manire de celle utilise dans
printf(). La valeur que vous passez ici ("sssd") signifie que les quatre paramtres
sont, respectivement, une chane ("s" comme string, en anglais), une chane, une chane
et un double. Les autres caractres possibles de cette chane de format sont i pour le
type entier et b pour BLOB. Aprs ce paramtre, vous devez numrer le mme nombre
de variables quil y a de points dinterrogation dans votre instruction. Ils seront remplacs
selon leur ordre dapparition.
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 295

Lappel $instr >execute() (mysqli stmt execute() dans la version procdurale)


excute la requte. Vous pouvez ensuite accder au nombre de lignes affectes et fermer
linstruction.
Lintrt de cette instruction prpare est que vous pouvez dsormais modifier les valeurs
des quatre variables lies puis rexcuter linstruction sans avoir la reprparer. Cette fonc-
tionnalit permet donc de traiter des insertions massives laide dune simple boucle.
Vous pouvez galement lier les rsultats. Pour les requtes de type SELECT, vous pouvez
utiliser $instr >bind result() (ou mysqli stmt bind result()) pour fournir une
liste de variables dans lesquelles vous souhaitez placer les colonnes du rsultat.
chaque appel de $instr >fetch() (ou mysqli stmt fetch()), les valeurs des colonnes
de la ligne suivante du rsultat viendront remplir ces variables lies. Par exemple, dans le
script de recherche de livre que nous avons examin plus haut, vous pourriez utiliser :
$instr->bind_result($isbn, $auteur, $titre, $prix);
pour lier ces quatre variables aux quatre colonnes renvoyes par la requte. Aprs avoir
appel :
$instr->execute();
vous pouvez appeler :
$instr->fetch();
dans la boucle. chaque fois que cette fonction est appele, elle extrait la ligne
suivante du rsultat et lutilise pour remplir les quatre variables lies.
Vous pouvez utiliser mysqli stmt bind param() et mysqli stmt bind result()
dans le mme script.

Autres interfaces PHP pour les bases de donnes


PHP dispose de plusieurs bibliothques lui permettant de se connecter diverses bases
de donnes, comme Oracle, Microsoft SQL Server et PostgreSQL.
En gnral, les principes pour se connecter une base de donnes et pour lui envoyer des
requtes restent les mmes. Les noms des fonctions peuvent varier, tout comme les fonc-
tionnalits offertes par les diffrentes SGBDR mais, si vous pouvez vous connecter
MySQL, vous devriez tre capable de vous adapter nimporte quel autre environnement.
Si vous souhaitez utiliser une base de donnes ne possdant aucune bibliothque spci-
fique pour PHP, vous pouvez toujours passer par les fonctions ODBC (Open Database
Connectivity) gnriques. ODBC est un standard pour les connexions des bases de
donnes mais, pour des raisons videntes, il ne dispose que de fonctionnalits limites.
Lorsquun systme doit possder une compatibilit maximale, il ne peut pas exploiter
toutes les caractristiques de chaque systme.
296 Partie II Utilisation de MySQL

Outre les bibliothques fournies avec PHP, il existe des classes dabstraction pour les
bases de donnes, comme MDB2, qui permettent dutiliser les mmes noms de fonctions
pour tous les SGBDR.

Utilisation dune interface de base de donnes gnrique :


PEAR::MDB2
Nous allons nous intresser un petit exemple utilisant la couche dabstraction MDB2,
qui est lun des composants de PEAR le plus utilis. Si cette couche dabstraction nest
pas dj installe sur votre systme, consultez la partie de lAnnexe A consacre
linstallation de PEAR.
des fins de comparaison, examinons la manire dont nous aurions crit le script de
recherche avec MDB2.

Listing 11.5 : resultats_generique.php Rcupre les rsultats dune recherche


dans une base de donnes MySQL et les formate pour affichage

<html>
<head>
<title>Book-O-Rama Rsultats de la recherche</title>
</head>
<body>
<h1>Book-O-Rama Rsultats de la recherche</h1>
<?php
// Cration de variables aux noms abrgs
$type_recherche = $_POST[type_recherche];
$terme_recherche = trim($_POST[terme_recherche]);
// Cration de variables aux noms abrgs
$type_recherche = $_POST[type_recherche];
$terme_recherche = trim($_POST[terme_recherche]);

if (!$type_recherche ||!$terme_recherche) {
echo "Vous navez pas saisi les dtails de la recherche";
exit;
}

if (!get_magic_quotes_gpc()) {
$type_recherche = addslashes($type_recherche);
$terme_recherche = addslashes($terme_recherche);
}

// Configuration de PEAR MDB2


require_once(MDB2.php);
$utilisateur = bookorama;
$mdp = bookorama123;
$hote = localhost;
$nom_base = livres;

// Cration dune chane de connexion universelle ou DSN


// (Data Source Name)
$dsn = "mysqli://".$utilisateur.":".$mdp."@".$hote."/".$nom_base;
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 297

// Connexion la base
$db = &MDB2::connect($dsn);

// Teste la connexion
if (MDB2::isError($db)) {
echo $db->getMessage();
exit;
}

// Cration et excution de la requte


$requete = "select * from livres where " . $type_recherche .
"like %" . $terme_recherche . "%";

$resultat = $db->query($requete);

// Teste le rsultat
if (MDB2::isError($resultat)) {
echo $db->getMessage();
exit;
}

// Rcupre le nombre de lignes du rsultat


$nb_lig_resultat = $resultat->numRows();

// Affiche toutes les lignes du rsultat


for ($i = 0; $i < $nb_lig_resultat; $i++) {
$ligne = $resultat->fetchRow(MDB2_FETCHMODE_ASSOC);
echo "<p><strong>" . ($i+1) . ". Titre&nbsp;: ";
echo htmlspecialchars(stripslashes($ligne[titre]));
echo "</strong><br />Auteur&nbsp;: ";
echo stripslashes($ligne[auteur]);
echo "<br />ISBN&nbsp;: ";
echo stripslashes($ligne[isbn]);
echo "<br />Prix&nbsp;: ";
echo stripslashes($ligne[prix]);
echo </p>;
}
// Dconnexion de la base
$db->disconnect();
?>
</body>
</html>

Examinons les diffrences qui apparaissent dans ce script par rapport la version mysqli.
Pour nous connecter la base de donnes, nous nous servons de la ligne suivante :
$db = MDB2::connect($dsn);

Cette fonction prend en paramtre une chane de connexion universelle qui contient
toutes les informations indispensables pour se connecter une base de donnes. On
sen rend compte lorsquon examine le format de la chane de connexion :
$dsn = "mysqli://" . $utilisateur . ":" . $mdp .
"@". $hote . "/" . $nom_base";
298 Partie II Utilisation de MySQL

Puis nous vrifions le bon tablissement de la connexion avec la mthode isError() ; en


cas de problme, nous affichons le message derreur et nous arrtons lexcution du script :
if (DB::isError($db)) {
echo $db->getMessage();
exit;
}
Si tout sest bien pass, nous construisons une requte et nous lexcutons de la manire
suivante :
$resultat = $db->query($query);
Nous pouvons vrifier le nombre de lignes retournes :
$nb_lig_resultat = $resultat->numRows();
Nous rcuprons chaque ligne de la manire suivante :
$ligne = $resultat->fetchRow(MDB2_FETCHMODE_ASSOC);
La mthode gnrique fetchRow() peut rcuprer les lignes sous plusieurs formats ; le
paramtre MDB2 FETCHMODE ASSOC indique que nous souhaitons ici que la ligne soit
renvoye sous forme de tableau associatif.
Aprs le traitement des lignes du rsultat, nous fermons la connexion la base de donnes :
$db->disconnect();
Comme vous pouvez le voir, cet exemple gnrique ressemble beaucoup notre
premier script.
Lintrt de MDB2 est quil suffit de connatre un seul ensemble de fonctions de base de
donnes et que le code ne ncessitera donc que peu de modifications en cas de change-
ment du logiciel de base de donnes.
Ce livre tant consacr MySQL, nous ne nous servirons que des bibliothques natives
de MySQL pour des raisons de rapidit dexcution et de flexibilit. Cependant, le
recours une couche dabstraction peut parfois se rvler extrmement pratique.

Pour aller plus loin


Pour plus dinformations sur les connexions MySQL/PHP, reportez-vous aux sections
appropries des manuels de PHP et de MySQL.
Vous trouverez plus dinformations sur ODBC sur la page http://www.webope-
dia.com/TERM/O/odbc.html.

Pour la suite
Au prochain chapitre, nous nous intresserons aux dtails de ladministration MySQL
et nous verrons comment optimiser les bases de donnes.
12
Administration MySQL avance

Dans ce chapitre, nous prsenterons quelques aspects plus techniques de MySQL,


comme les privilges avancs, la scurit et loptimisation.

Les dtails du systme des privilges


Au cours du Chapitre 9, nous avons vu comment configurer des utilisateurs et leur attri-
buer des privilges avec la commande GRANT. Si vous avez lintention dadministrer une
base de donnes MySQL, il peut tre intressant de comprendre exactement comment
fonctionne cette commande et ce quelle fait rellement.

Lorsque vous excutez une commande GRANT, celle-ci modifie les tables dune base de
donnes particulire appele mysql. Les informations de privilges sont enregistres
dans six tables de cette base de donnes. Sachant cela, lorsque vous accordez des privi-
lges sur les bases de donnes, il faut faire attention ne pas octroyer daccs injustifis
la base mysql.

Vous pouvez examiner le contenu de la base de donnes mysql en ouvrant une session
sous le compte administrateur et en excutant la commande suivante :
use mysql;

Pour afficher les tables de cette base de donnes, faites la commande suivante :
show tables;
300 Partie II Utilisation de MySQL

Vous devriez obtenir un rsultat comparable ceci :


+---------------------------+
| Tables_in_mysql |
+---------------------------+
| columns_priv |
| db |
| event |
| func |
| general_log |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| ndb_binlog_index |
| plugin |
| proc |
| procs_priv |
| servers |
| slow_log |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| user |
+---------------------------+

Chacune de ces tables contient des informations systme. Six dentre elles ( user, host,
db, tables priv, columns priv et procs priv) stockent les informations des privil-
ges, et cest pour cette raison quon les appelle parfois tables grant. La fonction spci-
fique de ces tables varie, mais leur utilisation globale reste la mme : dterminer ce que
les utilisateurs ont le droit de faire et ce quils nont pas le droit de faire. Chacune
delles contient deux types de champs : les champs de porte, qui identifient lutilisa-
teur, lhte et une partie dune base de donnes laquelle le privilge fait rfrence, et
les champs de privilges, qui identifient les actions pouvant tre effectues par
lutilisateur en question pour le champ de porte correspondant.
Les tables user et host indiquent si un utilisateur peut se connecter au serveur MySQL et
sil possde des privilges dadministration. Les tables db et host dterminent les bases de
donnes auxquelles lutilisateur peut accder. La table tables priv dtermine les tables
dune base de donnes dont lutilisateur peut se servir, la table columns priv dtermine
les colonnes de ces tables auxquelles il peut accder et la table procs priv indique les
procdures que lutilisateur a le droit dexcuter.
Chapitre 12 Administration MySQL avance 301

La table user
La table user contient les dtails des privilges globaux de lutilisateur. Elle dtermine
si lutilisateur a le droit de se connecter au serveur MySQL et sil possde des privil-
ges globaux, cest--dire des privilges valables pour toutes les bases de donnes du
systme.
Vous pouvez consulter la structure de cette table avec linstruction describe user;.
Le schma de cette table user est prsent dans le Tableau 12.1.

Tableau 12.1 : Le schma de la table user dans la base de donnes mysql

Champ Type
Host varchar(60)
User varchar(16)
Password char(16)
Select priv enum(N,Y)
Insert priv enum(N,Y)
Update priv enum(N,Y)
Delete priv enum(N,Y)
Create priv enum(N,Y)
Drop priv enum(N,Y)
Reload priv enum(N,Y)
Shutdown priv enum(N,Y)
Process priv enum(N,Y)
File priv enum(N,Y)
Grant priv enum(N,Y)
References priv enum(N,Y)
Index priv enum(N,Y)
Alter priv enum(N,Y)
Show db priv enum(N,Y)
Super priv enum(N,Y)
Create tmp table priv enum(N,Y)
Lock tables priv enum(N,Y)
302 Partie II Utilisation de MySQL

Tableau 12.1 : Le schma de la table user dans la base de donnes mysql (suite)

Champ Type
Execute priv enum(N,Y)
Repl slave priv enum(N,Y)
Repl client priv enum(N,Y)
Create view priv enum(N,Y)
Show view priv enum(N,Y)
Create routine priv enum(N,Y)
Alter routine priv enum(N,Y)
Create user priv enum(N,Y)
Event priv enum(N,Y)
Trigger priv enum(N,Y)
ssl type enum(,ANY,X509,SPECIFIED)
ssl cipher blob
x509 issuer blob
x509 subject blob
max questions int(11) unsigned
max updates int(11) unsigned
max connections int(11) unsigned
max user connections int(11) unsigned

Chaque ligne de cette table correspond un ensemble de privilges pour un utilisateur


(User) provenant dun hte (Host) particulier et ayant ouvert une session avec le mot de
passe Password. Ces colonnes (les trois premires) correspondent aux champs de
porte de cette table, puisquils dcrivent la porte des autres champs, appels les
champs de privilges.
Les privilges indiqus dans cette table (et les suivantes) correspondent ceux que nous
avons accords avec GRANT au Chapitre 8. Par exemple, Select priv correspond au
privilge qui permet dexcuter une commande SELECT.
Si un utilisateur possde un privilge particulier, la valeur dans la colonne correspon-
dante est Y. Inversement, cette colonne vaut N sil ne possde pas le privilge.
Chapitre 12 Administration MySQL avance 303

Tous les privilges numrs dans la table user sont globaux, cest--dire quils
sappliquent toutes les bases de donnes du systme (y compris la base de donnes
mysql). Par consquent, les administrateurs possdent gnralement quelques Y dans
ces colonnes, mais la majorit des utilisateurs ne doit possder que des N. Les utilisa-
teurs normaux doivent possder des privilges pour les bases de donnes dont ils
doivent se servir et non pour toutes les tables.

Les tables db et host


La plupart des privilges des utilisateurs normaux sont enregistrs dans les tables db et host.
La table db dtermine les bases de donnes auxquelles les utilisateurs peuvent accder,
ainsi que les htes partir desquels ils peuvent y accder. Les privilges indiqus dans
cette table sont valables pour toutes les bases de donnes dont le nom se trouve dans les
lignes de cette table.
La table host complte les tables user et db. Si un utilisateur doit pouvoir se connecter
une base de donnes partir de plusieurs htes, aucun hte ne sera indiqu pour cet
utilisateur dans la table user ou db. En revanche, cet utilisateur possdera un ensemble
dentres dans la table host, qui permet de prciser les privilges associs chaque
combinaison utilisateur/hte.
Les schmas de ces deux tables sont prsents, respectivement, dans les Tableaux 12.2
et 12.3.

Tableau 12.2 : Le schma de la table db de la base de donnes mysql

Champ Type
Host char(60)
Db char(64)
User char(16)
Select priv enum(N,Y)
Insert priv enum(N,Y)
Update priv enum(N,Y)
Delete priv enum(N,Y)
Create priv enum(N,Y)
Drop priv enum(N,Y)
Grant priv enum(N,Y)
304 Partie II Utilisation de MySQL

Tableau 12.2 : Le schma de la table db de la base de donnes mysql (suite)

Champ Type
References priv enum(N,Y)
Index priv enum(N,Y)
Alter priv enum(N,Y)
Create tmp tables priv enum(N,Y)
Lock tables priv enum(N,Y)
Create view priv enum(N,Y)
Show view priv enum(N,Y)
Create routine priv enum(N,Y)
Alter routine priv enum(N,Y)
Execute priv enum(N,Y)
Event priv enum(N,Y)
Trigger priv enum(N,Y)

Tableau 12.3 : Le schma de la table host de la base de donnes mysql

Champ Type
Host char(60)
Db char(64)
Select priv enum(N,Y)
Insert priv enum(N,Y)
Update priv enum(N,Y)
Delete priv enum(N,Y)
Create priv enum(N,Y)
Drop priv enum(N,Y)
Grant priv enum(N,Y)
References priv enum(N,Y)
Index priv enum(N,Y)
Chapitre 12 Administration MySQL avance 305

Tableau 12.3 : Le schma de la table host de la base de donnes mysql (suite)

Champ Type
Alter priv enum (N,Y)
Create tmp tables priv enum(N,Y)
Lock tables priv enum(N,Y)
Create view priv enum(N,Y)
Show view priv enum(N,Y)
Create routine priv enum(N,Y)
Alter routine priv enum(N,Y)
Execute priv enum(N,Y)
Trigger priv enum(N,Y)

Les tables tables_priv, columns_priv et procs_priv


Ces trois tables servent, respectivement, enregistrer les privilges au niveau des
tables, au niveau des colonnes et pour les procdures stockes.
Ces tables ont une structure lgrement diffrente des tables user, db et host. Leurs
schmas sont prsents dans les Tableaux 12.4, 12.5 et 12.6.

Tableau 12.4 : Le schma de la table tables_priv de la base de donnes mysql

Champ Type
Host char(60)
Db char(64)
User char(16)
Table name char(60)
Grantor char(77)
Timestamp timestamp(14)
Table priv set(Select, Insert, Update, Delete,
Create, Drop, Grant, References, Index,
Alter, Create View, Show View, Trigger)
Column priv set(Select, Insert, Update, References)
306 Partie II Utilisation de MySQL

Tableau 12.5 : Le schma de la table columns_priv de la base de donnes mysql

Champ Type
Host char(60)
Db char(64)
User char(16)
Table name char(64)
Column name char(64)
Timestamp timestamp(14)
Column priv set(Select, Insert, Update, References)

Tableau 12.6 : Le schma de la table procs_priv de la base de donnes mysql

Champ Type
Host char(60)
Db char(64)
User char(16)
Routine name char(64)
Routine type enum(FUNCTION, PROCEDURE)
Grantor char(77)
Proc priv set(Execute,Alter Routine, Grant)
Timestamp timestamp(14)

La colonne Grantor des tables tables priv et procs priv contient le nom de lutili-
sateur qui a fourni ce privilge lutilisateur considr. La colonne Timestamp de ces
trois tables contient la date et lheure courantes au moment o ce privilge a t
accord.

Contrle daccs : utilisation des tables de privilges par MySQL


MySQL se sert des tables des privilges pour dterminer ce quun utilisateur a le droit
de faire. Cette opration seffectue en deux tapes :
1. Vrification de la connexion. Dans cette tape, MySQL vrifie si vous avez le droit
de vous connecter compte tenu des informations de la table user, comme nous
lavons dj vu. Cette authentification prend en compte votre nom dutilisateur,
Chapitre 12 Administration MySQL avance 307

votre nom dhte et votre mot de passe. Si un nom dutilisateur est laiss vide dans
la table user, il correspond tous les utilisateurs. Les noms dhtes peuvent conte-
nir un joker (%) qui peut remplacer lintgralit du champ (dans ce cas, le % corres-
pond tous les htes) ou uniquement une partie du nom dhte (par exemple,
%.tangledweb.com.au correspond tous les htes dont le nom se termine par
.tangledweb.com.au). Si le champ du mot de passe est laiss vide, aucun mot de
passe nest ncessaire. Pour des raisons de scurit, il vaut mieux viter que la table
user contienne une ligne ne contenant aucun nom dutilisateur, aucun mot de passe
et un nom dhte uniquement compos dun joker. Si le nom dhte est vide,
MySQL se rfre la table host afin de trouver une entre user et host correspon-
dante.
2. Vrification des requtes. chaque fois que vous envoyez une requte aprs avoir
tabli une connexion, MySQL vrifie si vous avez le niveau de privilges appropri.
Le systme commence par vrifier les privilges globaux (dans la table user) ; sils
ne sont pas suffisants, il vrifie les tables db et host. Si vous navez toujours pas les
privilges suffisants, MySQL vrifie la table tables priv et enfin la table
columns priv (si lopration implique des procdures stockes, il vrifie la table
procs priv au lieu de ces deux tables).

Mise jour des privilges : quel moment les modifications prennent-elles


effet ?
Le serveur MySQL lit automatiquement les tables des privilges lors de son dmarrage
et lorsque vous excutez des instructions GRANT et REVOKE. Cependant, maintenant que
nous savons o et comment ces privilges sont enregistrs, nous pouvons les modifier
manuellement. Dans ce cas, le serveur MySQL ne remarquera pas que vous les avez
modifis.
Il faut donc indiquer au serveur quune modification est intervenue. Pour cela, vous
disposez de trois techniques. Vous pouvez utiliser la commande :
flush privileges;

linvite de MySQL (vous devez avoir ouvert une session sous le compte dun adminis-
trateur). Il sagit de la manire la plus courante pour mettre jour les privilges.
Mais vous pouvez galement utiliser :
mysqladmin flush-privileges

ou :
mysqladmin reload

partir de linvite de commande de votre systme dexploitation.


308 Partie II Utilisation de MySQL

Aprs cette opration, les niveaux de privilges globaux seront vrifis lors de la
prochaine connexion dun utilisateur. Les privilges de niveau base de donnes
seront vrifis lors de lexcution de la prochaine instruction dutilisation, et les
privilges au niveau des tables et des colonnes le seront lors de la prochaine requte
dutilisateur.

Scuriser une base de donnes MySQL


La scurit est trs importante, en particulier lorsque vous connectez une base de
donnes MySQL votre site web. Dans cette section, nous allons nous intresser aux
prcautions que vous devez prendre afin de protger votre base de donnes.

MySQL du point de vue du systme dexploitation


Sur un systme Unix, il est fortement dconseill dexcuter le serveur MySQL
(mysqld) sous le compte de lutilisateur root. En effet, cela donnerait nimporte quel
utilisateur de MySQL des droits daccs complets en lecture et en criture sur tous les
fichiers du systme. Ce point est particulirement sensible et lon a tendance loublier
un peu trop souvent. Cette erreur a notamment t mise profit pour pirater le site web
dApache (heureusement, les pirates taient amicaux et navaient pour seul but que
damliorer la scurit du site).
Il vaut donc mieux crer un utilisateur MySQL particulier pour lexcution de mysqld.
En outre, il devient alors possible de rendre les rpertoires (dans lesquels les donnes
sont enregistres) accessibles uniquement pour cet utilisateur. Dans de nombreuses
installations, le serveur est configur pour tre excut sous le compte de lutilisateur
mysql avec le groupe mysql.
Idalement, il faut aussi placer votre serveur MySQL derrire un pare-feu. De cette
manire, vous pourrez interrompre les connexions provenant dordinateurs non autori-
ss. Testez si vous pouvez vous connecter votre serveur depuis lextrieur en passant
par le port 3306, qui est le port par dfaut de MySQL et qui devrait tre bloqu par votre
pare-feu.

Mots de passe
Vrifiez que tous vos utilisateurs possdent des mots de passe (et tout particulirement
root!), que ceux-ci sont bien choisis et quils sont rgulirement modifis, comme
pour les mots de passe de votre systme dexploitation. Il vaut mieux viter les mots de
passe contenant des mots provenant dun dictionnaire et leur prfrer des combinaisons
de lettres et de chiffres.
Chapitre 12 Administration MySQL avance 309

Sil vous faut stocker des mots de passe dans des scripts, assurez-vous que seul lutili-
sateur dont le mot de passe est enregistr dans un script a le droit de le lire.
Les scripts PHP utiliss pour se connecter la base de donnes ont besoin de connatre
le mot de passe de lutilisateur concern. Il est possible de scuriser cette opration en
plaant le nom dutilisateur et le mot de passe dans un fichier appel, par exemple,
dbconnect.php, puis dinclure celui-ci lorsque vous en avez besoin. Ce fichier doit tre
soigneusement conserv lextrieur de larborescence des documents web et tre
accessible uniquement lutilisateur appropri. Noubliez pas que, si vous placez ces
informations dans un fichier .inc (ou une autre extension) dans larborescence des docu-
ments web, vous devez vrifier que votre serveur web sait que ces fichiers doivent tre
interprts comme des fichiers PHP pour quils ne saffichent pas comme du texte brut
dans un navigateur web.
Ne stockez pas les mots de passe en clair dans votre base de donnes. Les mots de passe
MySQL ne sont pas enregistrs de cette manire, mais il arrive souvent que dans le
cadre dapplications web on souhaite enregistrer les noms des comptes utilisateurs et
les mots de passe des membres du site. Vous pouvez chiffrer (de manire non rversi-
ble) vos mots de passe avec la fonction password() de MySQL. Si vous utilisez un mot
de passe chiffr dans une clause SELECT (pour ouvrir une session utilisateur), vous
devrez utiliser la mme fonction de chiffrement pour tester le mot de passe saisi par
lutilisateur.
Nous reviendrons sur cette fonctionnalit lorsque nous implmenterons des projets,
dans la Partie 5.

Privilges des utilisateurs


La connaissance du systme de privilges est essentielle. Vous devez donc bien
comprendre ce systme, ainsi que les consquences de certains privilges. Dune
manire gnrale, ne donnez pas plus de droits vos utilisateurs quils en ont rellement
besoin. Pour vous en assurer, vous pouvez examiner les tables de privilges.
Les privilges PROCESS, FILE, SHUTDOWN et RELOAD, notamment, ne doivent tre accords
quaux administrateurs, moins quil ne soit absolument ncessaire de les octroyer un
autre utilisateur. Le privilge PROCESS permet de savoir ce que font les autres utilisa-
teurs et ce quils tapent au clavier, y compris leurs mots de passe. Le privilge FILE
permet de lire et de modifier les fichiers de nimporte quel rpertoire du systme
dexploitation (y compris le fichier /etc/passwd dun systme Unix, par exemple).
Le privilge GRANT doit galement tre accord avec prcaution, puisquil permet aux
utilisateurs de partager leurs privilges avec dautres.
310 Partie II Utilisation de MySQL

Lorsque vous crez les utilisateurs, assurez-vous de ne leur accorder laccs qu partir
de lordinateur do ils seront censs ouvrir une session. Par exemple, si lun de vos
utilisateurs sappelle jeanne@localhost, tout va bien. En revanche, si cet utilisateur
sappelle simplement jeanne, il pourra ouvrir une session depuis nimporte quel ordi-
nateur et il se peut quelle ne soit pas la jeanne que vous connaissez. Pour la mme
raison, vitez demployer des jokers dans les noms dhtes.
Vous pouvez encore amliorer la scurit de votre systme en utilisant des adresses IP
la place des noms de domaines dans la table host. Cela vous pargnera bien des probl-
mes en cas de piratage de votre DNS ou, plus simplement, en cas derreur. Pour aller
encore plus loin, vous pouvez dmarrer le dmon MySQL avec loption skip name
resolve, qui demande au serveur de ne lire que les adresses IP ou localhost dans les
colonnes contenant des noms dhtes.
Il faut galement empcher les utilisateurs normaux daccder au programme mysqlad
min de votre serveur web. Comme ce programme est excut partir de la ligne de
commande, il peut poser problme au niveau des droits du systme dexploitation.

Problmes relatifs au Web


Le fait de connecter une base de donnes MySQL au Web pose certains problmes de
scurit particuliers.
Il peut tre intressant de crer un utilisateur spcial, rserv aux connexions web. De
cette manire, vous pouvez lui fournir uniquement des privilges minimaux et ne pas
lui accorder, par exemple, les privilges DROP, ALTER ou CREATE. Vous pouvez galement
lui accorder le privilge SELECT seulement sur les tables des catalogues et INSERT
uniquement pour les tables des commandes. Cest, ici aussi, une illustration du principe
de privilges minimaux.

ATTENTION
Nous avons vu au chapitre prcdent comment utiliser les fonctions addslashes() et
stripslashes() de PHP pour se dbarrasser des caractres susceptibles de poser problme
dans les chanes. Il ne faut pas oublier cette tape. Noubliez pas non plus de nettoyer les
donnes que vous envoyez MySQL. Vous vous rappelez peut-tre que nous nous sommes
servis de la fonction doubleval() pour vrifier que les donnes numriques contiennent
rellement des nombres. Il arrive souvent que lon omette cette vrification : on pense
utiliser addslashes(), mais pas toujours vrifier les valeurs numriques.

Toutes les donnes provenant des utilisateurs doivent tre vrifies. Mme si votre
formulaire HTML ne contient que des cases cocher et des boutons radio, une
Chapitre 12 Administration MySQL avance 311

personne malveillante peut trs bien modifier lURL pour tenter de pirater votre script.
Il est galement conseill de vrifier la taille des donnes reues.
Si les utilisateurs saisissent des mots de passe ou des donnes confidentielles destins
tre enregistrs dans votre base de donnes, noubliez pas que ces informations sont
transmises en clair entre le navigateur et le serveur, moins que vous nutilisiez SSL
(Secure Sockets Layer). Nous reviendrons en dtail sur SSL et son utilisation.

Obtenir plus dinformations sur les bases de donnes


Jusqu maintenant, nous nous sommes servis de SHOW et de DESCRIBE pour identifier
les tables dune base de donnes et pour numrer les colonnes de ces tables. Nous
allons prsenter dautres techniques, comme lutilisation de linstruction EXPLAIN, pour
obtenir plus dinformations sur le fonctionnement de SELECT.

Obtenir des informations avec SHOW


Nous avons dj utilis :
show tables;

pour obtenir une liste des tables dune base de donnes.


Linstruction :
show databases;

affiche la liste de toutes les bases de donnes disponibles. Vous pouvez ensuite vous
servir de SHOW TABLES pour obtenir la liste des tables de lune de ces bases :
show tables from livres;

Lorsque vous utilisez SHOW TABLES sans prciser la base de donnes, cette instruction
choisit par dfaut celle qui est en cours dutilisation.
Lorsque vous connaissez les tables, vous pouvez obtenir la liste de leurs colonnes :
show columns from commandes from livres;

Si vous ne prcisez pas la base de donnes, linstruction SHOW COLUMNS choisit par
dfaut la base de donnes en cours dutilisation. Vous pouvez aussi utiliser la convention
base.table :
show columns from livres.commandes;

Une autre variante trs intressante de linstruction SHOW permet dafficher les privilges
dun utilisateur.
Si, par exemple, vous excutez :
show grants for bookorama;
312 Partie II Utilisation de MySQL

vous obtiendrez la sortie suivante :


+-----------------------------------------------------------------------+
| Grants for bookorama@% |
+-----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO bookorama@% |
| IDENTIFIED BY PASSWORD *1ECE648641438A28E1910D0D7403C5EE9E8B0A85 |
| GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER |
| ON `livres`.* TO bookorama@% |
+-----------------------------------------------------------------------+

Les instructions GRANT qui saffichent ne sont pas ncessairement celles qui ont t
excutes pour attribuer des privilges un utilisateur particulier, mais sont plutt les
instructions quivalentes qui produiraient le niveau de privilge actuel.
Il existe en fait plus dune trentaine de variantes de linstruction SHOW. Les plus utilises
sont prsentes dans le Tableau 12.7 ; pour en connatre la liste complte, consultez la
section approprie du manuel de MySQL, http://dev.mysql.com/doc/refman/5.1/en/
show.html. Dans le tableau, toutes les occurrences de [like ou where] peuvent tre
remplaces par LIKE motif ou WHERE expression.

Tableau 12.7 : Syntaxe de linstruction SHOW

Variante Description
SHOW DATABASES [like ou where] Donne la liste de toutes les bases de donnes disponibles.
SHOW [OPEN] TABLES [FROM Donne la liste des tables de la base de donnes en cours
basededonnes] [like ou where] dutilisation ou dans la base de donnes basededonnes.
SHOW [FULL] COLUMNS FROM table Donne la liste de toutes les colonnes dune table
[FROM basededonnes] particulire dans la base de donnes en cours
[like ou where] dutilisation ou partir de la base de donnes indique.
Vous pouvez utiliser SHOW FIELDS au lieu de SHOW
COLUMNS.
SHOW INDEX FROM table [FROM Donne les dtails de tous les index dune table
basededonnes] particulire de la base de donnes en cours dutilisation
ou dans la base de donnes appele basededonnes, si
elle est spcifie. Vous pouvez galement utiliser SHOW
KEYS.
SHOW [GLOBAL | SESSION] STATUS Donne des informations sur certains lments du systme,
[like ou where] comme le nombre de threads en cours dexcution.
Une clause LIKE permet de choisir les noms de ces
lments. Par exemple, Thread% peut correspondre
Threads cached, Threads connected,
Threads created ou Threads running.
Chapitre 12 Administration MySQL avance 313

Tableau 12.7 : Syntaxe de linstruction SHOW (suite)

Variante Description
SHOW [GLOBAL | SESSION] Affiche les noms et les valeurs des variables systme de
VARIABLES [like ou where] MySQL, comme son numro de version.
SHOW [FULL] PROCESSLIST Affiche la liste de tous les processus en cours
dexcution dans le systme, cest--dire les requtes en
cours de traitement. La plupart des utilisateurs voient
uniquement leurs threads mais, sils possdent le
privilge PROCESS, ils peuvent galement voir les
processus de tous les utilisateurs, y compris les mots de
passe si ceux-ci sont prciss dans les requtes. Par
dfaut, les requtes sont tronques aprs le centime
caractre. Vous pouvez utiliser le mot-cl facultatif FULL
pour afficher lintgralit des requtes.
SHOW TABLE STATUS [FROM Affiche des informations sur chacune des tables de la
basededonnes] [like ou where] base de donnes en cours dutilisation ou sur celles de la
base de donnes basededonnes si elle est indique,
ventuellement avec des jokers. Ces informations
contiennent notamment le type des tables et la date de
leur dernire mise jour.
SHOW GRANTS FOR utilisateur Affiche les instructions GRANT ncessaires pour donner
lutilisateur son niveau actuel de privilges.
SHOW PRIVILEGES Affiche les diffrents privilges reconnus par le serveur.
SHOW CREATE DATABASE Affiche une instruction CREATE DATABASE qui crerait la
basededonnes base de donnes indique.
SHOW CREATE TABLE nomtable Affiche une instruction CREATE TABLE qui crerait la
table indique.
SHOW [STORAGE] ENGINES Affiche les moteurs de stockage disponibles dans
linstallation et indique le moteur de stockage par dfaut
(nous reviendrons sur les moteurs de stockage au
Chapitre 13).
SHOW INNODB STATUS Affiche des donnes concernant ltat actuel du moteur
de stockage InnoDB.
SHOW WARNINGS [LIMIT [dcalage,] Affiche toutes les erreurs, tous les avertissements et
nombre lignes] toutes les notifications produites par la dernire
instruction qui a t excute.
SHOW ERRORS [LIMIT [dcalage,] Naffiche que les erreurs produites par la dernire
nombre lignes] instruction qui a t excute.
314 Partie II Utilisation de MySQL

Obtenir des informations sur les colonnes avec DESCRIBE


Outre linstruction SHOW COLUMNS, vous pouvez utiliser linstruction DESCRIBE, qui est
semblable linstruction DESCRIBE dOracle (un autre RDBMS). En voici la syntaxe
principale :
DESCRIBE table [colonne];

Cette instruction fournit des informations sur toutes les colonnes de la table ou sur une
colonne particulire si colonne est prcise. Il est possible de recourir des jokers pour
les noms des colonnes.

Comprendre le fonctionnement des requtes avec EXPLAIN


Linstruction EXPLAIN peut tre utilise de deux manires. Tout dabord, vous pouvez
utiliser :
EXPLAIN table;

Cette instruction renvoie un rsultat comparable celui de DESCRIBE table ou de SHOW


COLUMNS FROM table.
La seconde forme de EXPLAIN, la plus intressante, permet de voir exactement comment
MySQL value une requte SELECT. Pour lutiliser de cette manire, il suffit de placer le
mot-cl EXPLAIN devant une instruction SELECT.
Vous pouvez utiliser linstruction EXPLAIN pour dboguer une requte complexe qui ne
fonctionne pas correctement ou lorsque lexcution dune requte prend trop de temps.
Si vous mettez en uvre des requtes complexes, vous pouvez commencer par tracer
leur fonctionnement avant dexcuter rellement la requte. Grce au rsultat de cette
instruction, vous pouvez mme corriger des requtes et les optimiser, si ncessaire.
Il sagit aussi dun trs bon outil dapprentissage.
Par exemple, essayez dexcuter la requte suivante sur la base de donnes de Book-O-
Rama :
explain
select clients.nom
from clients, commandes, livres_commandes, livres
where clients.idclient = commandes.idclient
and commandes.idcommande = livres_commandes.idcommande
and livres_commandes.isbn = livres.isbn
and livres.titre like %Java%;

Cette requte produit la sortie suivante (notez que nous laffichons sous forme verti-
cale parce que les lignes de la table sont trop larges pour tenir dans ce livre ; vous
pouvez obtenir ce format en faisant terminer votre requte par \G au lieu dun point-
virgule).
Chapitre 12 Administration MySQL avance 315

*************************** 1. row ***************************


id: 1
select_type: SIMPLE
table: commandes
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra:
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: livres_commandes
type: ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: livres.commandes.idcommande
rows: 1
Extra: Using index
*************************** 3. row ***************************
id: 1
select_type: SIMPLE
table: clients
type: ALL
possible_keys: PRIMARY
key: NULL
key_len: NULL
ref: NULL
rows: 3
Extra: Using where; Using join buffer
*************************** 4. row ***************************
id: 1
select_type: SIMPLE
table: livres
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 13
ref: livres.livres_commande.isbn
rows: 1
Extra: Using where

Bien que cette sortie puisse paratre droutante au premier abord, elle se rvle trs
utile. Examinons les colonnes de cette table une une.
La premire colonne, id, fournit lidentifiant de linstruction SELECT dans la requte
laquelle cette ligne se rfre.
316 Partie II Utilisation de MySQL

La colonne select type explique le type de requte utilis. Lensemble de valeurs


possibles pour cette colonne est prsent dans le Tableau 12.8.
Tableau 12.8 : Valeurs possibles de select_type dans la sortie de EXPLAIN

Type Description
SIMPLE Requte SELECT standard, comme dans cet exemple
PRIMARY Requte externe (premire requte) lorsque lon utilise des sous-
requtes ou des unions
UNION Seconde ou requte suivante dans une union
DEPENDENT UNION Seconde ou requte suivante dans une union, dpendant de la requte
principale
UNION RESULT Rsultat dune union
SUBQUERY Sous-requte interne
DEPENDENT SUBQUERY Sous-requte interne, dpendant de la requte principale (sous-
requte corrle)
DERIVED Sous-requte utilise dans la clause FROM
UNCACHEABLE SUBQUERY Sous-requte dont le rsultat ne peut pas tre mis en cache et qui sera
donc rvalue pour chaque ligne
UNCACHEABLE UNION Seconde ou requte suivante dans une union appartenant sous-
requte non cachable

La colonne table numre simplement les tables utilises pour rpondre la requte.
Chaque ligne du rsultat fournit plus dinformations sur la manire dont cette table
particulire est utilise dans la requte. Ici, vous pouvez voir que les tables utilises sont
commandes, livres commandes, clients et livres (ce que vous pouvez dj savoir en
examinant tout simplement la requte).
La colonne type explique comment la table est utilise dans les jointures de la requte.
Le Tableau 12.9 numre les valeurs possibles de cette colonne, de la plus rapide la
plus lente en terme de rapidit dexcution. Cela vous donne une ide du nombre de
lignes qui doivent tre lues dans chaque table pour excuter une requte.
Tableau 12.9 : Les diffrents types de jointures affichs par EXPLAIN

Type Description
const ou system La table nest lue quune seule fois. Cela se produit lorsque la table ne
contient quune seule ligne. Le type system est utilis avec les tables
systmes et le type const dans les autres cas.
Chapitre 12 Administration MySQL avance 317

Tableau 12.9 : Les diffrents types de jointures affichs par EXPLAIN (suite)

Type Description
eq ref Pour chaque ensemble de lignes provenant des autres tables de la jointure,
une seule ligne est lue dans cette table. Ce type de jointure est utilis
lorsque la jointure se sert de toutes les parties de lindex sur la table et que
lindex est UNIQUE ou quil sagit de la cl primaire.
fulltext Une jointure sur un index textuel.
ref Pour chaque ensemble de lignes provenant des autres tables de la jointure,
vous lisez un ensemble de lignes qui correspondent dans cette table. Ce
type de jointure est utilis lorsque la jointure ne peut pas choisir une ligne
unique partir de la condition de jointure, cest--dire lorsque seule une
partie de la cl est utilise dans la jointure, ou si elle nest pas un index
UNIQUE ou une cl primaire.
ref or null Semblable une requte ref, mais MySQL recherche galement les lignes
NULL (ce type est principalement utilis dans les sous-requtes).
index merge Une optimisation spcifique, la fusion dindex, a t utilise.
unique subquery Ce type de jointure sert remplacer ref pour certaines sous-requtes IN
qui ne renvoient quune seule ligne.
index subquery Ce type de jointure est semblable unique subquery mais est utilis pour
les sous-requtes avec un index non UNIQUE.
range Pour chaque ensemble de lignes provenant des autres tables de la jointure,
vous lisez un ensemble de lignes de cette table qui appartiennent un
intervalle particulier.
index Parcours de lindex complet.
ALL Chaque ligne de la table est traite.

Dans lexemple prcdent, vous pouvez constater quune table est jointe avec eq ref
(livres), quune autre lest avec ref (livres commandes) et que les deux autres
(commandes et clients) sont jointes avec ALL, cest--dire en examinant chaque ligne
de la table.
La colonne rows conserve ces informations : elle contient une estimation approximative
du nombre de lignes de chaque table qui doivent tre parcourues pour effectuer la join-
ture. Vous pouvez les multiplier entre elles pour obtenir le nombre total de lignes
examines pour effectuer une requte. Ces chiffres doivent tre multiplis puisquune
jointure est comparable un produit des lignes appartenant diffrentes tables. Repor-
tez-vous au Chapitre 10 pour plus de dtails. Noubliez pas quil sagit du nombre de
lignes examines, pas du nombre de lignes renvoyes, et quil sagit seulement dune
318 Partie II Utilisation de MySQL

estimation : MySQL ne peut pas deviner le rsultat final avant deffectuer rellement la
requte.
Naturellement, plus ce nombre est faible, mieux cest. Pour linstant, notre base de
donnes contient trs peu de donnes mais, lorsque la taille dune base commence
augmenter, une requte de ce genre dmultiplie le temps dexcution. Nous y reviendrons
un peu plus loin dans ce chapitre.
La colonne possible keys fournit la liste des cls que MySQL peut utiliser lors dune
opration de jointure ralise avec la table. Dans ce cas, vous pouvez voir que les cls
possibles sont en fait toutes les cls primaires.
La colonne key correspond soit la cl de la table MySQL utilise, soit NULL si aucune
cl na t employe. Vous remarquerez que, bien quil y ait des cl primaires possibles
pour les tables clients et commandes, aucune na t utilise dans cette requte.
La colonne key len indique la longueur de la cl utilise. Vous pouvez vous en servir
pour savoir si la cl na t utilise que partiellement. Cette information est importante
lorsque des cls sont composes de plusieurs colonnes. Dans le cas prsent, pour lequel
des cls ont t utilises, cest la totalit de la cl qui a t employe.
La colonne ref montre les colonnes utilises avec la cl pour slectionner des lignes
dans la table.
Enfin, la colonne Extra fournit toutes les autres informations concernant la manire
dont la jointure a t effectue. Le Tableau 12.10 numre quelques valeurs que vous
pourrez rencontrer dans cette colonne. Pour disposer de la liste complte, qui contient
plus de quinze possibilits, consultez le manuel de MySQL, http://dev.mysql.com/
doc/refman/5.1/en/using-explain.html.

Tableau 12.10 : Les valeurs possibles de la colonne Extra, qui apparat dans la sortie
de EXPLAIN

Valeur Signification
Distinct Une fois la premire ligne correspondante trouve, MySQL cesse de
rechercher des lignes.
Not exists La requte a t optimise pour se servir de LEFT JOIN.
Range checked for Pour chaque ligne de lensemble de lignes des autres tables de la
jointure, MySQL tente de trouver le meilleur index utiliser, sil y en a
un.
Using filesort Il faudra deux passes pour trier les donnes, ce qui prend naturellement
deux fois plus de temps.
Chapitre 12 Administration MySQL avance 319

Tableau 12.10 : Les valeurs possibles de la colonne Extra, qui apparat dans la sortie
de EXPLAIN (suite)

Valeur Signification
Using index Toutes les informations de la table proviennent de lindex, cest--dire
que les lignes ne sont en ralit pas examines.
Using join buffer Les tables sont lues par portions en utilisant le tampon de jointure, puis
les lignes sont extraites de ce tampon pour terminer la requte.
Using temporary Il faut crer une table temporaire pour excuter cette requte.
Using where Une clause WHERE est utilise pour slectionner les lignes.

Il existe plusieurs manires de rsoudre les problmes mis en vidence par la sortie de
EXPLAIN.
Tout dabord, vrifiez les types des colonnes et assurez-vous que ce sont les mmes.
Ceci est particulirement valable pour la largeur des colonnes car les index ne peuvent
pas tre utiliss pour associer des colonnes si elles ont des largeurs diffrentes. Vous
pouvez rsoudre ce problme en modifiant le type des colonnes associer ou en int-
grant ces informations lors de la conception de votre base de donnes.
Ensuite, vous pouvez demander loptimiseur de jointure dexaminer les distributions
des cls et donc de mieux optimiser les jointures laide de lutilitaire myisamchk ou de
linstruction ANALYZE TABLE, qui sont quivalents. Vous pouvez invoquer cet outil grce
la ligne suivante :
myisamchk --analyze chemin_de_la_base_de_donnes_MySQL/table

Vous pouvez vrifier plusieurs tables en les indiquant toutes sur la ligne de commande
ou en utilisant la syntaxe suivante :
myisamchk --analyze chemin_de_la_base_de_donnes_MySQL/*.MYI

Pour vrifier toutes les tables de toutes les bases de donnes, utilisez la commande
suivante :
myisamchk --analyze chemin_du_rpertoire_de_donnes_MySQL/*/*.MYI

Vous pouvez galement numrer les tables dans une instruction ANALYZE TABLE
partir du moniteur MySQL :
analyze table clients, commandes, livres_commandes, livres;

Troisimement, vous pouvez envisager lajout dun nouvel index dans la table. Si la
requte est la fois lente et classique, cette opration est fortement recommande. Sil
sagit dune requte que vous ne serez plus amen effectuer, cette modification nen
vaut probablement pas la peine, dautant plus quelle pourrait ralentir dautres choses.
320 Partie II Utilisation de MySQL

Si la colonne possible keys de EXPLAIN contient plusieurs valeurs NULL, vous pouvez
amliorer les performances de votre requte en ajoutant un index dans la table en ques-
tion. Si la colonne que vous utilisez dans votre clause WHERE peut accepter un index,
vous pouvez vous servir de la commande suivante pour en crer un :
ALTER TABLE table ADD INDEX (colonne);

Astuces gnrales doptimisation


Outre les conseils doptimisation des requtes que nous venons de prsenter, il existe
plusieurs mesures que vous pouvez prendre pour amliorer globalement les performances
de votre base de donnes MySQL.

Optimisation de larchitecture
Dune manire gnrale, tous les lments de votre base de donnes doivent tre aussi
petits que possible. Pour cela, vous pouvez commencer par choisir une architecture
correcte, qui minimise les redondances. Vous pouvez galement choisir les types de
donnes les plus petits possibles pour vos colonnes. Il faut galement viter les valeurs
NULL autant que faire se peut et rendre vos cls primaires aussi courtes que possible.
vitez les colonnes largeur variable (comme VARCHAR, TEXT ou BLOB). Si vos tables
possdent des champs de largeur fixe, elles seront plus rapides utiliser, bien quelles
ncessitent plus de place.

Permissions
Outre les recommandations que nous venons de voir propos d EXPLAIN, vous pouvez
amliorer la vitesse de vos requtes en simplifiant les permissions. Nous avons dj
expliqu la manire dont les requtes sont vrifies par le systme de permissions avant
dtre excutes. Plus ce processus est simple, plus vos requtes seront excutes rapi-
dement.

Optimisation des tables


Quand une table a t utilise pendant un certain temps, ses donnes peuvent tre frag-
mentes si vous y avez apport des mises jour et des suppressions. Cette fragmenta-
tion ralentit les recherches dans cette table. Vous pouvez corriger cette situation grce
linstruction suivante :
OPTIMIZE TABLE nomtable;

ou en tapant cette commande linvite du systme dexploitation :


myisamchk -r table
Chapitre 12 Administration MySQL avance 321

Vous pouvez galement vous servir de lutilitaire myisamchk pour trier lindex dune
table et les donnes conformment cet index, comme ceci :
myisamchk --sort-index --sort-records=1
chemin_du_rpertoire_de_donnes_MySQL/*/*.MYI

Utilisation des index


Pour acclrer les requtes, servez-vous des index lorsque cela est ncessaire. Restez
simple et ne crez pas dindex superflus qui ne seront pas utiliss par vos requtes. Vous
pouvez vrifier si un index sera utilis en excutant EXPLAIN, comme nous lavons dj
vu.

Utiliser des valeurs par dfaut


Lorsque cela est possible, utilisez des valeurs par dfaut pour les colonnes et ninsrez
des donnes que si elles sont diffrentes de la valeur par dfaut. Cela permet de rduire
le temps dexcution de linstruction INSERT.

Autres astuces
Il existe beaucoup dautres astuces pour amliorer les performances dans des situations
particulires ou lorsque vous avez des besoins prcis. Le site web de MySQL, http://
www.mysql.com, propose plusieurs astuces de ce genre.

Sauvegarder votre base de donnes MySQL


Avec MySQL, vous disposez de plusieurs possibilits pour raliser une sauvegarde.
La premire mthode consiste verrouiller les tables, avec une commande LOCK
TABLES, et copier les fichiers physiques situs sur le disque dur. Voici la syntaxe de
cette commande :
LOCK TABLES table type_verrou [, table type_verrou ...]

Chaque table doit tre dsigne par son nom et le type du verrou peut tre READ ou
WRITE. Pour une sauvegarde vous navez normalement besoin que dun verrou en
lecture (READ). Vous devez galement excuter une commande FLUSH TABLES afin de
vous assurer que toutes les modifications de vos index ont t crites sur le disque avant
de raliser une sauvegarde.
Pendant cette sauvegarde, les utilisateurs et les scripts pourront continuer excuter des
requtes ne demandant quun accs en lecture. Cependant, si votre serveur doit satis-
faire un gros volume de requtes modifiant la base de donnes, comme des commandes
de clients, cette solution est viter.
322 Partie II Utilisation de MySQL

La seconde mthode, qui est suprieure, implique le recours la commande


mysql dump. Son utilisation (depuis la ligne de commande du systme dexploitation)
est gnralement de la forme :
mysqldump --opt --all-databases > all.sql
Cette ligne de commande crira dans le fichier all.sql tout le code SQL ncessaire la
reconstruction de la base de donnes.
Ensuite, il est prfrable darrter pendant un moment le processus mysqld et de le red-
marrer avec loption log bin[=fichierlog]. De cette faon, les mises jour seront
enregistres dans le fichier log, ce qui vous permettra de disposer des modifications
ralises sur la base de donnes depuis votre opration de sauvegarde (les fichiers log
doivent bien sr tre sauvegards lors de toutes les oprations de sauvegarde des
fichiers).
Une troisime mthode consiste utiliser le script mysqlhotcopy, que vous pouvez
appeler de la faon suivante :
mysqlhotcopy database /chemin/vers/sauvegarde
Vous devez ensuite suivre le processus de dmarrage et darrt de la base de donnes,
comme nous lavons indiqu prcdemment.
Une dernire mthode de sauvegarde (et de reprise) consiste grer une copie rplique
de la base de donnes. La rplication est traite plus loin dans ce chapitre.

Restauration de votre base de donnes MySQL


Pour restaurer une base de donnes MySQL, vous disposez de deux possibilits. Si le
problme provient dune table abme, vous pouvez lancer myisamchk avec loption r
(rparation).
Si vous avez employ la premire mthode de sauvegarde, vous pouvez copier les
fichiers de donnes aux mmes emplacements que les originaux dans une nouvelle
installation MySQL.
Si vous avez utilis la seconde mthode, il vous faut raliser deux tapes. Vous devez en
premier lieu excuter les requtes contenues dans le fichier de sauvegarde afin de
reconstruire la base de donnes dans ltat o elle se trouvait au moment de la sauve-
garde. Puis vous devez mettre jour la base de donnes jusquau point stock dans le
log binaire. Vous pouvez le faire en excutant la commande :
mysqlbinlog hte-bin.[0-9]* | mysql
Vous trouverez plus dinformations sur les oprations de sauvegarde et de restauration
sur le site web de MySQL, http://www.mysql.com.
Chapitre 12 Administration MySQL avance 323

Implmenter la rplication
La rplication est une technique grce laquelle plusieurs serveurs de base de donnes
peuvent servir les mmes donnes. Il est ainsi possible dquilibrer la charge et
damliorer la fiabilit du systme. Si un systme est en panne, les autres peuvent
toujours tre interrogs. Une fois configure, la rplication peut galement tre utilise
pour raliser des sauvegardes.
Lide fondamentale consiste avoir un serveur matre et lui ajouter un certain
nombre desclaves. Chacun des esclaves offre une rplication en miroir du matre. Lors-
que vous configurez initialement les esclaves, vous copiez un instantan de toutes les
donnes du matre ce moment prcis. Puis les esclaves demandent des mises jour de
la part du matre. Le matre transmet les dtails des requtes excutes grce son journal
binaire et les esclaves rappliquent ces requtes aux donnes.
Lapproche habituelle pour utiliser cette configuration consiste appliquer les requtes
en criture au matre et les requtes en lecture aux esclaves. Des architectures plus
complexes sont galement possibles, par exemple en incluant plusieurs matres, mais
nous ne traiterons ici que du cas de figure le plus courant.
Vous devez bien comprendre que les esclaves ne possdent gnralement pas des
donnes aussi jour que celles du matre. Cet tat de fait se produit dans nimporte
quelle base de donnes distribue.
Pour entamer la configuration dune architecture matre/esclaves, vous devez vous
assurer que la journalisation binaire est active sur le matre. Pour plus dinformations
ce sujet, consultez lAnnexe A.
Vous devez diter votre fichier my.ini ou my.cnf sur les serveurs matre et esclave. Sur le
matre, utilisez la configuration suivante :
[mysqld]
log-bin
server-id=1

Le premier rglage active la journalisation binaire (il devrait donc dj tre prsent ; sil
ne lest pas, ajoutez-le). Le second donne votre matre un identifiant unique. Chaque
esclave requiert galement un identifiant : vous devez donc ajouter une ligne semblable
aux fichiers my.ini/my.cnf sur chacun des esclaves. Assurez-vous que ces nombres
soient uniques ! Par exemple, votre premier esclave pourrait tre paramtr avec
server id=2, le second, avec server id=3, etc.

Configurer le matre
Sur le matre, vous devez crer un utilisateur pour la connexion des esclaves. Il existe
un niveau de privilge spcial pour les esclaves, appel esclave de rplication. Selon la
324 Partie II Utilisation de MySQL

manire dont vous prvoyez de raliser le transfert de donnes initial, il se peut que
vous deviez temporairement accorder certains privilges supplmentaires.
Dans la plupart des cas, vous utiliserez un instantan de la base de donnes pour trans-
frer les donnes, et, dans ce cas, seul le privilge spcial esclave de rplication est
ncessaire. Si vous dcidez dutiliser la commande LOAD DATA FROM MASTER pour trans-
frer les donnes (voir la prochaine section), lutilisateur aura besoin des privilges
RELOAD, SUPER et SELECT, mais uniquement pour la configuration initiale. Selon le prin-
cipe du moindre privilge expos au Chapitre 9, vous devrez rvoquer ces autres privi-
lges une fois que le systme est oprationnel.
Crez un utilisateur sur le matre. Vous pouvez lui attribuer le nom et le mot de passe de
votre choix, mais ne perdez pas ces informations. Dans notre exemple, nous appellerons
cet utilisateur esc rep :
grant replication slave
on *.*
to esc_rep@% identified by motdepasse;

Remplacez videmment motdepasse par le mot de passe de votre choix.

Raliser le transfert de donnes initial


Il existe plusieurs moyens de transfrer les donnes depuis le matre vers lesclave. Le
plus simple consiste configurer les esclaves (voir la section suivante) et excuter une
instruction LOAD DATA FROM MASTER. Le problme avec cette approche tient ce que les
tables sur le matre seront verrouilles pendant que les donnes sont transfres.
Comme cette opration peut prendre un certain temps, nous ne conseillons pas cette
mthode (vous ne pouvez lutiliser que si vous utilisez des tables MyISAM).
En gnral, il est prfrable de prendre un instantan de la base de donnes. Pour cela,
vous pouvez utiliser les procdures dcrites pour la ralisation des sauvegardes dans ce
chapitre. Vous devez au pralable purger les tables avec linstruction suivante :
flush tables with read lock;

Le verrou en lecture est requis parce que vous devez enregistrer la position du serveur
dans son journal binaire lorsque linstantan est effectu. Vous pouvez le faire en excutant
linstruction suivante :
show master status;

Cette instruction doit produire une sortie comme celle-ci :


+----------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------------+----------+--------------+------------------+
| laura-ltc-bin.000001 | 95 | | |
+----------------------+----------+--------------+------------------+
Chapitre 12 Administration MySQL avance 325

Notez le fichier et la position. Vous aurez besoin de ces informations pour configurer les
esclaves.
Puis prenez votre instantan et dverrouillez les tables avec linstruction suivante :
unlock tables;
Si vous utilisez des tables InnoDB, le moyen le plus simple consiste utiliser loutil
InnoDB Hot Backup, propos par Innobase Oy ladresse http://www.innodb.com. Il
ne sagit pas dun logiciel libre et sa licence nest pas gratuite. Sinon vous pouvez utili-
ser la procdure dcrite ici et, avant de dverrouiller les tables, fermer le serveur
MySQL et copier le rpertoire entier pour la base de donnes que vous souhaitez rpliquer
avant de redmarrer le serveur et de dverrouiller les tables.

Configurer lesclave ou les esclaves


Deux options vous sont proposes pour configurer lesclave ou les esclaves. Si vous
avez effectu un instantan de votre base de donnes, commencez par linstaller sur le
serveur esclave.
Ensuite, excutez les requtes suivantes sur votre esclave :
change master to
master-host=serveur,
master-user=utilisateur,
master-password=motdepasse,
master-log-file=fichier_journal,
master-log-pos=pos_journal;
start slave;
Vous devez remplacer les donnes en italique. serveur correspond au nom du serveur
matre. utilisateur et motdepasse proviennent de linstruction GRANT que vous avez
excute sur le serveur matre. fichier journal et pos journal proviennent de la sortie
de linstruction SHOW MASTER STATUS que vous avez excute sur le serveur matre.
Votre systme de rplication doit maintenant tre oprationnel.
Si vous navez pas effectu dinstantan, vous pouvez charger les donnes depuis le
matre aprs avoir excut la requte prcdente en excutant linstruction suivante :
load data from master;

Pour aller plus loin


Dans ces chapitres sur MySQL, nous nous sommes intresss aux utilisations et aux
parties du systme les plus troitement associes au dveloppement web, ainsi qu la
liaison entre MySQL et PHP.
Si vous souhaitez approfondir vos connaissances concernant MySQL, vous pouvez
visiter le site web de MySQL, http://www.mysql.com.
326 Partie II Utilisation de MySQL

Vous pouvez galement consulter le livre MySQL 5, Guide officiel de Paul Dubois,
publi par les ditions Pearson Education France en 2006.

Pour la suite
Dans le chapitre suivant, nous examinerons certaines des fonctionnalits avances de
MySQL utiles pour la programmation dapplications web, comme le choix des moteurs
de stockage, les transactions et les procdures stockes.
13
Programmation MySQL avance

Dans ce chapitre, nous traiterons de sujets MySQL plus avancs, comme les types de
tables, les transactions et les procdures stockes.

Linstruction LOAD DATA INFILE


Linstruction LOAD DATA INFILE fait partie des fonctionnalits utiles de MySQL que
nous navons pas encore traites. Elle permet de charger des tables partir dun fichier
et sexcute trs rapidement.
Cette commande flexible possde de nombreuses options, mais elle sutilise le plus
souvent de la manire suivante :
LOAD DATA INFILE "nouveaux_livres.txt" INTO TABLE livres;

Cette ligne lit les lignes du fichier newbooks.txt et les insre dans la table livres. Par
dfaut, les champs de donnes dans le fichier doivent tre spars par des tabulations et
entours dapostrophes, chaque ligne tant spare par un caractre de nouvelle ligne
(\n). Les caractres spciaux doivent tre protgs par un antislash ( \). Toutes ces
caractristiques sont configurables grce aux diverses options de linstruction LOAD ;
pour plus dinformations ce sujet, consultez le manuel MySQL.
Pour utiliser linstruction LOAD DATA INFILE, lutilisateur doit possder le privilge
FILE prsent au Chapitre 9.

Les moteurs de stockage


MySQL supporte un certain nombre de moteurs de stockage, que lon appelle parfois
aussi types de tables. En dautres termes, vous pouvez choisir limplmentation sous-
jacente des tables. Chaque table dune mme base de donnes peut utiliser un moteur de
328 Partie II Utilisation de MySQL

stockage diffrent et les tables peuvent aisment tre converties pour passer dun type
un autre.
Pour choisir le type de table lorsque vous crez votre table, utilisez linstruction
suivante :
CREATE TABLE table TYPE=type ....
Les types de tables gnralement disponibles sont les suivants :
m MyISAM. Il sagit du type par dfaut et cest celui que nous avons utilis jusqu
prsent dans ce livre. Il est fond sur le type ISAM (Indexed Sequential Access
Method, ou "mthode daccs squentiel index) traditionnel, une mthode stan-
dard pour stocker les enregistrements et les fichiers. MyISAM offre un certain
nombre davantages supplmentaires par rapport au type ISAM. Par comparaison
avec les autres moteurs de stockage, MyISAM est celui qui possde le plus doutils
pour la vrification et la rparation des tables. Les tables MyISAM peuvent tre
compresses et supportent la recherche plein texte. En revanche, elles ne permet-
tent pas dexcuter des transactions de faon sre et ne reconnaissent pas les cls
trangres.
m MEMORY (auparavant appele HEAP). Les tables de ce type sont stockes en
mmoire et leurs index sont hachs. Les tables MEMORY sont ainsi extrmement
rapides, mais vos donnes seront perdues si le serveur se plante. Ces caractristi-
ques font des tables MEMORY des candidates idales pour le stockage de donnes
temporaires ou drives. Vous devez indiquer MAX ROWS dans linstruction CREATE
TABLE ; sinon ces tables pourraient consommer toute votre mmoire. En outre, elles
ne peuvent pas possder de colonnes de types BLOB, TEXT ou AUTO INCREMENT.
m MERGE. Ces tables vous permettent de traiter une collection de tables MyISAM
comme une seule table lors de vos requtes. Il est ainsi possible de contourner les
limites relatives la taille de fichier maximale sur certains systmes dexploitation.
m ARCHIVE. Ces tables permettent de stocker de gros volumes de donnes avec une
empreinte mmoire minimale. Les tables de ce type nautorisent que les requtes
INSERT et SELECT ; vous ne pouvez pas leur appliquer dinstructions DELETE, UPDATE
ou REPLACE. En outre, elles nutilisent pas dindex.
m CSV. Ces tables sont stockes sur le serveur sous la forme dun unique fichier
contenant des valeurs spares par des virgules. Lavantage de ce type de table
napparat que lorsque vous devez consulter ou manipuler des donnes dans un
tableur comme Microsoft Excel.
m InnoDB. Ces tables permettent deffectuer des transactions correctement
puisquelles fournissent les fonctionnalits COMMIT et ROLLBACK. Les tables InnoDB
savent galement grer les cls trangres. Pour certaines applications, tous ces
Chapitre 13 Programmation MySQL avance 329

avantages peuvent compenser le fait quelles sont plus lentes que les tables
MyISAM.
Dans la plupart des applications web, vous utiliserez gnralement des tables MyISAM
ou InnoDB, ou une combinaison des deux.
Vous devriez choisir des tables MyISAM lorsque vous excutez un grand nombre
dinstructions SELECT ou INSERT (non entrelaces) sur une table car il sagit du moyen
le plus rapide de le faire. Pour de nombreuses applications web comme les catalogues
de produits, MyISAM est le meilleur choix. Vous devriez galement utiliser MyISAM
si vous avez besoin de fonctionnalits de recherche en plein texte. En revanche, utilisez
le moteur de stockage InnoDB lorsque les transactions sont importantes, par exemple
pour les tables stockant des donnes financires ou dans le cas o les instructions
INSERT et SELECT sont entrelaces, comme dans les forums en ligne.
Vous pouvez utiliser des tables MEMORY pour les tables temporaires ou pour impl-
menter des vues. Les tables MERGE sont utiles si vous devez grer des tables MyISAM
de trs grande taille.
Vous pouvez modifier le type dune table aprs sa cration laide dune instruction
ALTER TABLE, comme ceci :
alter table commandes type=innodb;
alter table livres_commandes type=innodb;
Dans la majeure partie de ce livre, nous avons utilis des tables MyISAM. Nous nous
concentrerons prsent sur lutilisation des transactions et leurs implmentations dans
les tables InnoDB.

Les transactions
Les transactions sont des mcanismes qui assurent la cohrence des bases de donnes,
notamment dans lventualit dune erreur ou dun plantage du serveur. Dans les sections
qui suivent, nous expliquerons ce que sont les transactions et comment les implmenter
avec InnoDB.

Comprendre la dfinition des transactions


Il convient tout dabord de dfinir le terme transaction. Une transaction est une requte
ou un ensemble de requtes dont il est garanti quil sera soit entirement excut sur la
base de donnes, soit pas excut du tout. La base de donnes restera donc toujours
dans un tat cohrent, que la transaction soit ralise ou non.
Pour mieux comprendre limportance de cette caractristique, considrez une base de
donnes doprations bancaires et imaginez que vous souhaitiez transfrer de largent
dun compte un autre. Cette action implique de supprimer largent dun compte et de
330 Partie II Utilisation de MySQL

linsrer dans un autre, ce qui ncessite au moins deux requtes. Il est de la plus haute
importance que ces deux requtes soient excutes toutes les deux ou quelles ne soient
excutes ni lune ni lautre. Si vous retirez largent dun compte et quune panne de
courant survienne avant que vous ne layez plac dans lautre compte, que se passera-t-il ?
Largent aura disparu ?
Vous avez peut-tre dj entendu parler de la conformit ACID. ACID est un acronyme
dcrivant quatre conditions que les transactions doivent satisfaire :
m Atomicit. Les transactions doivent tre atomiques. Autrement dit, elles doivent
tre soit entirement excutes, soit pas du tout excutes.
m Cohrence. Les transactions doivent laisser la base de donnes dans un tat cohrent.
m Isolation. Les transactions non termines ne doivent pas tre visibles pour les autres
utilisateurs de la base de donnes ; autrement dit, elles doivent rester isoles tant
quelles ne sont pas termines.
m Durabilit. Une fois crites dans la base de donnes, les transactions doivent rester
permanentes ou durables.
Une transaction qui a t crite de manire permanente dans la base de donnes est dite
valide. Une transaction qui nest pas crite dans la base de donnes (de sorte que la
base de donnes est replace dans ltat qui tait le sien avant que la transaction ne
commence) est dite annule.

Utiliser des transactions avec InnoDB


Par dfaut, MySQL sexcute en mode autocommit, ce qui signifie que chaque instruction
que vous excutez est immdiatement crite (valide) dans la base de donnes. Si vous utili-
sez un type de table transactionnel, vous ne voudrez srement pas de ce comportement.
Pour dsactiver le mode autocommit dans la session courante, tapez :
set autocommit=0;

Lorsque le mode autocommit est activ, vous pouvez le dsactiver temporairement


avec linstruction suivante :
start transaction;

Lorsque vous avez fini dentrer les instructions qui constituent une transaction, vous
pourrez la valider dans la base de donnes en tapant simplement :
commit;

Si vous avez chang davis, vous pouvez revenir ltat prcdent de la base de
donnes en tapant :
rollback;
Chapitre 13 Programmation MySQL avance 331

Tant que vous navez pas valid une transaction, cette dernire nest pas visible pour les
autres utilisateurs ni dans dans les autres sessions.
titre dexemple, excutez ces instructions ALTER TABLE sur votre base de donnes
livres si vous ne lavez pas dj fait en lisant la section prcdente.
alter table livres_commandes=innodb;
alter table commandes type=innodb;

Ces instructions convertissent deux des tables en tables InnoDB (vous pourrez les
reconvertir par la suite si vous le souhaitez, en excutant ces mmes instructions mais
avec type=MyISAM).
Puis ouvrez deux connexions la base de donnes livres. Dans une connexion, ajoutez
une nouvelle commande de livre la base de donnes :
insert into commandes values (5, 2, 69.98, 2008-06-18);
insert into livres_commandes values (5, 0-672-31697-8, 1);

Vrifiez que vous pouvez voir cette nouvelle commande :


select * from commandes where idcommande=5;

Vous devriez voir ce rsultat safficher :


+------------+----------+---------+------------+
| idcommande | idclient | montant | date |
+------------+----------+---------+------------+
| 5 | 2 | 69.98 | 2008-06-18 |
+------------+----------+---------+------------+

Conservez cette connexion ouverte, accdez votre autre connexion et excutez la


mme requte de slection. Vous ne devriez cette fois pas pouvoir voir la commande :
Empty set (0.00 sec)

(Si vous la voyez, cest srement parce que vous navez pas dsactiv le mode auto-
commit. Vrifiez et assurez-vous que vous avez bien converti la table au format
InnoDB. En effet, la transaction na pas encore t valide cest lillustration du prin-
cipe disolation des transactions.)
prsent, revenez la premire connexion et validez la transaction :
commit;

Vous devriez maintenant pouvoir retrouver la ligne dans votre autre connexion.

Les cls trangres


InnoDB reconnat galement les cls trangres, que nous avons traites au Chapitre 8.
Lorsque vous utilisez des tables MyISAM, vous navez aucun moyen de faire appliquer
les contraintes lies aux cls trangres.
332 Partie II Utilisation de MySQL

Dans le cas de linsertion dune ligne dans la table livres commandes, vous devez
inclure un idcommande valide. Avec MyISAM, vous devez vrifier quelque part dans le
code de votre application la validit de lidentifiant idcommande que vous insrez. Grce
aux cls trangres dans InnoDB, vous pouvez laisser la base de donnes le soin de
raliser cette vrification pour vous.
Pour crer la table pour quelle utilise une cl trangre, vous pouvez changer linstruction
de cration de table comme suit :
create table livres_commandes
( idcommande int unsigned not null references commandes(idcommande),
isbn char(13) not null,
quantite tinyint unsigned,
primary key (idcommande, isbn)
) type=InnoDB;
Les termes references commandes(idcommande) aprs idcommande signifient que cette
colonne est une cl trangre qui doit contenir une valeur de la colonne idcommande de
la table commandes.
Pour finir, nous avons ajout le type de table type=InnoDB la fin de la dclaration.
Cette indication est requise pour que les cls trangres fonctionnent.
Vous pouvez galement apporter ces modifications une table existante, en utilisant des
instructions ALTER TABLE :
alter table livres_commandes type=InnoDB;
alter table livres_commandes
add foreign key (idcommande) references commandes(idcommande);
Pour voir si la modification a fonctionn, essayez dinsrer une ligne avec un idcommande
qui nexiste pas dans la table commandes :
insert into livres_commandes values (77, 0-672-31697-8, 7);
Vous devriez alors obtenir une erreur comme celle-ci :
ERROR 1452 (23000): Cannot add or update a child row:
a foreign key constraint fails

Les procdures stockes


Une procdure stocke est une fonction cre et stocke lintrieur de MySQL. Cette
fonction peut tre constitue dinstructions SQL et dun certain nombre de structures de
contrle spciales. Elle peut tre utile lorsque vous souhaitez excuter la mme fonc-
tion partir de diverses applications ou plates-formes ou pouvoir encapsuler des
fonctionnalits. Les procdures stockes dans une base de donnes peuvent tre consi-
dres comme analogues lapproche oriente objet en programmation. Elles vous
permettent de contrler le mode daccs aux donnes.
Commenons par un exemple simple.
Chapitre 13 Programmation MySQL avance 333

Un exemple simple
Le Listing 13.1 dclare une procdure stocke.

Listing 13.1 : procedure_stockee_basique.sql Dclaration dune procdure stocke

# Exemple simple de procdure stocke


delimiter //

create procedure total_commandes (out total float)


BEGIN
select sum(montant) into total from commandes;
END
//

delimiter;

tudions ce code ligne par ligne.


La premire instruction :
delimiter //

modifie le dlimiteur de fin dinstruction en remplaant sa valeur courante (en gnral,


un point-virgule, moins que vous ne layez change prcdemment) par une double
barre de fraction. Cette tape est ncessaire afin de pouvoir utiliser le dlimiteur de
point-virgule dans la procdure stocke lorsque vous entrez le code de la procdure
sans que MySQL nessaie dexcuter le code en cours de route.
La ligne suivante :
create procedure total_commandes (out total float)

cre la procdure stocke elle-mme. Le nom de cette procdure est total commandes.
Elle possde un unique paramtre, appel total, qui correspond la valeur que vous
essayez de calculer. Le terme OUT indique que ce paramtre est pass en mode sortie
(cest la fonction qui le remplira).
Les paramtres peuvent galement tre dclars en mode IN, qui signifie que la valeur
est passe la procdure, ou en mode INOUT, qui signifie que la valeur est passe la
procdure mais que cette dernire peut la modifier.
Le terme float indique le type du paramtre. Ici, on renvoie un total de toutes les
commandes de la table commandes. Le type de la colonne montant de commandes tant
float, cest une valeur de ce type qui sera donc renvoye. Les types de donnes
autoriss dans les procdures stockes sont les mmes que les types de colonne auto-
riss.
334 Partie II Utilisation de MySQL

Si vous souhaitez passer plusieurs paramtres, vous pouvez utiliser une liste de paramtres
spars par des virgules, comme en PHP.
Le corps de la procdure est entour par les instructions BEGIN et END. Ces instruc-
tions sont analogues aux accolades en PHP ( {}) car elles dlimitent un bloc
dinstructions.
Le corps de la procdure excute simplement une instruction SELECT. La seule diff-
rence par rapport une instruction normale tient ce que lon utilise la clause into
total afin de charger le rsultat de la requte dans le paramtre total.
Aprs avoir dclar la procdure, on redfinit le dlimiteur comme tant le point-
virgule :
delimiter;

Une fois que la procdure a t dclare, vous pouvez lappeler en utilisant le mot-cl
call, comme ici :
call total_commandes(@t);

Cette instruction appelle la procdure total commandes en lui passant une variable
pour rcuprer le rsultat. Vous devez ensuite examiner cette variable :
select @t;

Le rsultat doit tre de la forme :


+-----------------+
| @t |
+-----------------+
| 289.92001152039 |
+-----------------+

Vous pouvez galement crer des fonctions. Une fonction accepte uniquement des para-
mtres en mode lecture et renvoie une seule valeur.
Comme le montre le Listing 13.2, la syntaxe de base est quasiment identique.

Listing 13.2 : fonction_basique.sql Dclaration dune fonction stocke

# syntaxe de base pour crer une fonction

delimiter //

create function prix_ttc(prix float) returns float


return prix * 1.1;
//

delimiter;
Chapitre 13 Programmation MySQL avance 335

Comme vous pouvez le constater, cet exemple utilise le mot-cl function au lieu de
procedure, mais il y a galement deux autres diffrences.
Les paramtres nont pas besoin dtre prciss en tant que IN ou OUT car ils sont nces-
sairement tous en mode IN. Aprs la liste des paramtres, vous pouvez voir la clause
returns float. Elle indique le type de la valeur de retour. Ce type, ici aussi, peut tre
nimporte quel type MySQL valide.
Pour renvoyer une valeur, on utilise linstruction return, comme en PHP.
Notez que cet exemple nutilise pas les instructions BEGIN et END. Vous pourriez les utili-
ser, mais elles ne sont pas requises. Comme en PHP, si un bloc dinstructions ne contient
quune seule instruction, vous navez pas besoin den marquer le dbut et la fin.
Lappel dune fonction est un peu diffrent de lappel dune procdure. Vous pouvez
appeler une fonction stocke de la mme manire que vous appelleriez une fonction
prdfinie :
select prix_ttc(100);

Cette instruction doit produire le rsultat suivant :


+---------------+
| prix_ttc(100) |
+---------------+
| 110 |
+---------------+

Vous pouvez visualiser le code utilis pour dfinir les procdures et les fonctions stockes
laide des instructions suivantes :
show create procedure total_commandes;

ou
show create function prix_ttc;

Vous pouvez les supprimer avec :


drop procedure total_commandes;

ou
drop function prix_ttc;

Les procdures stockes offrent la possibilit dutiliser des structures de contrle, des
variables, des gestionnaires DECLARE (comme les exceptions) et des curseurs. Nous
allons examiner chacun de ces outils dans les sections qui suivent.

Variables locales
Vous pouvez dclarer des variables locales dans un bloc begin...end en utilisant une
instruction declare. Vous pourriez, par exemple, modifier la fonction prix ttc de
336 Partie II Utilisation de MySQL

manire utiliser une variable locale pour stocker le taux de la taxe, comme le montre
le Listing 13.3.

Listing 13.3 : fonction_basique.sql Dclaration dune fonction stocke avec


des variables

# Syntaxe de base pour crer une fonction

delimiter //

create function prix_ttc (prix float) returns float


begin
declare taxe float default 0.10;
return prix * (1 + taxe);
end
//
delimiter;

Comme vous pouvez le constater, vous dclarez la variable avec declare suivi du nom
de la variable. La clause default est facultative et permet daffecter une valeur initiale
la variable. Vous pouvez ensuite utiliser la variable de faon classique.

Curseurs et structures de contrle


tudions un exemple plus complexe. Ici, on veut crire une procdure stocke qui
dtermine la commande dont le montant est le plus grand et en retourne lidentifiant
idcommande (on pourrait videmment obtenir le mme rsultat avec une simple requte,
mais nous voulons montrer ici comment utiliser les curseurs et les structures de
contrle). Le code de cette procdure stocke est prsent dans le Listing 13.4.

Listing 13.4 : structures_controle_curseurs.sql Utilisation de curseurs et de boucles


pour traiter un ensemble rsultat

# Procdure permettant de retrouver lidcommande du plus grand montant


# Peut tre ralise avec max, mais illustre les principes des procdures
# stockes

delimiter //

create procedure max_commande(out max_id int)


begin
declare cet_id int;
declare ce_montant float;
declare l_montant float default 0.0;
declare l_id int;

declare fini int default 0;


Chapitre 13 Programmation MySQL avance 337

declare continue handler for sqlstate 02000 set fini = 1;


declare c1 cursor for select idcommande, montant from commandes;

open c1;
repeat
fetch c1 into cet_id, ce_montant;
if not fini then
if ce_montant > l_montant then
set l_montant = ce_montant;
set l_id = cet_id;
end if;
end if;
until fini end repeat;
close c1;

set max_id = l_id;

end
//

delimiter;

Ce code utilise des structures de contrle (des structures conditionnelles et des


boucles), des curseurs et des gestionnaires declare. tudions-le ligne par ligne.
Au dbut de la procdure, on dclare un certain nombre de variables locales utiliser
dans la procdure. Les variables cet id et ce montant stockent les valeurs de idcom
mande et de montant pour la ligne courante. Les variables l montant et l id stockent le
montant de commande le plus lev et lidentifiant correspondant. Comme on veut
dterminer le plus grand montant en comparant chaque valeur la valeur la plus leve
actuellement, on initialise cette variable zro.
La variable suivante est fini, qui est initialise zro (faux). Cette variable sert de test
de boucle. Lorsquil ny a plus de ligne examiner, on le positionne 1 (vrai).
La ligne :
declare continue handler for sqlstate 02000 set fini = 1;

est appele gestionnaire declare. Elle ressemble une exception dans les procdures
stockes. Vous pouvez galement implmenter des gestionnaires continue et des
gestionnaires exit. Les gestionnaires continue, comme celui prsent ici, ralisent
laction indique puis poursuivent lexcution de la procdure, tandis que les gestion-
naires exit quittent le bloc begin...end le plus proche.
La partie suivante du gestionnaire declare indique quel moment le gestionnaire sera
appel. Ici, il sera appel lorsque sqlstate 02000 est atteint, ce qui est un moyen
cryptique de signifier que lappel se fera lorsque aucune ligne nest trouve. Vous trai-
tez un ensemble rsultat ligne par ligne et, lorsque vous tes court de lignes, ce
338 Partie II Utilisation de MySQL

gestionnaire sera appel. Vous pourriez galement indiquer FOR NOT FOUND, ce qui est
quivalent. Les autres options sont SQLWARNING et SQLEXCEPTION.
Vient ensuite un curseur. Celui-ci sapparente assez un tableau. Il rcupre un
ensemble rsultat dune requte (comme celui renvoy par mysqli query()) et vous
permet de le traiter ligne par ligne (comme vous le feriez par exemple avec
mysqli fetch row()). Considrez le curseur suivant :
declare c1 cursor for select idcommande, montant from commandes;

Ce curseur est appel c1. Il ne sagit que dune dfinition de ce quil va contenir. La
requte ne sera pas encore excute.
La ligne suivante :
open c1;

excute la requte elle-mme. Pour obtenir chaque ligne de donnes, vous devez excu-
ter une instruction fetch. Cela se fait dans une boucle repeat. Dans le cas prsent, la
boucle ressemble ceci :
repeat
...
until fini end repeat;

Notez que la condition (until fini) nest pas vrifie avant la fin. Les procdures stockes
supportent galement les boucles while de la forme suivante :
while condition do
...
end while;

Il existe aussi des boucles loop, de la forme suivante :


loop
...
end loop

Ces boucles ne possdent pas de conditions intgres, mais on peut les quitter laide
dune instruction leave;.
Notez quil nexiste pas de boucles for.
Toujours dans notre exemple, la ligne suivante du code extrait une ligne de donnes :
fetch c1 into cet_id, ce_montant;

Cette ligne rcupre une ligne partir de la requte du curseur. Les deux attributs
rcuprs par la requte sont stocks dans les deux variables locales spcifies.
On vrifie si une ligne a t rcupre puis on compare le montant de la boucle actuelle
avec le montant maximal stock, au moyen de deux instructions IF :
if not fini then
if ce_montant > l_montant then
Chapitre 13 Programmation MySQL avance 339

set l_montant = ce_montant;


set l_id = cet_id;
end if;
end if;

Notez que les valeurs de variable sont dfinies au moyen de linstruction set.
Outre if...then, les procdures stockes disposent galement dune structure
if...then...else de la forme suivante :
if condition then
...
[elseif condition then]
...
[else]
...
end if

Il existe galement une instruction case, qui possde la forme suivante :


case valeur
when valeur then instruction
[when valeur then instruction ...]
[else instruction]
end case

Pour revenir notre exemple, une fois que la boucle a termin, il reste un peu de
nettoyage faire :
close c1;
set max_id = l_id;

Linstruction close ferme le curseur.


Pour finir, vous positionnez le paramtre OUT la valeur que vous avez calcule. Vous
pouvez utiliser le paramtre non pas comme une variable temporaire mais uniquement
pour stocker la valeur finale (cet emploi est semblable celui dautres langages de
programmation, comme Ada).
Si vous crez cette procdure comme on la indiqu ici, vous pouvez lappeler comme
vous avez appel lautre procdure :
call max_commande(@l);
select @l;

Vous devriez obtenir une sortie comme celle-ci :


+------+
| @l |
+------+
| 3 |
+------+

Vous pouvez vrifier par vous-mme que le calcul est cor