Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
PHP &
MySQL
Luke Welling
Laura Thomson
Rseaux
et tlcom
Dveloppement
Web
Gnie logiciel
Scurit
Systme
4e dition
dexploitation
PHP
& MySQL
4e dition
Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions
thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle.
Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices
ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou
programmes.
Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs
propritaires respectifs.
Publi par Pearson Education France Titre original : PHP and MySQL Web Development,
47 bis, rue des Vinaigriers Fourth edition
75010 PARIS
Tl. : 01 72 74 90 00 Traduit et rvis de lamricain par ric Jacoboni
www.pearson.fr (dition prcdente : Patrick Fabre et David de Loenzien)
Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la
proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans
le respect des modalits prvues larticle L. 122-10 dudit code.
No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including
photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.
Table des matires
Introduction ...................................................................................................................... 1
Les points forts de ce livre .......................................................................................... 1
Ce que vous apprendrez en lisant ce livre .................................................................. 2
Prsentation de PHP ................................................................................................... 2
Prsentation de MySQL ............................................................................................. 3
Pourquoi utiliser PHP et MySQL ? ............................................................................ 4
Quelques avantages de PHP ....................................................................................... 4
Performances ................................................................................................... 5
Adaptabilit ..................................................................................................... 5
Intgration avec les bases de donnes ............................................................. 5
Bibliothques intgres ................................................................................... 5
Cot ................................................................................................................. 6
Facilit dapprentissage de PHP ...................................................................... 6
Support orient objet ...................................................................................... 6
Portabilit ........................................................................................................ 6
Souplesse dans le processus de dveloppement ............................................. 6
Code source ..................................................................................................... 7
Disponibilit du support et de la documentation ............................................. 7
Nouveauts de PHP 5 ................................................................................................. 7
Quelques avantages de MySQL .................................................................................. 8
Performances ................................................................................................... 8
Cot rduit ....................................................................................................... 8
Simplicit demploi ......................................................................................... 8
Portabilit ........................................................................................................ 9
Code source ..................................................................................................... 9
Disponibilit du support .................................................................................. 9
Nouveauts de MySQL 5 ........................................................................................... 9
Organisation de ce livre .............................................................................................. 10
Encore un mot ............................................................................................................. 11
IV PHP & MySQL
Partie I
Utilisation de PHP
Partie II
Utilisation de MySQL
11 Accs une base de donnes MySQL partir du Web avec PHP ........................ 281
Fonctionnement des architectures de bases de donnes web ..................................... 281
Principales tapes dans linterrogation dune base de donnes partir du Web ............ 285
Vrifier et filtrer les donnes saisies par lutilisateur ................................................. 285
tablissement de la connexion ................................................................................... 286
Choisir une base de donnes utiliser ........................................................................ 287
Interroger la base de donnes ..................................................................................... 288
Rcuprer les rsultats de la requte .......................................................................... 289
Dconnexion de la base de donnes ........................................................................... 290
Ajouter des informations dans la base de donnes ..................................................... 290
Utiliser des instructions prpares .............................................................................. 294
Autres interfaces PHP pour les bases de donnes ...................................................... 295
Utilisation dune interface de base de donnes gnrique : PEAR::MDB2 ............... 296
Pour aller plus loin ...................................................................................................... 298
Pour la suite ................................................................................................................ 298
Partie III
Scurit
Partie IV
Partie V
Partie VI
Annexes
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.
Prsentation de PHP
PHP est un langage de script ct serveur qui a t conu spcifiquement pour le Web.
Le code PHP est inclus dans une page HTML et sera excut chaque fois quun visiteur
Introduction 3
affichera la page. Le code PHP est interprt au niveau du serveur web et gnre du
code HTML ou toute autre donne affichable dans le navigateur de lutilisateur.
PHP a t conu en 1994 par Rasmus Lerdorf. Il a ensuite t adopt par dautres
personnes talentueuses et rcrit quatre fois avant de devenir le produit abouti que nous
connaissons aujourdhui. En novembre 2007, il tait install sur plus de 21 millions de
domaines et sa croissance est rapide. Vous trouverez des statistiques plus rcentes sur le
site http://www.php.net/usage.php.
PHP est un projet open-source, ce qui signifie que vous pouvez vous procurer son code,
lutiliser, le modifier et le redistribuer gratuitement.
PHP signifiait lorigine Personal Home Page, mais ce nom a t chang en un acro-
nyme rcursif comme GNU (Gnus Not Unix) : il signifie maintenant PHP Hypertext
Preprocessor.
La dernire version principale de PHP est la version 5. Elle bnficie dune rcriture
complte du moteur Zend et de quelques amliorations importantes au niveau du
langage.
La page daccueil de PHP est accessible ladresse http://www.php.net.
La page de Zend Technologies, lentreprise des fondateurs de PHP, se trouve ladresse
http://www.zend.com.
Prsentation de MySQL
MySQL est un systme de gestion de bases de donnes relationnelles (SGBDR) robuste
et rapide. Une base de donnes permet de manipuler les informations de manire effi-
cace, de les enregistrer, de les trier, de les lire et dy effectuer des recherches. Le serveur
MySQL contrle laccs aux donnes pour sassurer que plusieurs utilisateurs peuvent
se servir simultanment dune mme base de donnes pour y accder rapidement et
pour garantir que seuls les utilisateurs autoriss peuvent accder aux donnes. MySQL
est donc un serveur multi-utilisateur et multithread. Il utilise SQL (Structured Query
Language), le langage standard des requtes de bases de donnes. MySQL est disponi-
ble depuis 1996, mais son dveloppement remonte 1979. Il sagit de la base de
donnes open-source la plus employe au monde et elle a reu le Linux Journal
Readers Choice Award plusieurs reprises.
MySQL est dsormais disponible sous une double licence. Vous pouvez lutiliser
gratuitement sous licence open-source (GPL) condition de respecter les termes de
cette licence. Si vous souhaitez distribuer une application non GPL incluant MySQL,
vous pouvez aussi acheter une licence commerciale.
4 PHP & MySQL
m un systme dexploitation ;
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.
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.
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.
Bibliothques intgres
PHP ayant t conu pour tre utilis sur le Web, il possde de nombreuses fonc-
tions intgres permettant deffectuer la plupart des tches de programmation web.
6 PHP & MySQL
Vous pouvez ainsi gnrer des images en temps rel, vous connecter des services
web et dautres services rseaux, analyser des documents XML, envoyer du courrier
lectronique, manipuler les cookies et produire des documents PDF avec seulement
quelques lignes de code.
Cot
PHP est gratuit. Vous pouvez vous procurer la dernire version du langage sur le site
http://www.php.net, sans payer quoi que ce soit.
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.
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.
Nouveauts de PHP 5
Il se peut que vous soyez rcemment pass de lune des versions PHP 4.x PHP 5.
Comme on est en droit de lattendre dans une nouvelle version majeure, dimportantes
modifications ont vu le jour et le moteur Zend de PHP a t rcrit pour cette version.
Voici les principales nouvelles fonctionnalits :
m un meilleur support orient objet construit autour dun modle objet entirement
nouveau (voir Chapitre 6) ;
m la gestion des exceptions pour un traitement volutif des erreurs, facilitant la main-
tenance (voir Chapitre 7) ;
m SimpleXML pour une gestion simplifie des donnes XML (voir Chapitre 31).
Parmi les autres modifications, notons encore le dplacement de certaines extensions de
linstallation PHP par dfaut dans la bibliothque PECL, lamlioration de la gestion
des flux et lajout de SQLite.
Au moment o nous crivons ce livre, la version courante de PHP est la 5.2 et la
version 5.3 se profile lhorizon. PHP 5.2 ajoute un certain nombre de fonctionnalits
intressantes :
m une nouvelle extension pour filtrer les entres, afin damliorer la scurit ;
m lextension JSON pour amliorer linteroprabilit avec JavaScript ;
m le suivi de la progression des dpts de fichiers ;
8 PHP & MySQL
Performances
MySQL est indniablement un systme rapide. Vous pouvez consulter les statistiques
de ses performances sur le site http://web.mysql.com/why-mysql/benchmark.html.
La plupart des tests montrent que MySQL est bien plus rapide que ses concurrents, de
plusieurs ordres de grandeur. En 2002, eWeek a publi un banc dessais qui comparait
cinq bases de donnes alimentant une application web. Le meilleur rsultat a plac ex
quo MySQL et Oracle, qui est pourtant un produit bien plus cher.
Cot rduit
MySQL est disponible gratuitement sous une licence open-source ou, pour un prix trs
raisonnable, sous licence commerciale. Vous devez vous procurer une licence si vous
souhaitez redistribuer MySQL dans une application et que vous ne souhaitiez pas que
lapplication se trouve sous licence open-source. Si vous ne comptez pas distribuer
votre application (ce qui est gnralement le cas de la plupart des applications web) ou
si vous travaillez sur un logiciel open-source, il nest pas ncessaire dacheter une
licence.
Simplicit demploi
La plupart des bases de donnes modernes utilisent SQL. Si vous connaissez dj
dautres SGBDR, vous ne devriez pas avoir de problme pour vous adapter. En outre,
Introduction 9
MySQL est plus simple installer que la plupart des produits similaires. La courbe
dapprentissage ncessaire lacquisition des comptences dun administrateur de base
de donnes (DBA, ou DataBase Administrator) est bien plus courte que celle des autres
bases de donnes.
Portabilit
MySQL peut tre utilis sur un grand nombre de systmes Unix, ainsi quavec
Windows.
Code source
Comme pour PHP, vous pouvez vous procurer le code source de MySQL. Pour la
plupart des utilisateurs, ce point nest pas important, mais il doit vous tranquilliser
lesprit en vous assurant une continuit future et en vous offrant des possibilits en cas
durgence.
Disponibilit du support
Tous les produits open-source nont pas une entreprise parente qui propose des services
de support, de formations, de consultation et de certification : vous pouvez obtenir tout
cela de la part de MySQL AB (www.mysql.com).
Nouveauts de MySQL 5
Parmi les modifications majeures introduites par MySQL 5, nous citerons les suivantes :
m les vues ;
m les procdures stockes (voir Chapitre 13) ;
m un support minimal des triggers ;
m le support des curseurs.
On peut galement noter une meilleure compatibilit avec le standard ANSI et des
amliorations en matire de vitesse.
Si vous utilisez toujours une ancienne version 4.x ou 3.x du serveur MySQL, vous
devez savoir que les fonctionnalits suivantes ont t ajoutes aux diffrentes versions
depuis la version 4.0 :
m support des sous-requtes ;
m types GIS pour stocker les donnes gographiques ;
m support amlior pour linternationalisation ;
10 PHP & MySQL
Organisation de ce livre
Ce livre est dcoup en cinq parties.
La premire partie prsente les diffrents lments du langage PHP, ainsi que quelques
exemples. Tous ces exemples sont pratiques, issus de notre exprience dans limpl-
mentation dun site de commerce lectronique, et non thoriques. La prsentation de
PHP dbute avec le Chapitre 1 : si vous connaissez dj le langage, vous pouvez passer
directement au chapitre suivant. Si vous dbutez en PHP ou en programmation, en
revanche, il peut tre intressant de vous y arrter un peu plus longuement. Si vous
connaissez dj PHP 4, consultez quand mme le Chapitre 6 car les fonctionnalits
orientes objet ont sensiblement chang.
La deuxime partie aborde les concepts ncessaires lutilisation des systmes de bases
de donnes relationnelles, comme MySQL, lutilisation de SQL, linterconnexion de
votre base de donnes MySQL avec le monde extrieur, en passant par PHP et certains
concepts avancs de MySQL, comme la scurit et les optimisations.
La troisime partie est consacre aux problmes gnraux qui peuvent survenir lors du
dveloppement dun site web dans nimporte quel langage. Les problmes les plus
importants concernent la scurit. Nous verrons ensuite comment vous pouvez tirer
profit de PHP et de MySQL pour authentifier vos utilisateurs et collecter, transmettre et
enregistrer vos donnes en toute scurit.
La quatrime partie sintresse plus prcisment aux principales fonctions intgres dans
PHP. Nous avons slectionn des groupes de fonctions qui vous intresseront srement
Introduction 11
lorsque vous implmenterez un site web. Vous y apprendrez notamment ce quest linte-
raction avec le serveur, linteraction avec le rseau, la gnration dimages, les manipu-
lations de date et dheure et les variables de sessions.
La cinquime et dernire partie est notre prfre : nous y tudierons quelques probl-
mes rels, comme la gestion et le suivi de projets importants, ainsi que le dbogage des
applications. Nous prsenterons galement quelques projets mettant en vidence la
puissance et la flexibilit de PHP et de MySQL.
Encore un mot
Nous esprons que ce livre vous satisfera et que vous serez aussi passionn par
lapprentissage de PHP et de MySQL que nous lavons t lorsque nous avons
commenc nous servir de ces logiciels. Leur utilisation est un plaisir part entire.
Vous serez bientt mme de rejoindre les milliers de dveloppeurs web qui se servent
de ces outils puissants et robustes pour construire des sites web dynamiques.
I
Utilisation de PHP
Utilisation de PHP
La ralisation et lexcution des exemples prsents dans cet ouvrage ncessitent davoir
accs un serveur web sur lequel PHP est install. Pour tirer le meilleur parti des exemples
et des cas dcole traits ici, il est conseill de les excuter et dessayer de les modifier.
Pour cela, vous avez besoin dune installation de test o vous puissiez exprimenter loisir.
Si PHP nest pas install sur votre ordinateur, vous devez commencer par procder
son installation ou contacter votre administrateur systme pour quil sen charge. Vous
trouverez lAnnexe A, "Installation de PHP et de MySQL", une description de la
procdure dinstallation.
Formulaires HTML
Le traitement des formulaires HTML constitue une des applications les plus courantes
que doivent prendre en charge les langages de script excuts ct serveur. Cest pour-
quoi nous allons commencer lapprentissage de PHP par limplmentation dun formu-
laire de commande pour une entreprise fictive de vente de pices dtaches dnomme
Le garage de Bob. Vous trouverez tout le code relatif cette application modle dans le
rpertoire chapitre01 sur le site Pearson.
Code du formulaire
Nous allons partir du stade o le programmeur de lentreprise a tabli un formulaire
permettant aux clients de passer des commandes (voir Figure 1.1). Il sagit dun formu-
laire simple, comparable aux nombreux autres publis sur le Web.
Figure 1.1
Le formulaire initial
de Bob nenregistre
que les articles
et leurs quantits
respectives.
partir de ce formulaire, Bob veut en premier lieu rcuprer la liste des articles
commands par son client, tablir le montant total de la commande, ainsi que le
montant des taxes payer sur cette commande.
Chapitre 1 PHP : les bases 17
Une partie du code HTML gnrant ce formulaire est prsente dans le Listing 1.1.
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.
Enregistrez votre fichier, puis chargez-le dans votre navigateur web en remplissant le
formulaire de Bob et en cliquant sur le bouton Passer commande. La Figure 1.2 montre
le rsultat que vous devez alors obtenir.
Figure 1.2
Le texte pass une
instruction echo de
PHP est affich dans
le navigateur web.
Chapitre 1 PHP : les bases 19
Notez comment le code PHP a t incorpor dans un fichier HTML "normal". Affichez
la source de la page dans votre navigateur. Voici le code que vous devriez voir :
<html>
<head>
<title>Le garage de Bob - Rsultats de la commande</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Rsultats de la commande</h2>
<p>Commande traite.
</body>
</html>
Le code PHP brut nest pas affich tel quel dans le navigateur. En effet, linterprteur
PHP analyse le script et le remplace par le rsultat de son excution. partir dun
script PHP, nous pouvons ainsi produire du code HTML directement affichable dans un
navigateur, sans que le navigateur comprenne le langage PHP.
Cet exemple illustre le concept de programmation web ct serveur : le code PHP est
interprt et excut sur le serveur web, contrairement au code JavaScript et aux autres
technologies ct client, qui sont interprtes et excutes par le navigateur, sur lordi-
nateur de lutilisateur.
Le code contenu dans le fichier considr ici se compose de quatre lments :
m du HTML ;
m des balises PHP ;
m des instructions PHP ;
m des espaces.
Nous pouvons galement y ajouter des commentaires.
La plupart des lignes de cet exemple sont simplement du code HTML.
Balises PHP
Dans lexemple prcdent, le code PHP commence par les caractres <? et se
termine par les caractres ?>. Cette syntaxe est comparable la syntaxe des balises
du HTML, qui commencent elles aussi par le caractre < (infrieur ) et se terminent
par le caractre > (suprieur ). Ces symboles sont appels balises PHP et indiquent
au serveur web o commence et o finit le code PHP. Tout texte plac entre ces bali-
ses est interprt comme du code PHP et tout texte situ en dehors est trait comme
du code HTML normal. Les balises PHP permettent ainsi de "schapper" du
contexte HTML.
Il existe diffrents types de balises. Examinons-les plus en dtail.
20 Partie I Utilisation de PHP
Il sagit du style de balise qui sera employ dans ce livre. Ce style est le style de rf-
rence utiliser avec PHP 3 et PHP 4 car ladministrateur du serveur ne peut pas le
dsactiver, ce qui vous garantit sa disponibilit sur tous les serveurs et qui est particu-
lirement important si vous crivez des applications qui peuvent tre utilises sur
diffrentes installations. Ce style de balise est compatible avec des documents XML
(eXtensible Markup Language). Nous vous conseillons dutiliser ce style de balise.
m Style abrg :
<? echo "<p>Commande traite.";?>
Ce style de balise est le plus simple ; il respecte le style des instructions de traite-
ment SGML (Standard Generalized Markup Language). Pour utiliser ce type de
balise, qui est le plus rapide saisir au clavier, vous devez autoriser loption
open tag dans votre fichier de configuration ou compiler PHP en activant les bali-
ses abrges. Vous trouverez plus dinformations concernant ce style de balise dans
lAnnexe A. Nous vous dconseillons de lutiliser car il ne fonctionnera pas dans de
nombreux environnements puisquil nest plus activ par dfaut.
m Style SCRIPT :
<SCRIPT LANGUAGE=php> echo "<p>Commande traite."; </SCRIPT>
Ce style de balise est le plus long et le plus familier pour les utilisateurs de Java-
Script ou de VBScript. Vous pouvez ladopter si votre diteur HTML pose problme
avec les autres styles de balise.
m Style ASP :
<% echo "<p>Commande traite.";%>
Ce style de balise est analogue au style utilis dans les pages ASP (Active Server Pages)
ou ASP.NET. Pour lemployer, vous devez activer le paramtre de configuration
asp tags. Vous navez aucune raison dutiliser ce style, sauf si votre diteur de texte est
orient ASP ou ASP.NET. Notez que, par dfaut, ce style de balise est dsactiv.
Instructions de PHP
Pour informer linterprteur PHP des actions entreprendre, il faut insrer des instruc-
tions entre les balises PHP douverture et de fermeture.
Chapitre 1 PHP : les bases 21
Dans lexemple considr ici, nous nutilisons quun seul type dinstruction :
echo "<p>Commande traite.";
Espaces
Les caractres despacement, tels que les nouvelles lignes (retour chariot), les espaces
et les tabulations, constituent ce que lon appelle des espaces. Vous le savez probable-
ment dj, les navigateurs ignorent les espaces dans le code HTML. Il en va de mme
avec le moteur PHP.
Soit les deux fragments HTML suivants :
<h1>Bienvenue dans le garage de Bob!</h1><p>Que voulez-vous commander aujourdhui?
et
<h1>Bienvenue dans le garage
de Bob!</h1>
<p>Que voulez-vous commander
aujourdhui?
Lexcution de ces deux fragments donne le mme rsultat laffichage parce quils
apparaissent comme identiques pour le navigateur web. Vous pouvez toutefois utiliser
des espaces dans votre code HTML et vous tes mme fortement encourag le faire
avec soin pour amliorer la lisibilit de votre code. Il en va de mme en PHP. Rien ne
vous oblige insrer des espaces entre des instructions PHP, mais vous obtiendrez des
programmes PHP beaucoup plus lisibles si vous placez vos instructions sur des lignes
spares. Par exemple :
echo bonjour;
echo tous;
et
echo bonjour ;echo tous;
Commentaires
Les commentaires placs dans les programmes sont en quelque sorte des indications
crites lintention des personnes qui lisent le code. Vous pouvez insrer des commen-
taires pour expliquer les actions du script, indiquer lauteur du script, expliquer pour-
quoi limplmentation a t effectue de telle manire, donner la date de dernire
modification et ainsi de suite. En gnral, tous les scripts PHP contiennent des
commentaires, lexception peut-tre des plus simples.
Linterprteur PHP ignore tout le texte plac dans un commentaire. Plus prcisment,
lanalyseur PHP saute les commentaires, comme sil sagissait despaces.
Le langage PHP supporte les commentaires de style C, C++ et shell.
Voici un commentaire de plusieurs lignes crit dans le style C et qui pourrait figurer au
dbut dun script PHP :
/* Auteur: Bob Smith
Date de dernire modification: 10 avril
Ce script traite les commandes client.
*/
Les commentaires sur plusieurs lignes doivent tre encadrs par les paires de caractres
/* et */. Tout comme en C, il est interdit dimbriquer des commentaires multiligne.
Vous pouvez galement insrer des commentaires dune seule ligne, soit dans le style
C++ :
echo <p>Commande traite.; // Dbut de laffichage
soit dans le style des scripts shell :
echo <p>Commande traite.; # Dbut de laffichage
Avec ces deux derniers styles, tout le texte plac aprs le symbole de commentaire ( # ou
//) est considr comme du commentaire tant que la fin de la ligne ou la balise PHP de
clture na pas t atteinte.
Dans la ligne de code suivante, le texte avant la balise fermante, voici un commen
taire, fait partie dun commentaire. Le texte aprs la balise fermante, pas ici, est
trait comme du HTML parce quil se trouve aprs la balise fermante :
// voici un commentaire?> pas ici
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).
Dans cet exemple, ainsi que dans tout le reste de cet ouvrage, nous avons adopt le
style mdium de rfrencement des variables de formulaire (autrement dit,
$ POST[qte pneus]), mais nous crons des versions abrges des variables pour des
raisons de commodit (cette approche est recommande depuis PHP 4.2.0).
Pour vos programmes personnels, vous pouvez choisir une approche diffrente mais
vous devez tre conscient des enjeux ; cest pourquoi nous prsentons ds maintenant
les diffrentes mthodes.
Chapitre 1 PHP : les bases 25
En bref :
m Si le style abrg ($qte pneus) est pratique, il exige que le paramtre de configuration
register globals soit activ. Son activation ou sa dsactivation par dfaut dpend de
la version de PHP. Dans toutes les versions depuis 4.2.0, il a t dsactiv par dfaut.
Ce style favorisant les erreurs susceptibles de rendre votre code vulnrable aux atta-
ques, il est dsormais dconseill. Ce serait de toute faon une mauvaise ide de lutili-
ser dans du nouveau code car il y a de fortes chances pour quil disparaisse en PHP 6.
m Le style mdium ($ POST[qte pneus]) est maintenant lapproche recommande.
Il est assez pratique mais nest apparu quavec PHP 4.1.0 ; il ne fonctionnera donc
pas sur de trs anciennes installations.
m Le style long ($HTTP POST VARS[qte pneus]) est le plus "bavard". Notez
cependant quil a t dclar obsolte (deprecated) et quil est en consquence
vraisemblable quil disparatra dans le long terme. Ce style tait auparavant le
plus portable mais peut maintenant tre dsactiv via la directive de configuration
register long arrays, qui amliore les performances. L aussi, il est dconseill
de lutiliser dans du nouveau code, sauf si lon a de trs bonnes raisons de penser
que le script sera install sur un serveur ancien.
Lorsquon emploie le style abrg, les variables du script portent les mmes noms que
les champs du formulaire HTML, cest pourquoi il nest pas ncessaire de dclarer les
variables ou dentreprendre quoi que ce soit pour les crer dans le script. Les variables
sont passes au script de la mme faon que des arguments le sont une fonction. Avec
le style abrg, on peut donc se contenter dutiliser une variable comme $qte pneus car
le champ du formulaire la cre automatiquement dans le script de traitement.
Ce type daccs pratique aux variables est attrayant mais, avant dactiver
register globals, il convient de sintresser aux raisons pour lesquelles lquipe
charge du dveloppement de PHP la dsactive.
Le fait de pouvoir accder directement aux variables est trs pratique mais cela facilite
lapparition derreurs de programmation susceptibles de compromettre la scurit de
vos scripts. Lorsque les variables dun formulaire deviennent automatiquement des
variables globales, il ny a plus de sparation vidente entre les variables cres par le
programmeur et les variables douteuses directement envoyes par lutilisateur.
Si vous ne prenez pas la prcaution de donner toutes vos variables une valeur initiale,
les utilisateurs de vos scripts peuvent donc passer des variables et des valeurs, sous la
forme de variables de formulaire, qui se mlangeront aux vtres. En consquence, si
vous choisissez le style abrg pour accder aux variables, vous devez vous assurer de
donner une valeur initiale vos variables.
Le style mdium implique la rcupration des variables de formulaire partir dun
des tableaux $ POST, $ GET ou $ REQUEST. Un tableau $ GET ou $ POST contiendra
26 Partie I Utilisation de PHP
tous les dtails de toutes les variables du formulaire. Le choix du tableau dpend de
la mthode (GET ou POST, respectivement) utilise pour lenvoi du formulaire.
En outre, une combinaison de toutes les donnes envoyes via POST ou GET sera dispo-
nible par le biais de $ REQUEST.
Si le formulaire utilise la mthode POST, la valeur entre dans le champ qte pneus sera
enregistre dans $ POST[qte pneus]. Si cest la mthode GET qui est employe, cette
valeur sera contenue dans $ GET[qte pneus]. Dans les deux cas, la valeur sera
disponible dans $ REQUEST[qte pneus].
Ces tableaux font partie des tableaux "superglobaux", dont nous reparlerons lorsque
nous voquerons la porte des variables.
Si vous utilisez une version trs ancienne de PHP, il est possible que vous nayez pas
accs aux tableaux $ POST ou $ GET : dans les versions antrieures la 4.1.0, les
mmes informations taient enregistres dans des tableaux appels $HTTP POST VARS et
$HTTP GET VARS. Cest ce que nous appelons le style long. Comme nous lavons indi-
qu prcdemment, ce style a t dclar "obsolte". Il ny a pas dquivalent au tableau
$ REQUEST dans ce style.
Avec le style long, vous pouvez accder la rponse de lutilisateur via
$HTTP POST VARS[qte pneus] ou $HTTP GET VARS[qte pneus].
Les exemples dans ce livre ont t tests avec la version 5.2 de PHP et ils seront parfois
incompatibles avec des versions de PHP antrieures la version 4.1.0. Cest pourquoi nous
vous recommandons dutiliser, dans la mesure du possible, une version rcente de PHP.
Prenons un autre exemple. Le style mdium de rfrencement des variables utilisant un
type de variable appel tableau (lesquels ne seront vraiment tudis quau Chapitre 3),
nous commencerons lcriture du script en crant des copies de variables plus faciles
manipuler.
Pour copier la valeur dune variable dans une autre, servez-vous de loprateur daffec-
tation, qui, en PHP, est le signe "gal" (=). La ligne de code suivante cre une nouvelle
variable appele $qte pneus et y copie le contenu de $ POST[qte pneus] :
$qte_pneus = $_POST[qte_pneus];
Insrez le bloc de code qui suit au dbut du script. Tous les autres scripts prsents dans
ce livre et qui traitent des donnes issues de formulaire commenceront par un bloc du
mme genre. Ce bloc ne gnrant pas de sortie, il importe peu quil soit plac avant ou
aprs la balise <html> ou les autres balises HTML du dbut de votre page. En gnral,
nous le plaons au tout dbut du script afin quil soit facilement reprable.
<?php
// Cre des noms de variables abrges
$qte_pneus = $_POST[qte_pneus];
Chapitre 1 PHP : les bases 27
$qte_huiles = $_POST[qte_huiles];
$qte_bougies = $_POST[qte_bougies];
?>
Ce code cre trois nouvelles variables ($qte pneus, $qte huiles et $qte bougies) et
les dfinit de manire quelles contiennent les donnes envoyes via la mthode POST
du formulaire.
Pour que le script ait un effet visible, ajoutez les lignes de code suivantes la fin de
votre script PHP :
echo <p>Rcapitulatif de votre commande:</p>;
echo $qte_pneus . pneus<br />;
echo $qte_huiles . bidons d\huile<br />;
echo $qte_bougies . bougies<br />;
ce stade, vous navez pas vrifi le contenu des variables afin de vous assurer que les
valeurs entres dans chaque champ de formulaire soient cohrentes. Essayez dentrer
de manire dlibre des donnes errones et observez ce qui se passe. Aprs avoir lu la
suite de ce chapitre, vous souhaiterez peut-tre ajouter ce script du code pour la vali-
dation des donnes.
ATTENTION
Utiliser directement les donnes de lutilisateur pour les afficher dans le navigateur comme
ici est une opration risque du point de vue de la scurit. Vous devriez filtrer ces donnes
comme on lexplique au Chapitre 4. Les problmes de scurit sont prsents au Chapitre 14.
Si vous chargez le fichier ainsi cr dans votre navigateur, le script affichera une sortie
comme celle de la Figure 1.4. Les valeurs affiches dpendent videmment de celles
qui ont t entres dans le formulaire.
Figure 1.4
Les variables saisies
par lutilisateur dans le
formulaire sont facile-
ment accessibles dans
processorder.php.
28 Partie I Utilisation de PHP
Les quelques points intressants relever propos de cet exemple sont examins dans
les sous-sections qui suivent.
Concatnation de chanes
Dans ce script, la fonction echo sert afficher la valeur saisie par lutilisateur dans
chacun des champs du formulaire, suivie dun texte indiquant la signification de la
valeur affiche. Examinez attentivement les instructions echo : le nom de la variable et
le texte qui le suit sont spars par un point (.), comme dans la ligne de code suivante :
echo $qte_pneus . pneus<br>;
Cette ligne quivaut linstruction prsente plus haut. Chacun de ces deux formats est
correct et le choix de lun ou lautre est surtout une affaire de got personnel. Le
processus qui consiste remplacer un nom de variable par sa valeur dans une telle
chane est appel "interpolation". Cette fonctionnalit est spcifique aux chanes entre
apostrophes doubles : elle ne fonctionne pas avec les chanes entre apostrophes simples
de cette manire. Si vous excutez la ligne de code suivante :
echo $qte_pneus pneus<br />;
le navigateur affichera simplement "$qte pneus pneus<br />". Lorsque la variable est
encadre par des apostrophes doubles, son nom est remplac par sa valeur. Si elle est
place entre des apostrophes simples, son nom, ou tout autre texte, est envoy tel quel
au navigateur.
Variables et littraux
La variable et la chane concatnes lune avec lautre dans chacune des instructions
echo sont deux entits de nature diffrente. Une variable est un symbole reprsentant
des donnes, tandis quune chane constitue les donnes elles-mmes. Lorsque des
donnes brutes sont spcifies directement dans un programme, comme cest le cas
Chapitre 1 PHP : les bases 29
dans lexemple considr ici, les donnes sont qualifies de "littrales", pour marquer la
diffrence avec une variable. $qte pneus est une variable, cest--dire un symbole dsi-
gnant les donnes saisies par le client. En revanche, pneus<br /> est un littral (cette
chane na pas besoin dtre interprte pour tre envoye au navigateur).
Nous nen avons pas tout fait fini sur ce point. Dans la dernire instruction cite, PHP
remplace dans la chane le nom de variable $qte pneus par la valeur stocke dans la
variable.
Nous avons dj mentionn deux types de chanes : celles encadres par des apostro-
phes doubles et celles encadres par des apostrophes simples. PHP tente dvaluer les
chanes entre apostrophes doubles, ce qui conduit au rsultat du traitement de linstruc-
tion prcdente. Les chanes places entre apostrophes simples sont traites comme des
littraux.
Il existe galement un troisime type de chane : les "documents sur place". Leur
syntaxe (<<<) est familire aux utilisateurs de Perl et a t ajoute PHP 4. Elle permet
de spcifier des chanes longues de manire soigne, en utilisant un marqueur de fin qui
sera utilis pour terminer la chane. Lexemple suivant cre et affiche une chane de trois
lignes :
echo <<<FIN
ligne1
ligne2
ligne3
FIN
Le lexme FIN est entirement arbitraire, mais il ne doit pas apparatre dans le contenu
de la chane. Pour fermer un document sur place, il suffit de placer le lexme au dbut
dune ligne.
Les documents sur place sont interpols, comme les chanes entre apostrophes doubles.
Identificateurs
Les noms des variables sont des identificateurs (tout comme les noms de fonctions et de
classes les fonctions et les classes sont traites aux Chapitres 5 et 6). Le choix des
identificateurs doit tre effectu en respectant quelques rgles simples :
m La longueur dun identificateur nest pas limite. Un identificateur peut se composer
de lettres, de nombres et de blancs souligns.
m Un identificateur ne peut pas commencer par un chiffre.
m En PHP, les identificateurs sont sensibles la casse ( la prsence de minuscules et
de majuscules). $qte pneus est un identificateur diffrent de $Qte Pneus. Le non-
respect de la casse constitue une erreur de programmation commune. Les noms des
30 Partie I Utilisation de PHP
fonctions font exception cette rgle puisquils peuvent tre orthographis sans
respect de la casse.
m Une variable peut porter le mme nom quune fonction. Cette pratique est toutefois
dconseille parce quelle prte confusion. Par ailleurs, vous ne pouvez pas crer
une fonction portant le mme nom quune autre fonction.
Cration de variables
Vous pouvez dclarer et utiliser vos propres variables en plus des variables passes au
script partir du formulaire HTML.
Lune des particularits de PHP est quil nest pas ncessaire de dclarer des variables
avant de les utiliser. Une variable est automatiquement cre lorsquune valeur lui est
affecte pour la premire fois (voir la section suivante pour plus de dtails ce sujet).
Intrt du typage
On dit que PHP est un langage faiblement typ ou quil utilise un typage dynamique.
Dans la plupart des langages de programmation (C, par exemple), une variable ne
peut appartenir qu un seul type de donnes, qui doit tre prcis avant toute utilisa-
tion de la variable. En PHP, le type dune variable est dtermin par la valeur qui lui est
affecte.
Lorsque nous avons cr $qte totale et $montant total, par exemple, leurs types
initiaux ont t dtermins lors de lexcution des instructions suivantes :
$qte_totale = 0;
$montant_total = 0.00;
La valeur entire 0 ayant t affecte la variable $qte totale, celle-ci prend le type
entier. Selon la mme logique, $montant total est de type flottant.
Bien que cela puisse sembler trange, nous pourrions ajouter la ligne suivante notre
script :
$montant_total = Bonjour;
La variable $montant total serait alors de type chane car PHP adapte le type de
chaque variable aux donnes qui y sont contenues, chaque instant.
Cette capacit du langage PHP modifier les types des variables " la vole" peut se
rvler extrmement utile. Souvenez-vous que PHP dtecte "automatiquement" le type
des donnes stockes dans chaque variable et quil renvoie par consquent toujours les
donnes avec le type appropri, lorsque vous rcuprez le contenu dune variable.
LivrePHP&MSQL.book Page 32 Mardi, 25. novembre 2008 1:02 13
Transtypage
Si PHP est un langage faiblement typ, il donne nanmoins la possibilit de forcer le
type dune valeur ou dune variable par un transtypage (casting). Le principe est identi-
que au transtypage du langage C. Il suffit de spcifier le type temporaire entre parenthses,
juste avant la variable concerne.
Nous pourrions ainsi dclarer les deux variables cites prcdemment, $qte_totale et
$montant_total, en effectuant un transtypage comme suit :
$qte_totale = 0;
$montant_total = (double)$qte_totale;
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 concept peut sembler abscons, mais vous en saisirez mieux lutilit lorsque nous
lappliquerons dans lexemple donn dans la section consacre aux boucles for, un peu
plus loin dans cet ouvrage. Plutt qunumrer et utiliser chaque variable dun formu-
laire sparment, nous utiliserons une boucle et une mme variable pour traiter automa-
tiquement toutes les variables du formulaire.
Chapitre 1 PHP : les bases 33
Constantes
Comme nous lavons mentionn plus haut, nous pouvons modifier la valeur stocke dans
une variable. Nous pouvons galement dclarer des constantes. Tout comme une variable,
une constante stocke une valeur mais, contrairement une variable, cette valeur est fixe
"une fois pour toutes" et ne peut plus tre modifie un autre endroit du script.
Dans notre exemple du site de Bob, les prix des diffrents articles proposs la vente
pourraient tre stocks dans des constantes. La dfinition dune constante seffectue au
moyen de la fonction define :
define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(PRIX_BOUGIES, 4);
Ajoutez ces lignes de code votre script. Nous disposons prsent de trois constantes
qui peuvent tre utilises pour calculer le total de la commande passe par le client.
Vous remarquerez que tous les noms de constante sont ici spcifis en majuscules. Cette
convention est emprunte au langage C : elle permet de distinguer dun coup dil
variables et constantes. Elle nest pas obligatoire, mais fortement recommande parce
quelle facilite la lecture et la maintenance du code.
Contrairement aux variables, les constantes ne sont pas prfixes par le caractre dollar.
Pour utiliser la valeur dune constante, il suffit de spcifier son nom. Pour utiliser lune
des constantes cres prcdemment, nous pourrions donc crire :
echo PRIX_PNEUS;
Outre les constantes cres par le programmeur, PHP utilise un grand nombre de constantes
prdfinies. Pour en connatre la liste, utilisez la fonction phpinfo() :
phpinfo();
Lappel phpinfo fournit, entre autres, la liste de toutes les variables et constantes
prdfinies dans PHP. Nous tudierons et utiliserons plusieurs de ces constantes et
variables dans la suite de cet ouvrage.
Lune des autres distinctions entre les variables et les constantes tient ce que les constantes
ne peuvent stocker que des donnes de type boolen, entier, flottant ou chane, cest--
dire des types scalaires.
m Les constantes, une fois dclares, sont toujours visibles globalement ; autrement
dit, elles peuvent tre utilises lintrieur et lextrieur de fonctions.
m Les variables globales dclares dans un script sont visibles dans tout le script, mais
pas lintrieur des fonctions.
m Une variable utilise lintrieur dune fonction et qui est dclare comme tant
globale fait rfrence la variable globale de mme nom.
m Les variables cres lintrieur de fonctions et dclares comme statiques sont
invisibles en dehors de la fonction mais conservent leur valeur entre deux excutions
de la fonction (nous reviendrons sur ce mcanisme au Chapitre 5).
m Les variables cres lintrieur dune fonction sont locales la fonction et cessent
dexister lorsque cette dernire se termine.
partir de PHP 4.2, les tableaux $ GET et $ POST ainsi que dautres variables spciales
utilisent des rgles particulires pour leur porte. Celles-ci sont appeles variables
superglobales ou autoglobales et sont visibles nimporte quel endroit du script, aussi
bien lintrieur qu lextrieur des fonctions.
Voici la liste complte des variables superglobales :
m $GLOBALS. Tableau de toutes les variables globales (comme le mot-cl global, ce
tableau vous permet daccder des variables globales dans une fonction avec
$GLOBALS[ma_variable], par exemple).
m $ SERVER. Tableau des variables denvironnement du serveur.
m $ GET. Tableau des variables passes au script par le biais de la mthode GET.
m $ POST. Tableau des variables passes au script par le biais de la mthode POST.
m $ COOKIE. Tableau des variables des cookies.
m $ FILES. Tableau des variables associes aux transferts de fichiers.
m $ ENV. Tableau des variables denvironnement.
m $ REQUEST. Tableau de toutes les variables entres par lutilisateur, ce qui comprend
les entres de $ GET, $ POST et $ COOKIE (mais pas celles de $ FILES depuis
PHP 4.3.0).
m $ SESSION. Tableau des variables de session.
Nous tudierons chacune de ces variables mesure de nos besoins et reviendrons plus
en dtail sur la notion de porte des variables lorsque nous examinerons les fonctions et
les classes. Jusque-l, toutes les variables que nous utiliserons seront de porte globale.
Chapitre 1 PHP : les bases 35
Oprateurs
Les oprateurs sont reprsents par des symboles et servent manipuler des valeurs et
des variables en les soumettant des oprations. Pour calculer les totaux et la taxe du
bon de commande client de Bob, nous devons recourir des oprateurs.
Nous avons dj mentionn deux oprateurs : loprateur de concatnation de chanes .
et loprateur daffectation =. Dans les sections qui suivent, nous allons passer en revue
la liste complte des oprateurs disponibles en PHP.
En gnral, les oprateurs peuvent prendre un, deux ou trois arguments, la majorit
dentre eux prenant deux arguments. Par exemple, loprateur daffectation prend deux
arguments : lemplacement de stockage gauche du symbole = et une expression,
place sa droite. Ces arguments sont appels oprandes. Un oprande est un lment
auquel sapplique loprateur.
Oprateurs arithmtiques
Les oprateurs arithmtiques de PHP sont trs simples : il sagit en fait des oprateurs
mathmatiques traditionnels. Le Tableau 1.1 numre les oprateurs arithmtiques.
Avec chacun de ces oprateurs, nous pouvons stocker le rsultat de lopration, comme
ici :
$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;
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
Oprateur de rfrence
Loprateur de rfrence & (esperluette) peut tre utilis avec loprateur daffectation.
Normalement, lorsquune variable est affecte une autre, linterprteur PHP effectue
une copie de la premire variable quil stocke quelque part dans la mmoire de lordi-
nateur. Par exemple, considrez les instructions suivantes :
$a = 5;
$b = $a;
Chapitre 1 PHP : les bases 39
Loprateur de rfrence & permet dviter de faire une copie, comme le montre lexemple
suivant :
$a = 5;
$b = &$a;
$a = 7; // les variables $a et $b ont toutes les deux la valeur 7
Les rfrences peuvent tre un peu difficiles comprendre, mais il suffit de considrer
quune rfrence sapparente un alias plutt qu un pointeur. $a et $b pointent toutes
deux vers la mme section de mmoire, mais vous pouvez modifier cela en rinitialisant
lune delles comme ceci :
unset($a);
Cette instruction ne change pas la valeur de $b (7) mais rompt le lien entre $a et la
valeur 7 stocke en mmoire.
Oprateurs de comparaison
Les oprateurs de comparaison servent comparer deux valeurs entre elles. Les expres-
sions contenant de tels oprateurs renvoient les valeurs logiques true (vrai) ou false
(faux), selon le rsultat de la comparaison.
Oprateur dgalit
Loprateur dgalit == (deux signes gal) permet de dterminer si deux valeurs sont
gales. Par exemple, nous pourrions utiliser lexpression :
$a == $b
pour tester si les valeurs stockes dans $a et $b sont identiques. Linterprteur PHP
renvoie la valeur true si les valeurs sont gales et la valeur false si elles sont diff-
rentes.
Loprateur dgalit se confond facilement avec loprateur daffectation. Une telle
confusion est dautant plus dangereuse quelle ne provoque pas une erreur mais conduit
simplement un rsultat qui nest pas celui escompt. En effet, les valeurs non nulles
sont gnralement values comme true tandis que les valeurs nulles sont values
comme false. Supposons que deux variables soient initialises de la manire suivante :
$a = 5;
$b = 7;
40 Partie I Utilisation de PHP
Sil est amen tester lexpression $a = $b, linterprteur PHP renvoie la valeur true et
la raison est facile comprendre : la valeur de lexpression $a = $b est la valeur affecte
loprande qui figure gauche de loprateur daffectation, cest--dire ici 7. Cette
valeur tant non nulle, lexpression est value comme true. Si votre intention initiale
tait de tester lexpression $a == $b (au lieu de $a = $b), qui serait value comme false
par linterprteur PHP, vous avez introduit dans votre code une erreur logique qui peut se
rvler trs difficile dtecter. Vous devez par consquent vous montrer trs prudent lors-
que vous avez recours loprateur daffectation ou loprateur dgalit et vrifier
systmatiquement que vous ne confondez pas ces deux oprateurs.
Cette confusion entre les oprateurs daffectation et dgalit est trs courante et
vous vous y heurterez probablement plusieurs fois au cours de votre carrire de
programmeur.
Oprateurs logiques
Les oprateurs logiques servent combiner les rsultats de conditions logiques. Par exem-
ple, considrons le cas dune variable $a dont la valeur est comprise entre 0 et 100. Pour
Chapitre 1 PHP : les bases 41
vrifier que la valeur de $a est bien situe dans cette plage, il nous faudrait tester les condi-
tions $a >= 0 et $a <= 100 en nous servant de loprateur ET de la manire suivante :
$a >= 0 && $a <=100
Le langage PHP comprend les oprateurs logiques ET, OU, OU EXCLUSIF et NON.
Le Tableau 1.4 dcrit ces diffrents oprateurs.
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.
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
Cette expression permet de dterminer si les tudiants sont reus ou recals leur examen.
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>;
Lexcution de chacun de ces fragments de code produit une liste du contenu du rper-
toire et la stocke dans la variable $out. Celle-ci peut ensuite tre passe en paramtre la
fonction echo pour un affichage dans le navigateur ou traite dune tout autre manire.
Au Chapitre 17, nous tudierons dautres faons dexcuter des commandes sur un
serveur.
Oprateurs de tableau
Loprateur [ ] permet daccder aux lments dun tableau. On se sert galement de
loprateur => dans certains contextes de tableau. Ces oprateurs seront examins au
Chapitre 3.
Vous avez galement accs un certain nombre dautres oprateurs de tableau. Nous
les prsenterons en dtail au Chapitre 3, mais ils sont inclus ici par souci dexhaus-
tivit.
Vous remarquerez que les oprateurs de tableau du Tableau 1.6 ont tous des opra-
teurs quivalents qui fonctionnent avec les variables scalaires. Pour autant que vous
vous souveniez que + opre une addition avec les types scalaires et une union avec les
tableaux, les comportements devraient tre cohrents. Vous ne pouvez pas comparer
des tableaux des types scalaires de manire utile.
Loprateur de type
Il nexiste quun seul oprateur de type : instanceof. Cet oprateur est utilis dans la
programmation oriente objet, mais nous le mentionnons ici par souci dexhaustivit (la
programmation oriente objet est prsente au Chapitre 6).
instanceof vous permet de vrifier si un objet est une instance dune classe parti-
culire, comme dans cet exemple :
class classeExemple{};
$monObjet = new classeExemple();
if ($monObjet instanceof classeExemple)
echo "monObjet est une instance de classeExemple";
$montant_total = 0.00;
define(PRIX_PNEUS, 100);
define(PRIX_HUILES, 10);
define(SPARKPRICE, 4);
+ $qte_bougies * PRIX_BOUGIES;
Si vous actualisez la page dans votre navigateur, vous devriez obtenir un rsultat
comme celui de la Figure 1.5.
Figure 1.5
Les totaux de la
commande client
ont t calculs, mis
en forme et affichs.
Comme vous pouvez le constater, ce morceau de code fait intervenir plusieurs opra-
teurs. Les oprateurs daddition (+) et de multiplication (*) y sont utiliss pour calculer
les montants, tandis que loprateur de concatnation de chanes ( .) sert mettre en
forme la sortie des donnes dans la fentre du navigateur.
Par ailleurs, nous faisons appel la fonction number format() pour mettre en forme les
totaux sous forme de chanes deux dcimales. Cette fonction appartient la bibliothque
mathmatique de PHP.
Si vous examinez attentivement les calculs effectus dans le dernier fragment de code
ajout votre script, vous vous interrogerez peut-tre sur lordre dans lequel ces calculs
sont effectus. Considrez par exemple linstruction :
$montant_total = $qte_pneus* PRIX_PNEUS
+$qte_huiles* PRIX_HUILES
+$qte_bougies * PRIX_BOUGIES;
Le total obtenu semble correct (voir Figure 1.5), mais pourquoi les multiplications ont-
elles t effectues avant les additions ? La rponse cette question rside dans la
notion de priorit des oprateurs, cest--dire dans lordre selon lequel linterprteur
PHP value les oprateurs.
46 Partie I Utilisation de PHP
Associativit Oprateur
de gauche droite ,
de gauche droite or
de gauche droite xor
de gauche droite and
de droite gauche print
de gauche droite = += = *= /= .=%= &= |= ^= ~= <<= >>=
de gauche droite ?:
de gauche droite ||
de gauche droite &&
de gauche droite |
de gauche droite ^
de gauche droite &
non pertinent ==!= ===!==
non pertinent < <= > >=
de gauche droite << >>
de gauche droite + .
de gauche droite * /%
de droite gauche ! ~ ++ (int) (double) (string) (array) (object) @
de droite gauche []
non pertinent new
non pertinent ()
Chapitre 1 PHP : les bases 47
Notez que nous navons pas encore tudi loprateur de plus forte priorit : la tradi-
tionnelle paire de parenthses. Celle-ci sutilise pour renforcer la priorit dune partie
dune expression, afin de forcer son valuation et de contourner les rgles de priorit
des oprateurs.
Considrez linstruction qui suit, tire du dernier exemple tudi :
$montant_total = $montant_total * (1+$taux_taxe);
Si nous avions crit :
$montant_total = $montant_total * 1+$taux_taxe;
loprateur de multiplication aurait t valu en premier puisque sa priorit est plus
forte que celle de loprateur daddition. Le rsultat obtenu aurait alors t incorrect. En
utilisant des parenthses, nous pouvons contraindre linterprteur PHP valuer en
premier la sous-expression 1+$taux taxe.
Vous pouvez insrer dans une expression autant de paires de parenthses que nces-
saire. Le jeu de parenthses le plus interne est valu en premier.
Notez galement la prsence dans ce tableau dun autre oprateur que nous navons pas
encore couvert : linstruction print, qui quivaut echo.
Nous utiliserons gnralement echo dans ce livre, mais vous pouvez utiliser print si
vous le trouvez plus lisible. print et echo ne sont ni lun ni lautre vritablement des
fonctions mais peuvent tous deux tre appels comme des fonctions avec des paramtres
entre parenthses. Tous les deux peuvent galement tre traits comme des oprateurs : il
suffit de placer la chane afficher aprs le mot-cl echo ou print.
Le fait dappeler print comme une fonction lamne renvoyer une valeur (1), ce qui
peut se rvler utile si vous souhaitez produire une sortie lintrieur dune expression
plus complexe, mais cela signifie que print est un peu plus lent que echo.
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
Cette fonction prend un nom de variable comme argument et renvoie true si la variable
existe et false dans le cas contraire. Vous pouvez galement passer une liste de variables
spares par des virgules et isset() renverra true si toutes les variables sont dfinies.
Vous pouvez supprimer une variable au moyen de la fonction unset(), qui fait pendant
la fonction isset(). La fonction unset() a le prototype suivant :
void unset(mixed var[, mixed var[,]]);
La fonction unset() supprime la ou les variables qui lui sont passes en paramtre.
La fonction empty() dtermine si une variable existe et contient une valeur non vide et non
nulle. Elle renvoie true ou false selon le rsultat obtenu. Son prototype est le suivant :
bool empty(mixed var);
Examinons un exemple utilisant ces trois fonctions. Tapez les lignes suivantes la fin
de votre script :
echo isset($qte_pneus): .isset($qte_pneus).<br />;
echo isset($absent): .isset($absent).<br />;
echo empty($qte_pneus): .empty($qte_pneus).<br />;
echo empty($absent): .empty($absent).<br />;
Actualisez la page dans votre navigateur pour observer le rsultat produit par cette srie
dinstructions.
La fonction isset() applique la variable $qte pneus devrait retourner la valeur 1
(true), quelle que soit la valeur saisie dans le champ de formulaire associ cette
variable. Le rsultat retourn par la fonction empty() applique cette variable dpend
en revanche de la valeur saisie (ou non saisie) dans le champ de formulaire.
La variable $absent nexistant pas, la fonction isset() applique ce nom de varia-
ble retourne un rsultat vide (false), tandis que la fonction empty() renvoie 1 (true).
Ces fonctions se rvlent donc trs pratiques pour dterminer si lutilisateur du formu-
laire a ou non rempli les champs qui lui sont proposs.
Chacune de ces fonctions prend une variable en paramtre et renvoie la valeur de cette
variable aprs avoir ralis sa conversion dans le type appropri. La fonction intval()
peut galement vous permettre de spcifier la base pour la conversion lorsque la varia-
ble convertir est une chane (vous pouvez ainsi convertir des chanes hexadcimales
en entiers, par exemple).
Structures de contrle
Dans un langage de programmation, les structures de contrle permettent de contrler
le flux dexcution au sein dun programme ou dun script. Les structures de contrle
peuvent tre classes en deux groupes : les structures conditionnelles (ou de branche-
ment) et les structures de rptition, ou boucles. Les sections qui suivent sont consacres
ltude de chacune de ces structures en PHP.
Instructions if
Nous pouvons utiliser une structure if pour prendre une dcision. Pour cela, nous
devons spcifier une condition. Si la condition est vraie, le bloc de code qui la suit
est excut. Les conditions des instructions if doivent tre spcifies entre paren-
thses ().
Par exemple, si le formulaire de commande en ligne de lentreprise de Bob est renvoy
par un client sans aucun article command, cest sans doute que le client a actionn par
inadvertance le bouton "Passer commande" avant davoir fini de remplir le formulaire.
Au lieu dafficher le message "Commande traite", le navigateur pourrait alors produire
un texte plus appropri, comme "Votre commande ne contient aucun article !".
Laffichage dun tel avertissement simplmente trs facilement au moyen dune
instruction if :
if( $qte_totale == 0 )
echo Votre commande ne contient aucun article!<br />;
La condition utilise ici est $qte totale == 0. Rappelez-vous que loprateur dgalit
(==) est diffrent de loprateur daffectation (=).
La condition $qte totale == 0 est vraie si la variable $qte totale est gale zro. Si
$qte totale est diffrente de zro, la condition est fausse. Lorsque la condition est
value comme vraie (true), linstruction echo est excute.
Chapitre 1 PHP : les bases 51
Blocs de code
Dans les structures conditionnelles telles quune structure if, il est souvent ncessaire
dexcuter plusieurs instructions. Dans ce cas, vous navez pas besoin de placer une
nouvelle instruction if avant chaque instruction excuter : il suffit de regrouper les instruc-
tions de manire former un bloc. Pour dclarer un bloc, encadrez-le par des accolades :
if( 0 == $qte_totale )
{
echo <p style="color:red">;
echo Votre commande ne contient aucun article!;
echo </p>;
}
Les trois lignes de code places ici entre accolades forment un bloc de code. Lorsque la
condition est value comme vraie, tout le bloc (cest--dire les trois lignes qui le consti-
tuent) est excut. Lorsque la condition se rvle fausse, le bloc est intgralement
ignor par linterprteur PHP.
INFO
Comme nous lavons dj mentionn, linterprteur PHP ignore la mise en forme du code. Il
est par consquent fortement recommand dindenter votre code pour en amliorer la lisi-
bilit. Des mises en retrait judicieuses permettent de discerner dun seul coup dil les lignes
des structures conditionnelles qui sont excutes lorsque les conditions sont satisfaites, les
instructions qui sont regroupes en blocs et les instructions qui font partie de boucles ou de
fonctions. Dans les exemples prcdents, linstruction qui dpend de linstruction if et les
instructions qui constituent le bloc sont indentes.
Instructions else
Souvent, il ne suffit pas de dcider quune action doit tre accomplie : il faut aussi choisir
celle qui, parmi un ensemble dactions, doit tre excute.
Une instruction else permet de spcifier une action alternative accomplir lorsque la
condition spcifie dans une instruction if se rvle fausse. Dans lexemple de lentre-
prise de Bob, il est ncessaire dalerter les clients sils transmettent une commande
vide. Par ailleurs, sils soumettent une commande valide, il faut leur renvoyer un rcapitu-
latif de leur commande, pas un message davertissement.
Pour prsenter aux clients soit une alerte, soit un rcapitulatif, nous pouvons introduire
une instruction else dans notre code, comme suit :
if( $qte_totale == 0 )
{
echo Votre commande ne contient aucun article!<br>;
}
else
{
echo $qte_pneus . pneus<br>;
echo $qte_huiles . bidons d\huile<br>;
echo $qte_bougies . bougies<br>;
}
52 Partie I Utilisation de PHP
Vous pouvez ainsi construire des processus logiques complexes en imbriquant des
instructions if les unes dans les autres. Dans le code qui suit, le message davertissement
ne saffichera que lorsque la condition $qte totale == 0 est value comme vraie et
chaque ligne de ce rcapitulatif ne sera produite que si sa propre condition est vraie.
if( $qte_totale == 0)
{
echo Votre commande ne contient aucun article!<br>;
}
else
{
if ( $qte_pneus > 0 )
echo $qte_pneus . pneus<br>;
if ( $qte_huiles > 0 )
echo $qte_huiles . bidons d\huile<br>;
if ( $qte_bougies > 0 )
echo $qte_bougies . bougies<br>;
}
Instructions elseif
Dans bon nombre de situations de prise de dcision, vous devez choisir entre plus de
deux possibilits. Linstruction elseif permet alors de crer une suite de plusieurs
options ; cest une combinaison dune instruction else et dune instruction if. Lorsque
lon prcise une suite de conditions, le programme peut tester chaque condition, jusqu
en trouver une qui soit vraie.
Pour les grosses commandes de pneus, Bob accorde des remises ses clients. Le prin-
cipe de ces remises est le suivant :
m moins de 10 pneus achets, aucune remise ;
m 10-49 pneus achets, 5 % de remise ;
m 50-99 pneus achets, 10 % de remise ;
m 100 pneus achets ou plus, 15 % de remise.
Nous pouvons crire le code pour calculer la remise accorde en utilisant des conditions et
des instructions if et elseif, ainsi que loprateur ET (&&) pour combiner deux conditions :
if( $qte_pneus < 10 )
$remise = 0;
elseif( $qte_pneus >= 10 && $qte_pneus <= 49 )
$remise = 5;
elseif( $qte_pneus>= 50 && $qte_pneus <= 99 )
$remise = 10;
elseif( $qte_pneus > 100 )
$remise = 15;
Notez que vous pouvez indiffremment crire elseif ou else if (avec ou sans espace
intermdiaire).
Dans cette cascade dinstructions elseif, une seule instruction (ou un seul bloc
dinstruction) sera excute. Ce point na pas dimportance dans ce cas prcis parce que
Chapitre 1 PHP : les bases 53
les diffrentes conditions spcifies sexcluent mutuellement les unes des autres (une
seule est vraie un moment donn). En revanche, lorsque plusieurs conditions dun
ensemble peuvent tre vraies simultanment, seule linstruction (ou le bloc dinstructions)
qui suit la premire condition value comme vraie sera excute.
Instructions switch
Une instruction switch est comparable une instruction if, si ce nest quelle permet
dimplmenter une condition susceptible de prendre plus de deux valeurs diffrentes.
Dans une instruction if, la condition peut tre value soit comme vraie, soit comme
fausse alors quavec une instruction switch la condition peut prendre diffrentes
valeurs, pourvu quelles soient toutes du mme type (entier, chane ou double). Vous
devez alors faire appel une instruction case pour grer chaque valeur possible de la
condition et ajouter, ventuellement, un cas par dfaut pour prendre en compte toutes
les situations qui ne correspondent aucune des instructions case.
Bob aimerait connatre la forme de publicit qui se rvle la plus profitable son
commerce. cette fin, il souhaite inclure un sondage dans le formulaire de commande.
Insrez ce code HTML dans votre formulaire de commande et vous obtiendrez le rsultat
montr la Figure 1.6 :
<tr>
<td>Comment avez-vous eu connaissance de notre site?</td>
<td><select name="trouver">
<option value = "a">Client rgulier</option>
<option value = "b">Par un spot publicitaire</option>
<option value = "c">Dans un annuaire tlphonique</option>
<option value = "d">Par un ami</option>
</select>
</td>
</tr>
Figure 1.6
Le formulaire de
commande demande
aux visiteurs comment
ils ont connu le site de
Bob.
54 Partie I Utilisation de PHP
Ce code HTML ajoute la variable de formulaire trouver, qui peut prendre les valeurs
"a", "b", "c" ou "d". Son traitement en PHP pourrait seffectuer au moyen dune srie
dinstructions if et elseif, comme ici :
if($trouver == a)
echo <P>Client rgulier.</P>;
elseif($trouver == b)
echo <P>Client attir par un spot TV. </P>;
elseif($trouver == c)
echo <P>Client attir par un annuaire tlphonique. </P>;
elseif($trouver == d)
echo <P>Client attir par un ami. </P>;
else
echo <P>Impossible de savoir comment ce client nous a
trouvs.</P>;
Nous pourrions galement parvenir au mme rsultat avec une instruction switch :
switch($trouver)
{
case a:
echo <P>Client rgulier. </P>;
break;
case b:
echo <P> Client attir par un spot TV. </P>;
break;
case c:
echo <P>Client attir par un annuaire tlphonique. </P>;
break;
case c:
echo <P>Client attir par un ami. </P>;
break;
default:
echo <P>Impossible de savoir comment ce client nous a
trouvs.</P>;
break;
}
Ces deux exemples supposent que vous ayez extrait $trouver du tableau $ POST.
Une instruction switch se comporte un peu diffremment dune instruction if ou dune
instruction elseif. Une instruction if naffecte quune seule instruction, moins quun
bloc de code nait t dlibrment cr avec une paire daccolades. Une instruction
switch a le comportement inverse : lorsquune instruction case dune structure switch
est active, linterprteur PHP excute les instructions qui suivent jusqu rencontrer
une instruction break. En labsence dinstruction break, une structure switch conduit
lexcution de tout le code succdant linstruction case value comme vraie. Lors-
que linterprteur PHP atteint une instruction break, il excute la ligne de code qui suit
la structure switch.
Chapitre 1 PHP : les bases 55
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
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.
<html>
<body>
<table border="0" cellpadding="3">
<tr>
<td bgcolor="#CCCCCC" align="center">Distance</td>
<td bgcolor="#CCCCCC" align="center">Cot</td>
</tr>
<?php
$distance = 50;
while ($distance <= 250 )
{
echo "<tr>\n <td align=right>$distance</td>\n";
echo " <td align =right>". $distance / 10 ."</td>\n</tr>\n";
$distance += 50;
}
?>
</table>
</body>
</html>
Pour que le code HTML produit par ce script soit plus lisible, vous devez ajouter des
sauts de lignes et des espaces. Comme on la dj voqu, les navigateurs les ignore-
ront, mais ils seront utiles aux lecteurs. Examinez le code HTML produit par vos scripts
pour vous assurer quil reste lisible.
Dans le Listing 1.3, vous pouvez constater que lon a ajout la squence \n dans certai-
nes chanes. Cette squence reprsente le caractre de nouvelle ligne et produira donc
un saut de ligne lorsquil sera affich.
58 Partie I Utilisation de PHP
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 );
pourrait tre converti dans cette nouvelle syntaxe en utilisant les mots-cls if et endif :
if( $qte_totale == 0):
echo Votre commande ne contient aucun article!<br />;
exit;
endif;
Utiliser declare
Une autre structure de contrle de PHP, la structure declare, nest pas utilise aussi
frquemment pour la programmation quotidienne que ne le sont les autres structures.
La forme gnrale de cette structure de contrle est la suivante :
declare (directive)
{
// bloc
}
Chapitre 1 PHP : les bases 61
Cette structure sert dfinir des directives dexcution pour le bloc de code autrement
dit, des rgles spcifiant de quelle manire le code qui suit doit tre excut. Actuelle-
ment, seule une directive dexcution, appele ticks, a t implmente. Elle se dfinit
en insrant la directive ticks=n et vous permet dexcuter une fonction spcifique
toutes les n lignes dans le bloc de code, ce qui est principalement utile pour le profilage
et le dbogage.
La structure de contrle declare nest mentionne ici que par souci dexhaustivit.
Nous prsenterons quelques exemples concernant lutilisation des fonctions tick aux
Chapitres 23 et 24.
Maintenant que vous savez accder aux donnes saisies dans un formulaire HTML et
manipuler ces donnes, nous pouvons examiner les moyens de stockage de ces infor-
mations qui permettent de les retrouver et de les utiliser ultrieurement. Dans notre
exemple, les commandes passes en ligne par les clients doivent tre enregistres, de
sorte pouvoir les traiter et les satisfaire ultrieurement.
Dans ce chapitre, nous verrons comment, dans le contexte de lexemple prcdent,
crire dans un fichier la commande transmise par un client et comment la lire ensuite
partir de ce fichier. Nous verrons galement quun tel stockage ne constitue pas toujours
une bonne solution. Si le nombre de commandes est lev, lemploi dun systme de
gestion de base de donnes comme MySQL devient indispensable.
INFO
Vous trouverez tous les scripts HTML et PHP utiliss dans ce chapitre dans le rpertoire
chapitre 02 tlcharger sur le site Pearson.
Nous avons modifi le formulaire pour lui ajouter un champ permettant de saisir
ladresse de livraison du client (voir Figure 2.1).
Figure 2.1
Dans cette version du for-
mulaire de commande
de lentreprise de Bob,
un champ supplmentaire
est propos pour la saisie
de ladresse de livraison.
Lorsquelle est invoque, la fonction fopen() attend deux, trois ou quatre paramtres.
Le plus souvent, vous nen donnerez que deux, comme dans la ligne de code prc-
dente.
Le premier paramtre est le nom du fichier ouvrir. Ce nom peut ventuellement conte-
nir un chemin daccs, comme dans linstruction prcdente (le fichier orders.txt est
enregistr dans le rpertoire orders). Nous avons utilis la variable prdfinie de PHP
$ SERVER[DOCUMENT ROOT] mais, comme il est peu pratique de manipuler des variables
aux noms longs, nous lui avons attribu un nom abrg.
Cette variable pointe sur la racine de larborescence des documents du serveur web. La
paire de points ("..") signifie "le rpertoire pre du rpertoire racine des documents" :
ce rpertoire est donc situ lextrieur de larborescence des documents pour des
raisons de scurit. En effet, ce fichier doit demeurer inaccessible partir du Web, sauf
par le biais de linterface que nous allons fournir cet effet. Un tel chemin daccs est
qualifi de relatif, parce quil dcrit un emplacement dans le systme de fichier par
rapport la racine de larborescence des documents.
Puisque nous prfrons utiliser le style abrg pour le rfrencement des variables, il
nous faut ajouter la ligne suivante au dbut de notre script :
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
pour copier le contenu de la variable exprime dans le style long dans une variable au
nom abrg.
De la mme faon que nous disposons de plusieurs possibilits pour accder des
donnes de formulaire, il y a diffrentes possibilits pour accder aux variables prdfi-
nies du serveur. Selon la configuration de votre serveur, vous pouvez dsigner la racine
de larborescence des documents par :
m $ SERVER[DOCUMENT ROOT]
m $DOCUMENT ROOT
m $HTTP SERVER VARS[DOCUMENT ROOT]
Comme pour les donnes de formulaire, nous conseillons dutiliser le premier style.
Il est galement possible dindiquer un chemin daccs absolu, cest--dire partant du
rpertoire racine (/ dans un systme Unix et gnralement C:\ dans un systme
Chapitre 2 Stockage et rcupration des donnes 67
Trs peu de gens utilisent des barres obliques inverses (pour faire court, on les appelle
souvent antislashes) pour spcifier des chemins daccs en PHP car le code qui en
rsulte ne pourrait sexcuter que sur Windows. Si vous utilisez des barres obliques, au
contraire, votre code fonctionnera sans modification aussi bien sur des ordinateurs
Windows quUnix.
Le deuxime paramtre passer la fonction fopen() est le mode douverture du
fichier, qui doit tre spcifi sous la forme dune chane. Celui-ci indique lusage prvu
pour le fichier. Dans lexemple considr ici, nous avons utilis la valeur w, ce qui
signifie que le fichier doit tre ouvert en criture. Le Tableau 2.1 rcapitule les diff-
rents modes douverture disponibles.
Tableau 2.1 : Rcapitulatif des diffrents modes douverture dun appel fopen
Tableau 2.1 : Rcapitulatif des diffrents modes douverture dun appel fopen (suite)
Le choix du mode douverture dpend de la manire dont le systme doit tre utilis.
Dans lexemple donn ici, le choix du mode "w" implique que le fichier ne pourra conte-
nir quune seule commande client la fois : chaque entre dune nouvelle commande,
la commande existante sera efface et remplace par la nouvelle. Ce choix nest
videmment pas le plus judicieux et le mode "a" apparat plus appropri (avec le mode
binaire, selon la recommandation) :
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);
de PHP ; voir lAnnexe A). Pour effectuer une telle recherche, le troisime param-
tre doit valoir 1. Si vous demandez PHP de se servir de la valeur du paramtre
include path, il est inutile de fournir un nom de rpertoire ou un chemin daccs :
$fp = fopen(orders.txt, ab, true);
Le quatrime paramtre est galement facultatif. La fonction fopen() permet aux noms
de fichiers dtre prfixs avec un protocole (comme http://) et ouverts un emplace-
ment distant. Certains protocoles autorisent un paramtre supplmentaire. Nous traiterons
de cet usage de la fonction fopen() dans les sections suivantes de ce chapitre.
Si fopen() russit ouvrir le fichier, elle renvoie une ressource qui est un descripteur
du fichier et qui doit tre enregistr dans une variable ($fp dans le cas prsent). Cette
variable permet ensuite daccder au fichier pour y lire ou y crire des donnes.
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
Figure 2.2
PHP affiche un avertissement explicite lorsque louverture dun fichier est impossible.
Face une telle erreur, vous devez vrifier que lutilisateur sous le compte duquel le script
sexcute bnficie des permissions daccs adquates pour le fichier utiliser. Selon la
manire dont est configur votre serveur, le script peut tre excut sous le compte du
serveur web ou sous celui du propritaire du rpertoire contenant le script.
Dans la plupart des systmes, les scripts sont excuts sous le compte du serveur web.
Si, par exemple, votre script est plac dans le rpertoire ~/public_html/chapitre02/ dun
systme Unix, vous pouvez crer un rpertoire accessible tout le monde en criture
afin dy stocker la commande :
mkdir ~/orders
chmod 777 ~/orders
Chapitre 2 Stockage et rcupration des donnes 71
Gardez bien lesprit le danger que constituent les rpertoires et les fichiers dans
lesquels tout le monde peut crire. Vous devez imprativement viter dautoriser lcri-
ture dans des rpertoires directement accessibles partir du Web. Cest pour cette raison
que, dans lexemple dcrit ici, le rpertoire orders se situe deux sous-rpertoires en
amont, sous le rpertoire public_html. Nous aborderons plus en dtail cet aspect de la
scurit au Chapitre 13.
Si un mauvais paramtrage des permissions daccs constitue lerreur la plus commune
lors de louverture dun fichier, dautres erreurs peuvent galement tre commises.
Lorsquun fichier ne peut pas tre ouvert, il est capital que vous en soyez inform, pour
viter de tenter dy lire ou dy crire des donnes.
Lorsque lappel de la fonction fopen() choue, celle-ci renvoie la valeur false. Vous
pouvez alors traiter lerreur survenue avec plus de convivialit en supprimant le
message derreur PHP et en produisant votre propre message derreur :
@ $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", ab);
if (!$fp)
{
echo <p><strong>Nous ne pouvons pas traiter votre commande .
pour le moment. Ressayez plus tard.</strong></p> .
</body></html>;
exit;
}
La prsence du symbole @ avant lappel de la fonction fopen() informe PHP quil doit
supprimer toute erreur produite par lappel la fonction. Il est gnralement prfrable
dtre inform lorsquun problme survient mais, dans le cas prsent, nous nous occu-
perons des erreurs un autre endroit du script.
Cette ligne peut galement tre crite de la manire suivante :
$fp = @fopen("$DOCUMENT_ROOT/../orders/orders.txt", a);
Mais cette formulation rend moins vident le recours loprateur de suppression des
erreurs.
La mthode dcrite ici est un moyen trs simple de grer les erreurs. Nous prsenterons
une mthode plus lgante au Chapitre 7. Chaque chose en son temps.
Linstruction if teste la variable $fp pour dterminer si lappel fopen a renvoy un
descripteur de fichier valide. Si ce nest pas le cas, elle affiche un message derreur et
interrompt lexcution du script. La page se terminant alors ce stade, nous avons
inclus les balises de fermeture HTML appropries de manire produire un code
HTML valide.
72 Partie I Utilisation de PHP
Avec cette dernire approche, le rsultat obtenu lexcution du script est celui de la
Figure 2.3.
Figure 2.3
Pour plus de convivia-
lit, vous pouvez
afficher vos propres
messages derreur
la place des avertis-
sements produits par
PHP.
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.
20:30, le 31-03 4 pneus 1 bidons dhuile 6 bougies 434.00 22 rue de la pompe, Paris
20:42, le 31-03 1 pneus 0 bidons dhuile 0 bougies 100.00 33 grande rue, Toulouse
20:43, le 31-03 0 pneus 1 bidons dhuile 4 bougies 26.00 27 rue des acacias, Bordeaux
<?php
// Cre des noms de variables abrges
$qte_pneus = $_POST[qte_pneus];
$qte_huiles = $_POST[qte_huiles];
$qte_bougies = $_POST[qte_bougies];
$adresse = $_POST[adresse];
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob Rsultats de la commande</title>
</head>
<body>
Chapitre 2 Stockage et rcupration des donnes 75
$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 = number_format($montant_total, 2, ., );
if (!$fp)
{
echo <p><strong>Nous ne pouvons pas traiter votre commande .
pour le moment. Ressayez plus tard.</strong></p> .
</body></html>;
exit;
76 Partie I Utilisation de PHP
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
Figure 2.4
Lexcution du script
vieworders.php affiche
dans la fentre du navi-
gateur web toutes les
commandes enregistres
dans le fichier orders.txt.
La fonction fgets() lit une ligne la fois dans un fichier. Dans notre exemple, la
lecture se poursuit jusqu ce que linterprteur rencontre un caractre de nouvelle ligne
78 Partie I Utilisation de PHP
(\n), EOF ou jusqu ce que 998 octets aient t lus dans le fichier. Le nombre maximal
doctets lus est la longueur indique en deuxime paramtre, moins un.
Vous disposez de plusieurs fonctions pour lire le contenu dun fichier. La fonction
fgets() convient bien pour les fichiers au format texte seul qui doivent tre traits par
morceaux.
La fonction fgetss() constitue une variante intressante de la fonction fgets(). Son
prototype est le suivant :
string fgetss(resource fp, int longueur, string [balises_autorises]);
fgetss() est trs semblable fgets(), si ce nest quelle supprime toutes les balises
PHP et HTML contenues dans la chane lue. Pour empcher la suppression de certaines
balises, il suffit de les numrer dans la chane balises_autorises. La fonction
fgetss() sutilise par mesure de scurit lors de la lecture dun fichier crit par un tiers
ou contenant des donnes saisies par lutilisateur. La prsence de code HTML dans un
fichier peut en effet perturber la mise en forme que vous avez soigneusement mise en
place. Par ailleurs, ne pas vrifier la prsence de code PHP dans un fichier peut permettre
un utilisateur malveillant de prendre le contrle de votre serveur.
La fonction fgetcsv () est une autre variante de la fonction fgets(). Voici son proto-
type :
array fgetcsv ( resource fp, int longueur [, string dlimiteur [,
string encadrement]])
La fonction fgetcsv() semploie pour dcouper les lignes dun fichier en fonction dun
caractre de dlimitation (par exemple un caractre de tabulation comme ici ou une
virgule comme dans de nombreux fichiers produits par les tableurs et dautres applica-
tions). fgetscv() permet, par exemple, de reconstruire sparment les variables dune
commande plutt que les traiter sous la forme dune ligne de texte. Cette fonction
sutilise de la mme manire que fgets(), mais vous devez lui passer en paramtre le
dlimiteur utilis pour sparer les champs. Linstruction :
$commande = fgetcsv($fp, 100, "\t");
provoque la lecture dune ligne du fichier et son dcoupage selon chaque tabulation
(\t). Le rsultat obtenu est renvoy sous forme de tableau ($commande dans le
Listing 2.2). Les tableaux sont traits au Chapitre 3.
La valeur du paramtre longueur doit tre choisie de manire tre suprieure au
nombre de caractres de la ligne la plus longue du fichier lire.
Le paramtre encadrement indique le caractre qui encadre chacun des champs dune
ligne. Sil nest pas prcis, il prend comme valeur par dfaut lapostrophe double ( ").
Chapitre 2 Stockage et rcupration des donnes 79
Ce code lit un caractre la fois dans le fichier, via fgetc(), et le stocke dans la variable
$car. Le processus se rpte jusqu ce que la fin du fichier soit atteinte. Les caractres
de fin de ligne (\n) sont ensuite remplacs par des sauts de ligne HTML (<br />).
Ce petit traitement vise simplement purer la mise en forme. Si vous essayiez daffi-
cher le fichier en laissant les caractres de nouvelles lignes entre les enregistrements, la
totalit du fichier serait imprime sur une seule ligne (vous pouvez essayer par vous-
mme). En effet, les navigateurs web ignorent les caractres de nouvelles lignes quils
considrent comme des espaces : vous devez donc les remplacer par des sauts de ligne
HTML (<br />). Loprateur ternaire permet deffectuer ce remplacement de faon
simple et lgante.
Lutilisation de la fonction fgetc() au lieu de la fonction fgets() a une consquence
mineure : le caractre EOF est renvoy par la fonction fgetc(), ce qui nest pas le cas
avec la fonction fgets(). Il sensuit quaprs la lecture du caractre il est ncessaire
de tester nouveau feof() pour viter que le caractre EOF ne soit affich par le navi-
gateur.
La lecture dun fichier caractre par caractre na de sens que dans des contextes trs
particuliers, o les caractres doivent tre lus les uns aprs les autres.
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.
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.
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.
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).
Seulement, si vous voulez trouver des motifs dinformation (par exemple lister tous
les clients qui vivent Paris), il vous faudra lire chaque enregistrement et le vrifier
individuellement.
m La gestion des accs concurrents est problmatique. Nous avons vu comment
verrouiller des fichiers, mais nous avons galement mentionn le risque persistant
de situation concurrentielle. Des accs concurrents peuvent galement tre
lorigine de goulots dtranglements. Si le trafic sur le site prend de lampleur, il
peut arriver que de nombreux utilisateurs aient attendre le dverrouillage du
fichier pour valider leur commande. De trop longues attentes font fuir les clients.
m Dans toutes les manipulations de fichiers dcrites jusquici, les traitements taient
mis en uvre de faon squentielle, cest--dire en partant du dbut du fichier et en
parcourant le contenu du fichier jusqu la fin. Sil apparat ncessaire dinsrer ou
de supprimer des enregistrements partir du milieu du fichier (accs direct), le
mode de traitement squentiel peut poser problme : il implique de lire et de placer
en mmoire lintgralit du fichier, dapporter les modifications et de rcrire
nouveau le fichier. La charge du traitement peut alors devenir trs lourde avec des
fichiers de donnes volumineux.
m Au-del de la limite offerte par les permissions sur les fichiers, il nexiste pas de
moyen simple dimplmenter des niveaux daccs diffrents aux donnes.
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
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).
produit
Figure 3.1
Les articles vendus par lentreprise de Bob peuvent tre enregistrs dans un tableau.
Ds lors que des informations sont enregistres dans un tableau, elles peuvent tre
soumises diverses manipulations trs intressantes. Cest ainsi quavec les construc-
tions de boucles dcrites au Chapitre 1, vous pouvez vous simplifier la tche en effec-
tuant les mmes actions sur chacune des valeurs du tableau. Lensemble des
informations enregistres dans un tableau peut tre manipul comme sil sagissait
dune seule entit. Ainsi, avec une simple ligne de code, toutes les valeurs dun tableau
peuvent tre passes une fonction. Pour, par exemple, trier les articles de Bob par
ordre alphabtique, il nous suffira de passer le tableau qui les contient la fonction
sort().
Les valeurs stockes dans un tableau sont appeles lments du tableau. chaque
lment dun tableau est associ un indice (galement appel cl) qui permet daccder
cet lment.
Dans la plupart des langages de programmation, les tableaux ont des indices numriques
qui commencent gnralement 0 ou 1.
PHP permet dutiliser des nombres ou des chanes comme indices de tableau. Vous
pouvez utiliser des tableaux indics par des nombres, selon la manire traditionnelle, ou
choisir les valeurs que vous souhaitez pour les cls, afin de rendre lindexation plus
comprhensible et utile. Vous avez peut-tre dailleurs dj employ cette technique si
vous avez utilis des tableaux associatifs, des mappages, des hachages ou des diction-
naires dans dautres langages de programmation. Lapproche peut varier lgrement
selon que vous utilisez des tableaux classiques indics par des nombres ou tableaux
indics par des valeurs personnalises. Nous commencerons cette tude par les
tableaux indices numriques avant de passer aux cls dfinies par lutilisateur.
Chapitre 3 Utilisation de tableaux 89
Cette instruction cre un tableau $produits contenant les trois valeurs Pneus,
Huiles et Bougies. Notez que, comme echo, array() est une construction du
langage plutt quune fonction.
Selon le contenu enregistrer dans un tableau, il nest pas forcment ncessaire
dinitialiser manuellement ce contenu comme on la fait dans linstruction prcdente.
Si les donnes placer dans un tableau sont dj contenues dans un autre tableau, il
suffit de copier un tableau dans lautre au moyen de loprateur =.
Une srie de nombres croissants peut tre automatiquement enregistre dans un tableau
grce la fonction range(), qui se charge elle-mme de crer le tableau requis. La ligne
qui suit cre un tableau $nombres dont les lments sont les nombres entiers compris
entre 1 et 10 :
$nombres = range(1,10);
La fonction range() possde un troisime paramtre facultatif qui vous permet de dfi-
nir la taille du pas entre les valeurs. Par exemple, pour crer un tableau des nombres
impairs compris entre 1 et 10, procdez de la manire suivante :
$impairs = range(1, 10, 2);
La fonction range() peut galement tre utilise avec des caractres, comme dans cet
exemple :
$lettres = range(a, z);
Lorsque des informations sont contenues dans un fichier stock sur disque, le tableau
peut tre directement charg partir du fichier. Nous reviendrons sur ce point un peu
plus loin dans ce chapitre, dans la section "Chargement de tableaux partir de fichiers".
Lorsque des informations sont contenues dans une base de donnes, le tableau peut
tre directement charg partir de la base de donnes. Cette possibilit est traite au
Chapitre 11.
PHP offre galement diverses fonctions permettant dextraire des parties dun tableau
ou de rorganiser les lments. Certaines de ces fonctions seront dcrites plus loin dans
ce chapitre, dans la section "Autres manipulations de tableaux".
90 Partie I Utilisation de PHP
Bien que lanalyse des chanes par PHP soit particulirement bien labore, vous pouvez
commettre des erreurs dans ce domaine. Si vous avez des problmes avec des tableaux
ou des variables non correctement interprts lorsquils sont encadrs par des apostro-
phes doubles, mettez-les hors de ceux-ci ou utilisez la syntaxe complexe prsente au
Chapitre 4. La prcdente instruction echo fonctionnera correctement, mais vous
rencontrerez plusieurs autres exemples au cours de ce chapitre dans lesquels les variables
sont situes en dehors des chanes encadres par des apostrophes doubles.
Tout comme les autres variables PHP, les tableaux ne ncessitent pas une initialisation
ou une cration pralables. Ils sont automatiquement crs leur premire utilisation.
Le code qui suit conduit la cration du mme tableau $produits que celui que lon a
cr plus haut avec array() :
$produits[0] = Pneus;
$produits[1] = Huiles;
$produits[2] = Bougies;
Chapitre 3 Utilisation de tableaux 91
Si le tableau $produits nexiste pas encore, la premire ligne cre un nouveau tableau
form dun seul lment. Les lignes qui suivent ajoutent des valeurs au tableau qui vient
dtre cr. Le tableau est redimensionn dynamiquement lorsque vous lui ajoutez des
lments. Cette possibilit de redimensionnement nexiste pas dans la plupart des autres
langages de programmation.
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.
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
Voici une autre variante de ce fragment de code dont lexcution produit un rsultat
identique. Ce code ne cre pas explicitement le tableau, mais conduit indirectement sa
cration lors de lajout du premier lment :
$prix[Pneus] = 100;
$prix[Huiles] = 10;
$prix[Bougies] = 4;
Utilisation de boucles
Nous ne pouvons pas utiliser un simple compteur avec une boucle for pour parcourir le
tableau prcdent puisquil nest pas indic par des nombres. Cependant, nous pouvons
faire appel une boucle foreach ou aux constructions list() et each().
Avec un tableau associatif, la boucle foreach peut adopter une syntaxe lgrement
diffrente. Vous pouvez lutiliser exactement comme dans lexemple prcdent ou y
ajouter les cls :
foreach ($prix as $nom => $montant) {
echo "$nom: $montant<br />";
Le fragment de code qui suit affiche le contenu du tableau $prix avec each() :
while( $element = each( $prix ) ) {
echo $element[ key ];
echo : ;
echo $element[ value ];
echo <br />;
}
Figure 3.2
Utilisation dune instruction
each() pour parcourir
un tableau.
Dans cette ligne de code, la fonction each() est utilise pour obtenir llment
courant du tableau $prix, le renvoyer sous forme de tableau et pour passer
llment suivant. On utilise galement la fonction list() pour transformer les
lments 0 et 1 du tableau renvoy par la fonction each() en deux nouvelles variables
appeles $nom et $montant.
Nous pouvons parcourir tout le contenu du tableau $prix et lafficher dans la fentre du
navigateur au moyen des deux lignes de code suivantes :
while ( list( $nom, $montant ) = each( $prix ) ) {
echo "$nom: $montant<br />";
}
Lexcution de ces lignes de code produit le mme rsultat que celui de la Figure 3.2,
mais elles sont plus lisibles car la fonction list () permet daffecter des noms aux
variables.
94 Partie I Utilisation de PHP
Avec la fonction each(), le tableau mmorise la position courante. Si vous devez utili-
ser deux fois le mme tableau dans un script, il faut par consquent replacer la position
courante du tableau au dbut de celui-ci avec la fonction reset(). Pour afficher une
seconde fois les prix des articles, il nous faudrait donc excuter les lignes de code
suivantes :
reset($prix);
while ( list( $nom, $montant ) = each( $prices ) ) {
echo "$nom: $montant<br />";
Ces oprateurs sont assez vidents comprendre, mais lunion requiert quelques
explications supplmentaires. Cet oprateur tente dajouter les lments de $b la
fin de $a. Si des lments de $b possdent les mmes cls que certains lments qui
Chapitre 3 Utilisation de tableaux 95
se trouvent dj dans $a, ils ne seront pas ajouts. Autrement dit, aucun lment de
$a nest cras.
Vous remarquerez que les oprateurs de tableaux du Tableau 3.1 possdent tous des
oprateurs quivalents qui fonctionnent sur les variables scalaires. Pour autant que vous
vous souveniez que + ralise laddition sur les types scalaires et lunion sur les tableaux,
les comportements sont logiques. Vous ne pouvez pas comparer de manire utile des
tableaux des types scalaires.
Tableaux multidimensionnels
Les tableaux ne sont pas ncessairement de simples listes de cls et de valeurs. Chaque
lment dun tableau peut lui-mme tre un autre tableau. Cette proprit permet de
crer des tableaux deux dimensions, qui peuvent tre assimils une matrice, ou grille,
caractrise par une largeur et une hauteur, cest--dire un nombre dtermin de lignes
et de colonnes.
Par exemple, nous pourrions avoir recours un tableau deux dimensions pour stocker
plusieurs informations relatives chaque article vendu par lentreprise de Bob.
la Figure 3.3, chaque ligne dun tableau deux dimensions reprsente un article
particulier et chaque colonne reprsente un attribut (ou un type dinformation) relatif
aux produits.
HUI Huiles 10
BOU Bougies 4
Figure 3.3
Un tableau deux dimensions permet de stocker plus dinformations relatives aux articles vendus
par lentreprise de Bob.
Voici le code PHP qui pourrait tre utilis pour gnrer le tableau de la Figure 3.3 :
$produits = array( array( PNE, Pneus, 100 ),
array( HUI, Huiles, 10 ),
array( BOU, Bougies, 4 ) );
96 Partie I Utilisation de PHP
Ces lignes font bien apparatre que le tableau $produits se compose dsormais de trois
autres tableaux.
Souvenez-vous que, pour accder un lment dun tableau unidimensionnel, il faut
spcifier le nom du tableau et la cl de llment. Dans un tableau deux dimensions,
laccs seffectue de manire comparable, si ce nest qu chaque lment sont asso-
cies deux cls : une ligne et une colonne (la ligne la plus en haut est la ligne 0, tandis
que la colonne la plus gauche est la colonne 0).
Nous pourrions ainsi afficher le contenu du tableau considr ici en accdant dans
lordre et manuellement chaque lment, comme ici :
echo |.$produits[0][0].|.$produits[0][1].|.$produits[0][2].|<br />;
echo |.$produits[1][0].|.$produits[1][1].|.$produits[1][2].|<br />;
echo |.$produits[2][0].|.$produits[2][1].|.$produits[2][2].|<br />;
Nous pourrions obtenir le mme rsultat en insrant une boucle for dans une autre
boucle for, de la manire suivante :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
for ( $colonne = 0; $colonne < 3; $colonne++ ) {
echo |.$produits[$ligne][$colonne];
}
echo |<br />;
}
Chacune de ces deux variantes conduit au mme affichage dans la fentre du navigateur
web, cest--dire :
|PNE|Pneus|100|
|HUI|Huiles|10|
|BOU|Bougies|4|
La seule diffrence est que la seconde variante est bien plus courte que la premire dans
le cas de tableaux volumineux.
Au lieu de dsigner les colonnes par des numros, vous pouvez choisir dutiliser des
noms de colonnes (voir Figure 3.3). Pour cela, vous pouvez utiliser des tableaux asso-
ciatifs. Pour enregistrer le mme ensemble darticles dans un tableau associatif dont les
noms de colonnes seraient identiques ceux de la Figure 3.3, vous pouvez crire le
code suivant :
$produits = array( array( Code => PNE,
Description => Pneus,
Prix => 100
),
array( Code => HUI,
Description => Huiles,
Prix => 10
),
Chapitre 3 Utilisation de tableaux 97
Un tel tableau se rvle plus facile manipuler lorsquil sagit de rcuprer une seule
valeur. Il est en effet plus ais de se souvenir que la description dun article est stocke
dans la colonne Description, que de se souvenir quelle est stocke dans la colonne 1.
Avec les indices descriptifs, il nest pas ncessaire de mmoriser quune valeur est stocke
la position [x][y]. Les donnes peuvent y tre facilement retrouves en spcifiant les
noms explicites des lignes et des colonnes.
Nous sommes en revanche privs de la possibilit dutiliser une boucle for pour
parcourir successivement les diffrentes colonnes du tableau. Le fragment de code qui
suit permet dafficher le contenu de ce tableau :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
echo |.$produits[$ligne][Code].|.
$produits[$ligne][Description].|.
$produits[$ligne][Prix].|<br />;
}
Avec une boucle for nous pouvons parcourir le tableau "externe" $produits indic par
des nombres. Chaque ligne de notre tableau $produits constitue un tableau avec des
indices descriptifs. Les fonctions each() et list() peuvent ensuite tre insres dans
une boucle while pour parcourir les diffrents tableaux internes contenus dans
$produits. Voici le code form dune boucle while imbrique dans une boucle for :
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
while ( list( $cle, $valeur ) = each( $produits[ $ligne ] ) )
{
echo |$valeur;
}
echo |<br />;
}
Vous ntes pas limit deux dimensions : en suivant le mme principe, rien nempche
de crer un tableau dont les lments sont constitus de tableaux, eux-mmes constitus
de tableaux, et ainsi de suite.
Un tableau trois dimensions se caractrise par une largeur, une hauteur et une profon-
deur. Si vous prfrez vous reprsenter un tableau deux dimensions comme un tableau
compos de lignes et de colonnes, vous pouvez vous reprsenter un tableau trois
dimensions comme un empilement de tels tableaux. Chaque lment est alors rfrenc
par sa couche, sa ligne et sa colonne.
98 Partie I Utilisation de PHP
Figure 3.4
Ce tableau trois Pices camions
dimensions permet
its Code Description Prix
de classer les articles rodu
en catgories.
des p
Pices motos
orie
Pices voitures
Dans le fragment de code qui suit, il apparat clairement quun tableau trois dimensions
est un tableau contenant des tableaux de tableaux :
$categories = array( array ( array( VOI_PNE, Pneus, 100 ),
array( VOI_HUI, Huiles, 10 ),
array( VOI_BOU, Bougies, 4 )
),
array ( array( MOT_PNE, Pneus, 120 ),
array( MOT_HUI, Huiles, 12 ),
array( MOT_BOU, Bougies, 5 )
),
array ( array( CAM_PNE, Pneus, 150 ),
array( CAM_HUI, Huiles, 15 ),
array( CAM_BOU, Bougies, 6 )
)
);
Ce tableau ne comprenant que des cls numriques, nous pouvons nous servir de
boucles for imbriques pour afficher son contenu :
for ( $couche = 0; $couche < 3; $couche++ ) {
echo "Couche $couche<br />";
for ( $ligne = 0; $ligne < 3; $ligne++ ) {
for ( $colonne = 0; $colonne < 3; $colonne++ ) {
Chapitre 3 Utilisation de tableaux 99
echo |.$categories[$couche][$ligne][$colonne];
}
echo |<br />;
}
}
Compte tenu de la manire dont sont crs les tableaux multidimensionnels, vous
pouvez trs bien produire des tableaux quatre, cinq ou six dimensions. Le langage
PHP nimpose en ralit aucune limite sur le nombre de dimensions dun tableau.
Toutefois, les constructions plus de trois dimensions sont difficiles visualiser.
Des tableaux trois dimensions ou moins suffisent gnralement traiter la plupart des
problmes et situations du monde rel.
Tri de tableaux
Il est souvent trs utile de trier les donnes apparentes qui sont stockes dans un
tableau. Le tri dun tableau unidimensionnel est une opration trs simple.
Aprs lexcution de ce code, les lments contenus dans le tableau sont classs dans
lordre suivant : Bougies, Huiles, Pneus.
Il est galement possible de trier des valeurs en suivant lordre numrique. Prenons le
cas dun tableau contenant les prix des articles vendus par Bob. Le contenu de ce
tableau pourrait tre tri par ordre numrique croissant, au moyen des instructions
suivantes :
$prix = array( 100, 10, 4 );
sort($prix);
Les prix seraient alors classs dans lordre suivant : 4, 10, 100.
Notez que la fonction sort() est sensible la casse ( lutilisation de majuscules/
minuscules). Les lettres majuscules sont classes avant les lettres minuscules : "A" est
infrieur "Z", mais "Z" est infrieur "a".
La fonction admet galement un second paramtre facultatif. Vous pouvez passer lune
des constantes SORT REGULAR (par dfaut), SORT NUMERIC ou SORT STRING. Cette capa-
cit spcifier le type de tri est utile lorsque vous comparez des chanes qui peuvent
contenir des nombres, comme 2 et 12. Numriquement, 2 est infrieur 12 mais, en tant
que chane, 12 est infrieure 2.
100 Partie I Utilisation de PHP
La fonction asort() trie le contenu du tableau qui lui est fourni en paramtre daprs la
valeur de chaque lment. Dans le tableau considr ici, les valeurs sont les prix tandis
que les cls sont les descriptions textuelles. Pour trier le tableau non pas en fonction des
prix, mais des descriptions, cest la fonction ksort() qui doit tre employe. La fonc-
tion ksort() effectue un tri sur la base des cls et non pas des valeurs. Le fragment de
code qui suit gnre un tableau tri en tenant compte de lordre alphabtique des cls
(Bougies, Huiles, Pneus) :
$prix = array( Pneus=>100, Huiles=>10, Bougies=>4 );
ksort($prix);
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
<?php
$images = array(pneu.jpg, huile.jpg, bougie.jpg,
porte.jpg, volant.jpg,
thermostat.jpg, essuie_glace.jpg,
joint.jpg, plaquette_frein.jpg);
shuffle($images);
?>
<html>
<head>
<title>Le garage de Bob</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<div align="center">
<table width = 100%>
<tr>
<?php
for ( $i = 0; $i < 3; $i++ ) {
echo <td align="center"><img src=";
echo $images[$i];
echo " width="100" height="100"></td>;
}
?>
</tr>
</table>
</div>
</body>
</html>
Le code du Listing 3.1 effectuant une slection alatoire dimages, il conduit laffi-
chage dune page diffrente chaque chargement ou presque (voir Figure 3.5).
Figure 3.5
La fonction shuffle()
est utilise ici pour
afficher trois articles
choisis au hasard.
Chapitre 3 Utilisation de tableaux 105
<?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>";
}
Ce script produit presque le mme affichage que le Listing 2.3, au Chapitre 2 (voir
Figure 2.4). Cette fois, cependant, on utilise la fonction file() pour charger lintgra-
lit du fichier dans un tableau. Chaque ligne du fichier devient alors un lment du
tableau ainsi produit.
Par ailleurs, le Listing 3.2 utilise la fonction count() pour dterminer le nombre
dlments contenus dans le tableau cr.
Nous pouvons aller plus loin et charger chacune des sections des lignes de commandes
dans des lments tableaux distincts, afin de traiter les sections sparment les unes des
autres ou de les mettre en forme de manire plus attractive. Cest ce que fait le code du
Listing 3.3.
<?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
if ($nbre_de_cdes == 0) {
echo "<p><strong>Aucune commande en attente.
Ressayez plus tard.</strong></p>";
}
echo "</table>";
?>
</body>
</html>
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.
Cette instruction a pour effet de dcouper la chane passe comme deuxime paramtre.
Chaque caractre de tabulation devient une sparation entre deux lments. Ainsi, la
chane :
"15:42 le 20-04 4 pneus 1 bidons dhuiles 6 bougies 434.00 22 rue noire, Toulouse"
est dcoupe en six parties, "15:42 le 20 04", "4pneus", "1bidons dhuiles",
"6bougies", "434.00" et "22rue noire, Toulouse".
Vous pouvez galement utiliser le paramtre facultatif limit pour limiter le nombre
maximal de parties renvoyes.
Dans le code du Listing 3.3, le traitement auquel sont soumises les donnes extraites du
fichier des commandes est minimal. Nous nous contentons dafficher les quantits de
chaque article et dajouter au tableau une ligne den-tte indiquant la signification
des nombres affichs.
Chapitre 3 Utilisation de tableaux 109
Nous aurions pu procder de plusieurs autres manires pour extraire les nombres conte-
nus dans ces chanes. Dans le Listing 3.3, nous avons utilis la fonction intval() qui
convertit une chane en nombre entier. Cette conversion ne pose pas de problme puis-
que les parties qui ne peuvent pas tre converties en nombres entiers sont ignores.
Nous tudierons diverses autres mthodes de traitement des chanes au cours du
prochain chapitre.
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
Avec les fonctions each(), current(), reset(), end(), next(), pos() et prev(), vous
pouvez donc parcourir un tableau comme bon vous semble.
Tout comme la fonction usort(), array walk() requiert comme second paramtre une
fonction dfinie par lutilisateur.
La fonction array walk() prend trois paramtres. Le premier, tableau, est le tableau
dont on veut traiter le contenu. Le second, fonction, est le nom de la fonction dfinie
par lutilisateur et qui sera applique chaque lment du tableau. Le troisime para-
mtre, donnes utilisateur, est facultatif. Sil est prsent, il est pass en paramtre
la fonction dfinie par lutilisateur. Nous allons voir un peu plus loin un exemple de
mise en uvre de la fonction array walk().
Il pourrait, par exemple, se rvler trs pratique dattribuer chaque lment dun
tableau une fonction qui applique une mise en forme particulire.
Le code qui suit affiche chaque lment du tableau $tableau sur une nouvelle ligne, en
appliquant chaque lment la fonction mon affichage() :
function mon_affichage($valeur) {
echo "$valeur<br />";
}
array_walk($tableau, mon_affichage);
Dans la plupart des cas, le paramtre donnes utilisateur est inutile ; il ne sert que
lorsque la fonction que vous avez dfinie exige un paramtre.
Il peut galement arriver que la cl de chaque lment soit tout autant ncessaire la
manipulation effectue que la valeur de llment. Mais, comme dans le cas de
mon affichage(), votre fonction peut ignorer aussi bien la cl que le paramtre
donnes utilisateur.
Considrons prsent un exemple un peu plus complexe : nous allons crire une
fonction qui modifie les valeurs dun tableau et attend un paramtre. Notez que, dans
ce cas, nous devons indiquer la cl dans la liste des paramtres afin de pouvoir spci-
fier le troisime, mme si nous navons pas besoin de cette cl dans le corps de la
fonction :
function ma_multiplication(&$valeur, $cle, $facteur){
$valeur *= $facteur;
}
array_walk(&$tableau, ma_multiplication, 3);
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);
Cl Valeur
4 1
5 1
1 3
2 2
3 1
Dans ce cas prcis, le tableau retourn par array count values() indique que le
tableau $tableau contient une seule fois les valeurs 4, 5 et 3, trois fois la valeur 1, et
deux fois la valeur 2.
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
Le tableau $tableau contenant trois lments dont les cls sont cle1, cle2 et cle3, la
fonction extract() applique $tableau cre donc les trois variables scalaires $cle1,
$cle2 et $cle3. Vous pouvez constater dans le rsultat obtenu que les valeurs
de $cle1, $cle2 et $cle3 sont respectivement valeur1, valeur2 et valeur3, qui
proviennent du tableau initial.
La fonction extract() accepte deux arguments facultatifs : type extraction et
prfixe. Le premier indique extract() la manire dont doivent tre gres les colli-
sions, cest--dire les situations o il existe dj une variable de mme nom quune cl.
Le comportement par dfaut consiste craser la variable existante. Le Tableau 3.2
dcrit les quatre valeurs autorises pour type extraction.
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 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).
lemploy appropri. Si, par exemple, le message transmis par le client contient le mot
"publicit", il sera dirig vers la bote aux lettres du dpartement de marketing. Si le
message mane dun client important, il pourra tre directement transmis Bob.
Figure 4.1
Le formulaire de saisie
dun message du site de Bob
permet aux clients de trans-
mettre leurs commentaires,
aprs avoir saisi leur nom
et leur adresse de courrier
lectronique.
Nous commencerons ce projet par le script simple du Listing 4.1. Nous complterons
ensuite ce script au fur et mesure de notre avance dans ce chapitre.
<?php
// Cration de noms abrgs pour les variables
$nom = $_POST[nom];
$email = $_POST[email];
$commentaire = $_POST[commentaire];
<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]);
Vous pouvez vous servir du cinquime paramtre facultatif pour passer un paramtre au
programme que vous avez configur pour lenvoi de-mails.
118 Partie I Utilisation de PHP
Pour pouvoir mettre en uvre la fonction mail(), vous devez configurer votre installa-
tion PHP pour lui indiquer lexistence de votre programme denvoi des courriers. Si
lexcution de votre script pose problme, relisez attentivement lAnnexe A et vrifiez
votre installation PHP.
Tout au long de ce chapitre, nous amliorerons le script de base du Listing 4.1 en nous
servant de fonctions PHP de manipulation des chanes et dexpressions rgulires.
La fonction trim() limine les espaces existant en dbut et la fin de la chane qui lui
est fournie en paramtre et retourne la chane ainsi lague. Les caractres despace
supprims par la fonction trim() sont les nouvelles lignes et les retours chariot (\n, \r),
les tabulations horizontales et verticales (\t et \v), les caractres de fin de chane (\0) et
les caractres espaces. Vous pouvez galement passer cette fonction un second para-
mtre contenant une liste des caractres supprimer la place de cette liste par dfaut.
Selon le but recherch, les fonctions ltrim() ou rtrim() peuvent se rvler plus appro-
pries que la fonction trim(). Comme la fonction trim(), elles prennent toutes les
deux la chane traiter en paramtre et renvoient cette chane mise en forme. En
revanche, alors que la fonction trim() supprime tous les espaces qui encadrent la
chane, la fonction ltrim() limine uniquement les espaces en dbut de chane
(cest--dire la gauche de la chane) tandis que la fonction rtrim() les supprime
uniquement la fin de la chane (cest--dire droite).
Chapitre 4 Manipulation de chanes et dexpressions rgulires 119
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.
PHP offre galement la fonction print(), qui est analogue la construction echo, sauf
quelle renvoie une valeur (vrai ou faux, selon la russite ou lchec de laffichage).
echo, tout comme print(), affiche la chane "telle quelle". Vous pouvez toutefois appli-
quer une mise en forme plus sophistique au moyen des fonctions printf() et
sprintf(). Toutes les deux oprent pratiquement de la mme manire, sauf que
printf() affiche la chane mise en forme dans le navigateur, tandis que sprintf()
renvoie cette chane mise en forme.
Ces fonctions ont le mme comportement que leurs quivalents dans le langage C, bien
que leur syntaxe ne soit pas la mme. Si vous navez jamais programm en C, il vous
faudra peut-tre un peu de temps pour vous familiariser avec ces fonctions, mais le jeu
en vaut toutefois la chandelle, compte tenu de leur puissance et de leur utilit.
Les prototypes de ces fonctions sont les suivants :
string sprintf (string format [, mixed paramtres...])
int printf (string format [, mixed paramtres...])
Le premier paramtre requis par ces fonctions est une chane de format dcrivant la
forme de base de la sortie, avec des codes de mise en forme au lieu de variables. Les
autres paramtres sont des variables que PHP viendra insrer dans la chane, en lieu et
place des codes de mise en forme.
Par exemple, avec la fonction echo, nous pouvons afficher une chane en y insrant une
variable, comme suit :
echo "Le montant total de la commande est $total.";
Avec ce formatage et la valeur 12.4 stocke dans $total, linstruction affichera 12.40.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 121
Type Signification
b Largument est trait comme un entier et affich comme un nombre binaire.
c Largument est trait comme un entier et affich comme un caractre.
d Largument est trait comme un entier et affich comme un nombre dcimal.
122 Partie I Utilisation de PHP
Tableau 4.1 : Valeurs possibles pour le type dune spcification de conversion (suite)
Type Signification
f Largument est trait comme un double et affich comme un nombre virgule
flottante.
o Largument est trait comme un entier et affich comme un nombre octal.
s Largument est trait et affich comme une chane.
u Largument est trait comme un entier et affich comme un nombre dcimal non
sign.
x Largument est trait comme un entier et affich comme un nombre hexadcimal
(en minuscules sil sagit dune lettre).
X Largument est trait comme un entier et affich comme un nombre hexadcimal
(en majuscules sil sagit dune lettre).
Il est possible de numroter les paramtres, ce qui permet de passer les paramtres dans
un autre ordre que les spcifications de conversion. Par exemple :
printf ("Montant total : %2\$.2f (dont %1\$.2f de transport)",
$total_transport, $total);
Il suffit dajouter la position du paramtre dans la liste directement aprs le signe %,
suivi dun symbole $ protg par un antislash ; dans le cas prsent, 2\$ signifie donc
"remplacer par le deuxime paramtre de la liste". Ce procd peut aussi tre utilis
pour rpter des paramtres.
Il existe deux versions alternatives de ces fonctions, appeles vprintf() et
vsprintf(). Ces variantes acceptent deux paramtres : la chane de format et un
tableau des paramtres au lieu dun nombre variable de paramtres.
Tableau 4.2 : Fonctions de modification de la casse dune chane, avec leurs effets
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]));
Figure 4.3
Aprs traitement par la fonction
addslashes(), toutes les apostrophes
sont prcdes dune barre oblique.
La fonction stripslashes() limine
toutes les barres obliques servant
de caractre dchappement.
Figure 4.4
Tous les caractres problmatiques
ont t protgs deux fois ; cela
signifie que la fonction des apostro-
phes magiques est active.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 125
Si vous voyez ce rsultat, cela signifie que votre configuration de PHP est dfinie de
manire ajouter et supprimer les barres obliques automatiquement. Cette capacit
est contrle par la directive de configuration magic quotes gpc, qui est active par
dfaut dans les nouvelles versions de PHP. Les lettres gpc correspondent GET, POST et
cookie. Cela signifie que les variables provenant de ces sources sont automatiquement
mises entre apostrophes. Vous pouvez vrifier si cette directive est active dans votre
systme en utilisant la fonction get magic quotes gpc(), qui renvoie true si les cha-
nes provenant de ces sources sont automatiquement places entre apostrophes. Si cette
directive est active sur votre systme, vous devez appeler stripslashes() avant
dafficher les donnes utilisateur ; sans cela, les barres obliques seront affiches.
Lutilisation des guillemets magiques vous permet dcrire du code plus portable. Pour
en apprendre plus sur cette fonction, consultez le Chapitre 22.
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.
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.
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 les cinq premiers caractres de la chane, cest--dire "Votre". La ligne de code
suivante :
echo substr($test, 6, -13);
Comparaison de chanes
Jusqu prsent, les seules comparaisons de chanes que nous avons faites se sont limi-
tes au test de lgalit entre deux chanes, au moyen de loprateur ==. PHP permet
deffectuer des comparaisons plus sophistiques que nous classerons en deux catgo-
ries : les correspondances partielles et les autres. Nous commencerons par tudier ces
dernires, puis nous examinerons dans un second temps les correspondances partielles,
dont nous aurons besoin pour poursuivre le dveloppement de notre application
modle.
La fonction strcmp() compare les deux chanes qui lui sont passes en paramtre et renvoie
0 si elles sont gales, un nombre positif si chane1 vient aprs (ou est suprieure )
Chapitre 4 Manipulation de chanes et dexpressions rgulires 129
chane 2 dans lordre lexicographique et un nombre ngatif dans le cas contraire. Cette
fonction est sensible la casse.
La fonction strcasecmp() est identique strcmp(), sauf quelle nest pas sensible la
casse.
La fonction strnatcmp() et son homologue non sensible la casse strnatcasecmp()
comparent les chanes daprs lordre "naturel", plus proche du comportement humain.
Par exemple, la fonction strcmp() classerait la chane "2" aprs la chane "12", parce
que cette dernire est suprieure dun point de vue lexicographique. En revanche, la
fonction strnatcmp() effectuerait le classement inverse. Vous trouverez plus dinfor-
mations sur la notion dordre naturel sur le site http://www.naturalordersort.org/.
strlen() permet de valider les donnes saisies par lutilisateur. Par exemple, consid-
rons le cas de ladresse de courrier lectronique entre dans notre exemple de formu-
laire et stocke dans la variable $email. Une des mthodes de base de validation des
adresses de courrier lectronique consiste tester leur longueur. Une adresse de cour-
rier lectronique valide doit compter au moins six caractres (a@a.fr, par exemple),
dans le cas minimaliste dune adresse se composant dun code de pays sans deuxime
niveau de domaine, dun nom de serveur dun seul caractre et dune adresse e-mail
dune seule lettre. On pourrait donc produire un message derreur si ladresse saisie na
pas au moins cette longueur :
if (strlen($email) < 6) {
echo "Cette adresse email est incorrecte.";
exit; // Fin de lexcution du script PHP
}
La fonction strstr() recherche dans la botte de foin qui lui est passe comme
premier paramtre sil existe l aiguille qui lui est fournie en deuxime paramtre.
Lorsque strstr() tablit une correspondance exacte entre l aiguille et la
botte de foin, elle renvoie la partie de la botte de foin partir de laiguille loca-
lise. Dans le cas contraire, strstr() renvoie false. Lorsque plusieurs occurrences de
la sous-chane recherche sont dtectes, strstr() renvoie la partie de la chane qui
commence la premire occurrence de laiguille.
Par exemple, dans le cadre de notre application modle, nous pouvons choisir le desti-
nataire vers lequel un message reu doit tre dirig laide du code suivant :
$adresse_dest = "commentaires@exemple.com"; // la valeur par dfaut
$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";
}
Le nombre entier renvoy par cette fonction donne la position de la premire occur-
rence de laiguille dans la botte de foin. Comme dhabitude, le premier caractre
occupe la position 0.
Le code qui suit affichera donc 1 dans la fentre du navigateur :
$test = "Bonjour tous";
echo strpos($test, o);
Dans ce cas, laiguille nest constitue que dun seul caractre, mais il pourrait sagir
dune chane de nimporte quelle longueur.
Le paramtre facultatif offset permet dindiquer la position partir de laquelle
commencera la recherche dans la botte de foin. La ligne de code suivante :
echo strpos($test, o, 5);
132 Partie I Utilisation de PHP
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";
L encore, PHP offre un jeu de fonctions spcifiques pour le traitement des chanes ou
des expressions rgulires.
str replace() est la fonction de traitement de chane la plus utilise pour le remplacement.
Son prototype est le suivant :
string str_replace(string aiguille, string nouvelle_aiguille,
string botte_de_foin[, int &nombre]));
La fonction str replace() remplace dans la chane botte de foin toutes les occur-
rences de la sous-chane aiguille par la sous-chane nouvelle aiguille et renvoie la
nouvelle version de la botte de foin.
Chapitre 4 Manipulation de chanes et dexpressions rgulires 133
INFO
Vous pouvez passer tous les paramtres sous la forme dun tableau ; la fonction
str replace() agira de manire remarquablement intelligente. Vous pouvez passer un
tableau contenant les mots remplacer, un tableau des mots en remplacement (en corres-
pondance avec le premier) et un tableau des chanes auxquelles appliquer ces rgles. La
fonction renverra alors un tableau des chanes modifies.
Dans le cadre de notre formulaire de courrier lectronique, par exemple, les clients
pourraient glisser des termes injurieux dans leurs messages. Nous pouvons viter aux
divers services de lentreprise de Bob dtre importuns par de tels messages en utili-
sant un tableau $injures contenant les mots injurieux que vous souhaitez censurer.
Voici un exemple utilisant str replace() avec un tableau :
$commentaire = str_replace($injures, "%!@*", $commentaire);
Cette fonction remplace une partie de la chane chane par la chane remplacement. Les
valeurs des paramtres dbut et longueur dfinissent la partie remplacer.
La valeur de dbut reprsente un offset (ou dcalage) partir duquel entreprendre le
remplacement dans chane. Si la valeur de dbut est positive ou nulle, loffset est dfini
partir du dbut de la chane ; si elle est ngative, loffset est dfini partir de la fin de
la chane. Par exemple, la ligne de code qui suit remplace le dernier caractre de la
chane $test par un X :
$test = substr_replace($test, X, -1);
Le paramtre longueur est facultatif et indique la position dans la chane o PHP doit
stopper le remplacement. Lorsque cet argument nest pas fourni, la chane est remplace
partir de la position dbut jusqu la fin de la chane.
Si longueur vaut zro, la chane de remplacement est insre dans chane sans craser
la chane existante.
Si longueur a une valeur positive, il indique le nombre de caractres qui doivent tre
remplacs par nouvelle chane.
Si longueur a une valeur ngative, il indique la position partir de laquelle doit sinter-
rompre le remplacement, compte partir de la fin de chane.
134 Partie I Utilisation de PHP
INFO
Les expressions rgulires POSIX sont dun apprentissage plus simple mais elles ne sont pas
compatibles avec les donnes binaires.
Toutes les oprations de correspondance de motifs ralises jusquici ont fait appel
aux fonctions sur les chanes, qui nous ont limits la recherche de correspondances
exactes sur des chanes ou des sous-chanes. Pour raliser des oprations de corres-
pondance plus sophistiques, vous devez employer les expressions rgulires. Leur
apprentissage nest pas ais, mais elles sont dun secours apprciable en certaines
circonstances.
Notions de base
Une expression rgulire est un moyen de dcrire un motif dans un morceau de texte.
Les correspondances exactes (ou littrales) ralises dans les sections prcdentes
taient une forme dexpressions rgulires. Par exemple, avec "boutique" et "livraison",
nous avons effectu une recherche laide dexpressions rgulires.
En PHP, la recherche de correspondances avec des expressions rgulires sapparente
plus une recherche de correspondances avec la fonction strstr() qu une comparai-
son dgalit, parce quil sagit de rechercher loccurrence dune sous-chane dans une
autre chane (la sous-chane pouvant se situer nimporte o dans la chane, moins den
dfinir plus prcisment lemplacement). Par exemple, la chane " boutique" corres-
pond lexpression rgulire "boutique", mais elle correspond galement aux expressions
rgulires "o", "ou", etc.
Outre les caractres qui se correspondent exactement, vous pouvez utiliser des caractres
spciaux pour ajouter une mtasignification un motif. Vous pouvez, par exemple, utiliser
des caractres spciaux pour indiquer que le motif recherch doit se trouver en dbut ou
la fin dune chane, quune partie du motif peut tre rpte, ou bien encore que
certains caractres du motif doivent tre dun type particulier. Vous pouvez galement
Chapitre 4 Manipulation de chanes et dexpressions rgulires 135
rechercher des occurrences littrales de caractres spciaux. Nous allons nous pencher
sur chacune de ces possibilits.
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:]]+
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
Dnombrement de sous-expressions
Vous pouvez indiquer le nombre de rptitions dune sous-expression au moyen dune
expression numrique place entre accolades ({}). Vous avez ainsi la possibilit dindi-
quer un nombre dtermin de rptitions ({3}), une plage de rptitions ({2, 4} signifie
de 2 4 rptitions), ou bien encore une plage de rptition ouverte ( {2,} signifie au
moins deux rptitions).
Par exemple :
(trs ){1, 3}
correspond "trs ", "trs trs " et "trs trs trs ".
Enfin, lexpression :
^[a-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)
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
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.
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 la suite
Nous tudierons au prochain chapitre plusieurs manires dutiliser PHP pour conomi-
ser du temps et des efforts de programmation et empcher la redondance en rutilisant
du code prexistant.
5
Rutilisation de code
et criture de fonctions
Ce chapitre explique comment rutiliser du code pour dvelopper des applications plus
cohrentes, plus fiables et plus faciles grer, avec moins defforts. Nous examinerons
des techniques de modularisation et de rutilisation du code, en commenant par la
simple mise en uvre des fonctions require() et include() pour utiliser le mme
code dans plusieurs pages. Nous expliquerons pourquoi cette technique est meilleure
que les inclusions ct serveur. Lexemple donn expliquera comment utiliser des
fichiers include afin dobtenir une apparence cohrente sur tout un site web.
Nous montrerons galement comment crire et appeler ses propres fonctions en prenant
titre dexemple des fonctions gnrant des pages et des formulaires.
Cot
Sur la dure de vie dun composant logiciel, le temps pass sa maintenance, sa
modification, son test et sa documentation excde largement le temps initialement
consacr son dveloppement. Concernant le code commercial, il est fortement recom-
mand de limiter le nombre de lignes de code en usage au sein dune entreprise.
146 Partie I Utilisation de PHP
Une des meilleures mthodes pour observer cette recommandation consiste rutiliser
du code dj existant au lieu dcrire une version lgrement diffrente dun morceau
de code existant pour accomplir une nouvelle tche. Une rduction du volume du code
se traduit directement par une rduction des cots. Sil existe sur le march un logiciel
rpondant aux objectifs dun nouveau projet, achetez-le. Le prix des logiciels existants
est presque toujours infrieur au cot de dveloppement dun projet quivalent. Si un
programme existant correspond "presque" vos besoins, vous devrez toutefois exami-
ner soigneusement les modifications qui devront lui tre apportes, car modifier du
code existant peut tre plus difficile qucrire du nouveau code.
Fiabilit
Lorsquun module de code est utilis au sein dune entreprise, cest gnralement aprs
avoir fait lobjet de tests srieux. Mme si un composant logiciel ne requiert que quel-
ques lignes de code, vous courez le risque, en le rcrivant, doublier un point pris en
compte par lauteur du composant existant ou de ngliger une correction apporte au
code dorigine aprs que les tests ont mis en vidence un dfaut. Le code mature, existant,
est gnralement plus fiable que le code encore "vert".
Cohrence
Les interfaces externes vers votre systme, y compris les interfaces utilisateur et les
interfaces vers des systmes externes, doivent tre cohrentes. Il faut de lopinitret et
des efforts dlibrs pour crire du nouveau code qui reste cohrent avec les autres
parties du systme. En revanche, si vous rutilisez du code dj en service dans une
autre partie du systme, vous avez toutes les chances pour que la fonctionnalit obtenue
soit automatiquement cohrente.
Un avantage essentiel de la rutilisation du code est quelle minimise la charge de
travail du dveloppeur, mais condition que le code dorigine soit modulaire et bien
crit. Lorsque vous programmez, faites en sorte didentifier les sections de votre code
susceptibles de servir ultrieurement dans dautres applications.
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.
Si vous chargez directement reutilisable.php dans votre navigateur web, vous ne serez
pas surpris de le voir afficher la phrase Ceci est une instruction PHP trs simple. En
revanche, le chargement de principal.php a un effet un peu plus inattendu. Le rsultat
obtenu est montr la Figure 5.1.
Figure 5.1
Le chargement du fichier
principal.php fait apparatre
le rsultat de linstruction
require().
Une instruction require() exige un fichier. Dans lexemple prcdent, nous avons
utilis le fichier appel reutilisable.php. lexcution du script, linstruction
require() :
require( reutilisable.php );
148 Partie I Utilisation de PHP
est remplace par le contenu du fichier indiqu, puis le script contenu dans ce dernier
est alors excut. Lexcution qui sopre au chargement du fichier principal.php est
donc quivalente lexcution du script suivant :
<?
echo "Ceci est le fichier principal.<br />";
echo "Ceci est une instruction PHP trs simple.<br />";
echo "Fin du script.<br />";
?>
Pour bien utiliser linstruction require(), vous devez connatre la manire dont sont
traites les extensions des noms de fichier et les balises PHP.
PHP ignore lextension du nom du fichier qui est charg au moyen de la fonction
require(). Par consquent, vous pouvez donner ce fichier le nom qui vous convient
du moment que vous ne comptez pas lappeler directement. Lorsque le fichier est
charg par require(), celui-ci devient partie intgrante dun fichier PHP et est excut
en tant que tel.
Gnralement, des instructions PHP contenues dans un fichier appel, par exemple,
page.html ne seront pas traites. PHP ne traite normalement que les fichiers dont les
noms portent des extensions dfinies, comme .php (ce comportement peut tre modifi
dans le fichier de configuration de votre serveur web). Toutefois, si le fichier page.html
est charg via la fonction require(), toute instruction PHP contenue dans ce fichier
sera traite PHP. Par consquent, vous pouvez choisir nimporte quelle extension pour
les fichiers inclure via require(). Il est toutefois recommand de sen tenir une
convention logique pour le choix des noms de fichier (par exemple en adoptant syst-
matiquement lextension .inc ou .php pour tous les fichiers inclure).
Attention : lorsque des fichiers portant une extension non standard, telle que .inc, sont
stocks dans larborescence des documents du serveur, les utilisateurs qui les chargent
directement dans leur navigateur pourront visualiser leur contenu en texte clair, y
compris les mots de passe qui y sont ventuellement contenus ! Par consquent, il est
important de conserver ce type de fichier en dehors de larborescence des documents ou
bien alors demployer des extensions standard.
INFO
Dans lexemple considr plus haut, le fichier rutilisable reutilisable.php avait le contenu
suivant :
<?
echo "Ceci est une instruction PHP trs simple.<br />";
?>
Le code PHP de ce fichier est encadr par des balises PHP, ce qui est indispensable pour que
le code dun fichier charg via require() soit trait par linterprteur PHP. En labsence de
ces balises, le code sera considr comme du texte ou du code HTML et ne sera pas excut.
Chapitre 5 Rutilisation de code et criture de fonctions 149
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>
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);
?>
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>
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
Une telle approche permet dobtenir facilement une prsentation et une apparence
homognes sur tout un site. Une nouvelle page conue dans le mme style peut ainsi
tre aisment gnre en quelques lignes de code :
<?php require(entete.php);?>
Mettre ici le contenu de cette page
<?php require(pied.php);?>
Plus important encore, mme lorsque de nombreuses pages ont ainsi t produites
partir des mmes fichiers den-tte et de pied de page, vous pouvez facilement modifier
ces fichiers modles. Que la modification apporte soit mineure ou quelle vise
donner une apparence compltement nouvelle au site, elle ne devra tre apporte
quune seule fois. Cette technique vite davoir traiter chaque page sparment.
154 Partie I Utilisation de PHP
Dans lexemple considr ici, le corps, len-tte et le pied de page de chaque page ne
contiennent que du HTML pur. Des instructions PHP pourraient toutefois tre utilises
pour produire dynamiquement certaines parties des pages web du site.
Si vous souhaitez tre sr quun fichier sera trait comme du texte brut ou du HTML et
quaucun code PHP ne sera excut, vous pouvez utiliser readfile() la place de
require() car cette fonction affiche le contenu dun fichier sans lanalyser. Il peut
sagir dune mesure de prcaution importante si vous utilisez du texte fourni par lutili-
sateur.
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.
Appel de fonctions
Lappel de fonction le plus simple qui soit est le suivant :
nom_fonction();
Cette ligne de code appelle la fonction nom fonction, qui ne prend pas de paramtre.
Elle ignore toute valeur ventuellement renvoye par la fonction.
Un certain nombre de fonctions sont appeles exactement de cette manire. Par exem-
ple, cest le cas de la fonction phpinfo(), qui est trs utile lors des tests puisquelle affi-
che la version installe de PHP, les informations relatives PHP, la configuration du
serveur web et les valeurs des diverses variables de PHP et du serveur. Cette fonction ne
prend aucun paramtre et la valeur quelle renvoie est le plus souvent ignore.
156 Partie I Utilisation de PHP
Ici, le paramtre est une chane contenant seulement le mot paramtre. Les appels de
fonction qui suivent sont galement valides, selon la fonction appele :
nom_fonction (2);
nom_fonction (7.993);
nom_fonction ($variable);
Dans la dernire de ces trois lignes de code, $variable peut tre une variable PHP de
tout type, y compris un tableau ou un objet.
Les paramtres peuvent tre de nimporte quel type, mais certaines fonctions exigent
gnralement des types de donnes spcifiques.
Le prototype dune fonction dcrit le nombre de paramtres requis ainsi que la signifi-
cation et le type de chacun deux. Cet ouvrage donne gnralement le prototype de
chaque fonction dcrite.
Le prototype de la fonction fopen(), par exemple, est le suivant :
resource fopen( string nomFichier, string mode,
[, bool utiliser_include_path [, resource contexte]] )
Le prototype dune fonction fournit de prcieuses indications sur la fonction, quil est
important de savoir interprter. Dans le prototype de la fonction fopen(), le terme
resource plac avant le nom de la fonction indique quelle renvoie une ressource
(un descripteur de fichier ouvert). Les paramtres de la fonction sont indiqus entre
parenthses. Comme le montre ce prototype, fopen() attend donc quatre param-
tres. Les paramtres nomFichier et mode sont des chanes, tandis que le paramtre
utiliser include path est un boolen et que le paramtre contexte est une
ressource. La prsence de crochets de part et dautre des paramtres
utiliser include path et contexte indique que ces paramtres sont facultatifs : vous
pouvez leur fournir une valeur ou les ignorer, auquel cas PHP utilisera une valeur par
dfaut. Notez toutefois que, lorsquune fonction a plusieurs paramtres facultatifs, vous
ne pouvez ignorer que les paramtres placs droite. Lorsque vous appelez fopen(),
par exemple, vous pouvez ignorer simplement contexte ou utiliser include path et
Chapitre 5 Rutilisation de code et criture de fonctions 157
contexte, mais vous ne pouvez pas ignorer utiliser include path tout en fournissant
contexte.
Daprs le prototype de fopen(), nous pouvons affirmer que lappel de cette fonction
est correct dans le fragment de code qui suit :
$nom = monfichier.txt;
$mode_ouverture = r;
$fp = fopen($nom, $mode_ouverture);
Ce code appelle la fonction fopen(). La valeur renvoye par cette dernire sera stocke
dans la variable $fp. On passe la variable $name comme premier paramtre de fopen().
Celle-ci contient une chane reprsentant le nom du fichier ouvrir. Le deuxime para-
mtre pass est une variable appele $mode ouverture, qui contient une chane repr-
sentant le mode douverture du fichier. Dans cet exemple, nous navons pas fourni les
troisime et quatrime paramtres facultatifs.
Figure 5.3
Ce message derreur
rsulte de lappel
dune fonction qui
nexiste pas.
Les messages derreur affichs par linterprteur PHP sont gnralement trs utiles.
Celui de la Figure 5.3 nous indique exactement le contexte dans lequel sest produite
lerreur, cest--dire le nom du fichier, le numro de la ligne du script et le nom de la
fonction qui a t appele et qui nexiste pas. Ces indications permettent en principe de
corriger facilement et rapidement lerreur survenue.
laffichage dun tel message derreur, vous devez vous poser deux questions :
1. Le nom de la fonction est-il correctement orthographi dans le script ?
2. La fonction appele existe-t-elle dans la version de PHP utilise ?
Les noms des fonctions sont parfois difficiles mmoriser. Par exemple, certaines fonc-
tions prdfinies de PHP ont des noms composs de deux mots spars par un caractre
de soulignement (comme strip tags()), tandis que dautres ont des noms forms de
deux mots accols (comme stripslashes()). La prsence dune faute dorthographe
dans le nom dune fonction provoque lerreur montre la Figure 5.3.
158 Partie I Utilisation de PHP
Certaines fonctions dcrites dans cet ouvrage nexistent pas dans la version 4.0 de
PHP car nous partons du principe que vous tes au moins quip de la version 5.0.
Chaque nouvelle version de PHP apporte son lot de nouveauts qui enrichissent les
fonctionnalits et les performances du langage et justifient donc une mise jour.
Vous pouvez consulter dans le manuel en ligne de PHP (http://no.php.net/manual/
fr/) la date dajout de chaque fonction disponible. Lappel dune fonction non dcla-
re dans la version de PHP utilise provoque lerreur dont le message est montr la
Figure 5.3.
Lune des autres raisons qui peuvent conduire ce message derreur peut tre que la
fonction que vous appelez fait partie dune extension de PHP qui nest pas charge. Par
exemple, si vous essayez dutiliser des fonctions de la bibliothque gd (manipulation
dimages) alors que vous ne lavez pas installe, vous obtiendrez ce message.
Lorsque vous crivez un bloc de code pour effectuer une tche que vous serez vraisem-
blablement amen rutiliser plusieurs autres endroits dans votre script, voire dans
dautres scripts, vous avez tout intrt dclarer ce bloc de code comme une fonction.
Dclarer une fonction permet dutiliser du code personnalis la manire des fonctions
prdfinies de PHP : il suffit dappeler la fonction utilisateur et de lui fournir les para-
mtres requis. Vous pouvez ainsi appeler et rutiliser la mme fonction plusieurs fois
dans un mme script.
Cette dclaration de fonction commence par function pour que le lecteur et linterpr-
teur PHP sachent que le code qui suit est celui dune fonction personnalise. Le nom de
la fonction tant ma fonction, nous pouvons appeler notre nouvelle fonction au moyen
de linstruction suivante :
ma_fonction();
Vous lavez probablement devin, lappel de cette fonction se traduit par laffichage
dans la fentre du navigateur du texte "ma fonction a t appele.".
Alors que les fonctions prdfinies dans PHP sont utilisables dans tous les scripts PHP,
les fonctions personnalises ne le sont que par les scripts dans lesquels elles ont t
dclares. Il est conseill de placer dans un mme fichier, ou dans un ensemble de
fichiers, toutes les fonctions personnalises couramment utilises. Cette astuce permet
en effet au programmeur daccder toutes ses fonctions par une simple instruction
require() insre dans chacun des scripts.
Dans une dclaration de fonction, le code accomplissant la tche requise doit tre plac
entre accolades. Ce code peut contenir tout ce qui est autoris dans un script PHP, y
compris des appels dautres fonctions, des dclarations de nouvelles variables ou fonc-
tions, des instructions require() ou include(), des dclarations de classe et du code
HTML. Lorsque, au sein dune fonction, il est ncessaire de quitter PHP et dafficher
du code HTML brut, il suffit de procder comme en tout autre endroit dun script : en
plaant une balise PHP de fermeture avant le code HTML.
160 Partie I Utilisation de PHP
Le code qui suit est une variante possible de lexemple prcdent et il produit le mme
rsultat :
<?php
function ma_fonction() {
?>
ma_fonction a t appele.
<?php
}
?>
Vous remarquerez que le code PHP est encadr par des balises PHP douverture/ferme-
ture. Dans la plupart des fragments de code donns en exemple dans cet ouvrage, ces
balises ne sont pas montres. Nous les avons montres dans cet exemple car elles y sont
indispensables.
(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>";
}
Figure 5.4
Lappel de la fonction
creer_table() produit
laffichage de ce
tableau HTML.
162 Partie I Utilisation de PHP
Pour une prsentation plus are des donnes du tableau, nous pouvons appeler
creer table2() de la manire suivante :
creer_table2($mon_tableau, 3, 8, 8);
Lorsque des paramtres sont facultatifs, il nest pas indispensable de leur fournir des
valeurs. Linterprteur PHP assigne les paramtres de la gauche vers la droite.
Noubliez pas quil nest pas possible domettre un paramtre facultatif lors de lappel
dune fonction et de passer un autre paramtre facultatif plac sa droite dans la dfi-
nition de la fonction. Dans lexemple prcdent, il faut passer une valeur pour le
paramtre remplissage pour pouvoir passer une valeur pour le paramtre espace
ment. Le non-respect de cette rgle est lorigine de nombreuses erreurs de program-
mation. Par ailleurs, cette rgle est la raison pour laquelle les paramtres facultatifs
doivent toujours apparatre en dernier dans la liste des paramtres.
Lappel de fonction suivant :
creer_table2($mon_tableau, 3);
Chapitre 5 Rutilisation de code et criture de fonctions 163
est tout fait correct et cre une bordure large de 3 pixels ; les espacements entre les
cellules et lintrieur de celles-ci sont dfinis par leurs valeurs par dfaut.
Vous pouvez galement dclarer des fonctions qui acceptent un nombre variable de
paramtres. Le nombre de paramtres passs et leurs valeurs peuvent tre retrouvs
laide de trois fonctions auxiliaires : func num args(), func get arg() et
func get args().
tudiez par exemple la fonction suivante :
function params_variables() {
echo "Nombre de paramtres: ";
echo func_num_args();
Cette fonction indique le nombre de paramtres qui lui sont passs et affiche chacun
deux. La fonction func num args() renvoie le nombre darguments passs et
func get args() renvoie un tableau des paramtres. Vous pouvez galement accder
un paramtre particulier en utilisant la fonction func get arg(), laquelle il faut
passer le numro du paramtre souhait (les paramtres sont numrots en commenant
zro).
Porte
Vous avez peut-tre not que, lorsque nous avons besoin dutiliser des variables dans un
fichier charg via une instruction require() ou include(), nous les dclarons simple-
ment dans le script avant linstruction require() ou include(). En revanche, avec une
fonction, les variables requises au sein de la fonction doivent tre explicitement passes
la fonction sous forme de paramtres. Cette diffrence sexplique en partie par le fait
quil nexiste pas de mcanisme permettant de passer explicitement des variables des
fichiers inclus, et en partie parce que la porte dune variable est diffrente pour les
fonctions.
La porte dune variable dfinit les parties du code o cette variable est visible et utili-
sable. Chaque langage de programmation a ses propres rgles en la matire et celles de
PHP sont relativement simples :
m La porte dune variable dclare au sein dune fonction stend de linstruction
partir de laquelle elle est dclare jusqu laccolade de fermeture de la fonction. La
porte est alors dite "limite la fonction" et les variables portent le nom de variables
locales.
164 Partie I Utilisation de PHP
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
Les fonctions ntant excutes que lorsquelles sont appeles, la premire instruction
excute dans ce code est $var = "contenu 1";. Une variable appele $var est alors
cre, dont la porte est globale et qui contient la chane "contenu 1". PHP excute
ensuite lappel la fonction fn() en excutant dans lordre les lignes qui constituent la
dclaration de la fonction. La premire de ces lignes fait rfrence une variable appe-
le $var. Au moment de lexcution de cette ligne, linterprteur PHP ne peut pas voir
la variable $var dj cre et cre une nouvelle variable dont la porte se limite la
fonction fn(). Cest laffichage du contenu de cette nouvelle variable au moyen de
linstruction echo qui produit la premire ligne de la sortie.
La ligne qui vient ensuite dans la dclaration de la fonction donne $var le contenu
"contenu 2". Cette ligne de code appartenant la fonction, elle modifie la valeur de la
variable $var locale, pas celle de la variable globale. La deuxime ligne de la sortie met
en vidence ce fonctionnement.
Lorsque lexcution de la fonction sachve, la dernire ligne de notre script est excute.
Cette instruction echo finale montre que la valeur de la variable globale $var na pas t
affecte par lexcution de la fonction fn().
Pour quune variable cre au sein dune fonction soit de porte globale, nous devons
utiliser le mot-cl global, comme ici :
function fn() {
global $var;
$var = "contenu";
echo Dans la fonction, $var = . $var . <br />;
}
fn();
echo En dehors de la fonction, $var = . $var. <br />;
Dans cet exemple, la variable $var est explicitement dfinie comme globale. Aprs
lappel de la fonction fn(), la variable continue donc dexister en dehors de la fonction.
Lexcution de ce fragment de code produit laffichage suivant :
Dans la fonction, $var = contenu
En dehors de la fonction, $var = contenu
Notez que la porte de la variable commence au point o la ligne global $var; est
excute. Nous aurions aussi bien pu placer la dclaration de la fonction aprs quavant
la ligne contenant lappel de la fonction. Une dclaration de fonction peut tre indiff-
remment place en nimporte quel point dun script. En revanche, la position de lappel
166 Partie I Utilisation de PHP
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 />;
Cette utilisation du mot-cl return nest videmment pas des plus utiles. Normale-
ment, le mot-cl return semploie pour sortir dune fonction, au milieu de celle-ci,
lorsquune certaine condition a t vrifie.
Une condition derreur est une raison typique dutiliser une instruction return pour
interrompre lexcution dune fonction avant sa fin. Par exemple, supposez quil nous
faille crire une fonction dterminant quel est le plus grand de deux nombres. Il faudrait
que lexcution de la fonction puisse tre interrompue si lun des deux nombres na pas
t fourni.
function superieur( $x, $y ) {
if (!isset($x) ||!isset($y) ) {
echo "Cette fonction attend deux nombres.";
return;
}
if ($x >= $y) {
echo $x;
} else {
echo $y;
}
}
La fonction superieur() renvoie prsent la plus grande des deux valeurs qui lui sont
passes en paramtres. Elle renverra une valeur qui sera de toute vidence fausse en
cas derreur : si lun des nombres comparer nest pas fourni, la fonction retourne
false. La seule difficult avec cette approche est que les programmeurs appelant cette
fonction doivent tester le type du retour avec == pour sassurer de ne pas confondre
false avec 0.
titre de comparaison, la fonction max() ne renvoie rien si les deux variables nont pas
t dfinies. Si une seule a t dfinie, cest elle qui est renvoye.
Le code qui suit :
$a = 1; $b = 2.5; $c = 1.9;
echo superieur($a, $b) . "<br />";
echo superieur($c, $a) . "<br />";
echo superieur($d, $a) . "<br />";
produit le rsultat suivant parce que $d nexiste pas et que false nest pas visible :
2.5
1.9
Souvent, les fonctions qui effectuent certains traitements, mais qui nont pas besoin de
renvoyer de valeur, renvoient les valeurs true ou false pour signaler si elles ont russi
ou chou. Les valeurs boolennes true et false peuvent tre respectivement reprsentes
par 0 et 1, bien quil sagisse de types diffrents.
170 Partie I Utilisation de PHP
Rcursivit
Une fonction rcursive est une fonction qui sappelle elle-mme. Ce type de fonction se
rvle particulirement utile pour naviguer dans des structures de donnes dynamiques,
comme les listes chanes et les arborescences.
Toutefois, les applications web qui requirent des structures de donnes dune telle
complexit sont assez rares, si bien que la rcursivit nest que rarement exploite en
PHP. Dans nombre de cas, elle peut tre utilise la place dune structure itrative,
parce quelle consiste galement effectuer des rptitions du code. Cependant, les
fonctions rcursives tant plus lentes et consommant plus de mmoire que leurs homo-
logues itratives, vous avez tout intrt prfrer les itrations aux rcursions lorsque
cest possible.
Pour que cette tude soit complte, nous allons quand mme examiner lexemple
simple prsent dans le Listing 5.5.
Listing 5.5 : recursion.php Une chane peut tre facilement inverse au moyen
dune fonction rcursive. La version itrative est galement donne.
function inverser_recursive($chaine) {
if (strlen($chaine) > 0) {
inverser_recursive(substr($chaine, 1));
}
echo substr($chaine, 0, 1);
return;
}
function inverser_iterative($chaine) {
for ($i=1; $i<=strlen($chaine); $i++) {
echo substr($str, -$i, 1);
}
return;
}
Le Listing 5.5 contient deux fonctions qui affichent toutes deux lenvers la chane qui
leur est fournie en paramtre. La fonction inverser recursive () est rcursive, tandis
que la fonction inverser iterative () est itrative.
inverser recursive () prend une chane en paramtre. Lorsquelle est appele, elle
opre en sappelant elle-mme et en se passant chaque fois la sous-chane comprise
entre le deuxime et le dernier caractre de la chane. Cet appel, par exemple :
inverser_recursive(Bonjour);
se traduit par la srie dappels suivante :
inverser_recursive (onjour);
inverser_recursive (njour);
inverser_recursive (jour);
Chapitre 5 Rutilisation de code et criture de fonctions 171
inverser_recursive (our);
inverser_recursive (ur);
inverser_recursive (r);
inverser_recursive ();
chaque fois que la fonction sappelle elle-mme, une nouvelle copie du code de la
fonction est effectue dans la mmoire du serveur, mais avec un paramtre diffrent.
Tout se passe comme si une fonction diffrente tait appele chaque fois. Ce fonction-
nement permet dviter la confusion entre les diffrentes instances de la fonction.
chaque appel, la longueur de la chane est value. Lorsque linterprteur PHP atteint
la fin de la chane (strlen()==0), la condition nest plus satisfaite. Linstance de la
fonction la plus rcente (inverser recursive ()) se poursuit par lexcution de
la prochaine ligne de code, laquelle commande dafficher le premier caractre de la
chane passe en paramtre. ce stade, il ny a pas de caractre, parce que la chane est
vide.
Ensuite, cette instance de la fonction redonne le contrle linstance qui la appele,
cest--dire inverser recursive (r). Celle-ci affiche le premier caractre de sa
chane, en loccurrence r, et redonne le contrle linstance qui la appele.
Le processus se poursuit ainsi, affichant un caractre puis redonnant le contrle
linstance prcdente de la fonction selon lordre dappel, jusqu ce que le contrle soit
redonn au programme principal.
Les solutions rcursives sont lgantes et ont un aspect mathmatique indniable mais,
le plus souvent, la solution itrative leur est prfrable. Le Listing 5.5 donne galement
lquivalent itratif de la fonction inverser recursive : vous pouvez remarquer que
cette variante nest pas plus longue (ce qui nest pas toujours vrai de toutes les fonctions
itratives) et quelle produit exactement le mme rsultat.
La fonction rcursive se distingue principalement de la fonction itrative par le fait
quelle effectue des copies delle-mme dans la mmoire et gnre plusieurs appels de
fonction, ce qui est coteux en termes de mmoire et de temps dexcution.
Peut-tre choisirez-vous des solutions rcursives lorsquelles permettent dcrire un
code plus court et plus lgant que la version itrative, mais cela ne se produit pas
souvent dans le domaine des applications web.
Bien que la rcursion apparaisse plus lgante, les programmeurs oublient souvent de
fournir une condition de terminaison dans leurs fonctions rcursives. Dans ce cas,
lexcution rcursive de la fonction se poursuit jusqu ce que le serveur soit court de
mmoire ou que le temps dexcution maximal ait t dpass.
172 Partie I Utilisation de PHP
Pour la suite
Vous savez prsent amliorer la maintenabilit et la rutilisabilit de votre code par le
recours des fichiers de type "include" et "require" et des fonctions. Nous allons
donc pouvoir poursuivre notre tude par laspect orient objet du langage PHP. Lutili-
sation dobjets rpond aux mmes objectifs que ceux des concepts dcrits dans ce
chapitre, mais avec plus davantages encore lorsque les projets sont complexes.
6
PHP orient objet
Classes et objets
Dans le contexte de la POO, un objet peut tre quasiment tout lment ou concept,
cest--dire un objet physique comme un bureau ou un client, ou un objet conceptuel
qui nexiste que dans le programme lui-mme, comme un champ de saisie ou un fichier.
Le plus souvent, le dveloppeur sintresse aux objets du monde rel et aux objets
conceptuels qui doivent tre reprsents dans le programme.
Un logiciel orient objet est conu et construit sous la forme dun ensemble dobjets
indpendants dots la fois dattributs et doprations qui interagissent pour rpondre
nos besoins. Les attributs sont des proprits ou des variables qui se rapportent
lobjet. Les oprations sont des mthodes, des actions ou des fonctions que lobjet peut
accomplir, soit pour se modifier lui-mme, soit pour produire un effet externe (le terme
attribut est utilis de manire interchangeable avec les termes variable membre et
174 Partie I Utilisation de PHP
proprit, tandis que le terme opration est utilis de manire interchangeable avec le
terme mthode).
Le principal avantage dun logiciel orient objet rside dans sa capacit prendre en
charge et encourager lencapsulation, galement appele masquage de donnes. Pour
lessentiel, les donnes contenues dans un objet ne sont accessibles que par le biais des
oprations de celui-ci, qui forment linterface de lobjet.
La fonctionnalit dun objet est lie aux donnes quil utilise. Les dtails de limpl-
mentation dun objet peuvent tre facilement modifis pour amliorer les performances,
ajouter de nouvelles caractristiques ou corriger des bogues, sans quil soit ncessaire
de changer linterface. Le fait de modifier cette interface peut, en effet, avoir des rper-
cussions en cascade dans le projet, alors que lencapsulation vous permet deffectuer
des modifications et de raliser des corrections de bogues sans que vos actions ne se
rpercutent dans les autres parties du projet.
Dans les autres secteurs du dveloppement logiciel, la POO sest impose comme la norme
et le dveloppement orient fonctions est dsormais considr comme dmod. Cepen-
dant, pour diverses raisons, la plupart des scripts web restent malheureusement conus et
crits avec une approche ad hoc, utilisant une mthodologie oriente fonctions.
Ce "retard" a plusieurs causes. Une majorit de projets web sont de petite taille et rela-
tivement simples. Nul besoin dlaborer un plan dtaill pour construire une tagre
avec une scie. De la mme manire, la plupart des projets logiciels pour le Web peuvent
tre raliss de cette faon parce quils sont de petite taille. En revanche, si vous prenez
votre scie pour construire une maison sans avoir formellement planifi vos travaux,
vous ne pourrez pas obtenir des rsultats de qualit, si tant est que vous obteniez des
rsultats. Il en va exactement de mme pour les projets logiciels importants.
Nombre de projets web voluent dun ensemble de pages relies entre elles par des
hyperliens vers des applications complexes. Ces applications complexes, quelles
soient prsentes via des botes de dialogue et des fentres ou via des pages HTML
dynamiques, requirent une mthodologie de dveloppement mrement rflchie.
Lorientation objet peut aider grer la complexit des projets logiciels, augmenter la
rutilisabilit du code et, par consquent, rduire les cots de maintenance.
En POO, un objet est une collection unique et identifiable de donnes et doprations
agissant sur ces donnes. Par exemple, considrons le cas de deux objets reprsentant
des boutons. Mme si ces boutons portent tous deux lintitul "OK", ont une largeur de
60 pixels, une hauteur de 20 pixels et divers autres attributs identiques, nous devons
pouvoir les distinguer et les manipuler sparment lun de lautre. Dun point de vue
logiciel, cette distinction seffectue via des variables spares, qui servent de descripteurs
(didentificateurs uniques) pour les objets.
Chapitre 6 PHP orient objet 175
Les objets peuvent tre regroups en "classes". Une classe est un ensemble dobjets qui
peuvent tre diffrents les uns des autres, mais qui ont certains points communs. Une
classe contient des objets qui prsentent tous des oprations se comportant de la mme
manire et des attributs identiques reprsentant les mmes choses, bien que les valeurs
de ces attributs puissent varier dun objet lautre au sein de la classe.
Vous pouvez ainsi considrer le nom bicyclette comme celui dune classe dobjets qui
dcrit les nombreuses bicyclettes distinctes qui prsentent toutes des caractristiques ou
attributs communs, comme deux roues, une couleur et une taille, et des oprations,
comme le dplacement.
Ma propre bicyclette pourrait ainsi tre considre comme un objet appartenant la
classe bicyclette. Elle a des caractristiques identiques toutes les bicyclettes, y
compris lopration de dplacement, qui est tout fait comparable lopration de
dplacement des autres bicyclettes, mme si elle nest utilise que trs rarement. Les
attributs de ma bicyclette ont toutefois des valeurs qui leur sont propres ; par exemple,
sa couleur est verte, ce qui nest pas le cas de toutes les bicyclettes.
Polymorphisme
Un langage de programmation orient objet doit prendre en charge le polymorphisme,
qui signifie que diffrentes classes peuvent avoir des comportements diffrents pour la
mme opration. Par exemple, supposez que nous ayons dfini une classe voiture et une
classe bicyclette. Ces deux classes peuvent avoir des oprations de dplacement diff-
rentes. Dans lunivers des objets rels, cette diffrentiation pose rarement problme : il
est peu probable en effet quune bicyclette soit confondue avec une voiture et dmarre
avec une opration de dplacement de voiture au lieu dune opration de dplacement
de bicyclette. En revanche, un langage de programmation ne possde pas le sens
commun du monde rel : il doit par consquent disposer du polymorphisme pour quil
soit possible de distinguer lopration de dplacement approprie un objet particulier.
Le polymorphisme est plus une caractristique des comportements que des objets eux-
mmes. En PHP, seules les fonctions membres dune classe peuvent tre polymor-
phiques. Les verbes des langages naturels sont un peu lquivalent dans le monde rel
des fonctions membres dune classe. Considrez la manire dont peut tre utilise une
bicyclette dans la vie relle. Vous pouvez la nettoyer, la dplacer, la dmonter, la rparer
ou la peindre, entre autres choses.
Les verbes de cette dernire phrase dcrivent des actions gnriques parce que le type
dobjet auquel ils peuvent tre appliqus nest pas prcis (ce type dabstraction concer-
nant les objets et les actions est, du reste, lune des caractristiques distinctives de
lintelligence humaine).
176 Partie I Utilisation de PHP
Le dplacement dune bicyclette, par exemple, exige des actions totalement diffrentes
de celles requises pour dplacer une voiture, mme si les concepts sont similaires. Le
verbe "dplacer" peut donc tre associ un ensemble particulier dactions, mais
uniquement aprs que lobjet auquel il sapplique a t dfini.
Hritage
Lhritage permet de crer une relation hirarchique entre les classes au moyen de sous-
classes. Une sous-classe hrite des attributs et des oprations de sa superclasse. Les
voitures et les bicyclettes ont, par exemple, des points communs et nous pourrions donc
dfinir une classe vhicule contenant des attributs comme la couleur et des oprations
comme le dplacement qui sont communs tous les vhicules. Il suffirait ensuite de
laisser les classes voiture et bicyclette hriter de la classe vhicule.
Les termes sous-classe, classe drive et classe fille sont utiliss de manire interchan-
geable. Il en va de mme des termes superclasse, classe de base et classe parente.
Grce au concept dhritage, nous pouvons laborer et enrichir lensemble des classes
existantes. partir dune simple classe de base, des classes plus complexes et plus
spcialises peuvent tre cres au fur et mesure des besoins. Cette approche rend le
code plus rutilisable et constitue lun des atouts indniables de la programmation
oriente objet.
Exploiter la notion dhritage peut permettre dconomiser du temps et des efforts de
dveloppement lorsque des oprations peuvent tre implmentes une seule fois dans
une superclasse, au lieu de ltre chaque fois dans des sous-classes spares. Cette
approche favorise galement une modlisation plus prcise des relations du monde rel.
Lorsque la phrase dcrivant la relation entre deux classes peut contenir les mots "est un"
ou "est une", alors, le concept dhritage peut tre exploit. La phrase "une voiture est
un vhicule", par exemple, est tout fait sense, tandis que la phrase "un vhicule est
une voiture" nest pas vraie dans le monde rel. Par consquent, les voitures peuvent
hriter de la classe vhicule.
Pour quune classe ait une quelconque utilit, elle doit tre dote dattributs et dopra-
tions. Pour crer des attributs, il faut dclarer des variables au sein dune dfinition de
classe en les prcdant de mots-cls indiquant leur visibilit : public, private ou
protected (ces mots-cls seront prsents plus loin dans ce chapitre). Le code qui suit
cre une classe nomclasse dote des deux attributs publics, $attribut1 et $attribut2 :
class classname {
public $attribut1;
public $attribut2;
}
La cration doprations dans une classe seffectue en dclarant des fonctions dans la
dfinition de la classe. Le code suivant cre une classe nomclasse dote de deux opra-
tions qui neffectuent rien de particulier. Lopration operation1() ne prend aucun
paramtre, tandis que operation2() attend deux paramtres.
class nomclasse {
function operation1() {}
function operation2($param1, $param2) {}
}
Constructeurs
La plupart des classes disposent dun type spcial dopration appel constructeur. Un
constructeur est appel lors de la cration dun objet et effectue gnralement des tches
dinitialisation comme lassignation de valeurs initiales aux attributs ou la cration
dautres objets ncessaires lobjet concern.
Un constructeur se dclare de la mme manire que les autres oprations, sauf quil
porte le nom spcial construct().
Bien quun constructeur puisse tre appel manuellement, son rle principal est dtre
appel automatiquement la cration dun objet. Le code qui suit dclare une classe
dote dun constructeur :
class nomclasse {
function _ _construct($param) {
echo "Constructeur appel avec le paramtre " . $param . "<br />";
}
}
Destructeurs
Loppos dun constructeur est un destructeur. Les destructeurs permettent dexcuter
un traitement particulier juste avant quun objet ne soit dtruit, ce qui aura lieu automa-
tiquement lorsque toutes les rfrences cet objet ont t indfinies ou hors de porte.
Le destructeur dune classe doit sappeler destruct() et ne peut prendre aucun para-
mtre.
178 Partie I Utilisation de PHP
$a = new nomclasse("Premier");
$b = new nomclasse("Second");
$c = new nomclasse();
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;
}
}
vous pouvez utiliser les fonctions _ _get() et _ _set() pour tester et modifier la valeur
de nimporte quel attribut.
Si vous tapez :
$a->$attribut = 5;
cette instruction appellera implicitement la fonction _ _set() avec la valeur $nom posi-
tionne "attribut" et la valeur $valeur initialise 5. Si vous souhaitez effectuer
180 Partie I Utilisation de PHP
des contrles sur les valeurs affectes lattribut, vous devez crire la fonction _ _set()
en consquence.
La fonction _ _get() fonctionne de manire similaire. Dans votre code, si vous crivez :
$a->attribut
lexpression appellera implicitement la fonction _ _get() avec le paramtre $nom posi-
tionn "attribut". Cest vous dcrire la fonction _ _get() pour retourner la valeur
de lattribut.
Au premier coup dil, ce code peut sembler navoir que peu ou pas dintrt. Sous sa
forme actuelle, cest probablement le cas, mais il existe une raison simple de proposer
des fonctions daccs : vous naurez alors quune unique section de code qui accde
cet attribut particulier.
Avec un seul point daccs, vous pouvez implmenter des contrles de validit afin de
vous assurer que les donnes stockes sont cohrentes. Si vous jugez par la suite que la
valeur de $attribut doit tre comprise entre 0 et 100, vous pouvez ajouter quelques
lignes de code et oprer la vrification avant dautoriser les modifications. Vous pourriez
ainsi modifier la fonction _ _set() de la manire suivante :
function _ _set ($nom, $valeur) {
if( $nom == "attribut" && $valeur >= 0 && $valeur <= 100 ) {
$this->attribut = $valeur;
}
}
Avec un unique point daccs, vous tes libre de modifier limplmentation sous-jacente.
Si, pour une raison ou pour une autre, vous deviez modifier la manire dont $attribut
est stock, les fonctions accesseurs vous permettraient de le faire en ne modifiant le
code qu un seul emplacement.
Il se peut que vous dcidiez, au lieu de stocker $attribut sous forme de variable, de le
rcuprer partir dune base de donnes selon les besoins, de calculer une nouvelle
valeur chaque fois quelle est requise, de dduire une valeur partir de valeurs
dautres attributs ou dencoder les donnes sous un type de donnes plus compact.
Quelle que soit la modification que vous souhaitiez oprer, il suffit de modifier les fonc-
tions accesseurs. Les autres sections du code ne seront pas affectes, pour autant que
vous faites en sorte que les fonctions accesseurs continuent daccepter ou de renvoyer
les donnes que les autres parties du programme sattendent pouvoir utiliser.
m Loption par dfaut est public. Cela signifie que, si vous navez pas spcifi de
modificateur daccs pour un attribut ou une mthode, ceux-ci seront publics.
Laccs aux lments publics peut se faire depuis lintrieur ou lextrieur de la
classe.
m Le modificateur daccs private signifie quil nest possible daccder llment
marqu que depuis lintrieur de la classe. Vous pouvez lutiliser sur tous les attri-
buts si vous nutilisez pas _ _get() et _ _set(). Vous pouvez galement choisir de
rendre certaines mthodes prives, par exemple sil sagit de fonctions utilitaires
utiliser lintrieur de la classe uniquement. Les lments privs ne sont pas hrits
(nous y reviendrons dans la suite de ce chapitre).
m Le modificateur daccs protected signifie que lon ne peut accder llment
marqu que depuis lintrieur de la classe. Il existe galement dans toutes les sous-
classes. Nous reviendrons aussi sur cette question lorsque nous traiterons de lhri-
tage dans la suite de ce chapitre. Pour linstant, considrez que protected est mi-
distance entre private et public.
Le code suivant montre lutilisation du modificateur public :
class nomclasse {
public $attribut;
public function _ _get($nom) {
return $this->$nom;
}
public function _ _set ($nom, $valeur) {
$this->$nom = $valeur;
}
}
Ici, chaque membre de classe est prcd dun modificateur daccs qui indique sil est
priv ou public. Le mot-cl public peut tre omis car il sagit du rglage par dfaut,
mais le code est plus simple comprendre lorsque vous lincluez, notamment si vous
utilisez dautres modificateurs.
nous pouvons appeler des oprations en procdant de la mme faon que pour lappel
dautres fonctions : en spcifiant leur nom, suivi des paramtres requis, placs entre
parenthses. Ces oprations appartenant un objet, la diffrence des fonctions norma-
les, il est ncessaire de prciser lobjet concern. Le nom de cet objet est indiqu de la
mme manire que pour ses attributs :
$a->operation1();
$a->operation2(12, "test");
Si les oprations renvoient des valeurs, elles peuvent tre rcupres de la manire
suivante :
$x = $a->operation1();
$y = $a->operation2(12, "test");
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;
$a = new A();
$a->operation1();
$a->attribut1 = 10;
$a->operation2();
$a->attribut2 = 10;
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();
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();
Redfinition (overriding)
Nous venons de voir le cas dune sous-classe dans laquelle sont dclars de nouveaux
attributs et oprations. Il est galement permis et parfois utile de redclarer les mmes
attributs et oprations. Une telle redclaration, qualifie de "redfinition" (overriding),
permet en effet de donner un attribut dune sous-classe une valeur par dfaut diff-
rente de celle du mme attribut dans la superclasse, ou bien encore de donner une
opration dune sous-classe une fonctionnalit diffrente de la mme opration dans la
superclasse.
Par exemple, si nous disposons de la classe A suivante :
class A {
public $attribut = "Valeur par dfaut";
public function operation() {
echo "Quelque chose<br />";
echo La valeur de $attribut est . $this->attribut . "<br />";
}
}
Ce rsultat montre bien que la cration de B na pas affect A. Si nous crons un objet de
type B, nous obtiendrons un rsultat diffrent.
Les lignes suivantes :
$b = new B();
$b -> operation();
produiront :
Autre chose
La valeur de $attribut est Valeur diffrente
De la mme manire que fournir de nouveaux attributs ou oprations dans une sous-
classe naffecte pas la superclasse, la redfinition dattributs ou doprations dans une
sous-classe naffecte pas la superclasse.
Une sous-classe hrite de tous les attributs et oprations non privs de sa superclasse,
moins que vous effectuiez des remplacements. Si vous fournissez une dfinition de
remplacement, celle-ci devient prpondrante et remplace la dfinition dorigine.
Le mot-cl parent vous permet dappeler la version originale de lopration dans la
classe parente. Par exemple, pour appeler lopration A::operation depuis lintrieur
de la classe B, vous utiliseriez :
parent::operation();
La sortie produite est cependant diffrente. Bien que vous appeliez lopration depuis la
classe parente, PHP utilise les valeurs dattribut de la classe courante. Vous obtiendrez
donc la sortie suivante :
Quelque chose
La valeur de $attribut est Valeur diffrente
Lhritage peut tre implment sur plusieurs niveaux. Par exemple, nous pourrions
dclarer une classe appele C qui hrite de B, cest--dire qui hrite la fois des
proprits de B et de celles du parent de B, cest--dire de A. Tout comme pour la classe B,
nous serions libres de redfinir et de remplacer dans la classe C des attributs et oprations
des parents.
186 Partie I Utilisation de PHP
Vous pouvez galement utiliser le mot-cl final pour empcher la cration de sous-
classes partir dune classe. Pour empcher la cration de sous-classes partir de la
classe A, ajoutez le mot-cl de la manire suivante :
final class A {...}
Si vous essayez ensuite dhriter de A, vous obtiendrez une erreur comme celle-ci :
Fatal error: Class B may not inherit from final class (A)
Hritage multiple
Quelques langages OO (dont C++ et Smalltalk) prennent en charge lhritage multiple
mais, comme la plupart des autres, ce nest pas le cas de PHP. Il sensuit que chaque
classe ne peut hriter que dun seul parent. En revanche, aucune restriction nimpose
une limite sur le nombre denfants que peut engendrer un mme parent.
Les implications de cet tat de fait ne sont pas ncessairement videntes premire vue.
La Figure 6.1 montre trois modes dhritage diffrents.
Figure 6.1
A
PHP ne prend pas
en charge lhritage A A B
multiple.
B
B C C
Hritage simple Hritage multiple
C
Hritage simple
Chapitre 6 PHP orient objet 187
Dans le mode le plus gauche, la classe C hrite de la classe B, qui hrite son tour de
la classe A. Chaque classe possde au plus un parent : ce mode dhritage unique est
parfaitement valide en PHP.
Dans le mode du centre, les classes B et C hritent toutes deux de la classe A. L encore,
chaque classe possde au plus un parent : ce mode dhritage unique est galement valide
en PHP.
Dans le mode le plus droite, la classe C hrite la fois des classes A et B. Dans ce cas,
la classe C possde deux parents : il sagit l dune situation dhritage multiple, non
supporte par PHP.
Implmentation dinterfaces
Si vous devez implmenter une fonctionnalit analogue lhritage multiple, vous
pouvez le faire grce aux interfaces, qui sont un moyen de contourner labsence de
lhritage multiple. Leur implmentation est semblable celle des autres langages
orients objet, dont Java.
Le principe dune interface consiste prciser un ensemble de fonctions qui devront tre
implmentes dans les classes qui implmentent linterface. Par exemple, vous pourriez
souhaiter quun ensemble de classes soient capables de safficher. Au lieu de crer une
classe parente avec une fonction Afficher() dont hriteraient toutes les sous-classes et
quelles redfiniraient, vous pouvez utiliser une interface de la manire suivante :
interface Affichable {
function Afficher(){
}
Cet exemple prsente une alternative lhritage multiple car la classe pageWeb peut
hriter dune seule classe et implmenter une ou plusieurs interfaces.
Si vous nimplmentez pas les mthodes spcifies dans linterface (dans le cas prsent,
Afficher()), vous obtiendrez une erreur fatale.
Conception de classes
Maintenant que nous avons pass en revue les principaux concepts de lapproche orien-
te objet concernant les objets et les classes, ainsi que la syntaxe de leur implmen-
tation en PHP, nous pouvons nous intresser la conception de classes qui nous seront
utiles.
188 Partie I Utilisation de PHP
Souvent, les classes implmentes dans le code reprsentent des classes ou des catgo-
ries dobjets rels. Dans le cadre dun dveloppement web, les classes peuvent notam-
ment servir reprsenter des pages web, des composants dinterface utilisateur, des
paniers virtuels, des gestionnaires derreur, des catgories de produits ou des clients.
Les objets de votre code peuvent galement reprsenter des instances spcifiques des
classes numres plus haut, comme une page daccueil, un bouton particulier ou le
panier dachat de Jean Dupont un moment donn. Jean Dupont lui-mme pourrait
dailleurs tre reprsent par un objet de type client. Chaque article achet par Jean peut
tre reprsent sous la forme dun objet, appartenant une catgorie ou une classe.
Dans le chapitre prcdent, nous nous sommes servis de fichiers inclus pour donner une
apparence cohrente toutes les pages du site de lentreprise fictive TLA Consulting.
Une version plus labore de ce site pourrait tre obtenue en utilisant des classes et en
exploitant le concept puissant dhritage.
Nous voulons maintenant pouvoir ajouter rapidement de nouvelles pages web au site de
TLA, qui aient la mme prsentation et un comportement similaire. Nous voulons
toutefois tre en mesure de modifier ces pages pour les adapter aux diffrentes parties
du site.
Pour les besoins de cet exemple, nous allons crer une classe Page dont le rle principal
est de limiter la quantit de code HTML ncessaire la cration dune nouvelle page.
Cette classe devra nous permettre de modifier les sections qui changent dune page
lautre, tout en produisant automatiquement les lments communs toutes les pages.
La classe Page devra donc fournir un cadre flexible pour la cration de nouvelles
pages, sans compromettre notre libert.
Comme les pages seront produites partir dun script et non avec du code HTML statique,
nous pouvons implmenter diverses possibilits astucieuses :
m Nautoriser la modification dlments de la page quen un emplacement seulement.
Par exemple, sil apparat ncessaire de changer la dclaration de copyright ou
dajouter un bouton supplmentaire, nous ne devrions avoir apporter la modification
quen un seul point du code.
m Disposer dun contenu par dfaut pour la plupart des sections de la page, tout en
gardant la possibilit de modifier chaque lment si ncessaire, de dfinir des
valeurs personnalises pour des lments tels que le titre et les mtabalises.
m Identifier la page en cours daffichage dans le navigateur et modifier en consquence
les lments de navigation (par exemple, un bouton permettant de retourner la
page de dmarrage na pas lieu dtre sur la page de dmarrage).
Chapitre 6 PHP orient objet 189
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
Pour que la classe Page fournisse des fonctionnalits, nous devons la munir dopra-
tions. Pour commencer, nous pouvons lui ajouter des fonctions accesseurs qui nous
permettront de dfinir et de rcuprer la valeur des attributs que nous venons de crer :
public function _ _set($nom, $valeur)
{
$this->$nom = $valeur;
}
Outre quelques instructions echo simple qui affichent le texte HTML, cette fonction
comprend essentiellement des appels dautres fonctions de la classe. Comme le lais-
sent deviner leurs noms, ces autres fonctions affichent des parties distinctes de la page.
Un tel dcoupage en fonctions nest pas indispensable et nous aurions trs bien pu
combiner ces diffrentes fonctions en une seule. Nous avons toutefois choisi ce dcou-
page pour diverses raisons.
Chaque fonction doit, en principe, accomplir une tche bien dfinie. Plus la tche est
simple, plus la fonction est facile tester. Ne poussez toutefois pas cette modularisation
trop loin : un programme morcel en trop dunits risque dtre difficile lire.
Grce au concept dhritage, nous avons la possibilit de redfinir des oprations. Nous
pouvons redfinir une fonction Afficher() volumineuse, mais il est peu probable que
nous soyons amens changer la manire dont toute la page est affiche. Il est par
Chapitre 6 PHP orient objet 191
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"
);
La classe Page comprend deux autres oprations que celles cites dans le paragraphe
prcdent. Lopration AfficherBouton() produit un simple bouton de menu. Si ce
bouton doit pointer sur la page courante, il est remplac par un bouton inactif, dappa-
rence lgrement diffrente et ne pointant sur aucune page. Cette astuce permet de
conserver une prsentation cohrente des pages du site et donne aux visiteurs une indi-
cation sur leur localisation dans le site.
Lopration EstPageCourante() dtermine si lURL qui lui a t passe en paramtre
pointe sur la page courante. Il existe de nombreuses techniques pour crire ce type de
test ; ici, nous faisons appel la fonction strpos() pour dterminer si lURL est contenue
dans lune des variables de serveur. Linstruction strpos( $ SERVER[PHP SELF],
$url ) renvoie un nombre si la chane stocke dans $url est contenue dans la variable
superglobale $ SERVER[PHP SELF] ou renvoie la valeur false dans le cas contraire.
Pour utiliser la classe Page, nous devons inclure le fichier page.inc dans un script et
appeler Afficher().
Le code du Listing 6.2 cre la page daccueil du site de lentreprise fictive TLA Consulting
et donne un rsultat trs semblable celui montr la Figure 6.2.
Le code du Listing 6.2 fonctionne de la manire suivante :
1. Il utilise linstruction require pour inclure le contenu de page.inc qui contient la
dfinition de la classe Page.
2. Il cre une instance de la classe Page. Cette instance est appele $page accueil.
3. Il dfinit le contenu, constitu de texte et de balises HTML qui doivent figurer dans
la page (ce qui appelle implicitement la mthode _ _set()).
4. Il appelle lopration Afficher() sur lobjet $page accueil pour provoquer laffi-
chage de la page dans le navigateur web du visiteur.
Listing 6.2 : accueil.php Cette page daccueil est obtenue en utilisant la classe Page
pour accomplir lessentiel du travail ncessaire la gnration de la page
<?php
require("page.inc");
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().
<?php
require ("page.inc");
Cette ligne appelle AfficherMenu() une seconde fois, de sorte crer la seconde barre
de menus.
En dehors de la dfinition de la classe, nous crons une instance de la classe Page
Services, nous dfinissons les valeurs qui requirent des valeurs diffrentes de celles
par dfaut, puis nous appelons Afficher().
Comme le montre la Figure 6.2, nous produisons bien ainsi une variante de la page
standard. Pour cela, nous nous sommes contents dcrire du nouveau code pour les
seules parties rellement diffrentes.
Figure 6.2
La page des services est produite sur le principe de lhritage, de sorte rutiliser lessentiel
du contenu de la page standard.
Chapitre 6 PHP orient objet 197
La cration de pages via des classes PHP prsente des avantages indniables. Comme
nous disposons dune classe capable de faire lessentiel du travail notre place, la cra-
tion dune nouvelle page ne ncessite que trs peu defforts. De plus, nous pouvons
facilement mettre jour toutes les pages du site en une seule fois, en travaillant directe-
ment la source, cest--dire sur la classe. Grce au principe de lhritage, il est facile
dobtenir diffrentes variantes dune mme classe tout en conservant les avantages de la
classe dorigine.
Comme cest hlas gnralement le cas, les avantages de cette approche ont un cot.
La gnration de pages partir dun script requiert plus deffort de la part du processeur
de lordinateur que le simple chargement dune page HTML statique partir dun
disque dur ou la transmission dune page un navigateur. Sur un site trs frquent, ce
dtail peut tre important et vous devrez alors faire en sorte dutiliser des pages HTML
statiques ou de mettre en cache la sortie de vos scripts chaque fois que cela est possible
afin de rduire la charge pesant sur le serveur.
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
Notez que vous ne pouvez pas utiliser le mot-cl this lintrieur dune mthode stati-
que, car il ny a aucune instance laquelle se rfrer.
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);
Notez que, si vous aviez indiqu A et pass une instance de B, aucune erreur ne serait
survenue, car B hrite de A.
Chapitre 6 PHP orient objet 199
Clonage dobjets
Le mot-cl clone permet de copier un objet existant. Linstruction suivante, par exemple :
$c = clone $b;
cre une copie de lobjet $b de la mme classe, avec les mmes valeurs dattributs.
Vous pouvez galement modifier ce comportement. Si vous souhaitez que le clonage
nadopte pas le comportement par dfaut, vous devez crer une mthode _ _clone()
dans la classe de base. Cette mthode est semblable un constructeur ou un destruc-
teur car on ne lappelle pas directement : elle est invoque lorsque lon utilise le mot-cl
clone comme ici. Dans cette mthode _ _clone(), vous pouvez ensuite dfinir exactement
le comportement de copie que vous souhaitez.
Le fait intressant concernant la fonction _ _clone() tient ce quelle est appele aprs
quune copie exacte eut t effectue en utilisant le comportement par dfaut, ce qui
permet ce stade de ne modifier que ce que vous souhaitez changer.
Le plus souvent, on ajoute _ _clone() du code pour garantir que les attributs de la
classe qui sont grs comme des rfrences seront correctement copis. Si vous vous
prparez cloner une classe qui contient une rfrence un objet, vous souhaiterez sans
doute obtenir une seconde copie de cet objet au lieu dune seconde rfrence au mme
objet. Il est alors judicieux dajouter cette fonctionnalit _ _clone().
Il est galement possible que vous choisissiez de ne rien changer mais de raliser
dautres actions, par exemple en mettant jour un enregistrement dune base de
donnes sous-jacente lie la classe.
Classes abstraites
PHP permet dcrire des classes abstraites qui ne peuvent pas tre instancies, ainsi que
des mthodes abstraites qui fournissent la signature dune mthode mais nen proposent
pas dimplmentation. Voici un exemple dune telle mthode :
abstract operationX($param1, $param2);
Toute classe qui contient des mthodes abstraites doit elle-mme tre abstraite, comme
le montre cet exemple :
abstract class A {
abstract function operationX($param1, $param2);
}
Lusage principal des mthodes et des classes abstraites concerne le cas des hirarchies
de classes complexes o vous souhaitez vous assurer que chaque sous-classe contient et
redfinit certaines mthodes particulires. Ce but peut galement tre atteint avec une
interface.
200 Partie I Utilisation de PHP
Utiliser _ _autoload()
La fonction _ _autoload() est une autre fonction spciale de PHP. Il sagit non pas
dune mthode de classe mais dune fonction autonome. Autrement dit, il faut la dcla-
rer en dehors de toute classe. Si vous limplmentez, elle sera automatiquement appele
lorsque vous tenterez dinstancier une classe qui na pas t dclare.
Lutilisation principale de _ _autoload() consiste inclure tous les fichiers requis pour
instancier une classe. Considrez lexemple suivant :
function _ _autoload($nom) {
include_once $nom . ".php";
}
Cette implmentation tente dinclure un fichier possdant le mme nom que la classe.
<?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++;
}
}
function _ _construct($in)
{
$this->donnees = $in;
}
function getIterator() {
return new ObjectIterator($this);
}
}
$monIter = $monObjet->getIterator();
for($monIter->rewind(); $monIter->valid(); $monIter->next()) {
$cle = $monIter->key();
$valeur = $monIter->current();
echo $cle . "=> " . $valeur . "<br />";
}
?>
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));
}
}
<?php
require_once("page.inc");
$classe = new ReflectionClass("Page");
echo <pre>;
echo $classe;
echo </pre>;
?>
Ici, vous utilisez la mthode _ _toString() de la classe Reflection pour imprimer ces
donnes. Notez que les balises <pre> se trouvent sur des lignes spares afin de ne pas
perturber la mthode _ _toString().
Le premier cran de sortie de ce code est prsent la Figure 6.3.
Figure 6.3
La sortie de lAPI dintro-
spection est tonnamment
dtaille.
Pour la suite
Le chapitre suivant prsente le traitement des exceptions en PHP, qui constituent un
mcanisme lgant pour la gestion des erreurs dexcution.
7
Gestion des exceptions
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.
<?php
try {
throw new Exception("Une terrible erreur sest produite", 42);
}
catch (Exception $e) {
echo "Exception " . $e->getCode() . ": " . $e->getMessage() .
" dans " . $e->getFile(). " en ligne ". $e->getLine() . "<br />";
}
?>
Dans le Listing 7.1, vous pouvez remarquer que nous avons utilis un certain nombre
de mthodes de la classe Exception, sur lesquelles nous reviendrons dans un instant.
Le rsultat de ce code est prsent la Figure 7.1.
Chapitre 7 Gestion des exceptions 207
Figure 7.1
Ce bloc catch signale le message derreur de lexception et lendroit o lexception est survenue.
Dans cet exemple, vous pouvez remarquer que nous levons une exception de la classe
Exception. Cette classe prdfinie possde des mthodes que vous pouvez utiliser dans
le bloc catch afin de produire un message derreur utile.
La classe Exception
PHP dispose dune classe prdfinie appele Exception. Son constructeur prend deux
paramtres, comme indiqu prcdemment : un message et un code derreur.
Outre ce constructeur, cette classe propose les mthodes suivantes :
m getCode(). Rennvoie le code tel quil a t pass au constructeur.
m getMessage(). Renvoie le message tel quil a t pass au constructeur.
m getFile(). Renvoie le chemin daccs complet au fichier dans lequel lexception a
t leve.
m getLine(). Renvoie le numro de ligne du fichier dans lequel lexception a t
leve.
m getTrace(). Renvoie un tableau contenant une trace dexcution de lendroit o
lexception a t leve.
m getTraceAsString(). Renvoie les mmes informations que getTrace, formates
sous forme de chane.
m _ _toString(). Permet deffectuer un simple echo dun objet Exception, en four-
nissant toutes les informations des mthodes prcdentes.
Comme vous le voyez, nous avons utilis les quatre premires mthodes dans le
Listing 7.1. Vous pouvez obtenir les mmes informations (ainsi que la trace dexcution)
laide de linstruction suivante :
echo $e;
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);
}
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.
<?php
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.
<?php
<?php
require_once("exceptions_fichiers.php");
$DOCUMENT_ROOT = $_SERVER[DOCUMENT_ROOT];
?>
<html>
<head>
<title>Le garage de Bob Résultats de la commande</title>
</head>
<body>
<h1>Le garage de Bob</h1>
<h2>Résultats de la commande</h2>
<?php
$date = date(H:i, \l\e j-m-Y);
echo <p>Commmande traitée à ;
echo $date;
echo </p>;
$qte_totale = 0;
$qte_totale = $qte_pneus + $qte_huiles + $qte_bougies;
echo Articles commandés: . $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 = number_format($montant_total, 2, ., );
?>
</body>
</html>
Comme vous pouvez le constater, la section des E/S de fichier de ce script est encapsu-
le dans un bloc try. En gnral, le bon usage en matire de programmation consiste
utiliser des blocs try de petite taille et capturer les exceptions appropries la fin de
chacun dentre eux. Le code de gestion des exceptions est ainsi plus facile crire et
maintenir car vous pouvez voir ce que vous grez.
Si vous ne pouvez pas ouvrir le fichier, vous levez une ExceptionOuvertureFichier;
si vous ne pouvez pas verrouiller le fichier, vous levez une ExceptionVerrouillage
Fichier; enfin, si vous ne pouvez pas crire dans le fichier, vous levez une Exception
EcritureFichier.
Examinez les blocs catch. des fins illustratives, nous nen utilisons que deux : lun
pour grer les ExceptionOuvertureFichier, lautre pour grer les Exception. Les
autres exceptions hritant de Exception, elles seront donc captures par le second bloc
catch. Les blocs catch sont mis en correspondance selon le mme principe que
loprateur instanceof. Il sagit dune bonne raison dtendre vos propres classes
dexception partir dune seule classe.
Attention : si vous levez une exception pour laquelle vous navez pas crit de bloc
catch correspondant, PHP signalera une erreur fatale !
Lectures complmentaires
La gestion des exceptions tant rcente en PHP, il ny a que peu dcrits sur ce sujet. En
revanche, on trouve dabondantes informations sur la gestion des exceptions. Sun,
notamment, propose un excellent didacticiel qui explique ce que sont les exceptions et
les raisons qui pourraient vous amener les utiliser (dans loptique dune programma-
tion en Java, videmment). Ce didacticiel est disponible ladresse http://
java.sun.com/docs/books/tutorial/essential/exceptions/handling.html.
Prochaine tape
La prochaine tape de ce livre concerne MySQL. Nous montrerons comment crer et
remplir une base de donnes MySQ, puis nous mettrons en uvre ce que vous avez
appris sur PHP afin de pouvoir accder votre base de donnes depuis le Web.
II
Utilisation de MySQL
Maintenant que vous connaissez les lments essentiels de PHP, nous allons nous int-
resser lintgration dune base de donnes dans vos scripts. Au Chapitre 2, nous avons
prsent les avantages de lutilisation dune base de donnes relationnelle la place
dun fichier plat. Voici un rsum des atouts des SGBDR (systmes de base de donnes
relationnelles) :
m Ils permettent daccder aux donnes plus rapidement quavec des fichiers plats.
m On peut les interroger trs facilement pour rcuprer des ensembles de donnes
satisfaisant certains critres.
m Ils possdent des mcanismes intgrs permettant de grer les accs simultans,
pour que le programmeur, cest--dire vous-mme, nait pas besoin de sen
occuper.
m Ils permettent daccder directement aux donnes.
m Ils disposent dun systme de privilges intgr.
Concrtement, lutilisation dune base de donnes relationnelle permet de rpondre
rapidement et simplement des questions comme les suivantes : quelle est lorigine de
vos clients, quels sont les produits qui se vendent le mieux ou quelle catgorie de clients
dpense le plus dargent ? Ces informations pourront vous aider amliorer votre site
pour attirer un plus grand nombre dutilisateurs et les fidliser, et il serait bien plus diffi-
cile de les obtenir partir de fichiers plats.
218 Partie II Utilisation de MySQL
Dans cette partie du livre, nous utiliserons le SGBDR MySQL mais, avant dtudier ses
caractristiques spcifiques, nous devons prsenter :
m les concepts et la terminologie des bases de donnes relationnelles ;
m la conception dune base de donnes web ;
m larchitecture dune base de donnes web.
Voici un rsum des prochains chapitres :
m Le Chapitre 9 prsente la configuration de base dont vous aurez besoin pour connec-
ter votre base de donnes MySQL sur le Web. Vous apprendrez crer des utilisa-
teurs, des bases de donnes, des tables et des index. Vous dcouvrirez galement les
diffrents moteurs de stockage de MySQL.
m Le Chapitre 10 explique comment interroger la base de donnes, ajouter, supprimer
et modifier des enregistrements partir de la ligne de commande.
m Le Chapitre 11 explique comment connecter PHP et MySQL pour pouvoir adminis-
trer votre base de donnes partir dune interface web. Nous prsenterons deux
mthodes : lextension mysqli de PHP et la couche dabstraction PEAR:DB.
m Le Chapitre 12 couvre en dtail ladministration de MySQL, notamment le systme
des privilges, la scurit et loptimisation.
m Le Chapitre 13 dcrit les moteurs de stockage et traite notamment des transactions,
des recherches textuelles et des procdures stockes.
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
Figure 8.1
Les informations concernant les clients de Book-O-Rama sont enregistres dans une table.
Colonnes
Chaque colonne possde un nom unique et contient diffrentes donnes. En outre,
chaque colonne est associe un type de donnes particulier. Par exemple, dans la table
Clients de la Figure 8.1, vous pouvez constater que la colonne IDClient contient des
entiers, alors que les trois autres contiennent des chanes de caractres. Les colonnes
sont parfois appeles champs ou attributs.
Lignes
Chaque ligne de cette table reprsente un client particulier. Grce au format tabulaire,
toutes ces lignes possdent les mmes attributs. Les lignes peuvent galement tre
appeles enregistrements ou tuples.
Valeurs
Chaque ligne est forme dun ensemble de valeurs particulires correspondant chaque
colonne. Le type de chaque valeur doit correspondre au type de la colonne dans laquelle
elle se trouve.
Cls
Il nous faut ensuite un moyen didentifier chaque client. Gnralement, les noms des
clients ne sont pas trs adapts : si vous possdez un nom assez rpandu, vous avez
probablement dj compris pourquoi. Prenons, par exemple, le nom Julie Dupont dans
la table Clients. En ouvrant un annuaire tlphonique, on se rend aussitt compte quil
existe un grand nombre de personnes possdant ce nom.
220 Partie II Utilisation de MySQL
Nous pouvons identifier Julie de plusieurs manires. On peut supposer quil sagit de la
seule Julie Dupont habitant son adresse. Cependant, le fait de dsigner ce client par
"Julie Dupont, 25 rue neuve, Toulouse" est assez pnible et un peu trop administratif.
Cela implique galement dutiliser plusieurs colonnes dans la table.
Ici, nous avons choisi une approche que vous reprendrez probablement dans vos appli-
cations : nous utilisons un identificateur unique (IDClient) pour chaque client. Ce prin-
cipe est assez courant puisque vous possdez dj un numro de compte bancaire ou un
numro de scurit sociale qui sont uniques. Ces numros permettent denregistrer les
dtails qui vous concernent dans une base de donnes de faon plus efficace et plus
simple. De plus, ce numro tant artificiel et cr de toutes pices, nous pouvons garan-
tir quil sera unique. Dans la pratique, il existe peu dinformations qui possdent cette
proprit, mme si lon en utilise plusieurs conjointement.
La colonne didentification dune table est appele cl, ou cl primaire. Une cl peut
galement tre rpartie sur plusieurs colonnes. Si, par exemple, nous avions choisi
didentifier Julie par "Julie Dupont, 25 rue neuve, Toulouse", la cl serait forme des
colonnes Nom, Adresse et Ville ; dans ce cas, il serait impossible de garantir son
unicit.
CLIENTS
COMMANDES
Figure 8.2
Chaque commande de la table Commandes fait rfrence un client dans la table Clients.
Chapitre 8 Conception dune base de donnes web 221
Les bases de donnes contiennent gnralement plusieurs tables et se servent des cls
comme dune rfrence dune table une autre. Dans la Figure 8.2, nous avons ajout
une seconde table dans la base de donnes, afin de stocker les commandes effectues
par les clients. Chaque ligne de la table Commandes reprsente une seule commande,
effectue par un seul client, identifi par son IDClient. Si, par exemple, nous exami-
nons la commande dont lIDCommande est 2, nous pouvons voir quelle a t effectue
par le client dont lIDClient est 1. Si nous nous reportons ensuite la table Clients,
nous pouvons constater que cet identifiant dsigne Julie Dupont.
Dans la terminologie des bases de donnes relationnelles, cette relation est appele une
cl trangre. IDClient est la cl primaire dans Clients mais, lorsquelle apparat dans
une autre table comme Commandes, elle devient une cl trangre dans cette table.
Vous vous demandez peut-tre pourquoi nous avons choisi davoir deux tables diffren-
tes et pourquoi nous ne nous sommes pas contents denregistrer ladresse de Julie dans
Commandes ? Nous expliquerons ce choix dans la prochaine section.
Schmas
Lensemble des structures des tables dune base de donnes est appel schma de la
base de donnes. Il sagit dune sorte de plan. Un schma doit reprsenter les tables
ainsi que leurs colonnes, la cl primaire de chaque table et toutes les cls trangres. Il
ne contient aucune donne, mais vous pouvez choisir de prsenter quelques donnes
typiques avec votre schma pour expliquer son fonctionnement. Un schma peut tre
reprsent par un diagramme informel comme celui des figures prcdentes, par un
diagramme entits-relations (que nous ne prsenterons pas dans ce livre) ou, plus
simplement, sous forme textuelle, comme ici :
Clients(IDClient, Nom, Adresse, Ville)
Commandes(IDCommande, IDClient, Montant, Date)
Les termes souligns dans ce schma sont les cls primaires de la relation dans laquelle
ils apparaissent, tandis que les termes en italique sont les cls trangres de la relation
dans laquelle ils apparaissent en italique.
Relations
Les cls trangres reprsentent une relation entre des donnes de deux tables. Par
exemple, le lien de la table Commandes vers la table Clients reprsente une relation
entre une ligne de Commandes et une ligne de Clients.
Il existe trois principaux types de relations dans une base de donnes relationnelle. Ces
relations peuvent tre classes en fonction du nombre dlments intervenant dans
chaque membre de la relation : un-vers-un, un-vers-plusieurs, ou plusieurs-vers-
plusieurs.
222 Partie II Utilisation de MySQL
Une relation un-vers-un signifie que la relation fait intervenir un seul lment de chaque
ct. Par exemple, si nous avions plac les adresses dans une autre table que Clients, il
existerait une relation un-vers-un entre elles. Vous pourriez alors avoir une cl trangre
de Addresses vers Clients ou dans lautre sens (cette rciprocit nest pas ncessaire).
Dans une relation un-vers-plusieurs, une ligne dune table est associe plusieurs
lignes dune autre table. Dans notre exemple, un client de la table Clients peut effec-
tuer plusieurs commandes, qui apparatront alors dans la table Commandes. Dans ce type
de relation, la table dont plusieurs lignes participent la relation possde une cl tran-
gre vers lautre table. Ici, nous avons plac IDClient dans la table Commandes pour
illustrer cette relation.
Dans une relation plusieurs-vers-plusieurs, plusieurs lignes dune table sont associes
plusieurs lignes dune autre table. Par exemple, si nous prenons lexemple de deux
tables, Livres et Auteurs, il se peut quun livre ait t crit par deux auteurs, chacun
dentre eux ayant crit dautres livres, soit indpendamment, soit avec dautres auteurs.
Ce type de relation est gnralement assez complexe, cest pourquoi il peut tre intres-
sant de possder les tables Livres, Auteurs et Livres Auteurs. Cette dernire table ne
contiendra que les cls des autres tables sous forme de cls trangres, afin de connatre
les auteurs associs chaque livre.
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
COMMANDES
LIVRES
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
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.
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.
COMMANDES
IDCommande IDClient Montant Date Livres Commandes
Figure 8.5
Avec cette architecture, lattribut Livres commands de chaque ligne contient plusieurs valeurs.
Cette organisation nest pas trs judicieuse pour plusieurs raisons. Elle revient imbri-
quer une table complte dans une colonne, une table qui associe les commandes aux
livres. Il est alors plus difficile de rpondre des questions comme : "Combien dexem-
plaires du livre Java 2 pour les professionnels ont t commands ?" Le systme ne
peut plus se contenter de compter les champs qui correspondent cette requte ; il doit
226 Partie II Utilisation de MySQL
analyser la valeur de chaque attribut pour vrifier si elle contient la chane de caractres
recherche.
Au lieu dinsrer une table lintrieur dune autre table, il suffit en fait de crer un
nouvelle table, Livres Commandes, comme celle de la Figure 8.6.
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.
LIVRES
COMMENTAIRES LIVRES
ISBN Commentaire
Figure 8.7
Pour fournir des commentaires, nous pouvons ajouter une colonne Commentaire dans la table
Livres ou ajouter une autre table, consacre aux commentaires.
La premire mthode consiste ajouter une colonne Commentaire dans la table Livres.
De cette manire, il existe un champ Commentaire pour chaque livre. Si la base de
donnes contient beaucoup de livres, et si la personne qui rdige les commentaires na
pas lintention de le faire pour chaque livre, il se peut que plusieurs lignes ne possdent
aucune valeur associe cet attribut. On parle dans ce cas de valeurs null.
La prsence de nombreuses valeurs null dans une base de donnes doit tre vite car
elles gaspillent lespace de stockage et peuvent entraner divers problmes lorsque vous
calculez des totaux ou dautres fonctions sur des colonnes numriques. En outre,
lorsquun utilisateur voit une valeur null dans une table, il ne peut pas savoir si la valeur
de cet attribut na aucune signification, sil sagit dune erreur dans la base de donnes
ou sil sagit dune donne qui na pas encore t saisie.
Vous pouvez viter tous ces problmes en utilisant la seconde architecture prsente
la Figure 8.7. Dans cette organisation, seuls les livres qui possdent un commentaire
apparaissent dans la table Commentaires Livres, accompagns de leur commentaire.
Vous remarquerez que la premire architecture implique quil ne peut y avoir quun
commentaire par livre. Si vous souhaitiez pouvoir ajouter plusieurs commentaires pour
le mme livre, il faut utiliser une relation un--plusieurs que seule la seconde architec-
ture est capable de vous apporter. Cette dernire permet galement de reprsenter une
228 Partie II Utilisation de MySQL
relation un-vers-un puisquil suffit dutiliser lISBN comme cl primaire dans la table
Commentaires Livres. Pour reprsenter une relation un--plusieurs, vous devez en
revanche dfinir un identificateur unique pour chaque ligne de cette table.
Architecture
Le fonctionnement fondamental dun serveur web est prsent la Figure 8.8. Ce
systme est compos de deux objets : un navigateur web et un serveur web. Un lien
de communication doit exister entre ces deux objets. Le navigateur effectue des
requtes auprs du serveur, qui lui renvoie des rponses. Cette architecture est parfai-
tement adapte un serveur qui fournit des pages statiques, mais celle qui permet de
mettre en place des sites web faisant intervenir des bases de donnes est un peu plus
complexe.
Requte
Navigateur Serveur web
Rponse
Figure 8.8
La relation client/serveur entre un navigateur web et un serveur web ncessite un lien
de communication.
Chapitre 8 Conception dune base de donnes web 229
Les applications de bases de donnes web que nous allons mettre en uvre dans ce livre
respectent une structure de base de donnes web gnrale, prsente la Figure 8.9.
Lessentiel de cette structure devrait dj vous sembler familier.
1 2 3
Navigateur Serveur web Moteur PHP Serveur MySQL
6 5 4
Figure 8.9
Larchitecture fondamentale des bases de donnes web est compose dun navigateur web,
dun serveur web, dun moteur de scripts et dun serveur de bases de donnes.
Une transaction de base de donnes web classique est compose des tapes numrotes
la Figure 8.9. Examinons ces tapes dans le contexte de la librairie Book-O-Rama.
1. Le navigateur web dun utilisateur envoie une requte HTTP pour une page web
particulire. Cette requte peut, par exemple, concerner tous les livres de Book-O-
Rama crits par Laura Thomson et tre envoye partir dun formulaire HTML. La
page de recherche des rsultats est appele resultats.php.
2. Le serveur web reoit une requte pour resultats.php, rcupre le fichier et le passe
au moteur PHP afin quil soit trait.
3. Le moteur PHP commence analyser le script. Dans celui-ci se trouve une commande
permettant de se connecter la base de donnes et dexcuter une requte (pour
rechercher les livres). PHP ouvre une connexion vers le serveur MySQL et transmet
la requte approprie.
4. Le serveur MySQL reoit la requte de base de donnes et la traite, puis renvoie les
rsultats (cest--dire une liste de livres) au moteur PHP.
5. Le moteur PHP termine lexcution du script, ce qui consiste gnralement forma-
ter les rsultats de la requte en HTML. Il envoie ensuite le fichier HTML obtenu au
serveur web.
6. Le serveur web transmet la page HTML au navigateur, pour que lutilisateur puisse
voir la liste des livres quil a demands.
Ce processus reste relativement identique, quels que soient le moteur de scripts et le serveur
de bases de donnes que vous utilisez. Le plus souvent, le serveur web, le moteur PHP
et le serveur de bases de donnes tournent tous sur le mme ordinateur. Cependant, il
arrive que le serveur de bases de donnes se trouve sur un autre ordinateur. Cette
dernire approche rpond des problmes de scurit, daugmentation des capacits
et de rpartition de la charge. Au niveau du dveloppement, cela ne change pas
230 Partie II Utilisation de MySQL
grand-chose, bien que cette approche fournisse des avantages significatifs en terme de
performances.
mesure quaugmenteront la taille et la complexit de vos applications, vous commen-
cerez les diviser en niveaux, ou couches. Cest ce que lon appelle une architecture
trois tiers car lapplication est alors forme dune couche de base de donnes qui se
charge de linterfaage avec MySQL, dune couche mtier qui contient le systme
central de lapplication et dune couche de prsentation qui gre la sortie HTML.
Larchitecture lmentaire prsente la Figure 8.9 vaut cependant toujours : vous
ajoutez simplement dautres lments de structure la section PHP.
Pour la suite
Au prochain chapitre, nous nous intresserons la construction dune base de donnes
MySQL. Nous commencerons par voir comment configurer une base de donnes MySQL
pour le Web, comment effectuer des requtes dans cette base de donnes et comment
linterroger partir de PHP.
9
Cration dune base
de donnes web
Dans ce chapitre, nous verrons comment configurer une base de donnes MySQL pour
pouvoir lutiliser sur un site web.
Nous reprendrons lexemple de la librairie virtuelle Book-O-Rama, prsente au chapi-
tre prcdent et dont nous rappelons ici le schma :
Clients(IDClient, Nom, Adresse, Ville)
Commandes(IDCommande, IDClient, Montant, Date)
Livres(ISBN, Auteur, Titre, Prix)
Livres_Commandes(IDCommande, ISBN, Quantite)
Commentaires_Livres(ISBN, Commentaire)
Noubliez pas que les cls primaires sont soulignes et que les cls trangres sont en
italique.
Pour pouvoir tirer profit des lments de cette section, vous devez avoir accs
MySQL. Cela signifie normalement que :
1. Vous avez effectu linstallation de base de MySQL sur votre serveur web. Pour
cela, il faut notamment :
installer les fichiers ;
crer un utilisateur sous le nom duquel MySQL sera excut ;
configurer votre chemin daccs ;
excuter mysql install db, si ncessaire ;
dfinir le mot de passe root de MySQL ;
supprimer lutilisateur anonymous et la base de donnes test ;
dmarrer le serveur MySQL pour la premire fois et le configurer pour quil se lance
automatiquement.
232 Partie II Utilisation de MySQL
Si vous avez bien fait tout cela, vous pouvez commencer lire ce chapitre. Dans le
cas contraire, vous trouverez lAnnexe A des instructions qui vous aideront.
Si, nimporte quel moment dans ce chapitre, vous avez des problmes, ce peut tre
d la configuration de votre systme MySQL. Dans ce cas, vrifiez nouveau
cette liste et consultez lAnnexe A pour vous assurer que votre configuration est
correcte.
2. Vous devriez galement avoir accs MySQL sur un ordinateur dont vous ntes
pas ladministrateur, comme un service dhbergement web, un ordinateur de votre
socit, etc.
Dans ce cas, pour que vous puissiez utiliser les exemples ou crer votre propre base
de donnes, votre administrateur doit configurer un utilisateur et une base de
donnes et vous fournir le nom dutilisateur, le mot de passe et le nom de la base de
donnes quil vous a affects.
Vous pouvez choisir de sauter les sections de ce chapitre qui expliquent comment
configurer les utilisateurs et les bases de donnes, ou les lire pour expliquer plus
prcisment votre administrateur ce dont vous avez besoin. En tant quutilisateur
normal, vous navez pas le droit dexcuter les commandes permettant de crer des
utilisateurs et des bases de donnes.
Tous les exemples de ce chapitre ont t dvelopps et tests avec la dernire version de
MySQL 5. Certaines versions antrieures de MySQL possdent moins de fonctionnali-
ts : il est donc prfrable dinstaller la version stable la plus rcente lorsque vous confi-
gurez votre systme. Vous pouvez charger la dernire version sur le site de MySQL,
http://mysql.com.
Dans ce livre, nous interagirons avec MySQL au moyen dun client en ligne de
commande, le moniteur MySQL fourni avec chaque installation de MySQL, mais vous
pouvez utiliser dautres clients. Par exemple, si vous utilisez MySQL dans un environ-
nement web, les administrateurs systme proposent souvent linterface phpMyAdmin
que vous pouvez utiliser dans votre navigateur. Les diffrents clients graphiques propo-
sent videmment des procdures lgrement diffrentes de celles dcrites ici, mais vous
devriez pouvoir adapter les instructions fournies assez facilement.
passera rien du tout. Il sagit dun problme trs frquent chez les nouveaux utilisa-
teurs.
Cela signifie galement que vous pouvez insrer des retours la ligne au milieu dune
commande. Nous nous sommes dailleurs servis de cette caractristique pour amliorer
la lisibilit de nos exemples. Cette situation se remarque facilement puisque MySQL
affiche un symbole indiquant quil attend la suite de la commande. Il sagit dune petite
flche qui ressemble ceci :
mysql> grant select
->
Vous obtiendrez cette invite jusqu ce que vous saisissiez un point-virgule, chaque
fois que vous appuyez sur la touche Entre.
Un autre point important est que les instructions SQL ne tiennent pas compte de la
diffrence majuscules/minuscules, mais ce nest pas forcment le cas pour les noms des
bases de donnes et des tables. Nous reviendrons sur ce point un peu plus loin.
Loption p indique au serveur que vous souhaitez vous connecter en utilisant un mot de
passe. Vous navez pas besoin de la spcifier si aucun mot de passe na t dfini pour
lutilisateur sous lequel vous voulez ouvrir une session.
Si vous avez ouvert votre session sous le nom root et quaucun mot de passe na t
dfini pour root, nous vous recommandons fortement de consulter sans tarder
lAnnexe A et de le dfinir tout de suite. Sans mot de passe root, votre systme nest
pas du tout scuris.
Vous navez pas besoin de donner le mot de passe sur cette ligne, puisque le serveur
MySQL vous le demandera. En fait, il vaut mieux ne pas le donner car, si vous le saisis-
sez sur la ligne de commande, il apparatra clairement lcran et pourra donc tre
intercept trs facilement.
Aprs avoir saisi la commande prcdente, vous devriez obtenir une rponse comme
celle-ci :
Enter password:
Si vous nobtenez pas cette ligne, vrifiez que le serveur MySQL fonctionne correcte-
ment et que la commande mysql se trouve dans votre PATH.
Il faut ensuite saisir votre mot de passe. Si tout se passe bien, vous devriez ensuite obte-
nir une rponse ressemblant ceci :
Welcome to the MySQL monitor. Commands end with; or \g.
Your MySQL connection id is 1 to server version: 5.0.0-alpha-max-debug
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
m global ;
m base de donnes ;
m table ;
m colonne.
La commande GRANT cre des utilisateurs et leur octroie des privilges. Voici son format
gnral :
GRANT privilges [colonnes]
ON lment
TO nom_utilisateur [IDENTIFIED BY mot de passe]
[REQUIRE options ssl]
[WITH GRANT OPTION | limites ] ]
Les clauses entre crochets sont facultatives. Cette syntaxe comprend plusieurs paramtres
en italique que nous allons passer en revue.
Le premier, privilges, est une liste de privilges spars par des virgules. Ces privi-
lges doivent tre choisis dans une liste prdfinie de MySQL, que nous prsenterons
dans la prochaine section.
Chapitre 9 Cration dune base de donnes web 237
Le paramtre colonnes est facultatif. Vous pouvez lutiliser pour prciser les privilges
associs certaines colonnes. Il peut correspondre au nom dune seule colonne ou une
liste de noms de colonnes spars par des virgules.
Vous pouvez octroyer des privilges sur toutes les bases de donnes en indiquant *.* la
place de lment. On accorde alors des privilges globaux. Vous pouvez aussi indiquer * si
vous nutilisez aucune base de donnes particulire.
Le plus souvent, vous dsignerez toutes les tables dune base de donnes avec
nom base.*, une table particulire avec nom base.nom table, ou des colonnes spcifi-
ques avec nom base.nom table et les colonnes en question la place de colonnes. Ces
trois approches reprsentent respectivement les trois autres niveaux de privilges dispo-
nibles : sur une base de donnes, une table et une colonne. Si vous utilisez une base de
donnes spcifique lorsque vous excutez cette commande, nom table sera interprt
comme une table de la base de donnes courante.
nom utilisateur doit correspondre au nom de lutilisateur sous lequel vous souhai-
tez ouvrir une session dans MySQL. Noubliez pas que ce nom ne doit pas forcment
correspondre votre nom dutilisateur sur votre systme dexploitation. Avec
MySQL, nom utilisateur peut galement correspondre un nom dhte. Vous
pouvez utiliser cette particularit pour diffrencier, par exemple, laura (qui sera
interprt comme laura@localhost) et laura@autre part.com. Cette particularit
est trs intressante puisquil arrive souvent que des utilisateurs de diffrents domai-
nes aient le mme nom en local. En outre, cette caractristique amliore la scurit du
systme, puisque vous pouvez spcifier lendroit partir duquel les utilisateurs se
connectent, et mme les tables et les bases de donnes auxquelles ils ont accs partir
dun emplacement particulier.
mot de passe dsigne le mot de passe que vous avez choisi pour lutilisateur indiqu.
Les rgles gnrales pour choisir les mots de passe doivent toujours tre respectes.
Nous reviendrons un peu plus loin sur les problmes de scurit, mais, dune manire
gnrale, un mot de passe ne doit pas pouvoir tre devin facilement. Cela signifie quil
ne doit figurer dans aucun dictionnaire et quil doit tre diffrent du nom de lutilisa-
teur. Idalement, il doit contenir des lettres majuscules, des lettres minuscules et des
caractres non alphabtiques.
La clause REQUIRE vous permet de prciser que lutilisateur doit se connecter via SSL
(Secure Sockets Layer) et dindiquer dautres options SSL. Pour plus dinformations
238 Partie II Utilisation de MySQL
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
dun utilisateur normal sont prsents dans le Tableau 9.1. La deuxime colonne indique
les objets auxquels chaque privilge peut tre appliqu.
Privilge Description
CREATE TEMPORARY TABLES Permet un administrateur dutiliser le mot-cl TEMPORARY
dans une instruction CREATE TABLE.
FILE Autorise les donnes tre lues dans des tables depuis des
fichiers et vice versa.
LOCK TABLES Autorise lutilisation explicite dune instruction LOCK TABLES.
PROCESS Permet un administrateur de visualiser les processus serveur
qui appartiennent tous les utilisateurs.
RELOAD Permet un administrateur de recharger les tables de
privilges et de rinitialiser les privilges, les htes, les
journaux et les tables.
REPLICATION CLIENT Autorise lutilisation de SHOW STATUS sur les matres et les
esclaves de rplication. La rplication est traite au
Chapitre 12.
REPLICATION SLAVE Autorise les serveurs esclaves de rplication se connecter au
serveur matre. La rplication est traite au Chapitre 12.
SHOW DATABASES Autorise la consultation de la liste de toutes les bases de
donnes avec une instruction SHOW DATABASES. Sans ce
privilge, les utilisateurs ne voient que les bases de donnes
pour lesquelles ils possdent dautres privilges.
SHUTDOWN Autorise un administrateur arrter le serveur MySQL.
SUPERT Autorise un administrateur tuer des threads appartenant
nimporte quel utilisateur.
Vous pouvez attribuer ces privilges des utilisateurs normaux, mais nous vous
conseillons de ne le faire quaprs avoir trs soigneusement estim toutes les cons-
quences.
Le cas est un peu diffrent pour le privilge FILE car il peut tre intressant pour les
utilisateurs puisquil permet de charger des donnes partir de simples fichiers, ce qui
peut leur faire gagner beaucoup de temps en leur vitant davoir saisir leurs donnes
dans leurs bases. Cependant, le mcanisme de chargement de fichiers peut servir
charger nimporte quel fichier visible par le serveur MySQL, y compris des bases de
donnes appartenant dautres utilisateurs et, ventuellement, des fichiers de mots
Chapitre 9 Cration dune base de donnes web 241
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
Cette commande accorde tous les privilges sur toutes les bases de donnes un utilisateur
appel fred, avec le mot de passe mnb123, et lautorise transmettre ces privilges.
Si vous vous ravisez et que vous ne vouliez pas de cet utilisateur dans votre systme,
vous pouvez le supprimer avec la commande suivante :
mysql> revoke all privileges, grant
-> on *
-> from fred;
242 Partie II Utilisation de MySQL
Voyons maintenant comment configurer le compte dun utilisateur normal, sans aucun
privilge :
mysql> grant usage
-> on livres.*
-> to martine identified by magic123;
Aprs avoir discut un peu avec Martine, et aprs avoir appris ce quelle souhaite rel-
lement faire, vous pouvez lui fournir les privilges appropris :
mysql> grant select, insert, update, delete, index, alter, create, drop
-> on livres.*
-> to martine;
Vous remarquerez quil ny a pas besoin de spcifier le mot de passe de Martine pour
effectuer cette opration.
Si vous vous rendez compte que Martine abuse de ses privilges, vous pouvez les
rduire :
mysql> revoke alter, create, drop
-> on livres.*
-> from martine;
Et, pour terminer, lorsquelle na plus besoin dutiliser la base de donnes, vous pouvez
supprimer tous ses droits :
mysql> revoke all
-> on livres.*
-> from martine;
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.
Lorsque vous tapez cette commande, MySQL devrait vous rpondre par une ligne
comme celle-ci :
Database changed
244 Partie II Utilisation de MySQL
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
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.
Une fois encore, il sagit dun petit compromis : varchar utilise moins de place, mais
char est plus rapide.
Vous remarquerez que toutes les colonnes sont dclares comme tant NOT NULL. Il
sagit dune petite optimisation quil ne faut pas hsiter mettre en uvre lorsque cest
possible.
Nous reviendrons sur les questions doptimisation au Chapitre 12.
La syntaxe de certaines instructions CREATE est lgrement diffrente. Examinons main-
tenant la table commandes:
create table commandes
( idcommande int unsigned not null auto_increment primary key,
idclient int unsigned not null,
montant float(6,2),
date date not null
);
La colonne montant est indique comme un nombre virgule flottante de type float.
Avec la plupart des types de donnes flottantes, il est possible de prciser la largeur de
laffichage et le nombre de chiffres aprs la virgule. Dans ce cas, le montant des
commandes sera en euros, cest pourquoi nous avons choisi une largeur assez impor-
tante (6) et deux chiffres dcimaux, pour les centimes.
La colonne date possde le type de donnes date.
Dans cette table particulire, toutes les colonnes (sauf montant) sont marques avec NOT
NULL. En effet, lorsquune commande est entre dans la base de donnes, nous devons
lajouter dans la table des commandes, puis ajouter les lments correspondants dans
commandes livres avant de traiter la commande. Il est donc tout fait possible que
nous ne connaissions pas le montant de la commande lorsque celle-ci est effectue,
cest pourquoi nous lautorisons tre NULL.
La table livres possde des caractristiques similaires :
create table livres
( isbn char(13) not null primary key,
auteur char(50),
titre char(100),
prix float(4,2)
);
Ici, nous navons pas besoin de produire une cl primaire parce que les numros ISBN
sont crs un autre endroit. Les autres champs peuvent tre NULL, puisquune librairie
peut connatre le code ISBN dun livre avant de connatre ses autres caractristiques
(titre, auteur ou prix).
248 Partie II Utilisation de MySQL
La table livres commandes montre comment crer une cl primaire sur plusieurs colonnes :
create table livres_commandes
( idcommande int unsigned not null,
isbn char(13) not null,
quantite tinyint unsigned,
primary key (idcommande, isbn)
);
Nous avons indiqu les quantits de livres avec TINYINT UNSIGNED, qui peut contenir
des nombres entiers positifs compris entre 0 et 255.
Comme nous lavons dj mentionn, les cls primaires rparties sur plusieurs colonnes
doivent tre spcifies avec une clause de cl primaire particulire. Cest ce que nous
utilisons ici.
Pour terminer, voici la table commentaires livres :
create table commentaires_livres
(
isbn char(13) not null primary key,
commentaire text
);
Cette table utilise un nouveau type de donnes, text, que nous navons pas encore
mentionn. Ce type est intressant pour les chanes de caractres plus longues, comme
un commentaire ou un article. Il en existe plusieurs variantes, que nous examinerons un
peu plus loin dans ce chapitre.
Pour comprendre plus finement la cration des tables, intressons-nous aux noms des
colonnes et aux identificateurs en gnral, puis aux types de donnes que nous pouvons
choisir pour les colonnes. Mais, pour linstant, examinons dabord la base de donnes
que nous venons de crer.
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
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`;
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
Types de chanes
Il existe trois types de chanes. Tout dabord les chanes classiques, cest--dire des
chanes de texte courtes. Ces chanes correspondent aux types CHAR (longueur fixe) et
VARCHAR (longueur variable). Vous pouvez spcifier la largeur de ces chanes. Les
colonnes de type CHAR sont justifies avec des espaces pour atteindre la taille indique,
alors que la taille de stockage des colonnes VARCHAR varie automatiquement en fonction
de leur contenu. MySQL supprime les espaces placs la fin des CHAR lorsquils sont
lus et ceux des VARCHAR lorsquils sont stocks. Le choix entre ces deux types revient
faire un compromis entre lespace de stockage et la vitesse. Nous y reviendrons au
Chapitre 12.
Chapitre 9 Cration dune base de donnes web 255
Il existe galement les types TEXT et BLOB, dans diffrentes tailles. Ces types correspon-
dent des donnes texte ou binaires plus longues. Les BLOB sont des "objets binaires de
grande taille" (Binary Large OBjects). Ils peuvent contenir ce que vous voulez, comme
des images ou du son.
Dans la pratique, les colonnes BLOB et TEXT sont identiques, sauf que les colonnes BLOB
tiennent compte de la diffrence majuscules/minuscules, contrairement aux colonnes TEXT.
Comme ces types de colonnes peuvent contenir des donnes trs volumineuses, leur
emploi ncessite certaines prcautions. Nous voquerons ce problme au Chapitre 12.
Le troisime groupe contient deux types spciaux, SET et ENUM. Le type SET permet de
prciser que les valeurs dune colonne doivent faire partie dun certain ensemble de
valeurs. Les valeurs de la colonne peuvent contenir plusieurs valeurs provenant de cet
ensemble. Vous pouvez avoir au maximum 64 lments provenant de lensemble spcifi.
ENUM ressemble beaucoup SET, sauf que les colonnes de ce type ne peuvent contenir
quune seule des valeurs indiques, ou NULL. Par ailleurs, une numration ne peut pas
contenir plus de 65 535 lments.
Les types de chanes sont rsums dans les Tableaux 9.9, 9.10 et 9.11. Le Tableau 9.9
prsente les types de chanes classiques.
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
Pour la suite
Maintenant que vous savez comment crer des utilisateurs, des bases de donnes et des
tables, vous pouvez vous intresser linteraction avec la base de donnes. Nous
verrons au prochain chapitre comment insrer des donnes dans des tables, comment
les mettre jour, les supprimer et comment interroger la base.
10
Travailler avec une base
de donnes MySQL
Dans ce chapitre, nous prsenterons SQL (Structured Query Language) et nous verrons
comment lutiliser pour interroger des bases de donnes. Nous continuerons le dvelop-
pement de la base de donnes Book-O-Rama en apprenant insrer, supprimer et
mettre jour des donnes. Nous verrons galement comment interroger la base de
donnes.
Nous commencerons par prsenter SQL et verrons en quoi cet outil peut nous tre utile.
Si vous navez pas encore configur la base de donnes de Book-O-Rama, vous devez
le faire avant dexcuter les requtes SQL de ce chapitre. Vous trouverez tous les dtails
de cette procdure au Chapitre 9.
Pour, par exemple, insrer une ligne dans la table Clients de Book-O-Rama, vous
pouvez saisir la commande suivante :
insert into clients values
(NULL, Julie Dupont, 25 rue noire, Toulouse);
Vous remarquerez que nous avons remplac table par le nom de la table dans laquelle
nous souhaitions placer nos donnes et que nous avons plac les valeurs insrer dans
la liste qui suit la clause values. Toutes les valeurs de cet exemple ont t mises entre
apostrophes simples. Avec MySQL, les chanes de caractres doivent toujours tre
mises entre apostrophes simples ou doubles (dans ce livre, nous utiliserons ces deux
types dapostrophes). Les nombres et les dates nen ont pas besoin.
Linstruction INSERT mrite quelques commentaires.
Les valeurs indiques sont utilises pour remplir la table, dans lordre o elles sont
fournies. Cependant, si vous souhaitez remplir uniquement certaines colonnes ou si
Chapitre 10 Travailler avec une base de donnes MySQL 259
vous voulez donner les valeurs dans un ordre diffrent, vous pouvez prciser le nom des
colonnes dans linstruction. Par exemple :
insert into clients (nom, ville) values
(Melissa Martin, Albi);
Cette approche nest intressante que si vous possdez des donnes partielles pour un
enregistrement particulier ou si certains champs de lenregistrement sont facultatifs.
Voici une autre syntaxe similaire :
insert into clients
set nom = Michel Archer,
adresse = "12 Avenue plate ,
ville = Montauban;
Vous remarquerez galement que nous avons donn la valeur NULL la colonne
idclient lorsque nous avons ajout Julie Dupont et que nous avons ignor cette
colonne lorsque nous avons ajout les autres clients. Vous vous rappelez peut-tre que,
lorsque nous avons configur la base de donnes, nous avons indiqu que idclient
tait la cl primaire de la table clients : cette procdure peut donc vous sembler
trange. Cependant, nous avions galement attribu lattribut AUTO INCREMENT ce
champ, ce qui signifie que si nous insrons une ligne avec la valeur NULL (ou aucune
valeur) dans ce champ, MySQL produira le nombre suivant dans la squence dauto-
incrmentation et linsrera automatiquement notre place. Cette fonctionnalit est
particulirement apprciable.
Il est galement possible dinsrer plusieurs lignes dun seul coup dans une table.
Chaque ligne doit tre mise entre parenthses et les ensembles de parenthses doivent
tre spars par des virgules.
Linstruction INSERT na que peu de variantes. Aprs le mot INSERT, vous pouvez ajou-
ter les mots-cls LOW PRIORITY ou DELAYED. Le premier indique que le systme peut
attendre et effectuer linsertion plus tard, lorsquil ny aura plus de lecture dans la table.
Le second, que les donnes insres seront mises en tampon. Si le serveur est occup,
vous pouvez donc continuer excuter des requtes au lieu davoir attendre que
lopration INSERT soit termine.
Immdiatement aprs ces mots-cls, vous pouvez ventuellement ajouter IGNORE pour
quune tentative dinsertion de lignes produisant une cl duplique supprime ces lignes
sans prvenir. Lautre solution consiste utiliser ON DUPLICATE KEY UPDATE expression
la fin de linstruction INSERT. Cette clause permet de modifier la valeur duplique en
utilisant une instruction UPDATE classique (voir plus loin dans ce chapitre).
Nous avons runi quelques donnes pour remplir la base de donnes grce quelques
instructions INSERT qui se servent de lapproche multiligne que nous venons dvoquer.
260 Partie II Utilisation de MySQL
use livres;
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
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
Tableau 10.1 : Les oprateurs de comparaison utiles dans les clauses WHERE (suite)
Les trois dernires lignes de ce tableau font rfrence LIKE et REGEXP, qui effectuent
des comparaisons de motifs.
LIKE utilise la concordance de motif de SQL. Les motifs peuvent contenir du texte classi-
que, plus les caractres % et . Le caractre % sert de joker pour indiquer une correspon-
dance sur un nombre quelconque (ventuellement nul) de caractres, et correspond
nimporte quel caractre unique.
Le mot-cl REGEXP est utilis pour les recherches de correspondances ralises avec
des expressions rgulires. MySQL utilise les expressions rgulires POSIX. Vous
pouvez aussi vous servir de RLIKE la place de REGEXP, car ce sont deux synonymes.
Les expressions rgulires POSIX sont celles que nous avons prsentes au Chapi-
tre 4).
264 Partie II Utilisation de MySQL
Vous pouvez tester plusieurs critres en les associant avec AND et OR. Par exemple :
select *
from clients
where idclient = 3 or idclient = 4;
Ce faisant, nous avons prcis un type de jointure sans le savoir. En effet, la virgule qui
spare les noms des tables est quivalente INNER JOIN ou CROSS JOIN. Il sagit dun
type de jointure parfois appel jointure complte ou produit cartsien de deux tables.
Ce type de jointure signifie littralement : " partir des tables indiques, crer une seule
grande table qui doit contenir une ligne pour chaque combinaison possible des
lignes de ces tables, que cela ait un sens ou non." En dautres termes, nous obtenons
une table contenant toutes les lignes de la table clients associes toutes les lignes de
la table commandes, quelles que soient les commandes effectues par les clients.
Cette opration brutale na pas beaucoup de sens dans la plupart des cas. En effet, on
souhaite le plus souvent ne retenir que les lignes qui ont un sens, cest--dire ici les
commandes passes par un client qui correspondent ce client.
Pour obtenir ce rsultat, il suffit dajouter une condition de jointure dans la clause
WHERE. Ce type dinstruction conditionnelle spciale exprime la relation qui doit exister
entre les deux tables. Ici, notre condition de jointure est la suivante :
clients.idclient = commandes.idclient
Elle demande MySQL de ne placer dans la table finale que les lignes dont le idclient
de la table clients correspond au idclient de la table commandes.
En ajoutant cette condition de jointure notre requte, nous avons cr un autre type de
jointure, appel qui-jointure.
Vous avez galement remarqu la notation avec le point, qui permet de prciser sans
ambigut la table dont proviennent les colonnes : clients.idclient fait rfrence la
colonne idclient de la table clients et commandes.idclient fait rfrence la colonne
idclient de la table commandes.
Cette notation est ncessaire lorsque le nom dune colonne est ambigu, cest--dire sil
apparat dans plusieurs tables.
En outre, cette notation pointe peut galement tre utilise pour lever les ambiguts
sur des noms de colonnes de bases de donnes diffrentes. Dans cet exemple, nous nous
sommes servis de la notation table.colonne, mais il est galement possible dy ajouter
le nom dune base de donnes (base de donnes.table.colonne), par exemple pour
tester une condition comme celle-ci :
livres.commandes.idclient = autre_bd.commandes.idclient
Enfin, vous pouvez vous servir de cette notation pour toutes les rfrences de colonnes dans
une requte. Cest gnralement conseill, surtout lorsque vos requtes deviennent un peu
plus complexes car, mme si ce nest pas impos par MySQL, cela facilite beaucoup la lisi-
bilit et la maintenance des requtes. Vous remarquerez dailleurs que nous avons respect
cette convention dans le reste de la requte prcdente, par exemple dans la condition :
clients.nom = Julie Dupont
266 Partie II Utilisation de MySQL
La colonne nom nexistant que dans la table clients, nous navions pas rellement
besoin de prciser la table dont elle provient. Pour les utilisateurs qui relisent le code,
en revanche, la rfrence nom seule reste vague et elle devient plus claire sous la forme
clients.nom.
Vous remarquerez que nous avons suivi les donnes dans quatre tables diffrentes. Pour
faire cela avec une qui-jointure, nous avons besoin de trois conditions de jointure
diffrentes. Comme il faut gnralement une condition de jointure pour chaque paire de
tables que vous souhaitez runir, il y a au total une jointure de moins que le nombre
de tables joindre. Cette rgle est assez utile pour dboguer les requtes qui ne fonc-
tionnent pas. Vrifiez vos conditions de jointure et assurez-vous que vous respectez
Chapitre 10 Travailler avec une base de donnes MySQL 267
bien les enchanements ncessaires pour obtenir ce que vous vouliez partir des infor-
mations que vous avez donnes.
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
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.
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
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).
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 croise Comme ci-dessus. Peut galement tre utilise en utilisant la clause
CROSS JOIN entre les noms des tables de la jointure.
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.
La clause ORDER BY trie les lignes dune ou de plusieurs colonnes de la clause SELECT.
Par exemple :
select nom, adresse
from clients
order by nom;
Cette requte renvoie les noms et les adresses des clients, en les triant par ordre alphab-
tique des noms :
+-----------------+--------------------+
| nom | adresse |
+-----------------+--------------------+
| Alain Wong | 147 Avenue Haines |
| Julie Dupont | 25 rue noire |
| Melissa Jones | |
| Michel Archer | 12 Avenue plate |
| Michelle Arthur | 357 rue de Paris |
+-----------------+--------------------+
Vous remarquerez que, dans ce cas, les noms tant au format prnom nom de famille, ils
sont tris en fait daprs le prnom. Si vous souhaitez les trier daprs le nom de famille, il
faut sparer les prnoms et les noms de famille, et les mettre dans deux champs diffrents.
Par dfaut, lordre de tri est croissant. Vous pouvez le prciser explicitement laide du
mot-cl ASC :
select nom, adresse
from clients
order by nom asc;
Mais il est galement possible de trier par ordre dcroissant, en spcifiant le mot-cl DESC :
select nom, adresse
from clients
order by nom desc;
Vous pouvez aussi trier sur plusieurs colonnes, ou vous servir des alias des colonnes, ou
mme de leur position dans la table (par exemple, 3 correspond la troisime colonne
de la table) au lieu de leur nom.
Les fonctions dagrgation les plus utilises sont prsentes dans le Tableau 10.3.
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;
Pour obtenir des informations plus dtailles, nous pouvons nous servir de la clause
GROUP BY. Celle-ci va nous permettre, par exemple, dafficher la moyenne des comman-
des de chaque client. Grce ce mcanisme, nous pouvons connatre le client qui a
dpens le plus dargent :
select idclient, avg(montant)
from commandes
group by idclient;
Lorsque vous utilisez la clause GROUP BY avec une fonction dagrgation, cette clause
modifie le comportement de la fonction. Au lieu de fournir la moyenne des montants
272 Partie II Utilisation de MySQL
des commandes de toute la table, cette requte fournit la moyenne des montants des
commandes pour chaque client (ou, plus prcisment, pour chaque idclient) :
+----------+--------------+
| idclient | avg(montant) |
+----------+--------------+
| 1 | 49.990002 |
| 2 | 74.980003 |
| 3 | 47.485002 |
+----------+--------------+
En SQL ANSI, si vous utilisez une clause GROUP BY, les seuls lments qui peuvent
apparatre dans la clause SELECT sont les fonctions dagrgation et les colonnes indi-
ques dans la clause GROUP BY. En outre, si vous voulez utiliser une colonne dans une
clause GROUP BY, celle-ci doit apparatre dans la clause SELECT.
MySQL accorde en fait un peu plus de libert. Il accepte une syntaxe tendue qui permet
de ne pas spcifier des lments dans la clause SELECT si vous ne souhaitez pas les y mettre.
Nous pouvons galement tester le rsultat dune agrgation laide dune clause HAVING.
Celle-ci doit tre indique immdiatement aprs la clause GROUP BY et elle fonctionne
comme une clause WHERE qui ne sappliquerait quaux groupes et aux agrgats.
Pour poursuivre notre exemple prcdent, nous pouvons nous servir de la requte
suivante pour connatre les clients dont la moyenne des commandes est suprieure
50 euros :
select idclient, avg(montant)
from commandes
group by idclient
having avg(montant) > 50;
La clause HAVING sapplique aux groupes. Cette requte renvoie donc le rsultat suivant :
+----------+--------------+
| idclient | avg(montant) |
+----------+--------------+
| 2 | 74.980003 |
+----------+--------------+
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.
Sous-requtes lmentaires
Lusage le plus courant des sous-requtes consiste utiliser le rsultat dune requte
dans une comparaison dune autre requte. Vous pouvez, par exemple, utiliser la requte
suivante pour retrouver la plus grosse commande :
select idclient, montant
from commandes
where montant = (select max(montant) from commandes);
Cette requte donne le rsultat suivant :
+----------+---------+
| idclient | montant |
+----------+---------+
| 2 | 74.98 |
+----------+---------+
Dans ce cas, la sous-requte renvoie une seule valeur (le montant maximal) qui est utili-
se ensuite pour la comparaison dans la requte externe. Il sagit dun bon exemple
dusage de sous-requte, car cette requte particulire ne peut pas tre reproduite de
manire lgante en utilisant des jointures en ANSI SQL.
Vous obtiendrez toutefois le mme rsultat avec la jointure suivante :
select idclient, montant
from commandes
order by montant desc
limit 1;
Mais, parce quelle sappuie sur LIMIT, cette requte nest pas compatible avec la plupart
des SGBDR. Cependant, elle sexcutera plus efficacement sur MySQL que la version
avec une sous-requte.
274 Partie II Utilisation de MySQL
Lune des principales raisons pour lesquelles MySQL a tant tard proposer des sous-
requtes tient au nombre trs rduit doprations quelles vous permettent de raliser.
Techniquement, vous pouvez crer une seule requte ANSI SQL ayant le mme effet,
mais qui sappuie sur un hack inefficace appel MAX-CONCAT.
Vous pouvez utiliser des valeurs de sous-requte de cette manire avec tous les opra-
teurs de comparaison classiques et il existe galement certains oprateurs de comparai-
son spcifiques aux sous-requtes que nous dcrirons dans la section suivante.
Sous-requtes et oprateurs
Il existe cinq oprateurs spcifiques aux sous-requtes. Quatre dentre eux sont utiliss
avec les sous-requtes standard et un (EXISTS) nest gnralement utilis quavec des
sous-requtes corrles. Nous en traiterons dans la prochaine section. Les quatre opra-
teurs de sous-requte standard sont prsents dans le Tableau 10.4.
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
Sous-requtes de ligne
Toutes les sous-requtes que nous avons tudies jusqu prsent retournaient une seule
valeur, correspondant gnralement true ou false (comme dans lexemple prc-
dent avec EXISTS). Les sous-requtes de ligne renvoient une ligne entire, qui peut
ensuite tre compare des lignes entires dans la requte externe. Cette mthode est
gnralement adopte pour rechercher des lignes dans une table qui existent galement
dans une autre table. Aucun exemple intressant ne peut tre trouv dans la base de
donnes livres, mais on peut fournir un exemple dutilisation de la syntaxe de la
manire suivante :
select c1, c2, c3
from t1
where (c1, c2, c3) in (select c1, c2, c3 from t2);
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
Cette instruction met jour la table nom table en modifiant toutes les colonnes indi-
ques avec les expressions fournies. Vous pouvez restreindre une instruction UPDATE
certaines lignes avec une clause WHERE et limiter le nombre total de lignes affectes avec
une clause LIMIT. ORDER BY nest gnralement utilis quen conjonction avec une
clause LIMIT ; par exemple, si vous devez ne mettre jour que les dix premires lignes,
vous devez pralablement les placer dans un ordre particulier. Si les clauses
LOW PRIORITY et IGNORE sont utilises, elles fonctionnent de la mme manire que dans
une instruction INSERT.
Passons maintenant quelques exemples.
Si nous souhaitons augmenter tous les prix de 10 %, nous pouvons utiliser une instruction
UPDATE sans clause WHERE :
update livres
set prix = prix * 1.1;
Si, en revanche, nous ne souhaitons modifier quune seule ligne (par exemple pour
changer ladresse dun client), nous pouvons nous servir de la requte suivante :
update clients
set adresse = 250 rue Olsens
where idclient = 4;
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.
Syntaxe Description
ADD [COLUMN] description colonne Ajoute une nouvelle colonne lemplacement
[FIRST | AFTER colonne ] indiqu (sil nest pas indiqu, la colonne est
ajoute la fin). Notez que description colonne
ncessite un nom et un type, tout comme une
instruction CREATE.
ADD [COLUMN] (description colonne, Ajoute une ou plusieurs colonnes la fin de la table.
description colonne,...)
ADD INDEX [index] (colonne,...) Ajoute un index dans la table, sur les colonnes
indiques.
ADD [CONSTRAINT [symbole]] PRIMARY Transforme les colonnes indiques en cl primaire
KEY (colonne,...) de la table. La notation CONSTRAINT ne concerne
que les tables utilisant des cls trangres. Pour
plus dinformations ce sujet, consultez le
Chapitre 13.
ADD UNIQUE [CONSTRAINT [symbole]] Ajoute un index unique dans la table, sur les
[index] (colonne,...) colonnes indiques. La notation CONSTRAINT ne
concerne que les tables InnoDB utilisant des cls
trangres. Pour plus dinformations ce sujet,
consultez le Chapitre 13.
ADD [CONSTRAINT] [symbole]] FOREIGN Ajoute une cl trangre une table InnoDB.
KEY [index] (index col, )
[dfinition rfrence]
ALTER [COLUMN] colonne {SET DEFAULT Ajoute ou supprime une valeur par dfaut pour une
valeur | DROP DEFAULT} colonne particulire.
CHANGE [COLUMN] colonne Modifie la colonne indique en lui affectant la
description nlle colonne nouvelle description. Vous pouvez vous en servir
pour modifier le nom dune colonne, puisque la
description dune colonne contient son nom.
MODIFY [COLUMN] description colonne Comme CHANGE. Permet de modifier le type dune
colonne, pas son nom.
DROP [COLUMN] colonne Supprime la colonne indique.
278 Partie II Utilisation de MySQL
Tableau 10.5 : Les modifications possibles avec linstruction ALTER TABLE (suite)
Syntaxe Description
DROP PRIMARY KEY Supprime lindex principal (mais pas la colonne).
DROP INDEX index Supprime lindex indiqu.
DROP FOREIGN KEY cl Supprime la cl trangre (mais pas la colonne).
DISABLE KEYS Dsactive la mise jour de lindex.
ENABLE KEYS Active la mise jour de lindex.
RENAME [AS] nom nlle table Renomme une table.
ORDER BY nom col Recre la table avec les lignes dans un ordre
particulier (notez quaprs avoir modifi la table les
lignes ne seront plus dans lordre).
CONVERT TO CHARACTER SET jdc COLLATE Convertit toutes les colonnes texte avec le jeu de
odc caractres et lordre de classement indiqus.
[DEFAULT] CHARACTER SET cs COLLATE c Dfinit le jeu de caractres et lordre de classement
par dfaut.
DISCARD TABLESPACE Supprime le fichier despace de tables sous-jacent
pour une table InnoDB (pour plus dinformations
sur les tables InnoDB, voir le Chapitre 13).
IMPORT TABLESPACE Recre le fichier despace de tables sous-jacent
pour une table InnoDB (pour plus dinformations
sur les tables InnoDB, voir le Chapitre 13).
options table Permet de rinitialiser les options de table. Utilise
la mme syntaxe que CREATE TABLE.
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;
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 la suite
Au Chapitre 11, nous verrons comment rendre la base de donnes Book-O-Rama
disponible sur le Web.
11
Accs une base de donnes
MySQL partir du Web avec PHP
Auparavant, lorsque nous travaillions avec PHP, nous nous servions dun fichier plat
pour enregistrer et rcuprer nos donnes. Lorsque nous avons mentionn cette appro-
che (voir Chapitre 2), nous avons galement dit que les systmes de bases de donnes
relationnelles rendent ces deux tches (enregistrement et rcupration des donnes) la
fois plus simples, plus sres et plus efficaces dans le cadre dune application web.
Maintenant que nous sommes capables de nous servir de MySQL pour crer des bases
de donnes, nous pouvons commencer connecter cette base de donnes une inter-
face web.
Dans ce chapitre, nous verrons comment accder la base de donnes de Book-O-
Rama partir du Web, en utilisant PHP. Nous expliquerons comment lire et crire dans
cette base de donnes et comment filtrer les donnes dentre susceptibles de poser
problme.
<html>
<head>
<title>Recherche dans le catalogue de Book-O-Rama</title>
</head>
<body>
<h1>Recherche dans le catalogue de Book-O-Rama</h1>
</body>
</html>
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 283
Ce formulaire HTML est trs simple. Sa sortie est prsente la Figure 11.1.
Figure 11.1
Le formulaire de recherche
est trs gnral puisquil
permet de chercher un
livre partir de son titre,
de son auteur ou de son
code ISBN.
Le script appel lorsque lutilisateur clique sur le bouton Rechercher sappelle resul-
tats.php ; son code est celui du Listing 11.2. Tout au long de ce chapitre, nous allons
expliquer le but et le fonctionnement de ce script.
Listing 11.2 : resultats.php Le script qui rcupre les rsultats de notre base de donnes
MySQL et qui les formate pour les afficher correctement
<html>
<head>
<title>Rsultats de la recherche dans Book-O-Rama</title>
</head>
<body>
<h1>Rsultats de la recherche dans Book-O-Rama</h1>
<?php
// Cration de variables aux noms abrgs
$type_recherche = $_POST[type_recherche];
$terme_recherche = trim($_POST[terme_recherche]);
if (!$type_recherche ||!$terme_recherche) {
echo "Vous navez pas saisi les dtails de la recherche";
exit;
}
if (!get_magic_quotes_gpc()) {
$type_recherche = addslashes($type_recherche);
$terme_recherche = addslashes($terme_recherche);
}
if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}
284 Partie II Utilisation de MySQL
$nb_lig_resultat = $resultat->num_rows;
$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
Ltape suivante consiste vrifier que lutilisateur a bien entr une expression
rechercher et quil a slectionn un type de recherche. Vous remarquerez que nous
effectuons cette vrification aprs avoir supprim les espaces aux deux extrmits du
terme recherch : si nous inversions ces deux oprations, nous ne pourrions pas dtecter
le cas o lutilisateur a saisi uniquement des espaces et nous ne pourrions donc pas afficher
un message derreur puisque ces espaces nauraient pas t supprims par trim() :
if (!$type_recherche ||!$terme_recherche) {
echo "Vous navez pas saisi les dtails de la recherche."
exit;
}
Vous remarquerez que nous vrifions aussi la variable $type recherche, bien quelle
provienne dans notre cas dune instruction SELECT de HTML. Vous vous demandez
peut-tre pourquoi nous prenons la peine de vrifier des variables qui doivent tre
remplies automatiquement. Il est trs important de se rappeler quil peut exister
plusieurs interfaces votre base de donnes. Amazon, par exemple, possde plusieurs
filiales qui se servent de leur interface de recherche. En outre, il est important de filtrer
les donnes pour viter tout problme de scurit provenant des diffrentes interfaces
mises la disposition des utilisateurs pour saisir leurs donnes.
286 Partie II Utilisation de MySQL
Si vous comptez utiliser des donnes saisies par les utilisateurs, il faut les filtrer pour en
supprimer tous les caractres de contrle. Pour cela, utilisez les fonctions addslashes(),
stripslashes() et get magic quotes gpc() que nous avons vues au Chapitre 4. Vous
devez protger les donnes lorsque vous soumettez une entre utilisateur dans une base de
donnes comme MySQL.
Ici, il faut tester le rsultat de la fonction get magic quotes gpc(), qui vous indique si
la mise entre apostrophes est automatique. Si ce nest pas le cas, protgez les donnes
avec addslashes() :
if (!get_magic_quotes_gpc()) {
$type_recherche = addslashes($type_recherche);
$terme_recherche = addslashes($terme_recherche);
}
Vous devez galement utiliser stripslashes() sur les donnes qui proviennent de la base
de donnes. Si la fonctionnalit des apostrophes automatiques est active, les donnes
provenant de la base contiennent en effet des barres obliques que vous devez retirer.
Nous utilisons galement la fonction htmlspecialchars() pour encoder les caractres
qui ont une signification particulire en HTML. Nos donnes de test actuelles ne contien-
nent aucun de ces caractres (&, <, >, ou "), mais il existe plusieurs titres de livres qui
contiennent le symbole &. Grce cette fonction, nous pouvons liminer de futures
erreurs.
tablissement de la connexion
La bibliothque PHP pour se connecter MySQL sappelle mysqli (le i signifie improved,
cest--dire amlior). Vous avez le choix entre une syntaxe oriente objet ou une
syntaxe procdurale.
Dans le script, cest la ligne suivante qui nous permet de nous connecter au serveur
MySQL :
@$db = new mysqli(localhost, bookorama, bookorama123, livres);
Celle-ci cre une instance de la classe mysqli et une connexion lhte localhost
avec le nom dutilisateur bookorama et le mot de passe bookorama123. Cette
connexion est configure de manire utiliser la base de donnes appele livres.
Avec cette approche oriente objet, vous pouvez maintenant invoquer des mthodes sur
cet objet afin daccder la base de donnes. Si vous prfrez lapproche procdurale,
utilisez la ligne suivante pour crer la mme connexion :
@$db = mysqli_connect(localhost, bookorama, bookorama123,
livres);
Chapitre 11 Accs une base de donnes MySQL partir du Web avec PHP 287
Au lieu dun objet, cet appel renvoie alors une ressource qui reprsente la connexion
la base de donnes. Si vous utilisez lapproche procdurale, vous devrez passer cette
ressource tous les autres appels des fonctions mysqli. Ce mcanisme est trs semblable
celui des fonctions sur les fichiers comme fopen().
La plupart des fonctions mysqli ont une interface oriente objet et une interface procdu-
rale. En gnral, les diffrences tiennent ce que les noms de fonction de la version proc-
durale commencent par mysqli et exigent que vous passiez le descripteur que vous avez
obtenu de mysqli connect(). Les connexions de la base de donnes font exception cette
rgle car elles peuvent tre effectues par le constructeur de lobjet mysqli.
Il est prfrable de vrifier le rsultat de votre tentative de connexion, car rien dans le
reste du code ne fonctionnera si la connexion la base de donnes na pas fonctionn.
Pour cela, vous pouvez utiliser le code suivant :
if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}
Ce code est identique pour la version oriente objet et la version procdurale. La fonc-
tion mysqli connect errno() renvoie un numro derreur en cas derreur et zro en
cas de succs.
Lorsque vous vous connectez la base de donnes, commencez la ligne de code avec
loprateur de suppression derreur, @. Cette approche vous permettra de grer les
erreurs avec lgance (cela peut galement tre ralis avec des exceptions, que nous
navons pas utilises dans cet exemple simple).
Noubliez pas que le nombre de connexions MySQL simultanes est limit par le param-
tre MySQL max connections. Lintrt de ce paramtre et du paramtre Apache
MaxClients associ est de permettre au serveur de rejeter les nouvelles demandes de
connexion lorsquun ordinateur commence tre surcharg ou lors dun problme logiciel.
Vous pouvez modifier la valeur par dfaut de ces deux paramtres en modifiant les
fichiers de configuration. Pour modifier MaxClients dans Apache, ditez le fichier
httpd.conf de votre systme. Pour changer le paramtre max connections de MySQL,
modifiez le fichier my.conf.
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.
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.
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();
partir du tableau associatif $ligne, nous pouvons parcourir chaque champ et lafficher
de manire approprie, comme ici :
echo "<br />ISBN : ;
echo stripslashes($ligne[isbn]);
Comme nous lavons dj vu, nous nous servons de stripslashes() pour filtrer les
valeurs avant de les afficher.
Il existe plusieurs manires de rcuprer les lignes partir de lobjet ou du descripteur
de rsultat. Au lieu de passer par un tableau associatif, nous pouvons placer chaque
ligne dans un tableau classique avec mysql fetch row(), comme ici :
$ligne = $resultat->fetch_row();
290 Partie II Utilisation de MySQL
ou
$ligne = mysqli_fetch_row($resultat);
Les valeurs des colonnes seront alors les valeurs $ligne[0], $ligne[1], etc. La fonc-
tion mysqli fetch array() permet dextraire une ligne comme lun ou lautre de ces
deux types de tableaux.
Vous pouvez galement rcuprer une ligne sous la forme dun objet avec la fonction
mysql fetch object() :
$ligne = $result->fetch_object();
ou
$ligne = mysqli_fetch_object($resultat);
Vous pouvez ensuite accder chacun des champs avec $ligne >titre, $ligne
>auteur, etc.
Figure 11.3
Linterface permettant
dajouter de nouveaux
livres dans la base de
donnes.
<html>
<head>
<title>Book-O-Rama - Ajout dun nouveau livre</title>
</head>
<body>
<h1>Book-O-Rama - Ajout dun nouveau livre</h1>
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 (!get_magic_quotes_gpc())
{
$isbn = addslashes($isbn);
$auteur = addslashes($auteur);
$titre = addslashes($titre);
$prix = doubleval($prix);
}
if (mysqli_connect_errno()) {
echo "Impossible de se connecter la base de donnes.";
exit;
}
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
Figure 11.4
Le script se termine correctement et indique que le livre a t ajout la base de donnes.
Comme le prix de chaque livre est enregistr dans la base de donnes sous la forme
dun nombre virgule flottante, il ne doit contenir aucune barre oblique. Nous pouvons
filtrer ce caractre et tous les autres caractres gnants avec doubleval(), que nous
avons dj vue au Chapitre 1. Cela permet en outre de supprimer tous les symboles
montaires que lutilisateur aurait pu saisir dans le formulaire.
Une fois encore, nous nous sommes connects la base de donnes en instanciant
lobjet mysqli et en configurant une requte envoyer cette base. Ici, il sagit dune
requte SQL INSERT :
$requete = "insert into livres values
(".$isbn., ".$auteur., ".$titre., ".$prix.);
$resultat = $db->query($requete);
Cette requte est excute sur la base de donnes en appelant $db >query() (ou
mysqli query() si vous adoptez lapproche procdurale).
Une diffrence importante entre lutilisation de INSERT et de SELECT rside dans lutili-
sation de mysqli affected rows(). Il sagit dune fonction dans la version procdurale
ou dune variable de classe dans la version oriente objet :
echo $db->affected_rows . " livre ajout la base de donnes.";
294 Partie II Utilisation de MySQL
Dans le script prcdent, nous nous tions servis de mysqli num rows() pour dtermi-
ner le nombre de lignes renvoyes par SELECT. Lorsque vous crivez des requtes qui
modifient la base de donnes, comme INSERT, DELETE ou UPDATE, vous devez vous
servir de mysql affected rows().
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.
<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);
}
// Connexion la base
$db = &MDB2::connect($dsn);
// Teste la connexion
if (MDB2::isError($db)) {
echo $db->getMessage();
exit;
}
$resultat = $db->query($requete);
// Teste le rsultat
if (MDB2::isError($resultat)) {
echo $db->getMessage();
exit;
}
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
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
Lorsque vous excutez une commande GRANT, celle-ci modifie les tables dune base de
donnes particulire appele mysql. Les informations de privilges sont enregistres
dans six tables de cette base de donnes. Sachant cela, lorsque vous accordez des privi-
lges sur les bases de donnes, il faut faire attention ne pas octroyer daccs injustifis
la base mysql.
Vous pouvez examiner le contenu de la base de donnes mysql en ouvrant une session
sous le compte administrateur et en excutant la commande suivante :
use mysql;
Pour afficher les tables de cette base de donnes, faites la commande suivante :
show tables;
300 Partie II Utilisation de MySQL
Chacune de ces tables contient des informations systme. Six dentre elles ( user, host,
db, tables priv, columns priv et procs priv) stockent les informations des privil-
ges, et cest pour cette raison quon les appelle parfois tables grant. La fonction spci-
fique de ces tables varie, mais leur utilisation globale reste la mme : dterminer ce que
les utilisateurs ont le droit de faire et ce quils nont pas le droit de faire. Chacune
delles contient deux types de champs : les champs de porte, qui identifient lutilisa-
teur, lhte et une partie dune base de donnes laquelle le privilge fait rfrence, et
les champs de privilges, qui identifient les actions pouvant tre effectues par
lutilisateur en question pour le champ de porte correspondant.
Les tables user et host indiquent si un utilisateur peut se connecter au serveur MySQL et
sil possde des privilges dadministration. Les tables db et host dterminent les bases de
donnes auxquelles lutilisateur peut accder. La table tables priv dtermine les tables
dune base de donnes dont lutilisateur peut se servir, la table columns priv dtermine
les colonnes de ces tables auxquelles il peut accder et la table procs priv indique les
procdures que lutilisateur a le droit dexcuter.
Chapitre 12 Administration MySQL avance 301
La table user
La table user contient les dtails des privilges globaux de lutilisateur. Elle dtermine
si lutilisateur a le droit de se connecter au serveur MySQL et sil possde des privil-
ges globaux, cest--dire des privilges valables pour toutes les bases de donnes du
systme.
Vous pouvez consulter la structure de cette table avec linstruction describe user;.
Le schma de cette table user est prsent dans le Tableau 12.1.
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
Tous les privilges numrs dans la table user sont globaux, cest--dire quils
sappliquent toutes les bases de donnes du systme (y compris la base de donnes
mysql). Par consquent, les administrateurs possdent gnralement quelques Y dans
ces colonnes, mais la majorit des utilisateurs ne doit possder que des N. Les utilisa-
teurs normaux doivent possder des privilges pour les bases de donnes dont ils
doivent se servir et non pour toutes les tables.
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
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)
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
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)
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
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)
Champ Type
Host char(60)
Db char(64)
User char(16)
Routine name char(64)
Routine type enum(FUNCTION, PROCEDURE)
Grantor char(77)
Proc priv set(Execute,Alter Routine, Grant)
Timestamp timestamp(14)
La colonne Grantor des tables tables priv et procs priv contient le nom de lutili-
sateur qui a fourni ce privilge lutilisateur considr. La colonne Timestamp de ces
trois tables contient la date et lheure courantes au moment o ce privilge a t
accord.
votre nom dhte et votre mot de passe. Si un nom dutilisateur est laiss vide dans
la table user, il correspond tous les utilisateurs. Les noms dhtes peuvent conte-
nir un joker (%) qui peut remplacer lintgralit du champ (dans ce cas, le % corres-
pond tous les htes) ou uniquement une partie du nom dhte (par exemple,
%.tangledweb.com.au correspond tous les htes dont le nom se termine par
.tangledweb.com.au). Si le champ du mot de passe est laiss vide, aucun mot de
passe nest ncessaire. Pour des raisons de scurit, il vaut mieux viter que la table
user contienne une ligne ne contenant aucun nom dutilisateur, aucun mot de passe
et un nom dhte uniquement compos dun joker. Si le nom dhte est vide,
MySQL se rfre la table host afin de trouver une entre user et host correspon-
dante.
2. Vrification des requtes. chaque fois que vous envoyez une requte aprs avoir
tabli une connexion, MySQL vrifie si vous avez le niveau de privilges appropri.
Le systme commence par vrifier les privilges globaux (dans la table user) ; sils
ne sont pas suffisants, il vrifie les tables db et host. Si vous navez toujours pas les
privilges suffisants, MySQL vrifie la table tables priv et enfin la table
columns priv (si lopration implique des procdures stockes, il vrifie la table
procs priv au lieu de ces deux tables).
linvite de MySQL (vous devez avoir ouvert une session sous le compte dun adminis-
trateur). Il sagit de la manire la plus courante pour mettre jour les privilges.
Mais vous pouvez galement utiliser :
mysqladmin flush-privileges
ou :
mysqladmin reload
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.
Mots de passe
Vrifiez que tous vos utilisateurs possdent des mots de passe (et tout particulirement
root!), que ceux-ci sont bien choisis et quils sont rgulirement modifis, comme
pour les mots de passe de votre systme dexploitation. Il vaut mieux viter les mots de
passe contenant des mots provenant dun dictionnaire et leur prfrer des combinaisons
de lettres et de chiffres.
Chapitre 12 Administration MySQL avance 309
Sil vous faut stocker des mots de passe dans des scripts, assurez-vous que seul lutili-
sateur dont le mot de passe est enregistr dans un script a le droit de le lire.
Les scripts PHP utiliss pour se connecter la base de donnes ont besoin de connatre
le mot de passe de lutilisateur concern. Il est possible de scuriser cette opration en
plaant le nom dutilisateur et le mot de passe dans un fichier appel, par exemple,
dbconnect.php, puis dinclure celui-ci lorsque vous en avez besoin. Ce fichier doit tre
soigneusement conserv lextrieur de larborescence des documents web et tre
accessible uniquement lutilisateur appropri. Noubliez pas que, si vous placez ces
informations dans un fichier .inc (ou une autre extension) dans larborescence des docu-
ments web, vous devez vrifier que votre serveur web sait que ces fichiers doivent tre
interprts comme des fichiers PHP pour quils ne saffichent pas comme du texte brut
dans un navigateur web.
Ne stockez pas les mots de passe en clair dans votre base de donnes. Les mots de passe
MySQL ne sont pas enregistrs de cette manire, mais il arrive souvent que dans le
cadre dapplications web on souhaite enregistrer les noms des comptes utilisateurs et
les mots de passe des membres du site. Vous pouvez chiffrer (de manire non rversi-
ble) vos mots de passe avec la fonction password() de MySQL. Si vous utilisez un mot
de passe chiffr dans une clause SELECT (pour ouvrir une session utilisateur), vous
devrez utiliser la mme fonction de chiffrement pour tester le mot de passe saisi par
lutilisateur.
Nous reviendrons sur cette fonctionnalit lorsque nous implmenterons des projets,
dans la Partie 5.
Lorsque vous crez les utilisateurs, assurez-vous de ne leur accorder laccs qu partir
de lordinateur do ils seront censs ouvrir une session. Par exemple, si lun de vos
utilisateurs sappelle jeanne@localhost, tout va bien. En revanche, si cet utilisateur
sappelle simplement jeanne, il pourra ouvrir une session depuis nimporte quel ordi-
nateur et il se peut quelle ne soit pas la jeanne que vous connaissez. Pour la mme
raison, vitez demployer des jokers dans les noms dhtes.
Vous pouvez encore amliorer la scurit de votre systme en utilisant des adresses IP
la place des noms de domaines dans la table host. Cela vous pargnera bien des probl-
mes en cas de piratage de votre DNS ou, plus simplement, en cas derreur. Pour aller
encore plus loin, vous pouvez dmarrer le dmon MySQL avec loption skip name
resolve, qui demande au serveur de ne lire que les adresses IP ou localhost dans les
colonnes contenant des noms dhtes.
Il faut galement empcher les utilisateurs normaux daccder au programme mysqlad
min de votre serveur web. Comme ce programme est excut partir de la ligne de
commande, il peut poser problme au niveau des droits du systme dexploitation.
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.
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
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.
Variante Description
SHOW DATABASES [like ou where] Donne la liste de toutes les bases de donnes disponibles.
SHOW [OPEN] TABLES [FROM Donne la liste des tables de la base de donnes en cours
basededonnes] [like ou where] dutilisation ou dans la base de donnes basededonnes.
SHOW [FULL] COLUMNS FROM table Donne la liste de toutes les colonnes dune table
[FROM basededonnes] particulire dans la base de donnes en cours
[like ou where] dutilisation ou partir de la base de donnes indique.
Vous pouvez utiliser SHOW FIELDS au lieu de SHOW
COLUMNS.
SHOW INDEX FROM table [FROM Donne les dtails de tous les index dune table
basededonnes] particulire de la base de donnes en cours dutilisation
ou dans la base de donnes appele basededonnes, si
elle est spcifie. Vous pouvez galement utiliser SHOW
KEYS.
SHOW [GLOBAL | SESSION] STATUS Donne des informations sur certains lments du systme,
[like ou where] comme le nombre de threads en cours dexcution.
Une clause LIKE permet de choisir les noms de ces
lments. Par exemple, Thread% peut correspondre
Threads cached, Threads connected,
Threads created ou Threads running.
Chapitre 12 Administration MySQL avance 313
Variante Description
SHOW [GLOBAL | SESSION] Affiche les noms et les valeurs des variables systme de
VARIABLES [like ou where] MySQL, comme son numro de version.
SHOW [FULL] PROCESSLIST Affiche la liste de tous les processus en cours
dexcution dans le systme, cest--dire les requtes en
cours de traitement. La plupart des utilisateurs voient
uniquement leurs threads mais, sils possdent le
privilge PROCESS, ils peuvent galement voir les
processus de tous les utilisateurs, y compris les mots de
passe si ceux-ci sont prciss dans les requtes. Par
dfaut, les requtes sont tronques aprs le centime
caractre. Vous pouvez utiliser le mot-cl facultatif FULL
pour afficher lintgralit des requtes.
SHOW TABLE STATUS [FROM Affiche des informations sur chacune des tables de la
basededonnes] [like ou where] base de donnes en cours dutilisation ou sur celles de la
base de donnes basededonnes si elle est indique,
ventuellement avec des jokers. Ces informations
contiennent notamment le type des tables et la date de
leur dernire mise jour.
SHOW GRANTS FOR utilisateur Affiche les instructions GRANT ncessaires pour donner
lutilisateur son niveau actuel de privilges.
SHOW PRIVILEGES Affiche les diffrents privilges reconnus par le serveur.
SHOW CREATE DATABASE Affiche une instruction CREATE DATABASE qui crerait la
basededonnes base de donnes indique.
SHOW CREATE TABLE nomtable Affiche une instruction CREATE TABLE qui crerait la
table indique.
SHOW [STORAGE] ENGINES Affiche les moteurs de stockage disponibles dans
linstallation et indique le moteur de stockage par dfaut
(nous reviendrons sur les moteurs de stockage au
Chapitre 13).
SHOW INNODB STATUS Affiche des donnes concernant ltat actuel du moteur
de stockage InnoDB.
SHOW WARNINGS [LIMIT [dcalage,] Affiche toutes les erreurs, tous les avertissements et
nombre lignes] toutes les notifications produites par la dernire
instruction qui a t excute.
SHOW ERRORS [LIMIT [dcalage,] Naffiche que les erreurs produites par la dernire
nombre lignes] instruction qui a t excute.
314 Partie II Utilisation de MySQL
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.
Cette requte produit la sortie suivante (notez que nous laffichons sous forme verti-
cale parce que les lignes de la table sont trop larges pour tenir dans ce livre ; vous
pouvez obtenir ce format en faisant terminer votre requte par \G au lieu dun point-
virgule).
Chapitre 12 Administration MySQL avance 315
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
Type Description
SIMPLE Requte SELECT standard, comme dans cet exemple
PRIMARY Requte externe (premire requte) lorsque lon utilise des sous-
requtes ou des unions
UNION Seconde ou requte suivante dans une union
DEPENDENT UNION Seconde ou requte suivante dans une union, dpendant de la requte
principale
UNION RESULT Rsultat dune union
SUBQUERY Sous-requte interne
DEPENDENT SUBQUERY Sous-requte interne, dpendant de la requte principale (sous-
requte corrle)
DERIVED Sous-requte utilise dans la clause FROM
UNCACHEABLE SUBQUERY Sous-requte dont le rsultat ne peut pas tre mis en cache et qui sera
donc rvalue pour chaque ligne
UNCACHEABLE UNION Seconde ou requte suivante dans une union appartenant sous-
requte non cachable
La colonne table numre simplement les tables utilises pour rpondre la requte.
Chaque ligne du rsultat fournit plus dinformations sur la manire dont cette table
particulire est utilise dans la requte. Ici, vous pouvez voir que les tables utilises sont
commandes, livres commandes, clients et livres (ce que vous pouvez dj savoir en
examinant tout simplement la requte).
La colonne type explique comment la table est utilise dans les jointures de la requte.
Le Tableau 12.9 numre les valeurs possibles de cette colonne, de la plus rapide la
plus lente en terme de rapidit dexcution. Cela vous donne une ide du nombre de
lignes qui doivent tre lues dans chaque table pour excuter une requte.
Tableau 12.9 : Les diffrents types de jointures affichs par EXPLAIN
Type Description
const ou system La table nest lue quune seule fois. Cela se produit lorsque la table ne
contient quune seule ligne. Le type system est utilis avec les tables
systmes et le type const dans les autres cas.
Chapitre 12 Administration MySQL avance 317
Tableau 12.9 : Les diffrents types de jointures affichs par EXPLAIN (suite)
Type Description
eq ref Pour chaque ensemble de lignes provenant des autres tables de la jointure,
une seule ligne est lue dans cette table. Ce type de jointure est utilis
lorsque la jointure se sert de toutes les parties de lindex sur la table et que
lindex est UNIQUE ou quil sagit de la cl primaire.
fulltext Une jointure sur un index textuel.
ref Pour chaque ensemble de lignes provenant des autres tables de la jointure,
vous lisez un ensemble de lignes qui correspondent dans cette table. Ce
type de jointure est utilis lorsque la jointure ne peut pas choisir une ligne
unique partir de la condition de jointure, cest--dire lorsque seule une
partie de la cl est utilise dans la jointure, ou si elle nest pas un index
UNIQUE ou une cl primaire.
ref or null Semblable une requte ref, mais MySQL recherche galement les lignes
NULL (ce type est principalement utilis dans les sous-requtes).
index merge Une optimisation spcifique, la fusion dindex, a t utilise.
unique subquery Ce type de jointure sert remplacer ref pour certaines sous-requtes IN
qui ne renvoient quune seule ligne.
index subquery Ce type de jointure est semblable unique subquery mais est utilis pour
les sous-requtes avec un index non UNIQUE.
range Pour chaque ensemble de lignes provenant des autres tables de la jointure,
vous lisez un ensemble de lignes de cette table qui appartiennent un
intervalle particulier.
index Parcours de lindex complet.
ALL Chaque ligne de la table est traite.
Dans lexemple prcdent, vous pouvez constater quune table est jointe avec eq ref
(livres), quune autre lest avec ref (livres commandes) et que les deux autres
(commandes et clients) sont jointes avec ALL, cest--dire en examinant chaque ligne
de la table.
La colonne rows conserve ces informations : elle contient une estimation approximative
du nombre de lignes de chaque table qui doivent tre parcourues pour effectuer la join-
ture. Vous pouvez les multiplier entre elles pour obtenir le nombre total de lignes
examines pour effectuer une requte. Ces chiffres doivent tre multiplis puisquune
jointure est comparable un produit des lignes appartenant diffrentes tables. Repor-
tez-vous au Chapitre 10 pour plus de dtails. Noubliez pas quil sagit du nombre de
lignes examines, pas du nombre de lignes renvoyes, et quil sagit seulement dune
318 Partie II Utilisation de MySQL
estimation : MySQL ne peut pas deviner le rsultat final avant deffectuer rellement la
requte.
Naturellement, plus ce nombre est faible, mieux cest. Pour linstant, notre base de
donnes contient trs peu de donnes mais, lorsque la taille dune base commence
augmenter, une requte de ce genre dmultiplie le temps dexcution. Nous y reviendrons
un peu plus loin dans ce chapitre.
La colonne possible keys fournit la liste des cls que MySQL peut utiliser lors dune
opration de jointure ralise avec la table. Dans ce cas, vous pouvez voir que les cls
possibles sont en fait toutes les cls primaires.
La colonne key correspond soit la cl de la table MySQL utilise, soit NULL si aucune
cl na t employe. Vous remarquerez que, bien quil y ait des cl primaires possibles
pour les tables clients et commandes, aucune na t utilise dans cette requte.
La colonne key len indique la longueur de la cl utilise. Vous pouvez vous en servir
pour savoir si la cl na t utilise que partiellement. Cette information est importante
lorsque des cls sont composes de plusieurs colonnes. Dans le cas prsent, pour lequel
des cls ont t utilises, cest la totalit de la cl qui a t employe.
La colonne ref montre les colonnes utilises avec la cl pour slectionner des lignes
dans la table.
Enfin, la colonne Extra fournit toutes les autres informations concernant la manire
dont la jointure a t effectue. Le Tableau 12.10 numre quelques valeurs que vous
pourrez rencontrer dans cette colonne. Pour disposer de la liste complte, qui contient
plus de quinze possibilits, consultez le manuel de MySQL, http://dev.mysql.com/
doc/refman/5.1/en/using-explain.html.
Tableau 12.10 : Les valeurs possibles de la colonne Extra, qui apparat dans la sortie
de EXPLAIN
Valeur Signification
Distinct Une fois la premire ligne correspondante trouve, MySQL cesse de
rechercher des lignes.
Not exists La requte a t optimise pour se servir de LEFT JOIN.
Range checked for Pour chaque ligne de lensemble de lignes des autres tables de la
jointure, MySQL tente de trouver le meilleur index utiliser, sil y en a
un.
Using filesort Il faudra deux passes pour trier les donnes, ce qui prend naturellement
deux fois plus de temps.
Chapitre 12 Administration MySQL avance 319
Tableau 12.10 : Les valeurs possibles de la colonne Extra, qui apparat dans la sortie
de EXPLAIN (suite)
Valeur Signification
Using index Toutes les informations de la table proviennent de lindex, cest--dire
que les lignes ne sont en ralit pas examines.
Using join buffer Les tables sont lues par portions en utilisant le tampon de jointure, puis
les lignes sont extraites de ce tampon pour terminer la requte.
Using temporary Il faut crer une table temporaire pour excuter cette requte.
Using where Une clause WHERE est utilise pour slectionner les lignes.
Il existe plusieurs manires de rsoudre les problmes mis en vidence par la sortie de
EXPLAIN.
Tout dabord, vrifiez les types des colonnes et assurez-vous que ce sont les mmes.
Ceci est particulirement valable pour la largeur des colonnes car les index ne peuvent
pas tre utiliss pour associer des colonnes si elles ont des largeurs diffrentes. Vous
pouvez rsoudre ce problme en modifiant le type des colonnes associer ou en int-
grant ces informations lors de la conception de votre base de donnes.
Ensuite, vous pouvez demander loptimiseur de jointure dexaminer les distributions
des cls et donc de mieux optimiser les jointures laide de lutilitaire myisamchk ou de
linstruction ANALYZE TABLE, qui sont quivalents. Vous pouvez invoquer cet outil grce
la ligne suivante :
myisamchk --analyze chemin_de_la_base_de_donnes_MySQL/table
Vous pouvez vrifier plusieurs tables en les indiquant toutes sur la ligne de commande
ou en utilisant la syntaxe suivante :
myisamchk --analyze chemin_de_la_base_de_donnes_MySQL/*.MYI
Pour vrifier toutes les tables de toutes les bases de donnes, utilisez la commande
suivante :
myisamchk --analyze chemin_du_rpertoire_de_donnes_MySQL/*/*.MYI
Vous pouvez galement numrer les tables dans une instruction ANALYZE TABLE
partir du moniteur MySQL :
analyze table clients, commandes, livres_commandes, livres;
Troisimement, vous pouvez envisager lajout dun nouvel index dans la table. Si la
requte est la fois lente et classique, cette opration est fortement recommande. Sil
sagit dune requte que vous ne serez plus amen effectuer, cette modification nen
vaut probablement pas la peine, dautant plus quelle pourrait ralentir dautres choses.
320 Partie II Utilisation de MySQL
Si la colonne possible keys de EXPLAIN contient plusieurs valeurs NULL, vous pouvez
amliorer les performances de votre requte en ajoutant un index dans la table en ques-
tion. Si la colonne que vous utilisez dans votre clause WHERE peut accepter un index,
vous pouvez vous servir de la commande suivante pour en crer un :
ALTER TABLE table ADD INDEX (colonne);
Optimisation de larchitecture
Dune manire gnrale, tous les lments de votre base de donnes doivent tre aussi
petits que possible. Pour cela, vous pouvez commencer par choisir une architecture
correcte, qui minimise les redondances. Vous pouvez galement choisir les types de
donnes les plus petits possibles pour vos colonnes. Il faut galement viter les valeurs
NULL autant que faire se peut et rendre vos cls primaires aussi courtes que possible.
vitez les colonnes largeur variable (comme VARCHAR, TEXT ou BLOB). Si vos tables
possdent des champs de largeur fixe, elles seront plus rapides utiliser, bien quelles
ncessitent plus de place.
Permissions
Outre les recommandations que nous venons de voir propos d EXPLAIN, vous pouvez
amliorer la vitesse de vos requtes en simplifiant les permissions. Nous avons dj
expliqu la manire dont les requtes sont vrifies par le systme de permissions avant
dtre excutes. Plus ce processus est simple, plus vos requtes seront excutes rapi-
dement.
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
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.
Chaque table doit tre dsigne par son nom et le type du verrou peut tre READ ou
WRITE. Pour une sauvegarde vous navez normalement besoin que dun verrou en
lecture (READ). Vous devez galement excuter une commande FLUSH TABLES afin de
vous assurer que toutes les modifications de vos index ont t crites sur le disque avant
de raliser une sauvegarde.
Pendant cette sauvegarde, les utilisateurs et les scripts pourront continuer excuter des
requtes ne demandant quun accs en lecture. Cependant, si votre serveur doit satis-
faire un gros volume de requtes modifiant la base de donnes, comme des commandes
de clients, cette solution est viter.
322 Partie II Utilisation de MySQL
Implmenter la rplication
La rplication est une technique grce laquelle plusieurs serveurs de base de donnes
peuvent servir les mmes donnes. Il est ainsi possible dquilibrer la charge et
damliorer la fiabilit du systme. Si un systme est en panne, les autres peuvent
toujours tre interrogs. Une fois configure, la rplication peut galement tre utilise
pour raliser des sauvegardes.
Lide fondamentale consiste avoir un serveur matre et lui ajouter un certain
nombre desclaves. Chacun des esclaves offre une rplication en miroir du matre. Lors-
que vous configurez initialement les esclaves, vous copiez un instantan de toutes les
donnes du matre ce moment prcis. Puis les esclaves demandent des mises jour de
la part du matre. Le matre transmet les dtails des requtes excutes grce son journal
binaire et les esclaves rappliquent ces requtes aux donnes.
Lapproche habituelle pour utiliser cette configuration consiste appliquer les requtes
en criture au matre et les requtes en lecture aux esclaves. Des architectures plus
complexes sont galement possibles, par exemple en incluant plusieurs matres, mais
nous ne traiterons ici que du cas de figure le plus courant.
Vous devez bien comprendre que les esclaves ne possdent gnralement pas des
donnes aussi jour que celles du matre. Cet tat de fait se produit dans nimporte
quelle base de donnes distribue.
Pour entamer la configuration dune architecture matre/esclaves, vous devez vous
assurer que la journalisation binaire est active sur le matre. Pour plus dinformations
ce sujet, consultez lAnnexe A.
Vous devez diter votre fichier my.ini ou my.cnf sur les serveurs matre et esclave. Sur le
matre, utilisez la configuration suivante :
[mysqld]
log-bin
server-id=1
Le premier rglage active la journalisation binaire (il devrait donc dj tre prsent ; sil
ne lest pas, ajoutez-le). Le second donne votre matre un identifiant unique. Chaque
esclave requiert galement un identifiant : vous devez donc ajouter une ligne semblable
aux fichiers my.ini/my.cnf sur chacun des esclaves. Assurez-vous que ces nombres
soient uniques ! Par exemple, votre premier esclave pourrait tre paramtr avec
server id=2, le second, avec server id=3, etc.
Configurer le matre
Sur le matre, vous devez crer un utilisateur pour la connexion des esclaves. Il existe
un niveau de privilge spcial pour les esclaves, appel esclave de rplication. Selon la
324 Partie II Utilisation de MySQL
manire dont vous prvoyez de raliser le transfert de donnes initial, il se peut que
vous deviez temporairement accorder certains privilges supplmentaires.
Dans la plupart des cas, vous utiliserez un instantan de la base de donnes pour trans-
frer les donnes, et, dans ce cas, seul le privilge spcial esclave de rplication est
ncessaire. Si vous dcidez dutiliser la commande LOAD DATA FROM MASTER pour trans-
frer les donnes (voir la prochaine section), lutilisateur aura besoin des privilges
RELOAD, SUPER et SELECT, mais uniquement pour la configuration initiale. Selon le prin-
cipe du moindre privilge expos au Chapitre 9, vous devrez rvoquer ces autres privi-
lges une fois que le systme est oprationnel.
Crez un utilisateur sur le matre. Vous pouvez lui attribuer le nom et le mot de passe de
votre choix, mais ne perdez pas ces informations. Dans notre exemple, nous appellerons
cet utilisateur esc rep :
grant replication slave
on *.*
to esc_rep@% identified by motdepasse;
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;
Notez le fichier et la position. Vous aurez besoin de ces informations pour configurer les
esclaves.
Puis prenez votre instantan et dverrouillez les tables avec linstruction suivante :
unlock tables;
Si vous utilisez des tables InnoDB, le moyen le plus simple consiste utiliser loutil
InnoDB Hot Backup, propos par Innobase Oy ladresse http://www.innodb.com. Il
ne sagit pas dun logiciel libre et sa licence nest pas gratuite. Sinon vous pouvez utili-
ser la procdure dcrite ici et, avant de dverrouiller les tables, fermer le serveur
MySQL et copier le rpertoire entier pour la base de donnes que vous souhaitez rpliquer
avant de redmarrer le serveur et de dverrouiller les tables.
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.
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.
stockage diffrent et les tables peuvent aisment tre converties pour passer dun type
un autre.
Pour choisir le type de table lorsque vous crez votre table, utilisez linstruction
suivante :
CREATE TABLE table TYPE=type ....
Les types de tables gnralement disponibles sont les suivants :
m MyISAM. Il sagit du type par dfaut et cest celui que nous avons utilis jusqu
prsent dans ce livre. Il est fond sur le type ISAM (Indexed Sequential Access
Method, ou "mthode daccs squentiel index) traditionnel, une mthode stan-
dard pour stocker les enregistrements et les fichiers. MyISAM offre un certain
nombre davantages supplmentaires par rapport au type ISAM. Par comparaison
avec les autres moteurs de stockage, MyISAM est celui qui possde le plus doutils
pour la vrification et la rparation des tables. Les tables MyISAM peuvent tre
compresses et supportent la recherche plein texte. En revanche, elles ne permet-
tent pas dexcuter des transactions de faon sre et ne reconnaissent pas les cls
trangres.
m MEMORY (auparavant appele HEAP). Les tables de ce type sont stockes en
mmoire et leurs index sont hachs. Les tables MEMORY sont ainsi extrmement
rapides, mais vos donnes seront perdues si le serveur se plante. Ces caractristi-
ques font des tables MEMORY des candidates idales pour le stockage de donnes
temporaires ou drives. Vous devez indiquer MAX ROWS dans linstruction CREATE
TABLE ; sinon ces tables pourraient consommer toute votre mmoire. En outre, elles
ne peuvent pas possder de colonnes de types BLOB, TEXT ou AUTO INCREMENT.
m MERGE. Ces tables vous permettent de traiter une collection de tables MyISAM
comme une seule table lors de vos requtes. Il est ainsi possible de contourner les
limites relatives la taille de fichier maximale sur certains systmes dexploitation.
m ARCHIVE. Ces tables permettent de stocker de gros volumes de donnes avec une
empreinte mmoire minimale. Les tables de ce type nautorisent que les requtes
INSERT et SELECT ; vous ne pouvez pas leur appliquer dinstructions DELETE, UPDATE
ou REPLACE. En outre, elles nutilisent pas dindex.
m CSV. Ces tables sont stockes sur le serveur sous la forme dun unique fichier
contenant des valeurs spares par des virgules. Lavantage de ce type de table
napparat que lorsque vous devez consulter ou manipuler des donnes dans un
tableur comme Microsoft Excel.
m InnoDB. Ces tables permettent deffectuer des transactions correctement
puisquelles fournissent les fonctionnalits COMMIT et ROLLBACK. Les tables InnoDB
savent galement grer les cls trangres. Pour certaines applications, tous ces
Chapitre 13 Programmation MySQL avance 329
avantages peuvent compenser le fait quelles sont plus lentes que les tables
MyISAM.
Dans la plupart des applications web, vous utiliserez gnralement des tables MyISAM
ou InnoDB, ou une combinaison des deux.
Vous devriez choisir des tables MyISAM lorsque vous excutez un grand nombre
dinstructions SELECT ou INSERT (non entrelaces) sur une table car il sagit du moyen
le plus rapide de le faire. Pour de nombreuses applications web comme les catalogues
de produits, MyISAM est le meilleur choix. Vous devriez galement utiliser MyISAM
si vous avez besoin de fonctionnalits de recherche en plein texte. En revanche, utilisez
le moteur de stockage InnoDB lorsque les transactions sont importantes, par exemple
pour les tables stockant des donnes financires ou dans le cas o les instructions
INSERT et SELECT sont entrelaces, comme dans les forums en ligne.
Vous pouvez utiliser des tables MEMORY pour les tables temporaires ou pour impl-
menter des vues. Les tables MERGE sont utiles si vous devez grer des tables MyISAM
de trs grande taille.
Vous pouvez modifier le type dune table aprs sa cration laide dune instruction
ALTER TABLE, comme ceci :
alter table commandes type=innodb;
alter table livres_commandes type=innodb;
Dans la majeure partie de ce livre, nous avons utilis des tables MyISAM. Nous nous
concentrerons prsent sur lutilisation des transactions et leurs implmentations dans
les tables InnoDB.
Les transactions
Les transactions sont des mcanismes qui assurent la cohrence des bases de donnes,
notamment dans lventualit dune erreur ou dun plantage du serveur. Dans les sections
qui suivent, nous expliquerons ce que sont les transactions et comment les implmenter
avec InnoDB.
linsrer dans un autre, ce qui ncessite au moins deux requtes. Il est de la plus haute
importance que ces deux requtes soient excutes toutes les deux ou quelles ne soient
excutes ni lune ni lautre. Si vous retirez largent dun compte et quune panne de
courant survienne avant que vous ne layez plac dans lautre compte, que se passera-t-il ?
Largent aura disparu ?
Vous avez peut-tre dj entendu parler de la conformit ACID. ACID est un acronyme
dcrivant quatre conditions que les transactions doivent satisfaire :
m Atomicit. Les transactions doivent tre atomiques. Autrement dit, elles doivent
tre soit entirement excutes, soit pas du tout excutes.
m Cohrence. Les transactions doivent laisser la base de donnes dans un tat cohrent.
m Isolation. Les transactions non termines ne doivent pas tre visibles pour les autres
utilisateurs de la base de donnes ; autrement dit, elles doivent rester isoles tant
quelles ne sont pas termines.
m Durabilit. Une fois crites dans la base de donnes, les transactions doivent rester
permanentes ou durables.
Une transaction qui a t crite de manire permanente dans la base de donnes est dite
valide. Une transaction qui nest pas crite dans la base de donnes (de sorte que la
base de donnes est replace dans ltat qui tait le sien avant que la transaction ne
commence) est dite annule.
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);
(Si vous la voyez, cest srement parce que vous navez pas dsactiv le mode auto-
commit. Vrifiez et assurez-vous que vous avez bien converti la table au format
InnoDB. En effet, la transaction na pas encore t valide cest lillustration du prin-
cipe disolation des transactions.)
prsent, revenez la premire connexion et validez la transaction :
commit;
Vous devriez maintenant pouvoir retrouver la ligne dans votre autre connexion.
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
Un exemple simple
Le Listing 13.1 dclare une procdure stocke.
delimiter;
cre la procdure stocke elle-mme. Le nom de cette procdure est total commandes.
Elle possde un unique paramtre, appel total, qui correspond la valeur que vous
essayez de calculer. Le terme OUT indique que ce paramtre est pass en mode sortie
(cest la fonction qui le remplira).
Les paramtres peuvent galement tre dclars en mode IN, qui signifie que la valeur
est passe la procdure, ou en mode INOUT, qui signifie que la valeur est passe la
procdure mais que cette dernire peut la modifier.
Le terme float indique le type du paramtre. Ici, on renvoie un total de toutes les
commandes de la table commandes. Le type de la colonne montant de commandes tant
float, cest une valeur de ce type qui sera donc renvoye. Les types de donnes
autoriss dans les procdures stockes sont les mmes que les types de colonne auto-
riss.
334 Partie II Utilisation de MySQL
Si vous souhaitez passer plusieurs paramtres, vous pouvez utiliser une liste de paramtres
spars par des virgules, comme en PHP.
Le corps de la procdure est entour par les instructions BEGIN et END. Ces instruc-
tions sont analogues aux accolades en PHP ( {}) car elles dlimitent un bloc
dinstructions.
Le corps de la procdure excute simplement une instruction SELECT. La seule diff-
rence par rapport une instruction normale tient ce que lon utilise la clause into
total afin de charger le rsultat de la requte dans le paramtre total.
Aprs avoir dclar la procdure, on redfinit le dlimiteur comme tant le point-
virgule :
delimiter;
Une fois que la procdure a t dclare, vous pouvez lappeler en utilisant le mot-cl
call, comme ici :
call total_commandes(@t);
Cette instruction appelle la procdure total commandes en lui passant une variable
pour rcuprer le rsultat. Vous devez ensuite examiner cette variable :
select @t;
Vous pouvez galement crer des fonctions. Une fonction accepte uniquement des para-
mtres en mode lecture et renvoie une seule valeur.
Comme le montre le Listing 13.2, la syntaxe de base est quasiment identique.
delimiter //
delimiter;
Chapitre 13 Programmation MySQL avance 335
Comme vous pouvez le constater, cet exemple utilise le mot-cl function au lieu de
procedure, mais il y a galement deux autres diffrences.
Les paramtres nont pas besoin dtre prciss en tant que IN ou OUT car ils sont nces-
sairement tous en mode IN. Aprs la liste des paramtres, vous pouvez voir la clause
returns float. Elle indique le type de la valeur de retour. Ce type, ici aussi, peut tre
nimporte quel type MySQL valide.
Pour renvoyer une valeur, on utilise linstruction return, comme en PHP.
Notez que cet exemple nutilise pas les instructions BEGIN et END. Vous pourriez les utili-
ser, mais elles ne sont pas requises. Comme en PHP, si un bloc dinstructions ne contient
quune seule instruction, vous navez pas besoin den marquer le dbut et la fin.
Lappel dune fonction est un peu diffrent de lappel dune procdure. Vous pouvez
appeler une fonction stocke de la mme manire que vous appelleriez une fonction
prdfinie :
select prix_ttc(100);
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;
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.
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.
delimiter //
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;
end
//
delimiter;
est appele gestionnaire declare. Elle ressemble une exception dans les procdures
stockes. Vous pouvez galement implmenter des gestionnaires continue et des
gestionnaires exit. Les gestionnaires continue, comme celui prsent ici, ralisent
laction indique puis poursuivent lexcution de la procdure, tandis que les gestion-
naires exit quittent le bloc begin...end le plus proche.
La partie suivante du gestionnaire declare indique quel moment le gestionnaire sera
appel. Ici, il sera appel lorsque sqlstate 02000 est atteint, ce qui est un moyen
cryptique de signifier que lappel se fera lorsque aucune ligne nest trouve. Vous trai-
tez un ensemble rsultat ligne par ligne et, lorsque vous tes court de lignes, ce
338 Partie II Utilisation de MySQL
gestionnaire sera appel. Vous pourriez galement indiquer FOR NOT FOUND, ce qui est
quivalent. Les autres options sont SQLWARNING et SQLEXCEPTION.
Vient ensuite un curseur. Celui-ci sapparente assez un tableau. Il rcupre un
ensemble rsultat dune requte (comme celui renvoy par mysqli query()) et vous
permet de le traiter ligne par ligne (comme vous le feriez par exemple avec
mysqli fetch row()). Considrez le curseur suivant :
declare c1 cursor for select idcommande, montant from commandes;
Ce curseur est appel c1. Il ne sagit que dune dfinition de ce quil va contenir. La
requte ne sera pas encore excute.
La ligne suivante :
open c1;
excute la requte elle-mme. Pour obtenir chaque ligne de donnes, vous devez excu-
ter une instruction fetch. Cela se fait dans une boucle repeat. Dans le cas prsent, la
boucle ressemble ceci :
repeat
...
until fini end repeat;
Notez que la condition (until fini) nest pas vrifie avant la fin. Les procdures stockes
supportent galement les boucles while de la forme suivante :
while condition do
...
end while;
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
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
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;
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
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 informa-
tions confidentielles comme des numros de cartes de crdits, des informations
bancaires ou personnelles peut sembler assez prilleux. Mais le commerce doit conti-
nuer 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 scu-
rit. 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.
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 fonction-
nement dun systme (ou en crivant et en excutant des outils pour raliser automati-
quement 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.
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.
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 financi-
res 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 gale-
ment 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.
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 atta-
quer les serveurs depuis lintrieur du rseau de la socit. Se protger du monde ext-
rieur 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 confi-
dentielles.
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 atten-
tion 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 impi-
toyable 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.
Ce code produira laffichage prsent la Figure 14.1. Avec ce formulaire, nous pour-
rions 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 Scurit
case Masculin:
case Feminin:
case Autre:
echo <<<EOM
<p align=center>
Flicitations! Vous tes de sexe {$_POST[sexe]}.
</p>
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.
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;
}
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.