2
Dvelopper un site Web dynamique et interactif
OlivierHEURTEL
Rsum
Ce livre sadresse aux concepteurs et dveloppeurs qui souhaitent utiliser PHP 5.2 pour dvelopper un site Web dynamique et interactif.
Aprs une prsentation des principes de base du langage, lauteur se focalise sur les besoins spcifiques du dveloppement de sites
dynamiques et interactifs en sattachant apporter des rponses prcises et compltes aux problmatiques habituelles (gestion des
formulaires, accs aux bases de donnes, gestion des sessions, envoi de courriers lectroniques...).
Pour toutes les fonctionnalits dtailles, de nombreux exemples de code sont prsents et comments. Ce livre didactique, la fois
complet et synthtique, vous permet daller droit au but cest louvrage idal pour se lancer sur PHP.
Les exemples cits dans le livre sont en tlchargement sur le site de lditeur (www.eni-livres.com)."
L'auteur
Aprs plus de huit ans passs en socit de service, o il a successivement occup les postes de dveloppeur, chef de projet puis
directeur de projet sur des missions portant sur la ralisation de systmes d'information, Olivier Heurtel a dmarr une activit de
consultant/formateur indpendant spcialis sur les bases de donnes (Oracle essentiellement) et les outils de dveloppement Web, au
premier rang desquels... PHP bien sr ! Cet ouvrage est le fruit de toute son exprience dans ce domaine et de toute sa passion pour cet
outil de dveloppement.
Ce livre numrique a t conu et est diffus dans le respect des droits dauteur. Toutes les marques cites ont t dposes par leur diteur respectif. La loi du 11
Mars 1957 nautorisant aux termes des alinas 2 et 3 de larticle 41, dune part, que les copies ou reproductions strictement rserves lusage priv du copiste et non
destines une utilisation collective, et, dautre part, que les analyses et les courtes citations dans un but dexemple et dillustration, toute reprsentation ou
reproduction intgrale, ou partielle, faite sans le consentement de lauteur ou de ses ayants droit ou ayant cause, est illicite (alina 1er de larticle 40). Cette
reprsentation ou reproduction, par quelque procd que ce soit, constituerait donc une contrefaon sanctionne par les articles 425 et suivants du Code Pnal.
Copyright Editions ENI
L'objectifdecetouvrageestd'apprendredvelopperunsiteWebdynamiqueetinteractifl'aidedePHP5.
Pour rpondre cet objectif, ce livre prsente rapidement les fonctionnalits de base du langage PHP avant
d'tudierendtaillesfonctionnalitsncessairesaudveloppementd'unsiteWebdynamiqueetinteractif :
- accs aux bases de donnes, notamment MySQL, Oracle et Microsoft SQL Server ;
- gestion des sessions (authentification, gestion d'un contexte, utilisation des cookies) ;
- gestion des fichiers (dont le transfert de fichiers du poste de l'utilisateur vers le serveur "file upload").
Cet ouvrage s'adresse des chefs de projet, des concepteurs ou dveloppeurs ayant une connaissance de
base de la programmation Web en HTML (HyperText Markup Language) et quelques notions de SQL (Structured
Query Language langage standard d'accs aux bases de donnes relationnelles) pour le chapitre consacr aux
basesdedonnes.
Ce livre aborde la version 5 de PHP, les fonctionnalits nouvelles, spcifiques cette version, tant clairement
indiques.
Le langage PHP (historiquement Personal Home Page, officiellement acronyme rcursif de PHP : Hypertext
Preprocessor)atconuen1994parRasmusLerdorfpourcesbesoinspersonnels,avantd'trerendupublicau
dbutdel'anne1995.
Courant 1995, une nouvelle version, compltement rcrite, est publie sous le nom PHP/FI version 2. Cette
version, capable de grer les formulaires et d'accder la base mSQL, permet au langage de se dvelopper
rapidement.
En1997,ledveloppementdulangageestprisenchargeparunequipeautourdeRasmusLerdorfetaboutitla
sortiedelaversion3.
En 2000, l'analyseur PHP est migr sur le moteur d'analyse Zend afin d'offrir de meilleures performances et de
supporterunplusgrandnombred'extensions :c'estlaversion4dePHP.
En 2004, la version 5 voit le jour. Cette nouvelle version, base sur la version 2 du moteur Zend, apporte
plusieursnouveauts,laplupartconcernantledveloppementorientobjet.
ce jour, les analystes estiment que PHP est utilis par plus de 15 millions de sites Web dans le monde (en
nombrededomaines).
De nombreux sites Web sont consacrs au langage PHP. Ils permettent de tlcharger le langage, de consulter
desexemplesdescriptsoudedialoguersurdesforums :
Adresse Contenu
www.php.net Site officiel de PHP qui propose le tlchargement des sources
et un manuel de rfrence en ligne trs pratique. Vous pouvez
notamment saisir www.php.net/nom_fonction pour accder
directement l'aide en ligne d'une fonction PHP.
www.phpindex.com Site en franais consacr PHP qui propose le tlchargement
du langage (sources excutables Win32), des news, des
exemples ainsi qu'un forum de discussion... Bref, un site trs
complet mettre dans ses favoris.
www.phpfrance.com Autre site francophone consacr PHP proposant des rubriques
similaires, l'exception du tlchargement.
www.easyphp.org Site francophone qui propose gratuitement un produit installable
(Easy PHP) sur plate-forme Windows. Ce produit comprend : un
serveur Apache, PHP et MySQL. Vous tlchargez le produit et
double cliquez sur l'excutable qui installe les diffrents lments.
Cinq minutes aprs, votre environnement PHP est oprationnel.
Ce site est indispensable pour ceux qui souhaitent monter
rapidement une configuration oprationnelle complte sur
Windows. Les versions utilises par Easy PHP prsentent
toujours un lger retard par rapport aux dernires versions
officielles.
www.zend.com Site officiel (en anglais) du moteur de script Zend qui propose lui
aussi les rubriques classiques de tlchargement, d'exemples, de
forum...
www.editions-eni.com/ Page du site des ditions ENI sur laquelle les exemples traits
exemples/ dans cet ouvrage peuvent tre tlchargs.
Cette liste est videmment non exhaustive mais tous les sites prsents proposent de nombreux liens vers
d'autressites.N'hsitezpassurfer !
Lasyntaxedesfonctionsestdcritedelamaniresuivantedanscetouvrage :
type_retour
Typederetourdelafonction.
nom_fonction
Nomdelafonction.
type_paramtre
Typeduparamtreacceptparlafonction.
nom_paramtre
Nomdonnauparamtre.
Les types de donnes possibles seront prsents dans le chapitre 3. Dans le cas o la fonction accepte un
paramtreden'importequeltypeet/ouretourneunevaleurden'importequeltype,letermemixteestutilis.
Silafonctionneretournepasdevaleur,l'informationtype_retourestomise.
Exemple
nom_fonction(type_paramtre nom_paramtre)
Silafonctionneprendaucunparamtre,lesinformationstype_paramtreetnom_paramtresontomises.
Exemple
type_retour nom_fonction()
Lesparamtresoptionnelssontindiqusentrecrochets([ ]).
Exemple
Si la fonction accepte plusieurs paramtres, ces derniers sont indiqus, spars par une virgule, selon la mme
convention.
Exemple
Siunparamtrepeuttrerptunnombrequelconquedefois,ilestsimplementsuividelasquence[,...].
Exemple
PHP est un langage de script qui s'excute ct serveur, le code PHP tant inclus dans une page HTML
classique. Il peut donc tre compar d'autres langages de script qui fonctionnent sur le mme principe : ASP
(ActiveServerPages),JSP(JavaServerPages)ouPL/SQLServerPages(PSP).
la diffrence d'un langage comme le JavaScript, o le code est excut ct client (dans le navigateur), le
code PHP est excut ct serveur. Le rsultat de cette excution est intgr dans la page HTML qui est
envoyeaunavigateur.Cederniern'aaucuneconnaissancedel'existencedutraitementquis'estdroulsurle
serveur.
Cette technique permet de raliser des pages Web dynamiques dont le contenu peut tre compltement ou
partiellementgnraumomentdel'appeldelapage,grcedesinformationsrcupresdansunformulaireou
extraitesd'unebasededonnes.
ExemplesimpledepagePHP :
<HTML>
<HEAD>
<TITLE>Exemple de page PHP</TITLE>
</HEAD>
<BODY>
<?php
echo "Bonjour Olivier !";
?>
</BODY>
</HTML>
La partie en gras est du code PHP inclus dans la page HTML l'intrieur des balises <?php et ?>. Sur cet
exemplesimple,lecodePHPsecontented'afficheruntextestatique"BonjourOlivier !"grcelafonctionecho.
Dans un vrai programme PHP, il est probable que ce texte serait gnr dynamiquement en fonction de
l'identificationdel'utilisateur.
Pour indiquer au serveur Web qu'une page HTML contient du code PHP excuter, il suffit de donner au fichier
uneextensionparticulire :.php(saufconfigurationparticulireduserveur).
LesschmassuivantsexpliquentcommentesttraitunfichierPHPparrapportunfichierHTMLnormal.
CasdufichierHTML
DanslecasdufichierHTML,lapagedemandeestdirectementretourneaunavigateur.
CasdufichierPHP
De plus, PHP a t crit spcialement pour le Web et possde des fonctionnalits parfaitement adaptes ce
typededveloppement,cequin'estlecasnidePERLniduC(quisontparailleursd'excellentslangages).
LesbalisesPHP
Commenousl'avonsvuprcdemment,lecodePHPestinclusdansunepageHTMLl'intrieurdebalises(aussi
appelestags).
PHPacceptequatresyntaxespourlesbalises :
Lapremiresyntaxeestlasyntaxehabituelle,recommande.
La deuxime syntaxe n'est envisageable que si elle a t autorise dans le fichier de paramtrage de PHP
(php.ini) en mettant le paramtre short_open_tag on. Il est dconseill d'utiliser cette syntaxe si votre
code doit tre dploy sur un serveur dont vous ne matrisez pas la configuration et qui ne supporterait pas
cettesyntaxe.
La troisime syntaxe, plus lourde, utilise la balise standard SCRIPT elle peut tre utile si votre diteur HTML
interprtemallesautressyntaxes.
La quatrime syntaxe permet d'employer la balise ASP mais elle est envisageable uniquelent si elle a t
autorisedanslefichierdeparamtragedePHPenmettantleparamtreasp_tagson.
Dans l'exemple suivant, quatre lignes "Bonjour ..." sont affiches en utilisant les diffrentes syntaxes (en
supposantquelefichierdeparamtragedePHPestcorrectementconfigur).
<HTML>
<?php
echo "Bonjour Olivier !";
?>
<BR>
<?
echo "Bonjour Valrie !";
?>
<BR>
<script language="php">
echo "Bonjour Philippe !";
</script>
<BR>
<%
echo "Bonjour Anne !";
%>
</HTML >
Rsultat:
Bonjour Olivier !
Bonjour Valrie !
Bonjour Philippe !
Bonjour Anne !
Lafonctionecho
La fonction echo est la fonction de base de toute page PHP. Elle permet d'afficher une ou plusieurs chanes et
doncd'incluredutextedanslapageHTMLenvoyeaunavigateur.
Syntaxe :
echo(chane texte)
echo chane texte[,...]
Lapremiresyntaxen'acceptequ'unparamtrealorsqueladeuximeenaccepteplusieurs.
Exemple :
<HTML>
<?php
echo("Bonjour Olivier !");
?>
<?php
echo "Bonjour ","Valrie ", "!";
?>
</HTML>
Rsultat :
Iln'ypasdesautdeligneautomatiquedanslersultatdel'excutionducodePHP.Encasdebesoin,ilestdonc
ncessaired'insrerlabaliseHTML<BR>quiprovoqueunsautdelignedanslapageHTMLfinale.
<HTML>
<?php
echo("Bonjour Olivier !");
?>
<BR>
<?php
echo "Bonjour ","Valrie ", "!";
?>
</HTML>
Rsultat :
Bonjour Olivier !
Bonjour Valrie !
Le texte pass en paramtre la fonction echo peut tre crit sur plusieurs lignes dans le source mais il est
affichsuruneseuledanslersultat :
Exemple :
<HTML>
<?php
echo "Bonjour
Olivier ", "!";
?>
</HTML>
Rsultat :
Bonjour Olivier !
Lesparateurd'instructions
Exemple:
<HTML>
<?php
echo("Bonjour ");
echo("Olivier !");
?>
Rsultat:
Bonjour Olivier !
Encasd'omission,uneerreurestgnre.
Exemple:
<HTML>
<?php
echo("Bonjour ")
echo("Olivier !");
?>
</HTML>
Rsultat:
Parse error: parse error, unexpected T_ECHO, expecting ',' or ';' in d:\scripts php\index.php
on line 4
La seule exception concerne l'instruction qui prcde la balise de fin pour laquelle le pointvirgule peut tre
omis.
Exemple:
<HTML>
<?php
echo("Bonjour ");
echo("Olivier !")
?>
</HTML>
Rsultat:
Bonjour Olivier !
Il est conseill de systmatiquement mettre le point-virgule, mme sur la dernire instruction. En effet, lors d'une modification
du code, il est possible que cette instruction ne soit plus la dernire ; il est alors frquent d'oublier de lui ajouter le point-virgule.
Plusieurs instructions peuvent tre crites sur la mme ligne partir du moment o elles sont spares par un
pointvirgule.Nanmoins,cettecriturenuitparfoislalisibilitducode.
Exemple:
<HTML>
<?php
echo("Bonjour "); echo("Olivier !");
?>
</HTML>
Rsultat:
Bonjour Olivier !
Lecommentaire
PHPproposedeuxsyntaxes :
- // ou # pour insrer du commentaire sur une ligne "ddie" ou la suite d'une instruction ;
<HTML>
<?php
// commentaire sur une seule ligne
# commentaire sur une seule ligne
/* commentaire sur
plusieur lignes */
echo("Bonjour "); // commentaire jusqu' la fin de la ligne
echo("Olivier !"); # commentaire jusqu' la fin de la ligne
?>
</HTML>
Rsultat:
Bonjour Olivier !
Lescommentaires/*...*/nedoiventpastreimbriqus.
Exemple:
<HTML>
<?php
/* commentaire sur
/* plusieurs lignes */
qui pose problme */
echo("Bonjour Olivier !");
?>
</HTML>
Rsultat:
MixerduPHPetdel'HTML
IlexistedenombreusesapprochespourmixerduPHPetdel'HTML.
Cesdiffrentesapprochesreposentnanmoinssurdeuxprincipestrssimples :
- Le code PHP gnre du "texte" qui est intgr dans la page HTML envoye au navigateur. Tout "texte" comprhensible
par le navigateur peut donc tre gnr par le code PHP: du texte simple, du code HTML, du code JavaScript...
LesexemplesquisuiventutilisentdesvariablesetdesfonctionsPHP(rcuprationdeladateetdel'heure).Ces
notionssontprsentesplusendtaildanslechapitre3.
<?php
// dclaration de variables qui sont utilises plus loin
// cette section de code PHP ne gnre pas de sortie dans la page
// HTML (pas d'appel la fonction echo)
$nom = "Olivier"; // nom de l'utilisateur
$titre_page = "Les ditions ENI prsentent ..."; // titre de la page
$aujourdhui = date("d/m/Y"); // date du jour
$heure = date("H:i:s"); // heure
?>
<HTML>
<HEAD>
<TITLE> <?php /* affichage du titre */ echo $titre_page; ?> </TITLE>
</HEAD>
<BODY>
<?php
/* affichage du nom de l'utilisateur
les balises de mise en gras du nom (<B>) et de retour la ligne
(<BR>) sont incluses dans la chane envoye par la fonction echo */
Rsultat:
Bonjour Olivier !
Nous sommes le 08/03/2004 ; il est 09:41:55.
Sourcedelapagedanslenavigateur(leslmentsgnrsparPHPsontengras) :
<HTML>
<HEAD>
<TITLE> Les ditions ENI prsentent ... </TITLE>
</HEAD>
<BODY>
Bonjour <B>Olivier</B> !<BR>Nous sommes le 08/03/2004 ; il est 09:41:55.</BODY>
</HTML>
Exemple de page gnre entirement par du code PHP (suivant le principe CGI):
<?php
// dclaration de variables qui sont utilises plus loin
$nom = "Olivier"; // nom de l'utilisateur
$titre_page = "Les ditions ENI prsentent ..."; // titre de la page
$aujourdhui = date("d/m/Y"); // date du jour
$heure = date("H:i:s"); // heure
// gnration des balises d'ouverture du document HTML
echo "<HTML>";
echo "<HEAD>";
echo "<TITLE> $titre_page </TITLE>";
echo "</HEAD>";
echo "<BODY>";
/* affichage du nom de l'utilisateur
les balises de mise en gras du nom (<B>) et de retour la ligne
(<BR>) sont incluses dans la chane envoye par la fonction echo */
echo "Bonjour <B>$nom</B> !<BR>";
// affichage de la date et de l'heure
echo "Nous sommes le $aujourdhui ; il est $heure.";
// gnration des balises de fermeture du document HTML
echo "</BODY>";
echo "</HTML>";
?>
Rsultat:
Bonjour Olivier !
Nous sommes le 08/03/2004 ; il est 09:52:17.
Exemple de page contenant du code PHP qui gnre du JavaScript (en gras):
<?php
// dclaration de variables qui sont utilises plus loin
$nom = "Olivier"; // nom de l'utilisateur
$titre_page = "Les ditions ENI prsentent ..."; // titre de la page
?>
<HTML>
<HEAD>
<TITLE> <?php /* affichage du titre */ echo $titre_page; ?> </TITLE>
</HEAD>
<BODY>
<?php
// gnration du code JavaScript charg de l'affichage echo
Rsultat:
Bonjour Olivier !
Nous sommes le 08/03/2004 ; il est 10:31:42.
Source de la page dans le navigateur (les lments gnrs par PHP sont en gras):
<HTML>
<HEAD>
<TITLE> Les ditions ENI prsentent ... </TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
aujoudhui = new Date()
document.write('Bonjour <B>Olivier</B> !<BR>')
document.write('Nous sommes le ')
document.write(aujoudhui.getDate(),'/')
document.write(aujoudhui.getMonth()+1,'/')
document.write(aujoudhui.getYear(),' ;')
document.write('il est ')
document.write(aujoudhui.getHours(),':')
document.write(aujoudhui.getMinutes(),':')
document.write(aujoudhui.getSeconds(),'.')
</SCRIPT>
</BODY>
</HTML>
Surcedernierexemple,c'estlecodeJavaScript,excutdanslenavigateur,quiprovoquel'affichagedursultat
danslapageHTML.
Il n'y a pas de rgle pour mixer du PHP et de l'HTML. Une approche couramment employe par les dveloppeurs consiste
utiliser PHP uniquement pour gnrer la partie rellement dynamique de la page ; le reste est directement crit en HTML dans
le fichier. Cette technique rend le code moins lourd et permet de voir tout de suite o se trouve la logique applicative.
Directivesdeconfiguration
Toutaulongdecetouvrage,nousrencontreronsplusieursdirectivesdeconfigurationutilisablespourmodifierle
comportementdePHP.
CesdirectivesdeconfigurationsontsaisiesdanslefichierdeparamtragedePHP(php.ini).
PHPfournitdeuxexemplesdefichiersphp.ini :php.ini-distetphp.ini-recommended.
Le fichier php.ini-dist est un exemple de fichier de configuration, plutt destin tre utilis dans un
environnementdedveloppement.l'inverse,lefichierphp.ini-recommendedestpluttdestintreemploy
dansunenvironnementd'exploitation ilcontientdesrglagesquirendentPHPplusscuriset/ouperformant.
Ces deux fichiers prsentent beaucoup de commentaires qui expliquent le rle de chaque directive et donnent
desconseilssurleurusage.
Pour utiliser un de ces fichiers, copiezle l'emplacement appropri sur votre plateforme
(normalement /usr/local/lib sous Linux/Unix et c:\windows ou c:\winnt sous Windows) et renommezle en
php.ini.
display_errors = on
Leserreurssontaffiches.
error_reporting =
E_ALL & ~E_NOTICE
Toutesleserreurssontaffiches,saufleserreursdeniveau E_NOTICE(simplesinformations,parexemplelorsde
l'utilisationd'unevariablenoninitialise).
Lagestiondeserreursesttraiteendtaildanslechapitre12.
Informationssurlaconfiguration
PHP propose deux fonctions particulirement utiles pour obtenir des informations sur la configuration :
phpversionetphpinfo.
La fonction phpversion retourne le numro de version de PHP et la fonction phpinfo affiche une grande
quantitd'informationssurlaconfigurationdePHPetsonenvironnement.
Syntaxe
chane phpversion()
entier phpinfo([entier quoi])
Avec
quoi
Naturedel'informationdsire.Utiliseruneouplusieurs(somme)desconstantessuivantes :
INFO_GENERAL (1) : informations gnrales (version, emplacement du fichier php.ini, systme d'exploitation,
etc.)
INFO_CREDITS (2) :informationssurlesauteurs.
INFO_CONFIGURATION (4) :informationssurlaconfiguration(valeursdesdirectives).
INFO_MODULES (8) :informationssurlesmoduleschargs,avecleurconfigurationrespective.
INFO_ENVIRONMENT (16) :informationssurl'environnement(voirlavariable$_ENVenannexe).
INFO_VARIABLES (32) :valeursdetouteslesvariablesprdfinies(voirl'annexe).
INFO_LICENSE (64) :informationssurlalicence.
INFO_ALL (-1) :touteslesinformations(valeurpardfaut).
phpinforetourneTRUEencasdesuccsetFALSEencasd'erreur.
Exemple 1:
<?php
echo phpversion();
?>
Rsultat:
5.0.0RC2
Exemple 2:
<?php
// informations gnrales et informations
// de licence
phpinfo(INFO_GENERAL+INFO_LICENSE);
?>
Exemple 3:
<?php
// toutes les informations
phpinfo();
?>
Voir aussi les fonctions ini_get_all, ini_get et get_loaded_extensions qui permettent d'obtenir des informations
sur les directives de compilation et les extensions charges.
UtiliserPHPenlignedecommande
Depuislaversion4.3,PHPpeuttreutilisenlignedecommande.Cemodedefonctionnementnencessitepas
deserveurWebetconvientparexempleaudveloppementdesscriptsd'administration.
Avec
options
Optionsdelalignedecommande(parexemple,-hpourobtenirl'aide,-vpourlaversion,etc.)
script
FichiercontenantlecodePHPexcuter.
Exemples
C:\>php -v
PHP 5.0.0RC2 (cli) (built: Apr 25 2004 12:14:44)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v2.0.0RC2, Copyright (c) 1998-2004 Zend Technologies
Contenuduscriptscript.php :
<?php
// afficher un simple message
// en utilisant le paramtre
// pass sur la ligne de commande
echo "Bonjour $argv[1] !";
?>
TouteentitPHPnomme(variable,constante,fonction...)doitavoirunnomquirespectelesrglessuivantes :
Danscettedfinition,unelettrereprsentetoutelettreminusculeoumajusculecompriseentreaetz(azet
A Z) ainsi que tout caractre de code ASCII compris entre 127 et 255. Les caractres accentus sont donc
autoriss,maispaslescaractresdutype#$%&quiontunesignificationspcialedanslelangagePHP.
Dfinition
Lafonctiondefinepermetdedfiniruneconstante.
Une constante est une zone mmoire identifie par un nom qui contient une valeur lisible mais non modifiable
dansleprogramme.
Syntaxe
nom
Nomdelaconstante(cf.chapitreVued'ensembledePHPRglesdenommage).
valeur
Valeurdelaconstante.
sensible_casse
Indiquesilenomdelaconstanteestsensiblelacasse(TRUEvaleurpardfaut)ounon(FALSE).
LafonctiondefineretourneTRUEencasdesuccsetFALSEencasd'erreur.
Touttypededonnescalaire(cf.Typesdedonnesdanscechapitre)peuttreutiliscommetypededonne
d'uneconstante.
Le nom d'une constante ne doit pas commencer par un $ car ce prfixe est rserv au nom des variables (cf.
Variables dans ce chapitre). Dfinir une constante dont le nom commence pas un $ ne gnre pas d'erreur
(defineretourneTRUE).Cependant,l'utilisation,laconstanteseravuecommeunevariablenoninitialise.
Exemples
<?php
// dfinir une constante (dont le nom est par dfaut
// sensible la casse)
define("CONSTANTE","valeur de CONSTANTE");
// afficher la valeur de CONSTANTE (=> OK)
echo "CONSTANTE = ",CONSTANTE,"<BR>";
// afficher la valeur de constante (=> vide)
echo "constante = ",constante;
echo " => interprt en littral<BR>";
// tentative de modification de CONSTANTE
define("CONSTANTE","nouvelle valeur de CONSTANTE");
echo "CONSTANTE = ",CONSTANTE;
echo " => inchange<BR>";
// utilisation d'un mauvais nom de constante
define($MAUVAISNOM,"mauvais nom de constante");
echo "\$MAUVAISNOM = ",$MAUVAISNOM;
echo " => c'est une variable (non initialise)<BR>";
?>
Rsultat
Traditionnellement,lesnomsdesconstantessontdfinisenmajuscules.
Utiliser une constante non dfinie (ou une variable non initialise) ou tenter de redfinir une constante dj
dfinie gnre une erreur de niveau E_NOTICE. Le niveau d'erreur effectivement signal par PHP dpend de
directivesdeconfigurationdanslefichier php.ini(voirlechapitre12).Lersultatprcdentcorrespondune
configuration dans laquelle les erreurs de niveau E_NOTICE ne sont pas affiches dans le cas contraire, nous
obtiendrionslersultatsuivant :
Rsultat
Porte
La porte d'une constante est le script dans lequel elle est dfinie. Une constante peut donc tre dfinie dans
unepremiresectiondecodePHPetutilisedansuneautresectiondecodePHPdummescript.
Exemple
<?php
// dfinir une constante
define("NOM","Olivier");
?>
<HTML>
<BODY>
Bonjour <B><?php echo NOM; ?></B> !
</BODY>
</HTML>
Rsultat
Bonjour Olivier !
Fonctionsutiles
Lafonctiondefinedpermetdesavoirsiuneconstanteestdfinieounon.
Syntaxe
nom Nomdelaconstante
definedretourneTRUEsilaconstanteestdfinieetFALSEdanslecascontraire.
Exemple
<?php
// tester si la constante CONSTANTE est dfinie
$ok = defined("CONSTANTE");
Rsultat
Cet exemple utilise la structure de contrle if qui permet de tester une condition et d'agir en consquence (cf. chapitre
Structures de contrle).
Lafonctionconstantretournelavaleurd'uneconstantedontlenomestpassenparamtre.
Syntaxe
Avec
nom Nomdelaconstante.
Cettefonctionestpratiquepourrcuprerlavaleurd'uneconstantedontlenomn'estpasconnuapriori.
Exemple
<?php
// dfinir le nom de la constante dans une variable
$nomConstante = "CONSTANTE";
// dfinir la valeur de la constante
define($nomConstante,"valeur de CONSTANTE");
// afficher la valeur de la constante
echo $nomConstante," = ",constant($nomConstante);
?>
Rsultat
D'autres fonctions permettent de connatre le type d'une constante (cf. Chapitre Constantes Fonctions
utiles).
Une variable est une zone mmoire identifie par un nom qui contient une valeur lisible ou modifiable dans le
programme.
Initialisationetaffectation
En PHP, les variables sont identifies par le prfixe $ suivi d'un nom qui respectent les rgles de nommage
prsentesdanslechapitre2.
Le nom des variables est sensible la casse : $nom et $Nom sont vues par PHP comme deux variables
diffrentes. Ce comportement est dangereux car, en cas d'utilisation d'une mauvaise syntaxe, une nouvelle
variable vide est cre avec une simple erreur de niveau E_NOTICE qui n'est pas forcment affiche (voir le
chapitreGrerleserreursdansunscriptPHP).Ilestdoncprimordiald'adopteruneconventiondenommageetde
larespecter.Quelquessuggestions :
Les variables PHP sont automatiquement dfinies lors de leur premire utilisation. Il n'y a pas d'instruction
spcifiquepourcrerunevariable.
LesvariablesPHPsonttypesautomatiquement lorsdechaqueaffectationd'unevaleurunevariable,letype
delavariableestautomatiquementdfiniouredfini(cf.Typesdedonnes).
Une valeur peut tre affecte une variable grce l'oprateur d'affectation "= " (cf. chapitre Oprateurs pour
lalistedetouslesoprateurs).
Exemple
<?php
// initialiser une variable $nom
$nom = "Olivier";
// afficher la variable $nom
echo "\$nom = ",$nom,"<BR>";
// afficher la variable $Nom
echo "\$<B>N</B>om = ",$Nom;
echo " => vide (c'est une autre variable)<BR>";
// modifier la valeur (et le type) de la variable $nom
$nom = 123;
// afficher la variable $nom
echo "\$nom = ",$nom,"<BR>";
?>
$nom = Olivier
$Nom = => vide (c'est une autre variable)
$nom = 123
Tout au long de cet ouvrage, nous aurons l'occasion de rencontrer des variables automatiquement dfinies par PHP et
contenant des valeurs relatives l'environnement, PHP, aux formulaires, aux cookies...
Porteetduredevie
La porte d'une variable est le script dans lequel elle est dfinie. Une variable peut donc tre dfinie dans une
premiresectiondecodePHPetutilisedansuneautresectiondecodePHPdummescript.
La dure de vie d'une variable est le temps de l'excution du script. Lorsque le script se termine, les variables
sontsupprimes.Silemmescriptestappelplustard,denouvellesvariablessontdfinies.
<?php
// afficher le contenu de la variable $nom
echo "\$nom = ",$nom,"<BR>";
// initialiser la variable $nom
$nom = "Olivier";
// afficher de nouveau le contenu de la variable $nom
echo "\$nom = ",$nom,"<BR>";
?>
$nom =
$nom = Olivier
$nom =
$nom = Olivier
Entre les deux appels, la variable a t supprime. Au dbut du deuxime appel, elle ne contient plus la valeur
qu'ellepossdaitlafindupremierappel(cen'estpluslammevariable).
Nous verrons dans le chapitre 9 comment conserver la valeur d'une variable au-del de l'excution du script ou comment
transmettre la valeur d'une variable d'un script un autre.
Fonctionsutiles
PHPproposeuncertainnombredefonctionsutilessurlesvariables :
Nom Rle
empty Indique si une variable est vide ou non.
isset Indique si une variable est dfinie ou non.
unset Supprime une variable.
var_dump Affiche des informations sur une variable (type et valeur).
empty
Lafonctionemptypermetdetestersiunevariableestvideounon.
Syntaxe
variable Variabletester
emptyretourneTRUEsilavariableestvideetFALSEdanslecascontraire.
Unevariableestconsidrecommevidesiellen'apastaffecteousiellecontientunechanevide(""),une
chanegale0("0")ou0.
Exemple
<?php
// test d'une variable non initialise
$vide = empty($variable);
echo "\$variable = ",$variable,"<BR>";
if ($vide) {
echo "=> \$variable est vide.<BR>";
} else {
Rsultat
$variable =
=> $variable est vide.
$variable =
=> $variable est vide.
$variable = 0
=> $variable est vide.
$variable = 0
=> $variable est vide.
$variable = x
=> $variable n'est pas vide.
$variable = 1
=> $variable n'est pas vide.
isset
Lafonctionissetpermetdetestersiunevariableestdfinieounon.
Syntaxe
variable Variabletester
Exemple
<?php
// test d'une variable non initialise
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// test d'une variable contenant une chane vide
$variable = "";
$dfinie = isset($variable);
echo "\$variable = ",$variable,"
";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// test d'une variable contenant une chane gale 0
$variable = "0";
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// test d'une variable contenant 0
$variable = 0;
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// test d'une variable contenant une chane non vide
$variable = "x";
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// test d'une variable contenant une valeur diffrente de 0
$variable = 1;
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
?>
Rsultat
$variable =
=> $variable n'est pas dfinie.
$variable =
=> $variable est dfinie.
$variable = 0
=> $variable est dfinie.
$variable = 0
=> $variable est dfinie.
$variable = x
=> $variable est dfinie.
unset
Lafonctionunsetpermetdesupprimerunevariable.
Syntaxe
variable Variablesupprimer(ventuellementplusieurs,sparesparunevirgule).
unsetaccepteunelistedevariables.
Aprssuppression,lavariablesetrouvedanslemmetatquesiellen'avaitjamaistaffecte.L'utilisationde
lafonctionissetsurunevariablesupprimeretourneFALSEnotamment.
Exemple
<?php
// dfinir une variable
$variable = 1;
// afficher la variable et tester si elle est dfinie
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
// supprimer la variable
unset($variable);
// afficher la variable et tester si elle est dfinie
$dfinie = isset($variable);
echo "\$variable = ",$variable,"<BR>";
if ($dfinie) {
echo "=> \$variable est dfinie.<BR>";
} else {
echo "=> \$variable n'est pas dfinie.<BR>";
}
?>
Rsultat
$variable = 1
=> $variable est dfinie.
$variable =
=> $variable n'est pas dfinie.
var_dump
Lafonctionvar_dumpaffichedesinformationssurunevariable(typeetcontenu).
Syntaxe
var_dump(mixte variable)
variable Variableafficher.
Lafonctionvar_dumpestsurtoutintressantelorsdesphasesdemiseaupoint.
Exemple
Rsultat
NULL
int(10)
float(3.14)
string(3) "abc"
Pour une variable non initialise, var_dump retourne NULL. Pour un nombre, var_dump indique le type (int =
entier,float=nombredcimal)suividelavaleurentreparenthses.Pourunechane,var_dumpindiqueletype
(string)suividelalongueurentreparenthses,suiviedelavaleurentreguillemets.
PHPproposeaussilesfonctionsprint_retvar_exportsemblableslafonctionvar_dump.Lafonctionprint_r
affiche ou retourne le contenu de la variable sous une forme plus lisible, sans mention du type de donnes. La
fonction var_export affiche ou retourne une chane donnant un code PHP de dfinition de la variable cette
fonctionestnouvelleenversion5.
Dans la section C - Types de donnes de ce chapitre, nous tudierons d'autres fonctions qui permettent de dterminer le type
d'une variable et d'effectuer des conversions de type (nombre en chane, chane en nombre...).
Variabledynamique(ouvariablevariable)
PHP propose une fonctionnalit de variable dynamique (aussi appele variable variable) utile dans certaines
situations.
Leprincipeconsisteemployerunevariablequistockelenomd'uneautrevariableetd'yfairerfrenceensuite
avecunenotation,dutype$$variableou${$variable}.Aveccettenotation,le$variable"intrieur"estremplac
par la valeur de la variable $variable (valeur par exemple) qui est alors utilise comme nom de variable par le $
"extrieur"(soit$valeursurnotreexemple).
Exemple
<?php
$une_variable = 10;
$nom_variable = "une_variable";
echo "\$une_variable = ",$une_variable,"<BR>";
echo "\$nom_variable = ",$nom_variable,"<BR>";
echo "\$\$nom_variable = ",$$nom_variable,"<BR>";
?>
Rsultat
$une_variable = 10
$nom_variable = une_variable
$$nom_variable = 10
Typesdisponibles
PHP propose 4 types de donnes scalaires (ne pouvant contenir qu'une valeur), 2 types composs (pouvant
contenirplusieursvaleurs) et2typesspciaux:
- Types scalaires :
- nombre entier ;
- chane de caractre ;
- boolen
- Types composs :
- Types spciaux :
- NULL ;
- Ressource.
Entier
Letypeentier(integer)permetdestockerunnombreentiersignsur32bits,soitdesvaleurscomprisesentre
2147483648(2^31)et+2147483647(+2^311).
En cas de dpassement de capacit dans un calcul, le rsultat est automatiquement converti en nombre
virguleflottante.
Nombrevirguleflottante
Le type nombre virgule flottante (float) permet de stocker un nombre dcimal sur une plage de valeurs
dpendantedelaplateforme(gnralementdel'ordrede10308 10+308 ).
Un tel nombre peut tre exprim en notation dcimale x.y (par exemple 123.456) ou en notation scientifique
x.yEzoux.yez(parexemple1.23456E2).
Encasdeconversiond'unnombrevirguleflottanteenentier,lenombreesttronqu(pasarrondi)l'entierle
plusproche(1.9donne1parexemple).Encasdedpassementdecapacit,aucunmessagen'estaffich,mais
lavaleurl'arriveestindfinie(frquemment 0).
Des librairies particulires (aussi appeles Bibliothques) sont proposes par PHP pour traiter les nombres de grande taille
(librairies BC ou GMP).
Chanedecaractres
Letypechanedecaractres(string)permetdestockertoutesquencedecaractressurunoctet(codeASCII
comprisentre0et255),sanslimitedetaille.
Les guillemets prsents dans une chane dlimite par des guillemets ou les apostrophes prsents dans une
chanedlimitepardesapostrophesdoiventtre"chapps",c'estdireprcdsducaractreantislash(\).
En complment, un antislash prsent en fin de chane, juste avant le guillemet ou l'apostrophe finaux, doit lui
aussitrechappparunantislash.
Exemple
<?php
echo "c'est l't => pas de problme.<BR>";
echo 'je dis "bonjour" => pas de problme.<BR>';
// echo 'c'est l't => erreur de compilation.<BR>';
echo 'c\'est l\'t => problme corrig.<BR>';
// echo "je dis "bonjour" => erreur de compilation.<BR>";
echo "je dis \"bonjour\" => problme corrig.<BR>";
// echo "c:\"," => erreur de compilation.<BR>";
echo "c:\\"," => problme corrig.<BR>";
// echo 'c:\'," => erreur de compilation.<BR>";
echo 'c:\\'," => problme corrig.<BR>";
?>
Rsultat
Unechanepeuttresaisiesurplusieurslignes.
Exemple :
<?php
$chane = "Je m'appelle Olivier
et j'habite en France.";
echo $chane;
?>
Je m'appelle Olivier
et j'habite en France.
Le retour la ligne prsent dans la chane initiale est retrouv dans le source de la page, mais n'est pas
interprt comme tel par le navigateur. Il faut une balise <BR> pour obtenir un retour ligne dans le rsultat
affich.
Exemple :
<?php
$chane = "Je m'appelle Olivier<BR>
et j'habite en France.";
echo $chane;
?>
Je m'appelle Olivier
Lorsqu'unechaneestdlimitepardesguillemets,toutesquencedecaractrescommenantparlesigne$est
interprtecommeunevariableetremplaceparlavaleurdelavariable :c'estlemcanismedesubstitutiondes
variables par leur valeur. Cette fonctionnalit, trs pratique, ne fonctionne pas avec les chanes dlimites par
desapostrophes(premirediffrenceentrelesdeuxtypesdechanes).
Exemple
<?php
$nom = "Olivier";
echo "Je m'appelle $nom.<BR>";
echo "... est plus simple crire que<BR>";
echo "Je m'appelle ",$nom,".<BR>";
echo "... et donne le mme rsultat.<BR>";
echo 'Je m\'appelle $nom, par contre ne fonctionne pas.<BR>';
?>
Rsultat
Je m'appelle Olivier.
... est plus simple crire que
Je m'appelle Olivier.
... et donne le mme rsultat.
Je m'appelle $nom, par contre ne fonctionne pas.
Danscertainscas,cecomportementpeutnepastredsir.Ilsuffitd'chapperlesigne$avecl'antislash (\)
pourqu'ilsecomportecommeun$.
Exemple
<?php
$nom = "Olivier";
echo "\$nom = $nom";
?>
Rsultat
$nom = Olivier
Dans d'autres cas, le comportement peut tre souhait avec le besoin d'accoler du texte complmentaire
derrirelenomdelavariable.
Exemple
<?php
$fruit = "pomme";
echo "Une $fruit ne cote pas cher.<BR>";
echo "Deux $fruits cotent deux fois plus cher.<BR>";
?>
Rsultat
Surcetexemple,le"s"duplurielestinterprtparPHPcommeappartenantlasquencedecaractressitue
derrire le $ c'est donc la variable $fruits qui est reconnue et remplace par sa valeur (vide puisque la
variablen'ajamaistinitialise).
La solution consiste dlimiter le nom de la variable par des accolades sous la forme {$variable} ou
${variable}. L encore, si cette interprtation de l'accolade n'est pas souhaite, il est possible d'utiliser la
caractred'chappementantislashdevantlapremireaccoladeuniquement.
Exemple
<?php
Rsultat
Il n'y a pas de mcanisme de substitution quivalent pour les constantes ; c'est une raison valable pour utiliser des variables
en lieu et place de vraies constantes.
En complment, d'autres squences d'chappement peuvent tre utilises dans les chanes dlimites par des
guillemets, mais pas dans celles dlimites par des apostrophes (deuxime diffrence entre les deux types de
chanes).
Squence Valeur
\n Saut de ligne (= LF = code ASCII 10)
\r Retour chariot (= CR = code ASCII 13)
\t Tabulation (= HT = code ASCII 9)
\\ \ (dj abord)
\$ $ (dj abord)
\nnn Le caractre dsign par le code ASCII nnn exprim en octal
Exemple
<?php
echo "Je m'appelle Olivier.<BR>\n";
echo "Je m'appelle \117\154\151\166\151\145\162.";
?>
Rsultat
Je m'appelle Olivier.
Je m'appelle Olivier.
Rappel : un saut de ligne dans le source de la page envoye au navigateur ne provoque pas de saut de ligne dans la page
affiche. C'est le cas de la squence "\n" utilise dans notre exemple. Ici la balise <BR> provoque le retour la ligne dans la
page affiche.
PHPestcapabledeconvertirunechaneennombre(entieroudcimal)l'aidedesrglessuivantes :
- Si le premier caractre non "blanc" (autre que espace, tabulation, LF, CR) n'est ni un chiffre, ni un point ni le signe
"moins", la chane est value 0 (entier).
- Dans le cas contraire, PHP va extraire tous les caractres non "blancs" du dbut de chane jusqu' rencontrer un
caractre non numrique (c'estdire non compris entre 1 et 9, diffrent du point, du signe "moins" et du symbole
scientifique "e" ou "E"); la squence ainsi obtenue est convertie en entier (pas de point ni de symbole scientifique) ou
en dcimal (en cas de prsence d'un point ou du symbole scientifique).
Exemple
<?php
echo '1 + "1" = ',var_dump(1 + "1"),"<BR>";
echo '1 + "1.5" = ',var_dump(1 + "1.5"),"<BR>";
echo '1 + "1.5E2" = ',var_dump(1 + "1.5E2"),"<BR>";
echo '1 + "1e3" = ',var_dump(1 + "1e3"),"<BR>";
Rsultat
1 + "1" = int(2)
1 + "1.5" = float(2.5)
1 + "1.5E2" = float(151)
1 + "1e3" = float(1001)
1 + 1abc = int(2)
1 + "1.5abcd" = float(2.5)
1 + "1.5 abcd" = float(2.5)
1 + ".5" = float(1.5)
1 + "-5" = int(-4)
1 + " \t\n\r 5" = int(6)
1 + "abc1" = int(1)
Le dernier exemple montre qu'une chane qui ne commence pas par un caractre numrique est convertie en
entiergal0.
Ces mcanismes de conversion se rvlent pratiques dans certains cas mais peuvent galement conduire des
problmesdifficilesdtectercarPHPrefusepeudechoselacompilationduscript !
Il est possible d'accder au nime caractre d'une chane grce la notation $x{i} (ou $x[i] pour la compatibilit
ascendante), $x dsignant la variable de type chane et i le numro du caractre (le premier caractre portant le numro 0).
Boolen
Letypeboolen(boolean)peutprendredeuxvaleurs:TRUE(outrue)etFALSE(oufalse).
Ce type de donnes est principalement utilis dans les structures de contrle pour tester une condition (cf.
chapitreStructuresdecontrle).
PHPestcapabledeconvertirtouttypededonneenboolenselonlesrglessuivantes :
Inversement,PHPestcapabled'oprerlesconversionssuivantes :
TRUE FALSE
Boolen -> Nombre 1 0
Boolen -> Chane "1" "" (chane vide)
Compte tenu de la logique de conversion indique prcdemment, toute variable peut tre teste en tant que
boolen (PHP se chargeant de la conversion). Ce fonctionnement est souvent pratique mais peut facilement
conduiredeserreursdlicatesdceler.
Ce type, introduit dans PHP 4, est un peu particulier et correspond au type d'une variable utilise sans jamais
avoirtinitialise.Ilpossdeuneseulevaleur,lavaleurNULLdfinieparlaconstanteNULL(ounull).
Encasdeconversionenboolen,NULLprendlavaleurFALSE.
Exemple
<?php
var_dump($variable_non_dfinie);
?>
Rsultat
NULL
Letyperessource(resource)
Ce type gnrique, introduit dans PHP 4, est un peu particulier, et correspond une rfrence vers une
ressourceexterne :fichierouvert,connexiondebasededonnes,etc.
plusieurs reprises dans cet ouvrage, nous aurons l'occasion de prsenter des fonctions qui permettent de
manipulercesdonnesdetyperessource.
Conversions
PHPestcapabled'effectuerdesconversionsautomatiquesimplicitesdetype,selonlesrglesprsentesdansle
soustitreprcdentTypesdisponibles.
Lorsqu'unevaleur/expressionestaffecteunevariable,lavariabledevientdutypedelavaleur/expression.
Pour dterminer le type d'une expression compose d'oprandes de types diffrents, PHP value (mais ne
convertit pas) les oprandes en fonction des oprateurs traits dans l'ordre de prcdence (cf. chapitre
Oprateurs Prcdence des oprateurs). Par exemple, les deux oprandes utiliss dans une addition sont
valusennombrealorsquedeuxoprandesutilissavecl'oprateurdeconcatnation(cf.chapitreOprateurs
L'oprateurdechane)sontvalusenchane.
Exemple
<?php
$nombre = 123;
$chane = "456abc";
echo '$nombre + $chane = ';
var_dump($nombre + $chane);
echo '<BR>';
echo '$nombre . $chane = ';
var_dump($nombre . $chane);
echo '<BR>';
echo '$nombre = ';
var_dump($nombre);
echo '<BR>';
echo '$chane = ';
var_dump($chane);
?>
Rsultat
Surlepremierexemple,lavariable$chaneestvalueennombrepourtredutypeattenduparl'oprateur"+"
Encomplment,PHPproposeunenotationetunefonctionpoureffectueruneconversionmanuelleexplicite.
Notation
La notation consiste indiquer le nom du type souhait entre parenthses devant l'expression convertir. Les
valeursautorisessontlessuivantes :
Notation Conversion en
(int) ou (integer) entier
(bool) ou (boolean) boolen
(real), (double) ou (float) nombre virgule flottante
(string) chane
(array) tableau
(object) objet
Exemple
<?php
echo '(float)"1abc" = ',var_dump((float)"1abc"),"<BR>";
echo '(float)"1.5abc" = ',var_dump((float)"1.5abc"),"<BR>";
echo '(float)"abc1" = ',var_dump((float)"abc1"),"<BR>";
echo '(int)1.7 = ',var_dump((int)1.7),"<BR>";
echo '(int)TRUE = ',var_dump((int)TRUE),"<BR>";
echo '(int)FALSE = ',var_dump((int)FALSE),"<BR>";
echo '(bool)-1 = ',var_dump((bool)-1),"<BR>";
echo '(bool)0 = ',var_dump((bool)0),"<BR>";
echo '(bool)1 = ',var_dump((bool)1),"<BR>";
echo '(bool)"" = ',var_dump((bool)""),"<BR>";
echo '(bool)"0" = ',var_dump((bool)"0"),"<BR>";
echo '(bool)"1" = ',var_dump((bool)"1"),"<BR>";
echo '(bool)"a" = ',var_dump((bool)"a"),"<BR>";
?>
Rsultat
(float)"1abc" = float(1)
(float)"1.5abc" = float(1.5)
(float)"abc1" = float(0)
(int)1.7 = int(1)
(int)TRUE = int(1)
(int)FALSE = int(0)
(bool)-1 = bool(true)
(bool)0 = bool(false)
(bool)1 = bool(true)
(bool)"" = bool(false)
(bool)"0" = bool(false)
(bool)"1" = bool(true)
(bool)"a" = bool(true)
Cesdiffrentsexemplespermettentderetrouverlesrglesdeconversionvoquesprcdemment.
Fonctiondeconversion
Lafonctionsettypepermetdeconvertirunevariabled'untypeunautre.
Syntaxe
variable
type
Typesouhaitenutilisantunedesvaleurs suivantes:
booleanoubool(conversionenboolen)
integerouint(conversionenentier)
doubleoufloat(conversionennombrevirguleflottante)
string(conversionenchanedecaractres)
array(conversionentableau)
object(conversionenobjet)
settyperetourneTRUEencasdesuccsetFALSEencasd'erreur.
Exemple
<?php
$x = "1abc";
settype($x,"integer");
echo "\"1abc\" converti en entier = ",var_dump($x),"<BR>";
$x = 1.7;
settype($x,"integer");
echo "1.7 converti en entier = ",var_dump($x),"<BR>";
$x = TRUE;
settype($x,"string");
echo "TRUE converti en chane = ",var_dump($x),"<BR>";
$x = "0";
settype($x,"boolean");
echo "\"0\" converti en boolen = ",var_dump($x),"<BR>";
$x = -1;
settype($x,"boolean");
echo "-1 converti en boolen = ",var_dump($x),"<BR>";
?>
Rsultat
En rgle gnrale, il est conseill de choisir la conversion explicite : le code est plus lisible, plus facile maintenir et mettre
au point.
Fonctionsutiles
Encomplment,PHPproposeplusieursfonctionsutilesrelativesautypedesvariables :
Nom Rle
is_* indique si la variable est du type donn par * :
array = tableau ;
bool = bool en ;
double, float, real = nombre virgule flottante ;
int, integer, long = entier ;
null = type NULL ;
numeric = entier ou nombre virgule flottante ou cha ne
contenant un nombre (entier ou d cimal) ;
object = objet ;
string = cha ne ;
ressource = ressource ;
scalar = type scalaire.
strval Convertit une variable en cha ne.
is_double Convertit une variable en nombre virgule flottante.
floatval
is_*
Lafonctionis_*permetdetestersiunevariableestd'untypedonn.
Syntaxe
variable Variabletester
Lesdclinaisonssontlessuivantes :
LafonctionretourneTRUEsilavariableestdutypedemandetFALSEdanslecascontraire.
Exemple
<?php
if (is_null($x)) {
echo "Pour l'instant, \$x est du type NULL.<BR>";
}
$x = (1 < 2);
if (is_bool($x)) {
echo "\$x = (1 < 2) est du type boolen.<BR>";
}
$x = "123abc";
if (is_string($x)) {
echo "\$x = \"123abc\" est du type chane ...<BR>";
}
if (is_numeric($x)) {
echo "... mais aussi est du << type >> <I>numeric</I>.<BR>";
} else {
echo "... mais pas du "type" <I>numeric</I>.<BR>";
}
$x = "1.23e45";
if (is_numeric($x)) {
echo "Par contre, \$x = \"1.23e45\" est du << type >>
<I>numeric</I>.<BR>";
}
?>
Rsultat
Surcetexemple,lafonction is_numericn'appliquepastoutfaitlesmmesrglespourvaluersiunechane
contient un nombre que celles utilises pour la conversion. Avec la fonction is_numeric, la chane ne doit
conteniraucuncaractrenonnumrique.
strval
Lafonctionstrvalretournelavaleurd'unevariableaprsconversionenchane.
Syntaxe
variable Variabletraiter.
Cettefonctionnes'appliquequ'auxvariablesdetypescalaire(nonvalablepourlestableaux,nilesobjets).
Letypedelavariableresteinchang.
Exemple
<?php
$x = TRUE;
echo var_dump($x)," => ",var_dump(strval($x)),"<BR>";
$x = 1.23e45;
echo var_dump($x)," => ",var_dump(strval($x)),"<BR>";
?>
Rsultat
floatval(oudoubleval)
La fonction floatval retourne la valeur d'une variable aprs conversion en nombre virgule flottante. La
fonctiondoublevalestunaliasdelafonctionfloatval.
Syntaxe
variable Variabletraiter.
Cette fonction ne s'applique qu'aux variables de type scalaire (non valable pour les tableaux, ni les objets). Le
typedelavariableresteinchang.
Exemple
<?php
$x = TRUE;
echo var_dump($x)," => ",var_dump(floatval($x)),"<BR>";
$x = 123;
echo var_dump($x)," => ",var_dump(floatval($x)),"<BR>";
$x = "1.23e45";
echo var_dump($x)," => ",var_dump(floatval($x)),"<BR>";
$x = "123abc";
echo var_dump($x)," => ",var_dump(floatval($x)),"<BR>";
$x = " \n\t\r 123.45abc";
echo var_dump($x)," => ",var_dump(floatval($x)),"<BR>";
?>
Lesrglesdeconversionvoquesprcdemmentsontrespectes.
intval
Lafonctionintvalretournelavaleurd'unevariableaprsconversionenentier.
Syntaxe
Variable Variabletraiter
Cettefonctionnes'appliquequ'auxvariablesdetypescalaire(nonvalablepourlestableaux,nilesobjets).
Letypedelavariableresteinchang.
Exemple
<?php
$x = TRUE;
echo var_dump($x)," => ",var_dump(intval($x)),"<BR>";
$x = 123.9;
echo var_dump($x)," => ",var_dump(intval($x)),"<BR>";
$x = "1.23e45";
echo var_dump($x)," => ",var_dump(intval($x)),"<BR>";
$x = "123abc";
echo var_dump($x)," => ",var_dump(intval($x)),"<BR>";
$x = " \n\t\r 123.45abc";
echo var_dump($x)," => ",var_dump(intval($x)),"<BR>";
?>
Rsultat
Les rgles de conversion voques prcdemment sont respectes. L encore, il faut rappeler qu'un nombre
virguleflottanteconvertienentieresttronquetnonarrondi :surnotreexemple,123.9donne123etnon124.
Pourconvertirunnombrevirguleflottanteenentier,avecarrondi,ilfaututiliserlafonctionround().
Exemple
<?php
$x = 123.9;
echo "round($x) => ",var_dump(round($x)),"<BR>";
echo "intval(round($x)) => ",
var_dump(intval(round($x))),"<BR>";
echo "(int) round($x) => ",
var_dump((int) round($x)),"<BR>";
?>
Rsultat
Dfinition
EnPHP,untableauestunecollection(listed'lments)ordonnedecouplescl/valeur.
Laclpeuttredetypeentieroudetypechane.Danslepremiercas,letableauestditnumriqueetlaclest
dsigneparletermeindice.Dansledeuximecas,letableauestditassociatif:lesclsnesontpasforcment
conscutives,niordonnes,etcetableaupeutprsenterdesclsentiresetdesclsdetypechane.
La valeur associe la cl peut tre de n'importe quel type, et notamment de type tableau dans ce cas, le
tableauestditmultidimensionnel.
Exemple
Cl/Indice Valeur
0 zro
1 un
2 deux
3 trois
Cl/Indice Valeur
20 vingt
30 trente
10 dix
- Tableau mixte
Cl/Indice Valeur
0 zro
zro 0
un 1
1 un
deux 2
2 deux
trois 3
3 trois
Cl/Indice Valeur
FRANCE Cl/Indice Valeur
0 Paris
1 Lyon
2 Nantes
ITALIE Cl/Indice Valeur
0 Rome
Cration
Une variable de type tableau peut tre dfinie explicitement grce la fonction array ou implicitement en
utilisantunenotationcrochets([]).
Notationcrochets([])
Unevariableutilisepourlapremirefoisavecunenotationdelaforme $variable[...],estautomatiquement
creavecletypetableau.
La mme opration effectue sur une variable dj dfinie, avec un type scalaire, provoque un message
d'erreur.
Lecontenud'untableaupeuttreainsidfiniparplusieursaffectationsdutype$tableau[...] = valeur.
Avecuneaffectationdutype$tableau[] = valeur,PHPrechercheleplusgrandindiceentierutilisetassocie
lavaleurl'indiceimmdiatementsuprieur.Siletableauestvide,l'lmentestplacl'indice0.
Avec une affectation du type $tableau[cl] = valeur, PHP associe la valeur la cl indique (qui peut tre
detypeentieroudetypechane).
Lesdeuxnotationspeuventtremlangesdansunesquenced'affectation.
Exemple
<?php
$nombres[] = "zro"; // => indice 0
$nombres[] = "un"; // => indice max (0) + 1 = 1
$nombres[] = "deux"; // => indice max (1) + 1 = 2
$nombres[] = "trois"; // => indice max (2) + 1 = 3
$nombres[5] = "cinq"; // => indice 5
$nombres[] = "six"; // => indice max (5) + 1 = 6
$nombres["un"] = 1; // indice "un"
$nombres[] = "sept"; // => indice max (6) + 1 = 7
$nombres[-1] = "moins un"; // => -1
?>
Rsultat
Cl/Indice Valeur
0 zro
1 un
2 deux
3 trois
5 cinq
6 six
un 1
7 sept
-1 moins un
Cesnotationspeuventtreutilisespourconstruireuntableaumultidimensionnel,souslaforme $tableau[...]
= $tableau_intrieur ou$tableau[...][...] = valeur.Lapremirenotationpermetdestockeruntableau
dans un emplacement d'un autre tableau, et la deuxime notation, de stocker une valeur directement dans un
emplacementsitul'intrieurd'unautretableau.
Exemple
<?php
// cration d'un tableau contenant les villes de France
$villes_france[] = "Paris";
$villes_france[] = "Lyon";
$villes_france[] = "Nantes";
// stockage du tableau des villes de France dans le tableau
// des villes
$villes["FRANCE"] = $villes_france;
// idem avec les villes d'Italie
$villes_italie[] = "Rome";
$villes_italie[] = "Venise";
$villes["ITALIE"] = $villes_italie;
?>
- Deuxime mthode :
<?php
// stockage direct des villes dans le tableau
// - pour la France
$villes["FRANCE"][] = "Paris";
$villes["FRANCE"][] = "Lyon";
$villes["FRANCE"][] = "Nantes";
// - pour l'Italie
$villes["ITALIE"][] = "Rome";
$villes["ITALIE"][] = "Venise";
?>
Cl/Indice Valeur
FRANCE Cl/Indice Valeur
0 Paris
1 Lyon
2 Nantes
ITALIE Cl/Indice Valeur
0 Rome
1 Venise
Lafonctionarray
Lafonctionarraypermetdecreruntableaupartird'unelisted'lments.
Syntaxe
valeur lmentdutableau.
cl Valeurdelacl.
Dans la premire syntaxe, les cls/indices ne sont pas spcifies et c'est un tableau numrique indices
conscutifs commenant 0 qui est cr : le premier argument de la fonction tant stock l'indice 0, le
deuximel'indice1,etc.
Dansladeuximesyntaxe,l'indiceoulaclsontspcifissoitparunentier,soitparunechane etunevaleur
luiestassocieparl'oprateur=>.
Les deux syntaxes peuvent tre mlanges. Dans ce cas, lorsque l'indice ou la cl n'est pas spcifi(e), PHP
recherche le plus grand indice entier utilis et associe la valeur l'indice immdiatement suprieur s'il n'existe
Lafonctionarray,appelesansargument,creuntableauvide.
Exemple
<?php
$nombres = array("zro","un","deux","trois",
5 => "cinq","six","un" => 1,"sept",-1 => "moins un");
?>
Rsultat
Cl/Indice Valeur
0 zro
1 un
2 deux
3 trois
5 cinq
6 six
un 1
7 sept
-1 moins un
Lafonction arrayaccepteenargumentlesdonnesdetypetableau(soitunevariable,soitunappelimbriqu
array),cequipermetdeconstruireuntableaumultidimensionnel.
Exemple
- Premire mthode :
<?php
// cration d'un tableau contenant les villes de France
$villes_france = array("Paris","Lyon","Nantes");
// idem avec les villes d'Italie
$villes_italie = array("Rome","Venise");
// stockage des 2 tableaux dans le tableau des villes
$villes = array("FRANCE" => $villes_france,
"ITALIE" => $villes_italie);
?>
- Deuxime mthode :
<?php
// cration par imbrication des appels array
$villes = array("FRANCE" => array("Paris","Lyon","Nantes"),
"ITALIE" => array("Rome","Venise"));
?>
Cl/Indice Valeur
FRANCE Cl/Indice Valeur
0 Paris
1 Lyon
2 Nantes
ITALIE Cl/Indice Valeur
0 Rome
Manipulation
Deuxbesoins"types"existent,relatifslamanipulationd'untableau :
- parcourir le tableau.
Accderunlmentindividueldutableau
Lanotationcrochetsestutilisepouraccder,enlectureouencriture,unlmentindividueldutableau :
- $tableau[i] permet d'accder l'lment d'indice i du tableau (cas du tableau numrique, i tant un entier).
- $tableau["x"] permet d'accder l'lment de cl "x" du tableau (cas du tableau associatif, "x" tant une chane).
- $tableau[] permet d'accder, en criture uniquement, un nouvel lment du tableau qui se verra affecter un
indice entier immdiatement suprieur au plus grand indice entier existant dans le tableau (0 s'il n'y en a pas).
Pourlestableauxmultidimensionnels,plusieurssriesdecrochetsdoiventtreutilises.
Exemple
<?php
$nombres = array("zro","un","deux","trois",
5 => "cinq","six","un" => 1,"sept",-1 => "moins un");
echo $nombres[1],"<BR>";
echo $nombres["un"],"<BR>";
$villes = array("FRANCE" => array("Paris","Lyon","Nantes"),
"ITALIE" => array("Rome","Venise"));
echo $villes["FRANCE"][0],"<BR>";
echo $villes["ITALIE"][1],"<BR>";
?>
Rsultat
un
1
Paris
Venise
PHPacceptequevousomettiezledlimiteurdechane(guillemetouapostrophe)lorsquevousspcifiezunecl
detypechanedansuntableauassociatif.
Exemple
<?php
$nombres = array("un" => 1,"deux" => 2);
// utilisation de $nombres[un] et non $nombres["un"]
echo $nombres[un],"<BR>";
?>
Le principe de substitution des variables dans les chanes dlimites par des guillemets fonctionne avec les
tableaux.
Exemple
<?php
$nombres = array("zro","un","deux","trois",
5 => "cinq","six","un" => 1,"sept",-1 => "moins un");
echo "\$nombres[1] = $nombres[1]<BR>";
echo "\$nombres[\"un\"] = $nombres[un]<BR>";
echo "\$nombres[\"un\"] = {$nombres['un']}<BR>";
$villes = array("FRANCE" => array("Paris","Lyon","Nantes"),
"ITALIE" => array("Rome","Venise"));
echo "\$villes[\"France\"][0] = $villes[FRANCE][0]<BR>";
echo "\$villes[\"France\"][0] = {$villes[FRANCE][0]}<BR>";
?>
Rsultat
$nombres[1] = un
$nombres["un"] = 1
$nombres["un"] = 1
$villes["France"][0] = Array[0]
$villes["France"][0] = Paris
Cesexemplesappellentdeuxremarques :
- Pour les cls de type chane exprimes sous forme de littral, la syntaxe avec dlimiteur ncessite des accolades
({$nombres['un']}). crire directement $nombres['un'], $nombres["un"] ou $nombres[\"un\"] gnre
une erreur. Dans ce cas, il est acceptable d'utiliser la syntaxe sans dlimiteur ($nombres[un]).
- Pour les tableaux multidimensionnels, il faut utiliser des accolades ({$villes['FRANCE'][0]}). La syntaxe
$villes['FRANCE'][0] gnre une erreur et la syntaxe $villes[FRANCE][0] donne un mauvais rsultat car
PHP interprte $villes[FRANCE] comme une variable et la remplace par sa valeur (mais c'est un tableau que PHP ne
sait pas afficher nativement).
Parcourirletableau
Denombreusesmthodespeuventtreutilisespourparcouriruntableaul'aidedesconstructionssuivantes :
Dans ce chapitre, nous allons tudier les deux mthodes les plus simples, et finalement les plus efficaces. Elles
ne ncessitent aucune connaissance particulire sur la nature du tableau (numrique, associatif, plage des
indices/cls...).
- la structure foreach sans conteste la mthode la plus simple pour parcourir un tableau.
Syntaxe
foreach(tableau as variable_valeur)
{ instructions }
ou
foreach(tableau as variable_cl => variable_valeur)
Lapremiresyntaxepermetdeparcourirletableaududbutlafin chaqueitration,lavaleurcourantedu
tableaueststockedanslavariablevariable_valeuretlesinstructionsentreaccoladessontexcutes.Cette
syntaxeestsuffisantesiletraitementn'apasbesoindefairerfrenceauxvaleursdelacl.
Ladeuximesyntaxefonctionnesurlemmeprincipe,maischaqueitration,laclcouranteeststockedans
la variable variable_cl et la valeur dans la variable variable_valeur. Cette syntaxe est pratique si le
traitementabesoindefairerfrenceauxvaleursdelacl.
Exemple
<?php
// initialisation d'un tableau
$nombres = array("zro","un","deux",
"zro" => 0,"un" => 1,"deux" => 2);
// Parcours du tableau avec la premire syntaxe
echo "Premire syntaxe :<BR>";
foreach($nombres as $nombre) {
echo "$nombre<BR>";
}
// Parcours du tableau avec la deuxime syntaxe
echo "Deuxime syntaxe :<BR>";
foreach($nombres as $cl => $nombre) {
echo "$cl => $nombre<BR>";
}
?>
Rsultat
Premire syntaxe :
zro
un
deux
0
1
2
Deuxime syntaxe :
0 => zro
1 => un
2 => deux
zro => 0
un => 1
deux => 2
Ces deux exemples montrent bien qu'aucune connaissance pralable du tableau n'est ncessaire pour le
parcourir :nisataille,nisastructuredecls.
Exemple
<?php
// initialisation d'un tableau
$nombres = array("zro","un","deux",
"zro" => 0,"un" => 1,"deux" => 2);
// Parcours du tableau pour le modifier (mauvaise mthode)
foreach($nombres as $cl => $nombre) {
$nombre = "($nombre)"; // mettre le nombre entre ()
}
// Parcours du tableau pour l'afficher
echo "Rsultat de la mauvaise mthode :<BR>";
foreach($nombres as $cl => $nombre) {
echo "$cl => $nombre<BR>";
}
Rsultat
Une autre mthode (structure while en version 3), proche de la mthode foreach, peut tre utilise pour
parcouriruntableau.
Syntaxe
while(list(variable_cl,variable_valeur) = each(tableau))
{ instructions }
Cette construction permet de parcourir le tableau du dbut la fin chaque itration, la cl courante du
tableau est stocke dans la variable variable_cl, la valeur dans la variable variable_valeur et les
instructionsentreaccoladessontexcutes.L'uneoul'autredesvariablespeuttreomisesiletraitementn'en
apasbesoin.
Encomplment,siletableauapralablementtmanipul,ilfautfaireappellafonction resetpourremettre
le pointeur interne du tableau sur la premire ligne et ainsi tre certain de bien repartir du dbut. Dans la
pratique,cettefonctionestsystmatiquementappele.
Syntaxe
tableau Tableauconcern
Lafonctionresetpositionnelepointeurinternedutableausurlapremireligneetretournelavaleur(paslacl)
decettepremireligne.
<?php
$nombres = array("zro","un","deux",
"zro" => 0,"un" => 1,"deux" => 2);
reset($nombres); // ici le reset est important
while(list($cl,$nombre) = each($nombres)) {
echo "$cl => $nombre<BR>";
}
?>
Rsultat
0 => zro
1 => un
2 => deux
zro => 0
Pour modifier le contenu du tableau l'aide de cette structure, il faut utiliser la mme technique qu'avec la
constructionforeach.
En cas de besoin, dans les deux constructions, l'instruction break (cf. chapitre Structures de contrle ) peut tre employe
pour interrompre le parcours du tableau avant la fin.
Comme indiqu lors de la description de la fonction reset, un tableau possde un pointeur interne manipulable avec
diffrentes fonctions pour le dplacer (fonctions reset, next, prev et end) ou rcuprer la valeur pointe (current). Ces
fonctions ne sont pas prsentes plus en dtail dans cet ouvrage car elles sont d'un usage moins courant.
La structure for (cf. chapitre Structures de contrle) peut aussi tre utilise pour parcourir un tableau mais elle est moins
pratique car elle ncessite de bien connatre le contenu du tableau.
Dans le chapitre 6, nous allons construire une fonction gnrique qui permet d'afficher le contenu d'un tableau sans
connaissance pralable de sa structure (le tableau pourra mme tre multidimensionnel).
Porte
Les variables de type tableau suivent les mmes rgles de porte et de dure de vie que les variables de type
scalaire(cf.VariablesPorteetduredevie).
Fonctionsutiles
PHPproposeungrandnombredefonctionspermettantdemanipulerlestableaux.
Lesfonctionslesplusutilisessontlessuivantes :
Nom Rle
count Compte le nombre d'lments dans un tableau.
in_array Teste si une valeur est prsente dans un tableau.
array_search Recherche une valeur dans un tableau.
[a|k][r] Trie un tableau (plusieurs variantes possibles).
sort
explode Dcoupe une chane selon un sparateur et stocke les lments dans
un tableau.
implode Regroupe les lments d'un tableau dans un chane l'aide d'un
sparateur.
str_split Dcoupe une chane en morceaux de longueur fixe et stocke les
lments dans un tableau.
La fonction is_array (cf. Types de donnes Fonctions utiles) permet de savoir si une variable est de type
tableau.Nel'oubliezpas.
De nombreuses autres fonctions existent, la description de chaque fonction est accessible en ligne sur le site
www.php.net.Vousytrouvereznotammentdesfonctionspour :
- ddoublonner un tableau...
count
Syntaxe
variable Variableconcerne.
La fonction count retourne le nombre d'lments dans la variable. Si la variable n'est pas initialise, count
retourne 0. Si la variable est initialise mais n'est pas un tableau, count retourne 1 (il y a effectivement un
lmentdansunevariablescalaire).Silavariableestuntableau, countretournelenombred'lmentsprsents
dansletableau(0siletableauestvide).
Exemple
<?php
echo "\$x variable non initialis => ",count($x),"<BR>";
$x = 1;
echo "\$x variable de type scalaire => ",count($x),"<BR>";
$x = array();
echo "\$x tableau vide => ",count($x),"<BR>";
$x = array(1,2);
echo "\$x tableau de 2 lments => ",count($x),"<BR>";
?>
Rsultat
in_array
Lafonctionin_arraypermetdetestersiunevaleurestprsentedansuntableau.
Syntaxe
valeur_cherche Valeurcherchedansletableau.
tableau Tableaudanslequels'effectuelarecherche.
mme_type Indiquesilacomparaisondoitvrifierqueleslmentssontdummetype(FALSEpardfaut).
in_arrayretourneTRUEsil'lmentcherchestprsentdansletableauetFALSEdanslecascontraire.
PHP propose aussi la fonction array_key_exists qui permet de tester si une valeur est prsente dans les cls d'un
tableau.
Exemple
<?php
$nombres = array("zro","un","deux",
"zro" => 0,"un" => 1,"deux" => 2);
echo '"un" type indiffrent => ',
var_dump(in_array("un",$nombres)),"<BR>";
echo '"un" mme type => ',
var_dump(in_array("un",$nombres,TRUE)),"<BR>";
echo '"trois" type indiffrent => ',
var_dump(in_array("trois",$nombres)),"<BR>";
echo '"trois" mme type => ',
var_dump(in_array("trois",$nombres,TRUE)),"<BR>";
Rsultat
Les deux exemples avec "trois" montrent que la fonction in_array est manipuler avec beaucoup de
prcautionlorsqueletableaucontientdeslmentsdetypediffrent.Eneffet,surlarecherchedemmetype,
in_arrayfonctionnecorrectement(iln'yapasdechane"trois"dansletableau).Surlarechercheoletype
estindiffrent,toutsepassecommesilachanetaitconvertieenentier("trois"convertienentierdonne0)
et que la recherche s'effectuait sur le rsultat de cette conversion (0 est bien prsent dans le tableau). La
preuveenestlersultatlorsquel'lment0estenlevdutableau.
Exemple
<?php
$nombres = array("zro","un","deux",
"zro" => "0 est enlev","un" => 1,"deux" => 2);
echo '"trois" type indiffrent => ',
var_dump(in_array("trois",$nombres)),"<BR>";
echo '"trois" mme type => ',
var_dump(in_array("trois",$nombres,TRUE)),"<BR>";
?>
Rsultat
Cettefois,lesdeuxrecherchesdonnentlemme(bon)rsultat.
array_search
Syntaxe
valeur_cherche
Valeurcherchedansletableau.
tableau
Tableaudanslequels'effectuelarecherche.
Indiquesilacomparaisondoitvrifierqueleslmentssontdummetype(FALSEpardfaut).
array_search retourne la cl associe l'lment, si ce dernier est prsent dans le tableau et FALSE dans le
cascontraire(NULLavantlaversion4.2.0).
Exemple
<?php
$nombres = array("zro","un","deux",
"zro" => 0,"un" => 1,"deux" => 2);
echo '"un" type indiffrent => ',
var_dump(array_search("un",$nombres)),"<BR>";
echo '"un" mme type => ',
var_dump(array_search("un",$nombres,TRUE)),"<BR>";
echo '"trois" type indiffrent => ',
var_dump(array_search ("trois",$nombres)),"<BR>";
echo '"trois" mme type => ',
var_dump(array_search ("trois",$nombres,TRUE)),"<BR>";
echo '1 type indiffrent => ',
var_dump(array_search(1,$nombres)),"<BR>";
echo '1 mme type => ',
var_dump(array_search(1,$nombres)),"<BR>";
echo '3 type indiffrent => ',
var_dump(array_search(3,$nombres)),"<BR>";
echo '3 mme type => ',
var_dump(array_search(3,$nombres)),"<BR>";
echo '"1" type indiffrent => ',
var_dump(array_search("1",$nombres)),"<BR>";
echo '"1" mme type => ',
var_dump(array_search("1",$nombres,TRUE)),"<BR>";
?>
Rsultat
Nousretrouvons,surcesexemples,leproblmevoquaveclafonctionin_array :larecherchesur"trois",en
typeindiffrent,donnelacl"zro"quicorrespondeffectivementlavaleur0dansletableau.
[a|k][r]sort
Syntaxe
tableau Tableautrier.
Lesvariantesdefonctionnementsontlessuivantes :
CesfonctionsretournentTRUEencasdesuccsetFALSEencasd'chec.
Exemple
<?php
$tableau = array("c3" => "rouge","c1" => "vert",
"c2" => "bleu");
// affichage de contrle
echo "<B>Tableau de dpart :</B><BR>";
foreach($tableau as $cl => $valeur)
{ echo "$cl => $valeur<BR>"; }
// sort
echo "<B>sort : tri sur valeur, cls non prserves</B><BR>";
$tableau_bis = $tableau;
sort($tableau_bis);
foreach($tableau_bis as $cl => $valeur)
{ echo "$cl => $valeur<BR>"; }
// asort
echo "<B>asort : tri sur valeur,
couples cl/valeur prservs</B><BR>";
$tableau_bis = $tableau;
asort($tableau_bis);
foreach($tableau_bis as $cl => $valeur)
{ echo "$cl => $valeur<BR>"; }
// ksort
echo "<B>ksort : tri sur cl,
couples cl/valeur prservs</B><BR>";
$tableau_bis = $tableau;
ksort($tableau_bis);
foreach($tableau_bis as $cl => $valeur)
{ echo "$cl => $valeur<BR>"; }
?>
Rsultat
Tableau de dpart :
c3 => rouge
c1 => vert
c2 => bleu
sort : tri sur valeur, cls non prserves
0 => bleu
1 => rouge
2 => vert
asort : tri sur valeur, couples cl/valeur prservs
c2 => bleu
c3 => rouge
c1 => vert
ksort : tri sur cl, couples cl/valeur prservs
c1 => vert
c2 => bleu
c3 => rouge
explode
La fonction explode permet de dcouper une chane selon un sparateur et de stocker les lments dans un
tableau.
Syntaxe
_dcouper Chanedcouper.
limite Sispcifi,nombremaximumd'lmentsdansletableaursultat.
Exemple
<?php
$liste = "bleu, blanc, rouge";
$couleurs = explode(", ",$liste);
// sparateur = virgule+espace
foreach($couleurs as $cl => $valeur)
{ echo "$cl => $valeur<BR>"; }
?>
Rsultat
0 => bleu
1 => blanc
2 => rouge
implode
Lafonctionimplodepermetderegrouperleslmentsd'untableaudansunechanel'aided'unsparateur.
sparateur Sparateurutilis.
lments Tableaucontenantleslmentsregrouper.
Exemple
<?php
$couleurs = array("bleu","blanc","rouge");
$liste = implode(", ",$couleurs);
// sparateur = virgule+espace
echo $liste;
?>
Rsultat
str_split
La fonction str_split dcoupe une chane en morceaux de longueur fixe et stocke les lments dans un
tableau.
Syntaxe
chane Chanedcouper.
longueur Longueurdesmorceaux(1pardfaut).
Exemple
<?php
$chane = "A1B2C3";
$tableau = str_split($chane,2);
foreach($tableau as $cl => $valeur) {
Rsultat
$tableau[0] = A1
$tableau[1] = B2
$tableau[2] = C3
Prambule
L'objectif de cette section est de prsenter les fonctions les plus utiles, relatives la manipulation des chanes
decaractresetdesdates,typesdedonnestrsfrquemmentutilisesdanslesapplications.
PHP propose de nombreuses fonctions la description de chaque fonction est accessible en ligne sur le site
www.php.net.
Manipulationdeschanesdecaractres
Lesfonctionslesplusutilespourmanipulerleschanesdecaractressontlessuivantes :
Nom Rle
strlen Retourne le nombre de caractres d'une chane.
strtolower Conversions minuscules/majuscules ventuellement limites au(x)
strtoupper premier(s) mot(s).
ucfirst
ucwords
strcmp Comparaison de chane (sensible la casse ou non).
strcasemp
[s]printf Mise en forme d'une chane (identique aux fonctions C quivalentes).
v[s]printf
number_format Mise en forme d'un nombre.
[1|r]trim Suppression de caractres "blancs".
substr Extraction d'une sous-chane dans une chane.
str_repeat Construction d'une chane par rptition de caractres.
str[r][i]pos Recherche de la position d'une occurrence (caractre ou chane)
l'intrieur d'une chane.
str[i]str Extraction de la sous-chane dans une chane commenant partir
strrchr d'une certaine occurrence d'un caractre ou d'une chane.
str_[i] Remplacement des occurrences d'une chane par une autre chane.
replace
strtr Remplacement des occurrences d'un caractres par un autre caractre
ou d'une chane par une autre chane.
ereg[i] Recherche et remplacement l'aide d'expressions rgulires.
ereg[i]
_replace
N'oubliez pas les fonctions explode, implode et str_split prcdemment prsentes (cf. Tableaux - Fonctions utiles).
D'autres fonctions, plus spcifiquement lies la gestion des formulaires sont tudies dans le chapitre 7.
strlen
Lafonctionstrlenretournelenombredecaractresd'unechane.
Syntaxe
chane Chaneconcerne.
strtolowerstrtoupperucfirstucwords
Ces fonctions permettent de raliser des conversions minuscules/majuscules, ventuellement limites au(x)
premier(s)mot(s)delachane.
chane Chanetraiter.
Lafonctionstrtolowerconvertittouslescaractresd'unechaneenminuscules.
Lafonctionstrtoupperconvertittouslescaractresd'unechaneenmajuscules.
Lafonctionucfirstconvertitlepremiercaractred'unechaneenmajuscules.
Lafonctionucwordsconvertitlepremiercaractredechaquemotd'unechaneenmajuscules.
Exemple
<?php
echo "strtolower(\"OLIVIER\") = ",
strtolower("OLIVIER"),"<BR>";
echo "strtoupper(\"olivier\") = ",
strtoupper("olivier"),"<BR>";
echo "ucfirst(\"olivier heurtel\") = ",
ucfirst("olivier heurtel"),"<BR>";
echo "ucwords(\"olivier heurtel\") = ",
ucwords("olivier heurtel"),"<BR>";
?>
Rsultat
strtolower("OLIVIER") = olivier
strtoupper("olivier") = OLIVIER
ucfirst("olivier heurtel") = Olivier heurtel
ucwords("olivier heurtel") = Olivier Heurtel
strcmpstrcasecmp
Cesfonctionspermettentdecomparerdeuxchanesentenantcompteoupasdesmajusculesetminuscules.
Syntaxe
Les deux fonctions retournent un nombre ngatif si chane1 est plus petit que chane2, un nombre gal 0 si
ellessontgales,etunnombrepositifsichane1estplusgrandquechane2.
strcmpestsensiblelacassealorsquestrcasecmpnel'estpas.
Exemple
<?php
echo "strcmp(\"Olivier\",\"olivier\") = ",
strcmp("Olivier","olivier"),"<BR>";
echo "strcasecmp(\"Olivier\",\"olivier\") = ",
strcasecmp("Olivier","olivier"),"<BR>";
?>
Rsultat
strcmp("Olivier","olivier") = -1
strcasecmp("Olivier","olivier") = 0
[s]printf
Syntaxe
format Chanedemiseenformeprsentantdiversesdirectivesselonlesspcificationsdonnesciaprs
valeur Valeurintgrerdanslachane.
sprintf retourne le rsultat mis en forme (ou FALSE en cas d'erreur) alors que printf affiche directement le
rsultat(commel'instructionecho)etretourneNULLencasdesuccsouFALSEencasd'erreur.
La chane format doit contenir une directive de formatage pour chaque argument valeur cette directive de
formatageprcisel'emplacementetlamiseenformedelavaleurcorrespondante.Lacorrespondanceentreune
directivedeformatageetunevaleurestpositionnelle(premiredirectivepourlapremirevaleur...).
Lesdirectivesdeformatagecommencentparlecaractre%suivid'unecinqinformations,laderniretantla
seuleobligatoire :
%[remplissage][alignement][longueur][prcision]type
Lesinformationssontlessuivantes :
remplissage
Prciselecaractreventuellementutilispourleremplissage.Lecaractrepardfautestl'espace.Toutautre
caractre peut tre employ en le mentionnant prcd d'une apostrophe (seul le caractre zro peut tre
indiqudirectement) :'xindiquequelecaractrederemplissageestle"x".
alignement
Prcise l'alignement. Par dfaut, l'alignement est droite. Le caractre moins ("") permet d'obtenir un
alignementgauche.
longueur
Indiquelenombreminimumdecaractresdel'lmentmisenforme.
prcision
Indiquelenombredechiffresutilisspourlamiseenformed'unnombrevirguleflottante(valableuniquementsi
l'lmentassociestunnombre).
type
Donneletypedelavaleurinsrer :
c :entierremplacerparlecaractredontlecodeASCIIacettevaleur
d :entierreprsentercommetel
f :nombrevirguleflottantereprsentercommetel
s :quelconque,reprsentercommeunechane.
Pourobteniruncaractre"%"danslersultatfinal,ilfautledoublerdansleformat.
Quelquesexemples :
Exemple
<?php
echo "Mise en forme d'une date : ",
sprintf("%02d/%02d/%04d",1,1,2001),"<BR>";
echo "Mise en forme de nombres : ",
sprintf("1er = %01.2f - 2me = %01.2f",
1/3,12345678.9),"<BR>";
echo "Pourcentage : ",
sprintf("%01.2f %%",12.3),"<BR>";
echo "Utilisation des options de remplissage :<BR>";
Rsultat
v[s]printf
Les fonctions vprintf et vsprintf sont identiques aux fonctions printf et sprintf mais acceptent en
deuximeparamtreuntableaucontenantlesdiffrentesvaleursutiliser(laplacedesparamtresmultiples).
Syntaxe
Avec
format Chane de mise en forme comprenant diverses directives selon les spcifications donnes
valeurs Tableaudonnantlesvaleursintgrerdanslachane.
Exemple
<?php
$donnes = array(array("Livres",9.35),array("Disques",99.9));
echo "<TT>"; // police non proportionnelle
foreach($donnes as $ligne) {
vprintf("%'.-10s%'.5.2f<BR>",$ligne); // printf direct
}
echo "</TT>";
?>
Rsultat
Livres........9.35
Disques......99.90
number_format
Lafonctionnumber_formatpermetdemettreenformeunnombre.
Syntaxe
valeur Nombremettreenforme.
dcimales Nombrededcimales(aucunepartiedcimalepardfaut).
sparateur_dcimal Sparateurdcimal(pointpardfaut).
sparateur_milliers Sparateurdesmilliers(virgulepardfaut).
La fonction peut tre appele avec un, deux ou quatre arguments, pas trois : si le troisime est fourni, le
quatrimeestobligatoire.
Si le nombre a une prcision suprieure celle demande (paramtre dcimales), le nombre est arrondi
laprcisiondemande.
Exemple
<?php
$x = 1234.56;
echo "number_format(\"$x\") = ",
number_format($x),"<BR>";
echo "number_format(\"$x\",1) = ",
number_format($x,1),"<BR>";
echo "number_format(\"$x\",1,\".\",\" \") = ",
number_format($x,1,"."," "),"<BR>";
echo "number_format(\"$x\",3,\".\",\" \") = ",
number_format($x,3,"."," "),"<BR>";
?>
Rsultat
number_format("1234.56") = 1,235
number_format("1234.56",1) = 1,234.6
number_format("1234.56",1,"."," ") = 1 234.6
number_format("1234.56",3,"."," ") = 1 234.560
Notez,surcesexemples,lesarrondisautomatiqueslorsquelaprcisiondemandeestinfrieurelaprcisiondu
nombre.
Ces fonctions permettent de supprimer les caractres "blancs", ou d'autres caractres, en dbut de chane, en
findechaneoudesdeuxcts.
Syntaxe
Avec
chane Chanetraiter.
caractres Chanedonnantlalistedescaractressupprimer.Siceparamtreestabsent,lescaractres
"blancs"sontsupprims.
Les trois fonctions retournent une chane gale la chane initiale dans laquelle les caractres "blancs" ou les
caractresspcifisonttsupprimsaudbut(ltrim avec -l= left=gauche),lafin(rtrim avec -r=
right=droite)oudesdeuxcts(trim).
Les caractres "blancs" sont le saut de ligne (\n = code ASCII 10), le retour chariot (\r = code ASCII 13), la
tabulation(\t=codeASCII9),lecaractreNULL(\0=codeASCII0)etl'espace.
Exemple 1
<?php
$x = "\0\t\t x \n\r";
echo "strlen(\$x) = ",strlen($x),"<BR>";
echo "strlen(ltrim(\$x)) = ",strlen(ltrim($x)),"<BR>";
echo "strlen(rtrim(\$x)) = ",strlen(rtrim($x)),"<BR>";
echo "strlen(trim(\$x)) = ",strlen(trim($x)),"<BR>";
?>
Rsultat
strlen($x) = 8
strlen(ltrim($x)) = 4
strlen(rtrim($x)) = 5
strlen(trim($x)) = 1
Exemple 2
<?php
$x = "***+-Olivier-+***";
echo "trim(\"$x\",\"*+-\") = ",trim($x,"*+-"),"<BR>";
?>
Rsultat
trim("***+-Olivier-+***","*+-") = Olivier
substr
Lafonctionsubstrpermetd'extraireunesouschanedansunechane.
Syntaxe
chane Chanetraiter.
longueur Nombredecaractresextraire(pardfaut,jusqu'lafindelachane).
- Si l'argument dbut est positif, la souschane extraite commence au caractre dbut (0 = 1er caractre).
- Si l'argument dbut est ngatif, la souschane extraite commence au caractre dbut en partant de la fin (1 =
dernier caractre).
- Si l'argument longueur n'est pas spcifi, la souschane extraite se termine la fin de la chane.
- Si l'argument longueur est spcifi et positif, substr extrait le nombre de caractres indiqu par l'argument
longueur.
- Si l'argument longueur est spcifi et ngatif, la souschane extraite se termine la fin de la chane, moins le
nombre de caractres indiqu par la valeur absolue de l'argument longueur.
Exemple
<?php
// 012345678901234 => pour le contrle
$x = "Olivier Heurtel";
echo "substr(\"$x\",8) = ",substr($x,8),"<BR>";
echo "substr(\"$x\",8,3) = ",substr($x,8,3),"<BR>";
echo "substr(\"$x\",8,-3) = ",substr($x,8,-3),"<BR>";
echo "substr(\"$x\",-7) = ",substr($x,-7),"<BR>";
echo "substr(\"$x\",-7,3) = ",substr($x,-7,3),"<BR>";
echo "substr(\"$x\",-7,-3) = ",substr($x,-7,-3),"<BR>";
?>
Rsultat
str_repeat
Lafonctionstr_repeatpermetdeconstruireunechaneparrptitiondecaractres.
Syntaxe
squence Squencedecaractresrpter.
rptitions Nombrederptitionssouhaites.
CettefonctionatintroduiteavecPHP4.
Exemple
<?php
echo str_repeat("abc",3);
?>
Rsultat
abcabcabc
Ces fonctions permettent de rechercher la position d'une occurrence (caractre ou chane) l'intrieur d'une
chane.
Syntaxe
Avec
_traiter Chanetraiter.
chercher lmentrecherch.
dbut Numroducaractre(0=premiercaractre)partirduquellarecherchedoittreralise(pardfaut,le
dbutdelachane).
strpos recherche, dans la chane _traiter, la premire occurrence de la chane chercher, en commenant
ventuellementaucaractrenumrodbut(0=premiercaractre).
strrpos recherche, dans la chane _traiter, la dernire occurrence de la chane chercher, en commenant
ventuellement au caractre numro dbut (0 = premier caractre). Si dbut est ngatif (-n), les n derniers
caractresdelachane_traitersontignors.Leparamtre offsetatajoutdanslaversion5.Enversion
4,seullepremiercaractredelachanecherchertaitprisencompte.
Les deux fonctions sont sensibles la casse (une majuscule n'est pas gale une minuscule). Les fonctions
stripos et strripos sont identiques respectivement aux fonctions strpos et strrpos, mais ne sont pas
sensibleslacasse ellesonttintroduitesenversion5.
Cesquatrefonctionsretournentlapositiondel'occurrencetrouve(0=premiercaractre)ouFALSEsil'lment
recherchn'estpastrouv.
FALSEtantquivalent0,ilestfaciledeconfondrelecasol'lmentn'apasttrouvetlecasoilat
trouvendbutdechane.Latechnique,avecPHP4,consisteutiliserl'oprateurdecomparaison"==="(trois
signes gal) qui permet de comparer la valeur et le type de deux expressions (pour plus de dtail, cf. chapitre
Oprateurs).
Exemple
<?php
// 0123456789 ... => pour le contrle
$mail = "contact@olivier-heurtel.fr";
// strrpos
$position = strrpos($mail,"@");
echo "@ est la position $position dans $mail<BR>";
// strpos
$position = strpos($mail,"olivier");
echo "'olivier' est la position $position dans $mail<BR>";
Rsultat
strstrstristrstrrchr
Ces fonctions permettent d'extraire la souschane commenant partir d'une certaine occurrence d'un
caractreoud'unechane.
Syntaxe
_traiter Chanetraiter.
rechercher lmentrecherch.
strrchr recherche, dans la chane _traiter, la dernire occurrence du caractre rechercher et retourne la
portion terminale de la chane commenant cette occurrence (incluse). Si rechercher est une chane de
plusieurscaractres,seullepremierestprisencompte.strrchrestsensiblelacasse.
CestroisfonctionsretournentFALSEsil'lmentrecherchn'estpastrouv.
Exemple
<?php
$mail = "Olivier-Heurtel@olivier-heurtel.fr";
echo "Reste de $mail commenant par :<BR>";
// strrchr
$reste = strrchr($mail,"-");
echo "- la dernire occurrence de '-'<BR>----> $reste <BR>";
// strstr
$reste = strstr($mail,"olivier");
echo "- la premire occurrence de 'olivier'
(sensible la casse)<BR>----> $reste <BR>";
// stristr
$reste = stristr($mail,"olivier");
echo "- la premire occurrence de 'olivier'
(insensible la casse)<BR>----> $reste <BR>";
?>
Rsultat
La fonctionstr_replacepermetderemplacerlesoccurrencesd'unechaneparuneautrechane.Larecherche
estsensiblelacasse.
La fonction str_ireplace permet la mme action mais n'est pas sensible la casse elle a t introduite en
version5.
Syntaxe
_traiter Chanetraiteroutableaudechanestraiter.
rechercher Chanerechercheroutableaudechanesrechercher.
remplacer Chanederemplacementoutableaudonnantunelistedechanesderemplacement.
nombre Variablepermettantdercuprerlenombrederemplacements(version5).
Si rechercher et remplacer sont des tableaux, str_replace recherche toutes les occurrences de chaque
lmentderechercheretlesremplaceparl'lmentcorrespondantderemplacer.
Danslesdeuxcas,letraitementesteffectusurlachane _traiterousurchaquelmentde_traiter, si
cettedernireestuntableau.
Exemple
<?php
// premire syntaxe
$x = "cet t, la plage";
$rechercher = "t";
$remplacer = "hiver";
echo "<B>Premire syntaxe :</B><BR>";
echo "$rechercher => $remplacer <BR>";
echo "$x => ",str_replace($rechercher,$remplacer,$x),"<BR>";
// deuxime syntaxe
$x = array("cet t, la plage","le bateau bleu et vert");
$rechercher = array("t","plage","bleu","vert");
$remplacer = array("hiver","montagne","rouge","jaune");
echo "<B>Deuxime syntaxe :</B><BR>";
foreach($rechercher as $indice => $avant)
{ echo "$avant => $remplacer[$indice]<BR>"; }
// utilisation de la variable $nombre pour rcuprer
// le nombre de remplacements
$y = str_replace($rechercher,$remplacer,$x,$nombre);
echo "$x[0] = $y[0]<BR>";
echo "$x[1] = $y[1]<BR>";
echo "$nombre remplacements<BR>";
?>
Rsultat
Premire syntaxe :
t => hiver
cet t, la plage => cet hiver, la plage
Deuxime syntaxe :
t => hiver
plage => montagne
bleu => rouge
vert => jaune
cet t, la plage => cet hiver, la montagne
le bateau bleu et vert => le bateau rouge et jaune
strtr
La fonction strtr permet de remplacer les occurrences d'un caractre par un autre caractre ou d'une chane
paruneautrechane.
Syntaxe
_traiter Chanetraiter.
rechercher Chanedonnantlalistedescaractresremplacer.
remplacer Chanedonnantlalistedescaractresderemplacement.
correspondance Tableauassociatifdonnantunecorrespondancechaneremplacer/chanederemplacement.
strtracceptedeuxsyntaxes,lapremirepermettantderemplacerdescaractrespard'autres,etladeuxime,
deremplacerdeschanespard'autres.
Avec la premire syntaxe, la correspondance entre les caractres remplacer et les caractres de
remplacement est donne par deux chanes (le caractre n de la premire tant remplacer par le caractre n
deladeuxime).
Avecladeuximesyntaxe,lacorrespondanceentreleschanesremplaceretleschanesderemplacementest
donneparuntableauassociatif(lacltantlachanerechercher,etlavaleur,lachanederemplacement).
Exemple
<?php
// premire syntaxe
$x = "cet t, la plage";
$avant = "";
$aprs = "eea";
echo "<B>Premire syntaxe :</B><BR>";
echo "$avant => $aprs<BR>";
echo "$x => ",strtr($x,$avant,$aprs),"<BR>";
// deuxime syntaxe
$x = "le bateau bleu et vert";
$correspondance = array("bleu"=>"rouge","vert"=>"jaune");
echo "Deuxime syntaxe :</B><BR>";
foreach($correspondance as $avant => $aprs)
{ echo "$avant => $aprs<BR>"; }
echo "$x => ",strtr($x,$correspondance),"<BR>";
?>
Rsultat
Premire syntaxe :
=> eea
cet t, la plage => cet ete, a la plage
Deuxime syntaxe :
bleu => rouge
vert => jaune
le bateau bleu et vert => le bateau rouge et jaune
Lesexpressionsrguliresereg[i]ereg[i]_replace
PHP propose plusieurs fonctions qui permettent d'effectuer des recherches ou des remplacements dans une
chanel'aided'unmodleappel"expressionrgulire"dcrivantl'lmentrecherch.
Syntaxe
_traiter Chanetraiter.
rechercher Chanedonnantlemodle(l'expressionrgulire)del'lmentrecherch.
remplacer Chanederemplacement.
rsultat Sousformedetableau,listedesportionsdelachane_traiterquicorrespondentaumodle
recherch.
ereg et eregi recherchent, dans la chane _traiter, s'il existe une chane qui correspond au modle spcifi
par rechercher(voirciaprspourlesrgles).eregestsensiblelacasse(unemajusculeestdiffrented'une
minuscule)alorsque ereginel'estpas.CesfonctionsretournentTRUEsilemodleesttrouv,et FALSEdansle
cascontraire.
En complment, si le modle le demande (voir ciaprs pour les rgles) et si un troisime paramtre est fourni,
les diffrentes portions de la chane _traiter qui correspondent au modle sont stockes sous forme de
tableaudansletroisimeparamtre.
ereg_replace et eregi_replace effectuent la recherche sur le mme principe et remplacent les diffrentes
portions de la chane _traiter qui correspondent au modle, par la chane remplacer. ereg_replace est
sensible la casse alors que eregi_replace ne l'est pas. Si aucune occurrence n'est trouve, la chane
_traiterestretourne,inchange.
Plusieurscaractresspciauxpeuventtreutilissdanslemodlepourdcrirel'lmentrecherch :
Caractre
Signification
spcial
^ Si ^ est prsent comme premier caractre du modle, indique que la chane doit commencer par ce qui suit.
Si $ est prsent comme dernier caractre du modle, indique que la chane doit terminer par ce qui
prcde :
^abc : doit commencer par abc.
xyz$ : doit terminer par xyz.
$
^abcxyz$ : doit commencer par abcxyz et se terminer par abcxyz (bref tre gal abcxyz !).
Un modle ne comprenant ni ^, ni $, indique que le modle est recherch n'importe o l'intrieur de la
chane :
abc : contient abc.
Indique que le caractre qui prcde, ou la squence qui prcde (voir ci-aprs), peut tre prsente zro, une
* ou plusieurs fois :
ab*c accepte ac, abc, abbc...
Indique que le caractre qui prcde, ou la squence qui prcde (voir ci-aprs), doit tre prsente une ou
+ plusieurs fois :
ab+c accepte abc, abbc... mais refuse ac.
Indique que le caractre qui prcde, ou la squence qui prcde (voir ci-aprs), peut tre prsente zro ou
? une fois :
ab?c accepte ac et abc mais refuse abbc, abbbc...
Indique que le caractre qui prcde, ou la squence qui prcde (voir ci-aprs), doit tre prsente
{x} exactement x fois ({x}) ou au minimum x fois ({x,}) ou entre x et y fois ({x,y}) :
{x,} ab{2}c n'accepte que abbc.
{x,y} ab{2,4}c accepte abbc, abbbc, et abbbbc mais refuse abc (manque un b) ou abbbbbc (un b de trop).
ab{2,}c accepte abbc, abbbc, abbbbc... mais refuse abc (manque un b).
Permet de marquer une squence recherche, typiquement avec les symboles relatifs au nombre
(...) d'occurrences :
a(bc)*d accepte ad, abcd, abcbdd... mais refuse abd ou acd (la squence bc n'est pas trouve).
Les expressions rgulires sont des outils trs puissants pour effectuer des recherches dans une chane ou
validerlaconformitd'unesaisiecertainesrgles.
Les diffrents sites Web prsents dans le chapitre 1, regorgent d'exemples de code utilisant les expressions
rgulires.
En complment des quelques exemples prsents ciaprs, le chapitre 7 illustre l'utilisation des expressions
rgulirespourvaliderlasaisied'unutilisateur.
Exemple
<?php
// vrifier qu'une chane commence par une lettre et
// est suivie d'au moins 3 lettres ou chiffres ou caractres
// spciaux _#*$
// utilisation de eregi (insensible la casse)
$chane = "A0_#b*1$2";
echo "$chane OK => ",
(int) eregi("^[a-z][a-z0-9_#*$]{3,}",$chane),"<BR>";
$chane = "0_#b*1$2"; // ne commence pas par une lettre
echo "$chane : ne commence pas par une lettre => ",
(int) eregi("^[a-z][a-z0-9_#*$]{3,}",$chane),"<BR>";
$chane = " A0_#"; // longueur insuffisante
Rsultat
A0_#b*1$2 OK => 1
0_#b*1$2 : ne commence pas par une lettre => 0
A0_# : longueur insuffisante => 0
A0__# : caractre invalide => 0
Lersultatdeeregiestconvertienentierpourl'affichage(0=FALSE, 1=TRUE).
Quelquesexplicationssurl'expressionrgulireutilise(^[a-z][a-z0-9_#*$]{3,}) :
- eregi est utilise afin de ne pas faire de diffrence entre majuscules et minuscules.
- [a-z0-9_#*$]{3,} = suivi d'au moins 3 ({3,}) caractres parmi ceux indiqus: a z (et donc A Z), 0 9 et les
caractres _#*$.
Exemple
<?php
// effectuer des remplacements simples (en l'occurrence,
// remplacer par une chane vide = supprimer)
$chane = "aBc12dEFg453hijk";
echo "Expurger $chane :<BR>";
echo "- des chiffres => ",
ereg_replace("[0-9]+","",$chane),"<BR>";
echo "- des lettres => ",
eregi_replace("[a-z]+","",$chane),"<BR>";
// eregi_replace => insensible la casse
?>
Rsultat
Expurger aBc12dEFg453hijk :
- des chiffres => aBcdEFghijk
- des lettres => 12453
Exemple
<?php
// vrifier qu'une chane a une structure conforme celle
// d'une date au format [J]J/[M]M/AAAA et rcuprer
// les 3 composantes jour, mois et anne.
$date = "21/09/2001";
$ok = ereg(
"^([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})$",
$date,
$rsultat);
if ($ok) {
echo "$date valide.
";
echo "- jour = $rsultat[1]<BR>";
echo "- mois = $rsultat[2]<BR>";
echo "- anne = $rsultat[3]<BR>";
} else {
echo "$date invalide.<BR>";
}
Rsultat
21/09/2001 valide.
- jour = 21
- mois = 09
- anne = 2001
1/2/2001 valide.
- jour = 1
- mois = 2
- anne = 2001
21/09/01 invalide (anne incomplte).
210/09/2001 invalide (jour trop long).
Olivier invalide (rien voir !).
Quelquesexplicationssurl'expressionrgulireutilise(^([0-9]{1,2})/
([0-9]{1,2})/([0-9]{4})$) :
Ce test permet de vrifier qu'une chane cense contenir une date est bien forme. Il convient ensuite de vrifier, avec la
fonction checkdate par exemple, que les trois composantes correspondent une date valide.
Exemple
<?php
// utiliser ereg_replace pour rorganiser une chane
// en l'occurrence, il s'agit de transformer une date
// au format JJ/MM/AAAA en date au format AAAA-MM-JJ
$avant = "21/09/2001";
$aprs = ereg_replace(
"^([0-9]{2})/([0-9]{2})/([0-9]{4})$",
"\\3-\\2-\\1",
$avant);
echo "$avant => $aprs";
?>
Rsultat
Danslachanederemplacement,lessquences\\ndsignentlestroisportionscapturesparlesparenthses :
Le rsultat de la recherche, qui est gal la chane complte dans ce cas, est ensuite remplac par la chane
"\\3-\\2-\\1"soit2001-09-21.
Manipulationdesdates
PHP ne gre pas les dates avec un type de donne spcifique. Nanmoins, des dates peuvent tre manipules,
soitsouslaformed'unechanedecaractres,soitsouslaformed'untimestampUnix(correspondantaunombre
desecondescoulesdepuisle1e rjanvier197001:00:00).
Plusieursfonctionspermettentdemanipulerlesdatessousl'uneoul'autredecesformes :
Nom Rle
checkdate Vrifie que trois entiers reprsentant le jour, le mois et l'anne
correspondent une date valide.
date Convertit en chane une date donne sous la forme d'un timestamp Unix.
strftime Convertit en chane une date donne sous la forme d'un timestamp Unix,
en utilisant des caractristiques locales.
getdate Stocke dans un tableau les diffrentes composantes d'une date donne
sous la forme d'un timestamp Unix.
time Donne le timestamp Unix actuel.
checkdate
Lafonction checkdatevrifiequetroisentiersreprsentantlejour,lemoisetl'annecorrespondentunedate
valide.
Syntaxe
mois Numrodumois(112)
jour Numrodujour(131)
anne Anne(032767)
checkdate retourne TRUE si la date construite avec les trois composantes est valide et FALSE dans le cas
contraire.Cettefonctiontientcomptedesannesbissextiles.
Exemple
<?php
$jour = 13; $mois = 8 ; $anne = 1994;
echo "$jour/$mois/$anne => ",
var_dump(checkdate($mois,$jour,$anne)),"<BR>";
$jour = 31; $mois = 9 ; $anne = 2001;
echo "$jour/$mois/$anne => ",
var_dump(checkdate($mois,$jour,$anne)),"<BR>";
$jour = 29; $mois = 2 ; $anne = 2000;
echo "$jour/$mois/$anne => ",
var_dump(checkdate($mois,$jour,$anne)),"<BR>";
$jour = 29; $mois = 2 ; $anne = 2001;
echo "$jour/$mois/$anne => ",
var_dump(checkdate($mois,$jour,$anne)),"<BR>";
$jour = 29; $mois = 2 ; $anne = 2004;
echo "$jour/$mois/$anne => ",
var_dump(checkdate($mois,$jour,$anne)),"<BR>";
?>
Rsultat
date
Lafonctionconvertitenchaneunedatedonnesouslaformed'untimestampUnix.
Syntaxe
format Formatdeconversion
timestamp Timestampconvertir(pardfautletimestampactuel).
Leformatpeuttrespcifil'aidedescaractressuivants :
Encasdebesoin,cesdiffrentscaractrespeuventtrechappsavecunantislash(\).
Exemple
<?php
// sans deuxime paramtre = utilisation du timestamp courant
echo "Format long (anglais uniquement) : ",
date("l j F Y"),"<BR>";
echo "Date au format JJ/MM/AAAA : ",
date("d/m/Y"),"<BR>";
echo "Date au format J/M/AA : ",
date("j/n/y"),"<BR>";
echo "Heure : ",
date("H:i:s"),"<BR>";
Rsultat
strftime
La fonction strftime convertit en chane une date donne sous la forme d'un timestampUnix,enutilisantdes
caractristiqueslocales.
Syntaxe
format Formatdeconversion
timestamp Timestampconvertir(pardfautletimestampactuel)
ladiffrencedelafonctiondate, strftimeutiliselescaractristiqueslinguistiqueslocales(cellesduserveur).
Leformatpeuttrespcifil'aidedescaractressuivants :
Caractre Signification
%d Numro du jour du mois, sur deux positions, complt par un zro
(01 31)
%m Numro du mois sur deux chiffres (01 12)
%y Anne sur deux chiffres (par exemple 01)
%Y Anne sur quatre chiffres (par exemple 2001)
%H Heure, au format 24h
%I (" i " Heure, au format 12h, sur deux chiffres (01 12)
majuscule)
%M Minutes sur deux chiffres (00 59)
%S Secondes sur deux chiffres (00 59)
%j Jour de l'anne sur trois chiffres (001 366)
%w Numro du jour de la semaine (0 = dimanche 6 = samedi)
%p Symbole "AM"/"PM" (majuscules)
%a Nom abrg du jour de la semaine
%A Nom complet du jour de la semaine
%b Nom abrg du mois
%B Nom complet du mois
%U Numro de semaine dans l'anne ; en considrant le premier
dimanche de l'anne comme le premier jour de la premire semaine
%W Numro de semaine dans l'anne, en considrant le premier lundi
de l'anne comme le premier jour de la premire semaine
%Z Fuseau horaire, ou nom ou abrviation
%c Format par dfaut pour la date et l'heure
%x Format par dfaut pour la date seule
Tous les symboles ne sont pas forcment supports sur toutes les plates-formes.
Les caractristiques linguistiques locales peuvent tre lues et modifies par l'intermdiaire de la fonction
setlocale.
Syntaxe
catgorie
Fonctionnalit concerne par les caractristiques linguistiques locales et dfinie l'aide d'une des constantes
suivantes :
LC_COLLATE :comparaisondechaneaveclafonctionstrcoll ;
LC_CTYPE :classificationetconversions(fonctionstroupperparexemple)
LC_NUMERIC :sparateursdcimaux
LC_MONETARY:symbolemontaire(fonctionlocaleconv) ;
LC_TIME :formatsdedate(fonctionstrftime) ;
LC_ALL :touteslesprcdentes.
langue
Codedelalanguedevantgouvernerlafonctionnalitassocie.Extraitdesvaleurspossibles :
du :Hollande
fr :France
ge :Allemagne
it :Italie
ru :Russie
sp :Espagne
sw :Sude
uk :RoyaumeUni
us :tatsunis.
setlocale retourne la nouvelle valeur ou FALSE en cas d'erreur. Si le deuxime paramtre est gal zro,
setlocaleretournesimplementlavaleurcourante.
Exemple
Rsultat
getdate
Lafonction getdatestocke,dansuntableau,lesdiffrentescomposantesd'unedatedonnesouslaformed'un
timestampUnix.
Syntaxe
timestamp Timestamputiliser(pardfautletimestampactuel).
Lafonctiongetdateretourneuntableauassociatifcomprenantlesclssuivantes :
Cl Valeur
seconds Secondes (0 59)
minutes Minutes (0 59)
hours Heures (0 24)
mday Numro du jour du mois
wday Numro du jour de la semaine (0 = dimanche 6 = samedi)
mon Numro du mois (1 12)
year Anne
yday Numro du jour dans l'anne (0 365)
weekday Nom du jour de la semaine
month Nom du mois
0 Le timestamp
Exemple
<?php
$date = getdate(); // maintenant
foreach($date as $cl => $valeur) {
echo "$cl => $valeur<BR>";
}
Rsultat
seconds => 6
minutes => 31
hours => 18
mday => 9
wday => 2
mon => 3
year => 2004
yday => 68
weekday => Tuesday
month => March
0 => 1078853466
time
LafonctiontimedonneletimestampUnixactuel.
Syntaxe
entier time()
Exemple
<?php
$ts = time();
echo "timestamp Unix actuel = $ts";
?>
Rsultat
mktime
LafonctionmktimecreuntimestampUnixpartirdesdiffrentescomposantesd'unedate.
Syntaxe
entier mktime([entier heure[, entier minutes[, entier secondes[, entier mois[, entier jour[,
entier anne]]]]]])
heure Heure(023)
minutes Minutes(059)
secondes Secondes(059)
moi Mois(112)
jour Jour(131)
Lesparamtresomisprennentleurvaleuractuelle.
La fonction mktime a la particularit intressante de corriger les valeurs incorrectes en effectuant un calcul de
dateintelligent.Exemples :
Cefonctionnementesttrspratiquepourraliserdescalculssurlesdates.
Exemple
<?php
$ts = mktime();
echo "mktime() = maintenant = ",
date("d/m/Y - H:i:s",$ts),"<BR>";
$ts = mktime(1,0,0,1,1,1970);
echo "mktime(1,0,0,1,1,1970) = temps zro d'Unix = $ts<BR>";
$ts = mktime(0,0,0,1,1,2001);
echo "mktime(0,0,0,1,1,2001) = ",
date("d/m/Y - H:i:s",$ts),"<BR>";
$ts = mktime(0,0,0,12,31,2001);
echo "mktime(0,0,0,12,31,2001) = ",
date("d/m/Y - H:i:s",$ts),"<BR>";
$ts = mktime(0,0,0,09,20+100,2001);
echo "Dans 100 jours, nous serons le ",
date("d/m/Y",$ts),".<BR>";
$ts = mktime(1,0,0,1,1+20000,1970);
echo "Unix ftera son 20 000 me jour le ",
date("d/m/Y",$ts),".<BR>";
?>
Rsultat
microtime
LafonctionmicrotimeretourneletimestampUnixactuelaveclafractiondesecondesenmicrosecondes.
Syntaxe
type_rel Boolenindiquantsilafonctiondoitretournerunnombrerel.
Sans paramtre (ou si le paramtre est valu FALSE), la fonction retourne une chane donnant les
microsecondessuiviesd'unespaceetdu timestamp Unix actuel. Si le paramtre est valu TRUE, la fonction
retourneunnombrerel.Leparamtreatintroduitenversion5.
Exemple
<?php
// affichage de microtime sous la forme d'une chane
echo microtime()."<BR>";
// affichage de microtime sous la forme d'un rel
echo microtime(TRUE)."<BR>";
// pour ne conserver que les microsecondes, le plus
// simple est de transformer la chane en rel
echo (float) microtime()."<BR>";
?>
Rsultat
0.38789700 1078854985
1078854985.3879
0.387924
Lafonctionidateretournelesdiffrentescomposantes(anne,mois,etc.)d'untimestampUnix.
Syntaxe
composante Caractreindiquantlacomposantesouhaite(voirciaprs).
timestamp Timestamputiliser(pardfautletimestampactuel).
Lafonctionretourneunentiercorrespondantlacomposantedemande.
Lacomposantepeuttrespcifiel'aided'undescaractressuivants :
Caractre Signification
U Le timestamp !
Y Anne sur 4 chiffres
z Jour de l'anne
y Anne sur 2 chiffres
m ou n Numro du mois
d ou j Numro du jour du mois
G Heure sur 24
g ou h Heure sur 12
i Minutes
s Secondes
t Nombre de jours dans le mois
L Anne bissextile
Z Dcalage horaire en secondes
B Heure Internet Swatch
I (" i " majuscule) Heure d't (1)/Heure d'hiver (0)
W Numro de semaine de l'anne
Exemple
<?php
// affichage de la date/heure courante pour contrle
setlocale(LC_ALL,"fr");
echo strftime("%A %d %B %Y - %H:%M:%S"),"<BR>";
// extraction de diffrentes composantes
$composantes = str_split('UYmdHisztwW');
foreach($composantes as $composante) {
echo "$composante = ",idate($composante),"<BR>";
}
?>
Rsultat
Gnrerunnombrealatoire
Les fonctions rand et srand permettent respectivement de gnrer des nombres alatoires et d'initialiser le
gnrateurdenombresalatoires.
Syntaxe
srand([entier valeur])
entier rand([entier min[, entier max]])
Valeur
Valeurutilisepourinitialiserlegnrateurdenombresalatoires.galeunevaleuralatoiresinonspcifie.
min
et max
Bornesdesnombresalatoiresgnrer
Valeurpardfautdemin=0
Valeurpardfautdemax=unevaleurdonneparlafonctiongetrandmax
La fonction rand retourne un nombre alatoire entier, compris entre la borne minimum et la borne maximum
incluses.
Depuis la version 4.2, il n'est plus ncessaire d'appeler la fonction srand avant la fonction rand cela est fait
automatiquement.Demme,depuiscetteversion,leparamtred'initialisationdesrandestoptionnel.
Exemple
<?php
?>
Rsultat
29261
20738
18963
29332
4413
7474
L'oprateurd'affectationestlesignegal(=).
Syntaxe
$variable = expression;
Exemple
<?php
$nom = "Olivier";
$indice = 1;
?>
Aveccettesyntaxe,l'affectations'effectueparvaleur,c'estdirequelavaleurdel'expressionsituedroite
du signe gal est copie dans la variable mentionne gauche. Lors de l'affectation d'une variable dans une
autre,lamodificationultrieuredelapremirevariableestsanseffetsurlaseconde.
Exemple
<?php
// initialisation d'une variable
$x = 1;
// affectation de la variable $x dans la variable $y
$y = $x;
// modification de la variable $x
$x = 2;
// affichage du rsultat
echo "\$x = $x<BR>";
echo "\$y = $y<BR>";
?>
Rsultat
$x = 2
$y = 1
L'opration d'affectation est une expression qui possde une valeur gale la valeur affecte, et qui peut tre
utilise directement dans une autre expression. Par exemple, la valeur de l'expression $x=1 est 1,etilestlicite
d'crireuneinstructiondutype$y=($x=1)+2affectantlavaleur3$y.
Exemple
<?php
// affectation en une instruction de $x et $y
$y = ($x = 1) + 2;
// affichage du rsultat
echo "\$x = $x<BR>";
echo "\$y = $y<BR>";
?>
Rsultat
$x = 1
$y = 3
Cettetechniqueesttrspratiquemaispeutnuirelalisibilitducode.
Pour tous les oprateurs tudis dans ce chapitre, des espaces peuvent tre prsents autour de l'oprateur.
DepuisPHP4,ilestpossiblederaliseruneaffectationparrfrenceenutilisantl'oprateur&.
Syntaxe
$variable2 = &$variable1;
Avec cette syntaxe, la valeur de la variable $variable1 n'est pas copie dans la variable $variable2. La
variable $variable2 fait rfrence la variable $variable1 les deux variables pointent vers la mme zone
mmoireetlamodificationd'unedesdeuxvariablesserpercutesurl'autre.
Exemple
<?php
// initialisation d'une variable
$nom = "Olivier";
// affectation dans une autre variable par rfrence
$patronyme = &$nom;
// affichage du rsultat
echo "<B>Initialement :</B><BR>";
echo "\$nom = $nom<BR>";
echo "\$patronyme = $patronyme<BR>";
// modification de premire variable
$nom = "Heurtel";
// affichage du rsultat
echo "Aprs modification de \$nom :</B><BR>";
echo "\$nom = $nom<BR>";
echo "\$patronyme = $patronyme<BR>";
// modification de premire variable
$patronyme = "Olivier";
// affichage du rsultat
echo "<B>Aprs modification de \$patronyme :</B><BR>";
echo "\$nom = $nom<BR>";
echo "\$patronyme = $patronyme<BR>";
?>
Rsultat
Initialement :
$nom = Olivier
$patronyme = Olivier
Aprs modification de $nom :
$nom = Heurtel
$patronyme = Heurtel
Aprs modification de $patronyme :
$nom = Olivier
$patronyme = Olivier
Leseuloprateurdechaneestl'oprateurdeconcatnation,galaupoint(.).
Syntaxe
chane1.chane2;
Cette syntaxe retourne une chane gale la premire chane immdiatement suivie de la deuxime aucun
sparateurn'estplacentrelesdeuxchanes.
Exemple
<?php
// utilisation de l'oprateur de concatnation sur plusieurs
// expressions littrales
echo "Olivier"." "."Heurtel"."<BR>";
// initialisation de deux variables
$prnom = "Olivier";
$nom = "Heurtel";
// utilisation de l'oprateur de concatnation avec des
// variables et des expression littrales
echo $prnom." ".$nom."<BR>";
// peut tre crit plus simplement en utilisant la
// substitution des variables
echo "$prnom $nom<BR>";
?>
Rsultat
Olivier Heurtel
Olivier Heurtel
Olivier Heurtel
Lesoprateursdecomparaisonsontlessuivants :
Lesoprateurslogiquessontlessuivants :
Les oprateurs and et && ainsi que or et || sont identiques mais n'ont pas la mme prcdence (cf. I
Prcdencedesoprateurs).
Unautreoprateurconditionnel,l'oprateurternaire"?",fonctionnecommedanslelangage C.
Syntaxe
expression1?expression2:expression3
Cette instruction retourne la valeur de expression2 si expression1 est valu TRUE, et la valeur de
expression3,siexpression1estvaluFALSE.Si expression1n'estpasdetypeboolen,uneconversionest
effectueselonlesrglesdcritesdanslechapitre3.
Exemple
<?php
// affichage d'un message dpendant de la valeur de $nom
echo "Bonjour ".(empty($nom)?"inconnu":$nom)." ! <BR>";
// initialisation de la variable $nom
$nom = "Olivier";
// nouvelle tentative
echo "Bonjour ".(empty($nom)?"inconnu":$nom)." ! <BR>";
// autre mthode (moins lisible ?)
echo "Bonjour ".($nom?$nom:"inconnu")." ! <BR>";
?>
Rsultat
Bonjour inconnu !
Bonjour Olivier !
Bonjour Olivier !
Surledernierexemple,nousexploitonslefaitqu'unechanevideestvalue FALSEetunechanenonvide
TRUE.
Les oprateurs somme (+), diffrence (), multiplication (*), division (/), modulo (%) et concatnation (.)
peuventtrecombinsavecl'oprateurd'affectation(=)selonlasyntaxesuivante :
Syntaxe quivalent
$variable += expression $variable = $variable + expression
$variable -= expression $variable = $variable - expression
$variable *= expression $variable = $variable * expression
$variable /= expression $variable = $variable / expression
$variable %= expression $variable = $variable % expression
$variable .= expression $variable = $variable . expression
La prcdence des oprateurs dsigne l'ordre selon lequel les oprateurs sont traits dans une expression
complte.
Comme dans tous les langages, les parenthses peuvent tre utilises pour modifier l'ordre dans le traitement
desoprations.Danslapratique,n'hsitezpasutiliserlesparenthsespourvitertoutproblmeetamliorerla
lisibilitdesexpressions.
Laprcdencedesoprateursestlasuivante,dumoinsprioritaire(traitendernier)auplusprioritaire(traiten
premier) :
Oprateur
or
xor
and
= += = *= /= %= .=
?:
||
&&
== != ===
+ .
* / %
If
Lastructuredecontrleifpermetuneexcutionconditionnelled'instructions.
Cettestructurepossdedeuxsyntaxes :
Premire syntaxe
if (condition_1) {
instructions_1;
[ } elseif (condition_2) {
instructions_2; ]
[ ... ]
[ } else {
instructions_n; ]
}
Deuxime syntaxe
if (condition_1) :
instructions_1;
[ elseif (condition_2) :
instructions_2; ]
[ ... ]
[ else :
instructions_n; ]
endif;
Leprincipedefonctionnementdelastructuredecontrleifestlesuivant :
- Si condition_1 est vraie alors les instructions instructions_1 sont excutes puis le contrle est pass aux
instructions qui suivent la structure de contrle. Par exemple, l'excution du programme se poursuit l'instruction qui
suit directement la fin de la structure de contrle.
- Si condition_1 n'est pas vraie, le processus est rpt pour les ventuels couples
condition_i/instructions_i suivants, introduits par le mot cl elseif.
- Si aucune condition n'est vraie, les ventuelles instructions instructions_n, introduites par le mot cl else sont
excutes puis le contrle est pass aux instructions qui suivent la structure de contrle.
Plusieursclauseselseifpeuventtreprsentes.
Silesexpressionsdfinissantlesconditionsnesontpasdetypeboolen,uneconversionesteffectueselonles
rglesvoquesdanslechapitre3.
Exemple
<?php
// structure if simple
if (empty($nom)) {
echo "Bonjour inconnu ! Je vais vous appeler Olivier.<BR>";
$nom = "Olivier";
}
// structure if / else
if (empty($nom)) {
echo "Bonjour inconnu !<BR>";
} else {
echo "Bonjour $nom !<BR>";
}
// structure if / elseif / else
if (empty($nom)) {
echo "Bonjour inconnu !<BR>";
} elseif (empty($ge)) {
echo "Bonjour $nom ! Je ne connais pas votre ge.<BR>";
Rsultat
L'crituredelastructureestparfaitementlibre toutpeuttrecritsuruneligne.
Exemple
<?php
if (empty($nom)) { $nom = "Olivier"; }
if (empty($nom)) { echo "Bonjour inconnu !<BR>"; }
else { echo "Bonjour $nom !<BR>"; }
?>
Rsultat
Bonjour Olivier !
L'important est d'adopter une convention d'criture en essayant de rendre le code le plus lisible possible
(notammentenemployantdesindentations).
La deuxime syntaxe est surtout utilise pour crire une structure de contrle sur plusieurs blocs PHP entre
lesquelsducodeHTMLestintercal.
Le principe d'analyse de la structure if - elseif - else est le mme qu'avec la premire structure, mais au
lieud'excuterdesinstructionsPHP,lemoteurincorporedanslersultatlecodeHTMLassocilacondition.
Exemple
<?php
$nom = "Olivier";
?>
<HTML>
<HEAD><TITLE>Accueil</TITLE></HEAD>
<BODY>
<?php if (empty($nom)) : // condition PHP ?>
<!-- Code HTML -->
Bonjour inconnu !<BR>
<?php elseif (empty($ge)) : // suite de la condition PHP ?>
<!-- Code HTML -->
Je connais votre <B><FONT COLOR="green">nom</FONT></B>
mais pas votre <B><FONT COLOR="red">ge</FONT></B>.<BR>
<?php else : // suite de la condition PHP ?>
<!-- Code HTML -->
Je connais votre <B><FONT COLOR="green">nom</FONT></B>
et votre <B><FONT COLOR="green">ge</FONT></B>,
mais je ne dirai rien !<BR>
<?php endif; // fin de la condition PHP ?>
</BODY>
</HTML>
Cette syntaxe est rellement trs pratique pour raliser une construction conditionnelle d'une page HTML, en
vitantlalourdeurdel'utilisationd'unseulblocPHPgnranttoutlecodeHTMLavecl'instructionecho.
Switch
La structure de contrle switch, quivalente aux if - elseif multiples, est utilise pour la comparaison du
rsultatd'uneexpressionavecplusieursrsultats.
Cettestructurepossdedeuxsyntaxes :
Premire syntaxe
switch (expression) {
case expression_1:
instructions_1;
[break;]
[ case expression_2:
instructions_2;
[break;] ]
[ ... ]
[ default:
instructions_n;
[break;] ]
}
Deuxime syntaxe
switch (expression) :
case expression_1 :
instructions_1;
[break;]
[ case expression_2 :
instructions_2;
[break;] ]
[ ... ]
[ default :
instructions_n;
[break;] ]
endswitch;
Leprincipedefonctionnementdelastructuredecontrleswitchestlesuivant :
- Si expression est gal expression_i alors les instructions associes instructions_i sont excutes et les
comparaisons se poursuivent s'il n'y a pas d'instruction break.
- Si aucune galit n'est trouve, les ventuelles instructions instructions_n introduites par le mot cl default,
sont excutes.
Plusieursclausescasepeuventtreprsentes.
Lorsqu'une galit est vrifie et que les instructions associes sont excutes, l'instruction switch n'est pas
interrompueetlesexpressions casesuivantessontvalues.Pourinterromprel'excutiondel'instructionswitch
etl'valuationdesclausescase,ilfaututiliserl'instructionbreak(forcelasortiedelastructuredecontrle).
Exemple
<?php
// structure switch simple
switch ($nom) {
case "" :
echo "Bonjour inconnu !
Je vais vous appeler Olivier.<BR>";
$nom = "Olivier";
Nous voyons bien, sur cet exemple, que l'instruction switch n'est pas interrompue lorsqu'une expression case
estvrifie :
- La premire expression case est vrifie, cela provoque l'initialisation de $nom et l'valuation se poursuit.
- Ainsi, la deuxime expression case est vrifie, un message est affich et l'valuation se poursuit.
- Au final, l'expression default est, elle aussi, vrifie et un autre message est affich.
Sicefonctionnementn'estpassouhait,ilsuffitd'ajouterdesinstructionsbreakpourinterromprel'excutionde
l'instructionswitchlorsqu'uneexpressioncaseestvrifie.
Exemple
<?php
// structure switch simple
switch ($nom) {
case "" :
echo "Bonjour inconnu !
Je vais vous appeler Olivier.<BR>";
$nom = "Olivier";
break;
case "Olivier" :
echo "Bonjour Matre $nom !<BR>";
break;
default :
echo "Bonjour lve $nom !<BR>";
}
?>
Comme pour le if, la deuxime syntaxe permet d'imbriquer du code HTML dans une structure de contrle
switch.
LepremiercasedoittrecritdansleblocPHPswitch.
Exemple
<?php
Rsultat
While
La structure de contrle while permet d'excuter en boucle une srie d'instructions tant qu'une condition est
vraie.
Commepourlesstructuresdecontrleconditionnelles,deuxsyntaxessontdisponibles.
Premire syntaxe
while (condition) {
instructions;
}
Deuxime syntaxe
while (condition):
instructions;
endwhile;
Leprincipedefonctionnementdelastructuredecontrlewhileestlesuivant :tantquelaconditioncondition
estvraie,lesinstructionsinstructionssontexcutes.
Si l'expression dfinissant la condition n'est pas de type boolen, une conversion est effectue selon les rgles
voquesdanslechapitre3.
Exemple
<?php
// initialiser une variable
$nom = "OLIVIER";
// dterminer le nombre de caractres de la variable
$longueur = strlen($nom);
// initialiser un indice
$indice = 0;
// tant que l'indice est infrieur la longueur de la chane
while ($indice < $longueur) {
// afficher le caractre correspondant l'indice suivi
// d'un saut de ligne
echo "$nom[$indice]<BR>";
// incrmenter l'indice
$indice++;
}
?>
Rsultat
O
L
I
V
I
E
R
Classiquement,cettestructureadoptelescomportementssuivants :
- Si la condition est fausse la premire itration, les instructions situes l'intrieur de la boucle ne sont jamais
excutes.
- Si la condition n'est jamais fausse, les instructions l'intrieur de la boucle sont excutes sans fin (pas tout fait
puisque le temps d'excution d'un script est limit par la directive de configuration max_execution_time.
Comme pour les structures conditionnelles, la deuxime syntaxe permet d'imbriquer du code HTML dans une
structuredecontrlewhile.
<?php
$numro = 0;
$nombre = 5;
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<!-- Construction d'un formulaire HTML proposant $nombre
---- (5 sur cet exemple) zones de texte -->
<FORM>
Indiquez vos cinq comptences principales :<BR>
<?php while($numro++ <+$nombre) : // boucle PHP ?>
<!-- Code HTML -->
<INPUT TYPE="text" LENGTH="40"><BR>
<?php endwhile; // fin de la boucle PHP ?>
<INPUT TYPE="submit" VALUE = "OK">
</FORM>
</BODY>
</HTML>
Rsultat
Do...while
La structure de contrle do ... while permet d'excuter en boucle une srie d'instructions tant qu'une
conditionestvraie.
Contrairementauxautresstructuresdecontrle,uneseulesyntaxeestdisponible.
Syntaxe
do {
instructions;
} while (expression);
Le principe de fonctionnement de la structure de contrle do ... while est le suivant : tant que la condition
condition est vraie, les instructions instructions sont excutes. la diffrence de la structure while, la
condition est teste la fin de la boucle les instructions instructions sont donc forcment excutes au
moinsunefois.
Si l'expression dfinissant la condition n'est pas de type boolen, une conversion est effectue selon les rgles
voquesdanslechapitre3.
Exemple
<?php
// initialiser une variable
$nom = "OLIVIER";
Rsultat
O
L
I
V
I
E
R
Surcetexemple,lesinstructionsdelabouclesontexcutesunefoismmesilachaneestvide.Ici,l'utilisation
d'unestructurewhileseraitsansdoutepluspertinente.
For
Lastructuredecontrlefor,commedanslelangageC,permetd'excuterdesinstructionsdemanireitrative,
encontrlantlesitrationsl'aidedetroisexpressions.
Deuxsyntaxessontdisponibles.
Premire syntaxe
Deuxime syntaxe
Leprincipedefonctionnementdecettestructuredecontrleestlesuivant :
- expression2 est excute, et le rsultat est valu comme boolen, avant chaque itration (dont la premire): si le
rsultat est valu TRUE, les instructions instructions sont excutes; si le rsultat est valu FALSE, la
boucle s'arrte et le contrle est pass la premire instruction qui suit la construction.
Danslagrandemajoritdescas,lastructureforestemployedelamaniresuivante :
Exemple
<?php
// utilisation de la structure for pour parcourir un tableau
// indices entiers conscutifs
// initialisation du tableau
$couleurs = array("bleu","blanc","rouge");
// dtermination du nombre d'lments dans le tableau
$nombre = count($couleurs);
// boucle utilisant un indice $i qui dmarre 0 ($i = 0)
// qui est incrment d'une unit chaque itration ($i++) ;
// la boucle se poursuit tant que l'indice est infrieur au
// nombre d'lments prsents dans le tableau ($i < $nombre)
for ($i = 0; $i < $nombre; $i++) {
echo "$couleurs[$i]<BR>";
};
?>
Rsultat
bleu
blanc
rouge
Avecunpeud'habitude,ilestpossiblederaliserdestraitementsbeaucouppluscomplexes(audtrimentparfois
delalisibilitducode)l'aidedel'instructionfor(ventuellementutiliseseule).
Exemple
<?php
// tout se passe dans l'instruction for !
for
(
// premire itration : initialisation d'un indice $i 1
// et d'une variable $total 0
$i = 1,$total = 0;
// condition d'arrt de la boucle : $i = 5
$i <= 5;
// chaque itration : incrmentation de $total avec le
// valeur courante de $i puis stockage dans un tableau de
// la valeur courante de $i juste avant de l'incrmenter
$total += $i,$nombres[] = $i++
);
// la sortie de la boucle, le tableau contient la liste des
// cinq premiers entiers, et la variable $total la somme des
// cinq premiers entiers
// il ne reste plus qu' afficher tout cela ...
echo implode($nombres,"+")."=$total";
?>
Rsultat
1+2+3+4+5=15
De manire "classique", la deuxime syntaxe permet d'imbriquer du code HTML dans une structure de contrle
for :
Exemple
<?php
$nombre = 5;
?>
Rsultat
Continue
L'instruction continue peut tre utilise dans toutes les structures de contrle itratives pour interrompre
l'itrationencoursetpasserl'itrationsuivante.
Syntaxe
continue [n];
continue [(n)];
L'instruction continueaccepteunparamtrequiindiquedecombiendeniveau(x)remontersidesstructuresde
contrleitrativessontimbriques.Pardfaut,l'instructioncontinueremonted'unniveau.
<?php
// boucle qui affiche tous les nombres composs de deux
// chiffres compris entre 1 et 3
for ($premier = 1; $premier <= 3; $premier++) {
for ($deuxime = 1; $deuxime <= 3; $deuxime++) {
echo "$premier$deuxime ";
}
};
?>
Rsultat
11 12 13 21 22 23 31 32 33
<?php
// boucle qui affiche tous les nombres composs de deux
// chiffres compris entre 1 et 3
for ($premier = 1; $premier <= 3; $premier++) {
for ($deuxime = 1; $deuxime <= 3; $deuxime++) {
if ($deuxime == 2) {
Rsultat
11 13 21 23 31 33
Plusaucunnombreprsentantun2endeuximechiffren'estaffich.
<?php
// boucle qui affiche tous les nombres composs de deux
// chiffres compris entre 1 et 3
for ($premier = 1; $premier <= 3; $premier++) {
for ($deuxime = 1; $deuxime <= 3; $deuxime++) {
if ($deuxime == 2) {
// passer la suite de deux niveaux si $deuxime = 2
continue 2;
}
echo "$premier$deuxime ";
}
};
?>
Rsultat
11 21 31
Puisque le contrle passe la suite de la boucle principale lorsque le deuxime chiffre est gal 2, plus aucun
nombreprsentantun2,etmaintenantun3,endeuximechiffren'estaffich.
Fonctionnement
Les fonctions include, include_once, require et require_once permettent d'inclure un fichier dans un
scriptPHP.
Syntaxe
entier include(fichier)
entier include_once(fichier)
require(fichier)
require_once(fichier)
fichier Nomdufichierinclure(peuttreindiquavecuncheminabsoluourelatif).
En cas d'erreur, les fonctions include et include_once gnrent une simple erreur de niveau E_WARNING qui
n'interrompt pas l'excution du script. Ce n'est pas le cas des fonctions require et require_once qui
provoquentalorsuneerreurfataleinterrompantl'excutionduscript.
LefichierincluspeutcontenirducodeHTML,ducodePHPoulesdeux.S'iloffreducodePHP,cecodedoittre
crit entre les balises PHP habituelles. Le code HTML, prsent dans le fichier inclus, est intgr tel quel dans la
pageenvoyeaunavigateur,commes'iltaitdanslescriptappelant.LecodePHP,prsentdanslefichierinclus,
estexcutlencore,commes'iltaitdanslescriptappelant.
Lorsdel'inclusiondecodePHP,lesvariablesetconstantes,dfiniesdanslefichierinclussontutilisablesdansle
scriptappelantetrciproquement.Toutsepassecommes'iln'yavaitqu'unseulscriptaprsl'inclusion,etdonc,
uneportegalecescriptpourlesvariablesetconstantes.
Il est possible d'inclure plusieurs fichiers dans un script, ou d'imbriquer les inclusions (inclure un fichier qui lui
mmeinclutunfichierdansunautre).
Avec les fonctions include et require, le processus d'inclusion est rpt plusieurs fois si le mme fichier est
inclusplusieursfois.
Dans certains cas, cette situation peut tre indsirable et involontaire, notamment lorsqu'un fichier est inclus
unepremirefoisdirectementdansunscriptetunedeuximefoisindirectementparl'inclusiond'unautrefichier.
Ce comportement peut tre vit en utilisant les fonctions include_once et require_once qui garantissent
qu'unfichierneserainclusqu'unefois,mmes'ilestappelplusieursfois.
L'extension du fichier inclure est parfaitement libre. Il n'est notamment pas obligatoire d'utiliser l'extension .php pour inclure
du code PHP : le fichier inclus n'est pas directement excut par le moteur PHP (c'est le script appelant qui l'est). Pour les
fichiers inclus qui ne peuvent ou ne doivent pas tre excuts directement, il est alors possible d'utiliser une autre extension
(.inc par exemple).
<?php
// dclaration d'une variable $x dans le script principal
$x = 1;
// inclusion d'un fichier
include("commun.inc");
// affichage de la variable $x
echo "Valeur de \$x dans le script principal : $x<BR>";
// affichage de la variable $y (dfinie dans le fichier
// inclus)
echo "Valeur de \$y dans le script principal : $y<BR>";
?>
<?php
include("commun.inc");
$x = 1;
echo "Valeur de \$x dans le script principal : $x<BR>";
echo "Valeur de \$y dans le script principal : $y<BR>";
include("commun.inc");
?>
Rsultat de l'excution du script principal (si les erreurs de niveau E_NOTICE ne sont pas affiches)
Surcetexemple,lorsdelapremireinclusion,lavariable$xn'apasencoretdfiniedanslescriptprincipalet
donnedoncunevaleurvidelorsdel'affichage.
<?php
include_once("commun.inc");
$x = 1;
echo "Valeur de \$x dans le script principal : $x<BR>";
echo "Valeur de \$y dans le script principal : $y<BR>";
include_once("commun.inc");
?>
Rsultat de l'excution du script principal (si les erreurs de niveau E_NOTICE ne sont pas affiches)
La deuxime inclusion n'est pas effectue car le fichier a dj t inclus et l'inclusion est demande avec la
Dans le fichier php.ini, la directive include_path permet de dfinir des chemins de recherche pour l'inclusion des
fichiers.
Utilisation
Latechniqued'inclusionestpratiquepourdeuxgrandstypesd'utilisation :
- Inclure des dfinitions statiques: constantes, dfinitions de fonctions. Dans ce cas, il faut plutt utiliser les fonctions
include_once ou require_once afin d'viter une ventuelle double inclusion (qui provoquerait une erreur dans la
dfinition des fonctions).
- Inclure du code PHP ou HTML dynamique qui s'excute effectivement au moment de l'inclusion: section HTML
commune plusieurs pages (entte, pied de page) ou code commun plusieurs pages (bien que dans cette hypothse,
la dfinition d'une fonction soit plus pertinente). Dans ce cas, il faut plutt utiliser les fonctions include ou require
afin de garantir que l'inclusion se produit chaque appel.
Exemple
<?php
// dfinition des constantes
// par exemple, le nom du site
DEFINE("NOM_SITE","monSite.com");
?>
<?php
// inclusion du fichier des contantes
include_once("constantes.inc");
?>
<HTML>
<HEAD><TITLE><?php echo NOM_SITE; ?></TITLE></HEAD>
<BODY>
</BODY>
</HTML>
<?php
// inclusion du dbut de la page
include("dbut.inc");
?>
Contenu de la page ...
<?php
// inclusion de la fin de la page
include("fin.inc");
?>
<HTML>
<HEAD><TITLE>monSite.com</TITLE></HEAD>
<BODY>
Contenu de la page ...
</BODY>
</HTML>
Syntaxe
break [n];
ou
break[(n)];
L'instruction break accepte un paramtre qui indique de combien de niveau(x) remonter si des structures de
contrlesontimbriques.Pardfaut,l'instructionbreakremonted'unniveau.
<?php
// boucle qui affiche tous les nombres compose de deux
// chiffres compris entre 1 et 3
for ($premier = 1; $premier <= 3; $premier++) {
for ($deuxime = 1; $deuxime <= 3; $deuxime++) {
if ($deuxime == 2) {
// interrompre la boucle courante si $deuxime = 2
break; // = break 1
}
echo "$premier$deuxime ";
}
};
?>
Rsultat
11 21 31
Plusaucunnombrecomprenantunchiffresuprieur2endeuximechiffren'estaffich.
<?php
// boucle qui affiche tous les nombres composs de deux
// chiffres compris entre 1 et 3
for ($premier = 1; $premier <= 3; $premier++) {
for ($deuxime = 1; $deuxime <= 3; $deuxime++) {
if ($deuxime == 2) {
// interrompre la boucle principale si $deuxime = 2
break 2;
}
echo "$premier$deuxime ";
}
};
?>
Rsultat
11
La boucle principale est interrompue ds qu'un chiffre 2 est rencontr en deuxime chiffre (soit pour le nombre
12) seullenombre11estdoncaffich.
Syntaxe
exit[(chane message)];
exit[(entier statut)];
die[(chane message)];
die[(entier statut)];
message Messageafficheravantd'interromprelescript.
statut Statutderetour(entierentre1et254).Depuislaversion4.2,cetteinformationn'estpasafficheavant
l'interruptionduscript.
Lescripts'interromptbrutalementetl'affichageestlaiss"enl'tat".LapageHTMLenvoyeaunavigateurpeut
donctreincohrenteouvide.
Sil'instructionoulafonctionsontappelesdansunfichierinclus,c'estlescriptprincipalquiestinterrompu.
<?php
// gnrer le dbut de la page
echo "Bonjour ";
// une condition n'est pas vrifie, interrompre le script
if (empty($nom)) {
exit(1); // pas de message ...;
}
// poursuivre la gnration de la page
echo $nom;
?>
Rsultat
Bonjour
<?php
// gnrer le dbut de la page
echo "Bonjour ";
// une condition n'est pas vrifie, interrompre le script
if (empty($nom)) {
exit("Utilisateur inconnu.
Impossible de continuer.</B>");
}
// poursuivre la gnration de la page
echo $nom;
?>
Rsultat
Introduction
l'instar des diffrents langages de dveloppement, PHP offre la possibilit de dfinir ses propres fonctions
(appeles fonctions "utilisateur") avec tous les avantages associs (modularit, capitalisation...). Une fonction
est un ensemble d'instructions identifies par un nom, dont l'excution retourne une valeur et dont l'appel peut
tre utilis comme oprande dans une expression. Une procdure est un ensemble d'instructions identifies par
unnomquipeuttreappelcommeuneinstruction.
Dclarationetappel
Lemotclfunctionpermetd'introduireladfinitiond'unefonction.
Syntaxe
function nom_fonction([paramtre]) {
instructions;
}
nom_fonction Nomdelafonction(doitrespecterlesrglesdenommageprsentesdanslechapitreVue
d'ensembledePHP).
paramtre Paramtresventuelsdelafonctionexprimssousformed'unelistedevariables(cf.Paramtresci
aprs) :$paramtre1, $paramtre2, ...
instructions Ensembledesinstructionsquicomposentlafonction.
Silafonctionretourneunevaleur,ilestpossibled'utiliserl'instruction returnpourdfinirlavaleurderetourde
lafonction(cf.Valeurderetourciaprs).
LenomdelafonctionnedoitpastreunmotrservPHP(nomdefonctionnative,d'instruction)nitregalau
nomd'uneautrefonctionpralablementdfinie.
Une fonction utilisateur peut tre appele comme une fonction native de PHP : dans une affectation, dans une
comparaison...
Exemple
<?php
// fonction sans paramtre qui affiche " Bonjour ! "
// pas de valeur de retour
function afficher_bonjour() {
echo "Bonjour !<BR>";
}
// fonction avec 2 paramtres qui retourne le produit
// des deux paramtres
function produit($valeur1,$valeur2) {
return $valeur1 * $valeur2;
}
// utilisation de la fonction afficher_bonjour
afficher_bonjour();
// utilisations de la fonction produit
// - dans une affectation
$rsultat = produit(2,4);
echo "$rsultat<BR>";
// - dans une comparaison
if (produit(10,12) > 100) {
echo "Le rsultat est suprieur 100.<BR>";
}
// - dans une affectation et une comparaison (lisibilit ?)
if (($rsultat = produit(10,12)) > 100) {
echo "$rsultat est suprieur 100.<BR>";
}
?>
Bonjour !
8
Le rsultat est suprieur 100.
120 est suprieur 100.
Dans le langage PHP, il n'existe pas proprement parler de procdure. Pour dfinir quelque chose d'quivalent une
procdure, il suffit de dfinir une fonction qui ne retourne pas de valeur et d'appeler la fonction comme s'il s'agissait d'une
instruction (comme la fonction afficher_bonjour par exemple).
Ilestpossibled'utiliserunefonctionavantdeladfinir.
Exemple
<?php
// utilisation de la fonction produit
echo produit(5,5);
// dfinition de la fonction produit
function produit($valeur1,$valeur2) {
return $valeur1 * $valeur2;
}
?>
Rsultat
25
Iln'yadoncaucunproblmepourdfinirdesfonctionsquis'appellententreelles.
Une fonction est utilisable uniquement dans le script o elle est dfinie. Pour l'employer dans plusieurs scripts, il faut, soit
recopier sa dfinition dans les diffrents scripts (vous perdez l'intrt de dfinir une fonction), soit la dfinir dans un fichier inclus
partout o la fonction est ncessaire.
Exemple
<?php
// dfinition de la fonction produit
function produit($valeur1,$valeur2) {
return $valeur1 * $valeur2;
}
?>
<?php
// inclusion du fichier contenant la dfinition des fonctions
include("fonctions.inc");
// utilisation de la fonction produit
echo produit(5,5);
?>
Fonctionvariable
PHPproposeune"fonctionvariable"quipermetdestockerunnomdefonctiondansunevariableetd'appelerla
variable dans une instruction, comme si c'tait une fonction, avec la notation $variable(). Sur une telle
criture,PHPremplacelavariableparsavaleuretchercheexcuterlafonctioncorrespondante(quidoit,bien
entendu,exister).
Exemple
<?php
// fonction qui effectue un produit
function produit($valeur1,$valeur2) {
Rsultat
8
15
Paramtres
Lesparamtresventuelsdelafonctionsontdfinissouslaformed'unelistedevariables.
Danscetroisimepoint,nousallonstudierlespossibilitssuivantes :
Valeurpardfaut
Ilestpossibled'indiquerqu'unparamtrepossdeunevaleurpardfautgrcelasyntaxesuivante :
La valeur par dfaut d'un paramtre doit tre une expression littrale et ne peut tre ni une variable, ni une
fonction,niuneexpressioncompose.
La valeur par dfaut est utilise comme valeur d'un paramtre lorsque la fonction est appele, sans mentionner
devaleurpourleparamtreenquestion.
Exemple
<?php
produit() = 2
produit(3) = 6
produit("", 4) = 0
produit(NULL, 4) = 0
Ne pas donner de valeur un paramtre ayant une valeur par dfaut n'est possible qu'en partant de la droite.
Passer une valeur de "vide" ("" ou NULL) ne rsout pas le problme car la valeur en question est convertie par
PHPdansletypeadquat(icienentiergal0).
Exemple autoris
Passer un nombre insuffisant de paramtres et ne pas avoir de valeur par dfaut gnre une erreur. Passer trop de paramtres
ne gnre pas d'erreur ; les paramtres en trop sont ignors.
Passageparrfrence
Par dfaut, le passage des paramtres s'effectue par valeur : c'est une copie de la valeur qui est passe la
fonction. En consquence, la modification des paramtres l'intrieur de la fonction n'a aucun effet sur les
valeursdanslescriptappelant.
Exemple
<?php
// dfinition d'une fonction qui prend un paramtre
function par_valeur($paramtre) {
// incrmentation du paramtre
$paramtre++;
// affichage du paramtre l'intrieur de la fonction
echo "\$paramtre = $paramtre<BR>";
}
// initialisation d'une variable
$x = 1;
// affichage de la variable avant l'appel la fonction
echo "\$x avant appel = $x<BR>";
// appel de la fonction en utilisant la variable comme valeur
// du paramtre
par_valeur($x);
// affichage de la variable aprs l'appel la fonction
echo "\$x aprs appel = $x<BR>";
?>
Rsultat
$x avant appel = 1
$paramtre = 2
$x aprs appel = 1
En cas de besoin, il est possible d'avoir un passage par rfrence en utilisant l'oprateur de rfrence & (cf.
chapitre Oprateurs L'oprateurd'affectationparrfrence)devantlenomduparamtredansladfinitionde
la fonction. Avec une telle dfinition, c'est une rfrence vers la variable (plus une copie) qui est passe la
fonction cettederniretravailledirectementsurlavariableduscriptappelant.
Exemple
<?php
Rsultat
$x avant appel = 1
$paramtre = 2
$x aprs appel = 2
Avec une telle dfinition, il n'est plus possible de passer une constante ou une expression comme valeur du
paramtre.
Exemples interdits
par_rfrence(2);
par_rfrence(1+1);
par_rfrence(UN); // UN = constante dfinie prcdemment
Listevariabledeparamtres
l'intrieurd'unefonction,ilestpossibled'utiliserlestroisfonctionsPHPsuivantes :
Fonction Rle
func_num_args Donne le nombre de paramtres passs la fonction.
func_get_args Retourne la liste des paramtres passs la fonction (dans un
tableau).
func_get_arg Retourne la valeur d'un paramtre dont le numro est prcis.
Syntaxe
entier func_num_args()
tableau func_get_args()
mixte func_get_arg(entier numro)
numro Numroduparamtredemand(0=premierparamtre).
l'aidedecesfonctionsnatives,ilestalorstrssimpled'crireunefonctionquiaccepteunnombrevariablede
paramtres.Lesprincipessontlessuivants :
- rcuprer, dans le corps de la fonction, les paramtres avec les fonctions func_get_args ou func_get_arg et les utiliser
(typiquement dans une boucle).
Exemple
<?php
// fonction qui effectue le produit de tous les paramtres
function produit() {
if (func_num_args() == 0) {
Rsultat
0
1
2
6
24
Danslapratique,rienn'interditauxparamtresd'tredetypesdiffrents.
Par ailleurs, il est possible de dclarer explicitement les premiers paramtres et d'accepter ensuite une liste
variabledeparamtrescomplmentaires.Danscecas,lesparamtresexplicitementdclarssontreprisdansle
comptageetdanslalistedesparamtres.Ilconvientdoncdelesliminersoimmedutraitement.
Supposons, par exemple, que nous souhaitons disposer d'une fonction qui permet de stocker, dans un tableau
passenpremierparamtre,plusieurscouplescl/valeurpasssenparamtrescomplmentaires.
Exemple
Rsultat
Cl Valeur
cl1 valeur1
cl2 valeur2
...
Exemple
<?php
function affecte_tableau(&$tableau) {
// le premier paramtre (tableau alimenter) est
// explicitement dfini car il doit tre pass par
// rfrence (la fonction le modifie directement)
// rcuprer le nombre d'argument (tient compte
// de &$tableau)
$nombre_param = func_num_args();
if ($nombre_param < 2) {
// pas assez de paramtres => erreur (il doit y avoir au
// minimum 3 paramtres en tout, le tableau et un couple
// cl/valeur
$rsultat = "Pas assez de paramtres";
Rsultat
Pourtrerigoureux,ilfaudraitvrifierquelesclssontbienentiresoualphabtiques(parcontre,lavaleurpeut
treden'importequeltype,mmedutypetableau).
Valeurderetour
L'utilisationdel'instruction returnl'intrieurd'unefonction,permetdedfinirlavaleurderetourdelafonction
etdestoppersonexcution.
Syntaxe
return expression;
expression Expressiondontlersultatconstituelavaleurderetourdelafonction.
Lersultatd'unefonctionpeuttreden'importequeltype(chane,nombre,tableau...).
Exemple
<?php
// dfinition d'une fonction avec deux appels return
function valeur_retour($paramtre) {
if ($paramtre == 1) {
return "Premier return";
}
return "Deuxime return";
}
// appels la fonction
echo "valeur_retour(1) = ".valeur_retour(1)."<BR>";
echo "valeur_retour(0) = ".valeur_retour(0)."<BR>";
?>
Rsultat
Silafonctionneprsenteaucuneinstructionreturn(ousiaucuneinstructionreturnn'estexcute),lavaleur
deretourdelafonctionestNULL.
Considrationssurlesvariablesutilisesdanslesfonctions
Variablelocale
Lesvariablesutilisesl'intrieurd'unefonctionsontlocales :ellessontnondfiniesendehorsdelafonctionet
initialiseschaqueappeldelafonction.Ilenestdemmedesparamtresdelafonction.
Rciproquement, une variable dfinie en dehors de la fonction (dans le script appelant) n'est pas dfinie
l'intrieurdelafonction.
Exemple
<?php
// dfinition d'une fonction
function variable_locale() {
// initialisation de deux variables $x et $z l'intrieur
// de la fonction
$x<+>= 0;
$z = 3;
// affichage des variables $x, $y et $z
echo "Valeur de \$x dans la fonction = $x<BR>";
echo "Valeur de \$y dans la fonction = $y<BR>";
echo "Valeur de \$z dans la fonction = $z<BR>";
}
// initialisation de deux variables $x et $y dans le script
// appelant
$x = 1;
$y = 2;
// appel de la fonction
variable_locale();
// affichage des variables $x, $y et $z
echo "<P>";
echo "Valeur de \$x dans le script = $x<BR>";
echo "Valeur de \$y dans le script = $y<BR>";
echo "Valeur de \$z dans le script = $z<BR>";
?>
Cetexempleillustrelespointssuivants :
Variableglobale
PHP propose une notion de variable globale pour accder, dans une fonction, aux variables dfinies dans le
contexteduscriptappelant.
Pour cela, l'intrieur de la fonction, il faut dclarer les variables globales que la fonction utilise avec
l'instructionglobal.
Syntaxe
$variable Variableduscriptappelantquelafonctionsouhaiteutiliser.Plusieursvariablespeuventtre
mentionnes,enlessparantparunevirgule.
Exemple
<?php
// dfinition d'une fonction
function variable_globale() {
// dfinition des variables globales (ici $x)
global $x;
// affichage de $x au dbut de la fonction
echo "Valeur de \$x au dbut de la fonction = $x<BR>";
// modification de $x et initialisation de $z l'intrieur
// de la fonction
$x = 0;
$z = 3;
// affichage des variables $x, $y et $z
echo "Valeur de \$x la fin de la fonction = $x<BR>";
echo "Valeur de \$y dans la fonction = $y<BR>";
echo "Valeur de \$z dans la fonction = $z<BR>";
}
// initialisation de deux variables $x et $y dans le script
// appelant
$x = 1;
$y = 2;
// appel de la fonction
variable_globale();
// affichage des variables $x, $y et $z
echo "<P>";
Il est possible, sans dclaration, d'accder aux variables globales l'intrieur d'une fonction, en utilisant un
tableau associatif $GLOBALS gr par PHP. Dans ce tableau associatif, la cl est gale au nom de la variable
globale(sansle$),etlavaleur,lavaleurdelavariableglobale.
Exemple
<?php
// dfinition d'une fonction
function variable_globale() {
// affichage de variables globales en utilisant le tableau
// $GLOBALS
echo "Valeur de \$x au dbut de la fonction =
$GLOBALS[x]<BR>";
echo "Valeur de \$y au dbut de la fonction =
$GLOBALS[y]<BR>";
// modification de variables globales en utilisant le tableau
$GLOBALS["x"]++;
$GLOBALS["y"]++;
}
// initialisation de deux variables $x et $y dans le script
// appelant
$x = 1;
$y = 2;
// appel de la fonction
variable_globale();
// affichage des variables $x, $y et $z
echo "<P>";
echo "Valeur de \$x dans le script = $x<BR>";
echo "Valeur de \$y dans le script = $y<BR>";
?>
Rsultat
Un paramtre d'une fonction se comporte comme une variable locale la fonction, sauf, s'il est pass par rfrence, auquel
cas, il est quivalent une variable globale.
Variablestatique
Pardfaut,lesvariableslocalesd'unefonctionsontrinitialiseschaqueappeldelafonction.
L'instruction static permet de dfinir des variables locales statiques qui ont pour proprit de conserver leur
valeurd'unappell'autredelafonction,pendantladureduscript.
Syntaxe
$variable
Variableconcerne.
expression_littrale
Valeur initiale affecte la variable lors du premier appel la fonction l'intrieur du script. Seules les
expressionslittralesetlesconstantessontacceptes lesexpressionscomposesoulesfonctionsnesontpas
autorises.
Exemple
Rsultat
Cet exemple montre que la valeur de $variable_statique est bien conserve d'un appel l'autre, le premier
appel permettant de l'initialiser. Par contre, la variable $autre_variable est remise 0 chaque appel de la
fonction.
La valeur n'est conserve que pendant la dure du script : lorsque ce dernier se termine, la valeur est perdue et, au prochain
appel du script, la variable statique est rinitialise.
Lesconstantesetlesfonctions
Dans le chapitre Constantes, variables, types et tableaux, nous avons observ que la porte des constantes
taitlescriptdanslequelellessontdfinies.
la diffrence des variables, cette porte s'tend aux fonctions appeles dans le script : une constante peut
treutilisel'intrieurdelafonctionsansqu'ellesoitdclareglobale.
Rciproquement, une constante dfinie dans une fonction peut tre utilise dans un script, aprs appel de la
fonction.
Exemple
<?php
// dfinition d'une constante dans le script
define("CONSTANTE_SCRIPT","constante script");
// dfinition d'une fonction
function constante() {
// qui dfinit une constante
define("CONSTANTE_FONCTION","constante fonction");
// qui affiche une constante du script appelant
echo "Dans la fonction, CONSTANTE_SCRIPT = ".
CONSTANTE_SCRIPT."<BR>";
}
// appel de la fonction
Rsultat
Rcursivit
l'instar de nombreux langages, PHP autorise la rcursivit, c'estdire la possibilit pour une fonction de
s'appelerellemme.
Pour illustrer cette notion, nous allons crire une fonction gnrique qui permet d'afficher le contenu d'un
tableau,ventuellementmultidimensionnel.
Exemple
<?php
function afficher_tableau($tableau,$titre="",$niveau=0) {
// Paramtres
// - $tableau = tableau dont il faut afficher le contenu
// - $titre = titre afficher au dessus du contenu
// - $niveau = niveau d'affichage
// s'il y a un titre, l'afficher
if ($titre != "") {
echo "<P><B>$titre</B><BR>\n";
}
// tester s'il y a des donnes
if (isset($tableau)) { // il y a des donnes
// parcourir le tableau pass en paramtre
reset ($tableau);
while (list ($cle, $valeur) = each ($tableau)) {
// afficher la cl (avec indentation fonction
// du niveau)
echo
str_pad("",12*$niveau, " ").
htmlentities($cle)." = ";
// afficher la valeur
if (is_array($valeur)) { // c'est un tableau ...
// mettre une balise <BR>
echo "<BR>";
// et appeler rcursivement afficher_tableau pour
// afficher le tableau en question (sans titre et au
// niveau suprieur pour l'indentation)
afficher_tableau($valeur,"",$niveau+1);
} else { // c'est une valeur scalaire
// afficher la valeur
echo htmlentities($valeur)."<BR>";
}
}
} else {<+>// pas de donnes
// mettre une simple balise <BR>
echo "<BR>\n";
}
}
// Afficher un tableau de couleurs
$couleurs = array("Bleu","Blanc","Rouge");
afficher_tableau($couleurs,"Couleurs");
// Afficher un tableau de pays
$pays = array("FR" => "France","IT" => "Italie");
afficher_tableau($pays,"Pays");
// Afficher un tableau deux dimensions (couleurs et pays)
$cp = array("couleurs" => $couleurs,"pays" => $pays);
afficher_tableau($cp,"Couleurs & Pays");
?>
Rsultat
Couleurs
Pour tre rigoureux, il faudrait vrifier que la variable passe initialement en premier paramtre est bien un
tableau.
Nousallonsutilisercettefonctionplusieursreprisesdanscetouvrage,partantdel'hypothsequ'ellefaitpartie
d'unjeudefonctionsgnriquesdfiniesdansunfichierquiestinclusdanslescriptencasdebesoin.
Concept
Enversion5,lagestiondesobjetsdansPHPatcompltementrcriteafind'offrirdemeilleuresperformances
etplusdefonctionnalits.
PHPproposemaintenantdesfonctionnalitsclassiquesdeprogrammationorienteobjet :
- dfinition de classe ;
- hritage ;
- notions de classe ou mthode abstraite, de classe ou mthode finale, d'interface, d'attribut ou mthode statique (de classe) ;
- exceptions.
Une classe est un type composite regroupant des variables (appeles attributs de la classe) et des fonctions
(appeles mthodes de la classe). En soi, une classe ne contient pas de donnes c'est juste un modle, une
dfinition.
partir de la classe, il est possible de dfinir ("instancier") des objets qui ont la structure de la classe et qui,
eux,contiennentdesdonnes.
Dans cette partie, nous allons prsenter les fonctionnalits de base les plus couramment utilises : c'est une
introduction pratique aux fonctionnalits objet de PHP. Pour plus d'informations, reportezvous la
documentationdePHP.
Dfiniruneclasse
Lemotclclasspermetd'introduireladfinitiond'uneclasse.
Syntaxe
class nom_classe {
// dfinition des attributs
[
public | private | protected $attribut [= expression_littrale];
...
]
// dfinition des mthodes
[
[public | private | protected] function mthode() {
...
}
...
]
}
nom_classe
Nomdelaclasse(doitrespecterlesrglesdenommageprsentesdanslechapitreVued'ensembledePHP).
$attribut
Nomd'unevariablecorrespondantunattributdelaclasse.
expression_litrale
mthode
Dfinitiond'unefonctioncorrespondantunedesmthodesdelaclasse.
Lavisibilitdesattributsetdesmthodesestdfinieparundesmotsclssuivants :
public
L'attributoulamthodesontpublicsetl'onnepeutyaccderdel'extrieurdelaclasse.
private
L'attributoulamthodesontprivsetl'onnepeutyaccderquedel'intrieurdelaclasse.
protected
L'attribut ou la mthode sont protgs et l'on ne peut y accder que de l'intrieur de la classe ou des classes
drivesdelaclasse(voirlanotiond'hritage).
Pardfaut,unemthodeestpublique.Parcontre,lavisibilitdel'attributdoittrespcifie.
Ces variantes ont t introduites en version 5. En version 4, les attributs et mthodes sont obligatoirement
publics et le mot clvar (quivalent public) est utilis pour introduire la dfinition d'un attribut (pas de mot
clpourlesmthodes).
Les mthodes sont dfinies comme des fonctions utilisateur classiques (avec paramtres, instruction
return ...),mais,l'intrieurdelaclasse.Unemthoded'uneclassepeutavoirlemmenomqu'unefonction
utilisateurouqu'uneautremthoded'uneautreclasse.
Une des mthodes peut porter le mme nom que la classe dans laquelle elle est dfinie. Cette mthode
particulire, nomme mthode constructeur, est automatiquement appele la cration ("instanciation") d'un
nouvelobjet.Gnralement,cettemthodeestutilisepourinitialiserdesattributsquinepeuventl'treparune
simple expression littrale. En version 5, la mthode constructeur d'une classe peut tre nomme de manire
unifie __construct. Cette mthode de nommage est conseille car elle facilite l'appel de la mthode
constructeur d'une classe parent dans une classe drive (voir la notion d'hritage). En premier, PHP recherche
toujours une mthode nomme __construct s'il n'en trouve pas, il recherche une mthode portant le mme
nomquelaclasse.
Encomplment,enversion5,ilestpossibledespcifierunemthodedestructeurnomme __destruct(pasde
paramtre). Cette mthode destructeur est automatiquement appele lorsque la dernire rfrence un objet
estsupprime.Cettemthodepeuttreutilisepourlibrerdesressourcesutilisesparl'objet(dutypefichier,
informationsdansunebasededonnes,etc.).
Enfin,toujoursenversion5,ilestpossibledespcifierunemthodenomme__toString(pasdeparamtre)qui
permet de convertir un objet en chane. Cette mthode est automatiquement appele chaque fois que l'objet
est utilis dans un contexte o PHP attend une chane (par exemple dans un echo). Cette mthode doit
retournerunechanedanslaquellevouspouvezintgrerlesinformationsquevoussouhaitezsurl'objet.
l'intrieur des mthodes, l'objet courant (ou instance courante) peut tre rfrenc par la variable $this
pouraccderauxattributsouauxmthodes,ilsuffitd'utiliserl'oprateur >suividunomdel'attributoudunom
delamthode,derrirelenomdelavariable$this.
Syntaxe
$this->attribut
$this->mthode([valeur[, ...]])
Exemple
<?php
// dfinition d'une classe destine stocker des informations
// sur un utilisateur
class utilisateur {
// dfinition des attributs
public $nom; // nom de l'utilisateur
public $prnom; // prnom de l'utilisateur
public $langue = "fr"; // langue de l'utilisateur
// franais par dfaut
private $timestamp; // date/heure de cration
// attribut priv
// dfinition des mthodes
// - mthode constructeur
public function __construct($prnom,$nom) {
// initialiser le nom et le prnom
// avec les valeurs passes en paramtre
$this->prnom = $prnom;
$this->nom = $nom;
// initialiser le timestamp avec la fonction time()
$this->timestamp = time();
}
// - mthode destructeur
public function __destruct() {
// se contente d'afficher un message
echo "Suppression de $this-nom/B";
}
// - mthode de conversion de l'objet en chane
public function __toString() {
// retourne juste le nom et le prnom
return "__toString = $this-nom - $this-prnom";
}
// - mthode qui modifie la langue de l'utilisateur
public function langue($langue) {
$this->langue = $langue;
}
// - mthode (prive) qui met en forme la date/heure
// de cration de l'utilisateur
private function miseEnFormeTimestamp() {
setlocale(LC_TIME,$this-langue);
return strftime("%c", $this-timestamp);
}
// - mthode qui donne des informations sur l'utilisateur
public function informations() {
$cration = $this-miseEnFormeTimestamp();
return "$this->prnom $this->nom - $cration";
}
}
?>
Une classe est utilisable uniquement dans le script o elle est dfinie. Pour pouvoir l'employer dans plusieurs scripts, il faut,
soit recopier sa dfinition dans les diffrents scripts (vous perdez l'intrt de la dfinition d'une classe), soit la dfinir dans un
fichier qui est inclus partout o la classe est utilise.
Instancieruneclasse
Instancier une classe signifie crer un objet bas sur la dfinition de la classe. Dans une certaine mesure, cela
revientdfinirunevariableayantcomme"type",laclasse.
L'instanciations'effectuegrcel'oprateurnew.
Syntaxe
$nom_objet
Variabledestinestockerl'objet.
Nomdelaclassequisertde"modle"l'objet.
valeur
Paramtreventuelpasslamthodeconstructeurdelaclasseappelelorsdelacrationdel'objet.
Aprscrationdel'objet,lesattributsetmthodespublicsdel'objetpeuventtreatteintsavecl'oprateur >,
surlavariable$nom_objet,commeaveclavariable$this.
Il n'y a pas de protection des attributs publics des objets ; ils peuvent tre manipuls directement.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de la
// classe utilisateur prsente prcdemment
include("classes.inc");
// instanciation d'un objet
$moi = new utilisateur("Olivier","Heurtel");
// la variable $moi contient maintenant un objet
// bas sur la classe utilisateur
// les mthodes sont accessibles par l'oprateur ->
// utilisation des mthodes de l'objet
echo "$moi->informations()."<BR>";
$moi->langue("us"); //modification de la langue
echo $moi->informations()."<BR>";
// ou directement des attributs publics
$moi->nom = strtoupper($moi->nom);
echo $moi->nom."<BR>";
// affichage direct de l'objet = utilisation de __toString
echo $moi."<BR>";
// tentative d'accs un attribut priv = erreur
echo $moi->timestamp;
?>
Rsultat
Suppression de HEURTEL
Notez le message d'erreur sur la tentative d'accs l'attribut priv $timestamp et le message final
correspondantl'appelautomatiquedelamthodedestructeur.
Les variables objet peuvent tre substitues comme les autres (cf. chapitre Constantes, variables, types et
tableauxTypesdedonnes),dansleschanesdecaractresdlimitespardesguillemetsdoubles.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de la
// classe utilisateur prsente prcdemment
include("classes.inc");
// instanciation d'un objet
$moi = new utilisateur("Olivier","Heurtel");
// affichage
echo "\$moi->nom = $moi->nom";
?>
Rsultat
Encasdebesoin,lesaccoladespeuventtreutilisespourdlimiterlavariablel'intrieurdelachane.
Les rgles de porte et de dure de vie des variables s'appliquent aux objets (cf. chapitre Constantes, variables, types et
tableaux - Porte et dure de vie).
Hritage
Ilestpossiblededfinirunenouvelleclassequihrited'uneclasseexistanteaveclemotclextends.
Syntaxe
Lasignificationdesdiffrentslmentsestlammequepourladfinitiond'uneclasse.
Lanouvelleclassecreestappeleclassefilleetlaclassedebase(quiaservide"moule"cettecration)est
nommeclassemre.
La nouvelle classe possde implicitement les attributs et mthodes de la classe de base et peut en dfinir de
nouveaux, notamment une classe constructeur nomme __construct. Si la classe fille n'a pas de mthode
constructeur, c'est la mthode constructeur de la classe mre qui est appele lors de l'instanciation d'un objet
surlaclassefille.
Quand la mthode constructeur existe dans la classe fille, il n'y a pas d'appel automatique la mthode
constructeur de la classe mre : si ncessaire, il faut l'appeler explicitement en utilisant parent::__construct
().
Exemple
<?php
// dfinition d'une classe de base
class utilisateur {
// dfinition des attributs
public $nom; // nom de l'utilisateur
public $prnom; // prnom de l'utilisateur
// dfinition des mthodes
// - mthode constructeur
public function __construct($prnom,$nom) {
// initialiser le nom et le prnom
// avec les valeurs passes en paramtre
$this->prnom = $prnom;
$this->nom = $nom;
}
// - mthode qui donne les informations sur l'utilisateur
public function informations() {
return "$this->prnom $this->nom";
}
}
// dfinition d'une classe qui hrite de la premire
class utilisateur_couleur extends utilisateur{
// dfinition des attributs complmentaires
public $couleurs; // couleurs prfres de l'utilisateur
Rsultat
Olivier X
bleu,blanc,rouge
Dans une classe fille, il est possible de redclarer une mthode ou un attribut qui existe dans la classe mre. Dans ce cas,
l'oprateur parent:: peut tre utilis pour faire rfrence explicitement aux attributs (parent::attribut) ou mthodes
(parent::mthode()) de la classe mre et lever l'ambigut du nommage (cet oprateur peut tre utilis mme s'il n'y a pas
d'ambigut).
Autresfonctionnalitssurlesclasses
Lesdiffrentesfonctionnalitsprsentesdanscettesectiononttintroduitesenversion5.
Classeoumthodeabstraite
Une classe abstraite est une classe qui ne peut pas tre instancie (pas de cration d'objet sur la classe). Par
contre,unetelleclassepeutservirdebaseladfinitiond'uneclassefillequipourratreinstancie(saufsielle
estellemmeabstraite).
Une mthode abstraite est une mthode qui est dfinie dans une classe (ellemme obligatoirement abstraite)
mais pas implmente (le code de la mthode n'est pas prsent). Une telle mthode pourra tre implmente
dansuneclassefille.
Entermedesyntaxe,ilsuffitdemettrelemotclabstractdevantladfinitiondelaclasseoudelamthode.
Uneclassefillequin'implmentepastouteslesmthodesabstraitesdelaclassemreestimplicitementabstraite
(mmesilemotclabstractn'estpasprsent).
Exemple
<?php
// dfinition d'une classe abstraite
abstract class classeMre {
// attribut protg
protected $x;
// deux mthodes pour accder l'attribut protg
// - pour lire
public function get() {
return "GET = $this->x";
}
// - pour crire
// > mthode abstraite
abstract public function put();
}
// dfinition d'une classe fille qui hrite de la classe mre
class classeFille extends classeMre {
Rsultat
GET = 123
GET = 579
Classeoumthodefinale
Onnepeuthriterd'uneclassefinale.
Unemthodefinalenepeutpastreredfiniedansuneclassefille.
Entermedesyntaxe,ilsuffitdemettrelemotclfinaldevantladfinitiondelaclasseoudelamthode.
Exemple 1
<?php
// dfinition d'une classe mre avec une mthode finale
class classeMre {
final public function mthodeFinale() {
echo "Mthode finale dans la classe mre";
}
}
// dfinition d'une classe fille qui hrite de la classe mre
class classeFille extends classeMre {
// tentative de modification de la classe finale
public function mthodeFinale() {
echo "Mthode finale dans la classe fille";
}
}
?>
Rsultat
Exemple 2
<?php
// dfinition d'une classe mre finale
final class classeMre {
public $x;
}
// tentative de dfinition d'une classe fille qui hrite
// de la classe mre
class classeFille extends classeMre {
public $y;
}
?>
Fatal error: Class classeFille may not inherit from final class
(classeMre) in d:\scripts php\index.php on line 10
Interface
Une interface est une classe qui ne contient que des spcifications de mthodes sans implmentations. Une
interfacenecontientpasd'attributnonplus.
D'autres classes peuvent tre ensuite dfinies et implmenter une ou plusieurs interfaces, c'estdire
implmenterlesmthodesd'uneouplusieursinterfaces.
interface nom_interface {
// dfinition des mthodes
[public] function mthode();
...
}
nom_interface
Nomdel'interface(doitrespecterlesrglesdenommageprsentesdanslechapitreVued'ensembledePHP).
mthode
Spcificationd'unemthodedel'interface.
Lesmthodesd'uneinterfacesontforcmentpubliques lemotclpublicpeuttreomis.
Il est possible de dfinir une nouvelle classe qui implmente une ou plusieurs interfaces avec le mot cl
implements.
Syntaxe
Une telle classe doit implmenter les diffrentes mthodes des interfaces qu'elle implmente. Si l'une des
mthodesdesinterfacesn'estpasimplmente,laclassedoittredclareabstraite.
Exemple
<?php
// dfinition de deux interfaces
interface lecture {
function get();
}
interface criture {
function put();
}
// dfinition d'une classe qui implmente les deux interfaces
class uneClasse implements lecture,criture {
// dfinition d'un attribut quelconque
private $x;
// implmentation de la mthode de lecture
public function get() {
return $this->x;
}
// implmentation de la mthode d'criture
public function put($valeur) {
$this->x = $valeur;
}
}
AttributoumthodestatiqueConstantedeclasse
Un attribut ou une mthode statique est utilisable directement sans instanciation pralable d'un objet. On parle
aussid'attributoudemthodedeclasse.
Pour dfinir un attribut ou une mthode statique, il suffit de placer le mot cl static devant la dfinition de
l'attributoudelamthode.
Pour rfrencer un attribut ou une mthode statique, il faut utiliser la syntaxe nom_classe::$nom_attribut ou
nom_classe::nom_mthode().
Une constante de classe est une constante dfinie dans une classe utilisable directement sans instanciation
pralabled'unobjet(commeunattributdeclasse,maisconstant).
nom_constante
Nomdelaconstante.
valeur
Valeurdelaconstante.
Uneconstantedeclasseestimplicitementpublique.
Pourrfrenceruneconstantedeclasse,ilfaututiliserlasyntaxenom_classe::nom_constante.
Exemple
<?php
// dfinition d'une classe
class uneClasse {
// attribut priv quelconque
private $x;
// attribut priv statique pour stocker
// le nombre d'objets instancis
static private $nombre = 0;
// constante de classe pour dfinir une valeur
// par dfaut
const DEFAUT = "X";
// fonction publique statique qui retourne le
// nombre d'objets
static public function nombreObjets() {
return uneClasse::$nombre;
}
// mthode constructeur
// - rcuprer la valeur de l'attribut (valeur par dfaut
// = la constante de classe)
// - incrmenter le nombre d'objets
public function __construct($valeur = uneClasse::DEFAUT) {
$this->x = $valeur;
uneClasse::$nombre++;
echo "Cration de l'objet : $this->x<BR>";
}
// mthode destructeur
// - dcrmenter le nombre d'objets
public function __destruct() {
uneClasse::$nombre--;
echo "Suppression de l'objet : $this->x<BR>";
}
}
// crer deux objets
$inconnu = new uneClasse();
Rsultat
Cration de l'objet : X
Cration de l'objet : ABC
2 objet(s)
Suppression de l'objet : X
1 objet(s)
Suppression de l'objet : ABC
Exceptions
Les langages de programmation objet comme C++ et Java utilisent la notion d'exception pour grer les erreurs.
CettefonctionnalitatintroduitedanslagestiondesobjetsdePHPenversion5.
Le principe consiste inclure le code susceptible de gnrer des erreurs dans un bloc try et lui associer un
bloccatchdestinintercepterleserreursetlestraiter :
Structure gnrale
try {
// code susceptible de gnrer des erreurs
...
} catch (Exception $e) {
// code destin traiter les erreurs
...
}
LaclasseExceptionestuneclassequicontientnotammentlesmthodessuivantes :
__construct
Mthodeconstructeuracceptantdeuxparamtres :unmessaged'erreuretuncoded'erreur(optionnel).
getMessage
Mthodepermettantdercuprerlemessaged'erreur.
getCode
Mthodepermettantdercuprerlecoded'erreur.
l'intrieur du bloc try, une exception peut tre leve par une instruction du type throw new Exception
(message[,code]). Dans le bloc catch, les mthodes getMessage et getCode permettent de rcuprer des
informations sur l'erreur et de la traiter. En cas d'exception dans un bloc try, le traitement se branche
directementdanslebloccatch :lerestedubloctryn'estpasexcut.
Exemple
<?php
// dfinition d'une classe
class uneClasse {
// un attribut quelconque
private $x;
// mthode constructeur
public function __construct($valeur) {
$this->x = $valeur;
}
// mthode qui effectue une action quelconque
Rsultat
Objet 1 : OK
Objet 2 : ERREUR 123 - Action interdite
Petitrappelsurlesformulaires
Le formulaire est un outil de base indispensable pour les sites Web dynamiques puisqu'il permet l'utilisateur de
saisirdesinformationsetdoncd'interagiraveclesite.
UnformulaireHTMLestdfinientrelesbalises<FORM>et</FORM>.
Syntaxe
<FORM
[ ACTION="url_de_traitement" ]
[ METHOD="GET"|"POST" ]
[ NAME="nom_formulaire" ]
>
...
</FORM>
Lesoptionsdelabalise<FORM>sontlessuivantes :
ACTION
URL relative ou absolue (Uniform Resource Locator), qui va traiter le formulaire, en ce qui nous concerne, un
scriptPHP.Sirienn'estspcifi,lammeURLquelapageestutilise.
METHOD
Modedetransmissionversleserveurdesinformationssaisiesdansleformulaire.
GET(valeurpardfaut) :lesdonnesduformulairesonttransmisesdansl'URL.
POST :lesdonnesduformulairesonttransmisesdanslecorpsdelarequte.
NAME
Nom du formulaire. Si la page HTML contient plusieurs formulaires, le nom permet de les diffrencier. En ce qui
nous concerne, ce nom ne prsente pas d'intrt car il n'est pas rcupr dans le script de traitement du
formulaire.Parcontre,ilpeuttreutilisctclient,enJavaScriptparexemple.
Entre les balises <FORM> et </FORM>, il est possible de placer des balises <INPUT>, <SELECT> ou <TEXTAREA>
pourdfinirdeszonesdesaisies.
<FORM>
Nom :
<INPUT TYPE="text" NAME="nom" VALUE=""
SIZE="20" MAXLENGTH="20">
Mot de passe :
<INPUT TYPE="password" NAME="mot_de_passe" VALUE=""
SIZE="20" MAXLENGTH="20">
<BR>Sexe :
<INPUT TYPE="radio" NAME="sexe" VALUE="M"> Masculin
<INPUT TYPE="radio" NAME="sexe" VALUE="F"> Fminin
<INPUT TYPE="radio" NAME="sexe" VALUE="?"
CHECKED> Ne sait pas
<BR>Photo :
<INPUT TYPE="file" NAME="photo" VALUE="" SIZE="50">
<BR>Couleurs prfres :
<INPUT TYPE="checkbox" NAME="bleu"> Bleu
<INPUT TYPE="checkbox" NAME="blanc"> Blanc
<INPUT TYPE="checkbox" NAME="rouge"> Rouge
<INPUT TYPE="checkbox" NAME="nesaitpas" CHECKED> Ne sait pas
<BR>Langue :
<SELECT NAME="langue">
<OPTION VALUE="E">Espagnol
<OPTION SELECTED VALUE="F">Franais
InteractionentreunformulaireetunscriptPHP
PHPpeutintervenirdeuxendroitsparrapportauformulaire :
- pour le traitement du formulaire (c'estdire des donnes saisies par l'utilisateur dans le formulaire).
TroisgrandesmthodessontutilisablespourfaireinteragirunformulaireetunscriptPHP :
- placer le formulaire dans un document HTML "pur" (.htm ou .html), le formulaire ne contient alors aucun lment
dynamique, et indiquer le nom du script PHP qui doit traiter le formulaire dans l'option ACTION de la balise <FORM> ;
- placer le formulaire dans un script PHP (par exemple, pour construire une partie du formulaire dynamiquement) et faire
traiter le formulaire par un autre script PHP (mentionn dans l'option ACTION de la balise <FORM>) ;
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom" VALUE=""><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
<?php
/* A faire ...
- rcuprer les informations saisies
- faire le traitement
- afficher une nouvelle page
*/
?>
Par ailleurs, sur une autre page, un lien (Saisie par exemple) peut tre insr pour appeler le formulaire de
saisie :
<A HREF="saisie.htm">Saisie</A>
Rsultat
- Le rsultat du clic sur le bouton OK est une page vide car, pour l'instant, le script de traitement ne fait rien.
UnpeudecodePHP(engras)estutilispourgnrerlapartiedynamiqueduformulaire.
<?php
// inclure un fichier qui contient des dfinitions de
// constantes, dont le titre de la page (TITRE_PAGE_SAISIE)
require("constantes.inc");
// initialisation d'une variable qui contient la valeur
// initiale de la zone de saisie (dans la pratique, cette
// valeur vient sans doute d'ailleurs et n'est pas code
// en dur)
<?php
/* A faire ...
- rcuprer les informations saisies
- faire le traitement
- afficher une nouvelle page
*/
?>
Par ailleurs, sur une autre page, un lien (Saisie par exemple) peut tre insr pour appeler le formulaire de
saisie :
<A HREF="saisie.php">Saisie</A>
Rsultat
- Affichage initial du formulaire (une valeur initiale dynamique est propose pour la zone de saisie) :
- Le rsultat du clic sur le bouton OK est une page vide car, pour l'instant, le script de traitement ne fait rien.
C'estlemmescriptqueprcdemment,danslequelnousavonssimplementchangl'optionACTIONdelabalise
<FORM> pour indiquer que le formulaire doit tre trait par le mme script saisie.php (ne pas mettre d'option
ACTIONauraitlemmeeffet).
<?php
// inclure un fichier qui contient des dfinitions de
// constantes, dont le titre de la page (TITRE_PAGE_SAISIE)
require("constantes.inc");
// initialisation d'une variable qui contient la valeur
// initiale de la zone de saisie (dans la pratique, cette
// valeur vient sans doute d'ailleurs et n'est pas code en dur)
$nom = "X";
// dans le code HTML qui suit, inclusion de deux petits
// bouts de code PHP pour afficher respectivement le titre
// de la page et la valeur initiale de la zone de saisie
Par ailleurs, sur une autre page, un lien (Saisie par exemple) peut tre insr pour appeler le formulaire de
saisie :
<A HREF="saisie.php">Saisie</A>
Rsultat
- Affichage initial du formulaire (une valeur initiale dynamique est propose pour la zone de saisie) :
- Le rsultat du clic sur le bouton OK est la mme page de nouveau affiche, car, pour l'instant, le script de traitement
ne fait rien de plus.
Le script saisie.php a t appel de nouveau, par le clic sur le bouton OK il s'est donc excut comme lors
de son premier appel (lien Saisie). Comme le code ne fait rien, pour l'instant, afin de traiter le formulaire, il
s'affiche comme initialement. Utiliser le mme script pour l'affichage initial et le traitement ncessite d'tre en
mesuredefaireladiffrenceentrelesdeuxtypesd'appels(cf.B2.Lesdiffrentstypesdezones).
Quechoisir ?
Lechoixdetelleoutellemthodedpenddelacomplexitdusiteetdesprfrencesdechacun.
Quelquesconsidrationsgnrales :
- Sparer la page HTML (ou le script PHP qui gnre le formulaire) du script PHP prsente un inconvnient au niveau de
la maintenance: si des modifications sont apportes au formulaire, il y a deux fichiers modifier (avec des risques
d'erreur, d'oubli...).
- Inversement, si le formulaire n'a aucune partie dynamique, l'crire dans un fichier HTML spar du script PHP qui le
traite, permet de bien sparer l'interface utilisateur (la couche "prsentation") du traitement.
- Dans la pratique, pour faciliter la maintenance, il est souhaitable de dfinir certaines valeurs prsentes plusieurs
Dans la suite de ce chapitre, nous allons rentrer dans le dtail du traitement du formulaire en PHP, en utilisant
desexemplesconstruitssurlemodledelatroisimemthode.
Principe
ladiffrencedesscriptsCGI,iln'yapasbesoinderaliserdesanalysescomplexesdechanesdecaractres
("parser")pourrcuprerlesvaleurssaisiesparl'utilisateur. cesvaleursvonttrercupresdirectement(ou
presque,selonlaconfigurationdePHP).
Premiremthode
Par dfaut, toutes les zones de formulaire sont automatiquement enregistres dans le script PHP qui traite le
formulaire,dansuntableauassociatif $_POSTpourlesformulairesPOST et$_GETpourlesformulairesGET :lacl
du tableau est gale au nom de la zone dans le formulaire (option NAME de la balise <INPUT>, <SELECT> ou
<TEXTAREA>) et la valeur gale la valeur saisie dans la zone. Ces informations sont aussi disponibles dans le
tableau associatif $_REQUEST qui regroupe le contenu des tableaux $_GET et $_POST (et nous le verrons plus
tarddutableau$_COOKIEquicontientdesinformationssurlescookies).
Exemple
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<?php
// initialisation de deux variables destines rcuprer
// l'information souhaite dans les tableaux $_POST
// et $_REQUEST
$nom_POST = "";
$nom_REQUEST = "";
// pour les deux tableaux :
// - tester si le tableau contient une valeur associe la
// cl portant le mme nom que la zone de saisie du
// formulaire
// - si oui, rcuprer cette valeur dans une variable et
// l'afficher
if ( isset($_POST["nom"]) ) {
$nom_POST = $_POST["nom"];
echo "\$_POST -> $nom_POST<BR>";
}
if ( isset($_REQUEST["nom"]) ) {
$nom_REQUEST = $_REQUEST["nom"];
echo "\$_REQUEST -> $nom_REQUEST<BR>";
}
// ensuite, affichage du formulaire : c'est du HTML
// noter l'utilisation de la variable $nom_POST dans un petit
// bloc PHP pour initialiser la zone de saisie
?>
<FORM ACTION="saisie.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $nom_POST?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Rsultat
Lors du premier appel, les tableaux $_POST et $_REQUEST ne contiennent pas de valeur associe une cl
portantlemmenomquelazonedeformulaire :rienn'estaffich,nienhaut,nidanslazonedesaisie.
Aprs saisie d'une valeur et clic sur le bouton OK, le script est de nouveau appel : cette fois, les tableaux
$_POST et$_REQUESTcontiennentunevaleurassocielaclportantlemmenomquelazonedeformulaire
la valeur saisie. Cette valeur saisie est afiche en haut, mais aussi dans la zone de saisie. S'il n'y avait pas
d'instructionecho $nom_POSTdansl'optionVALUE,lavaleursaisieneseraitpasraffichedanslazone.
Siunautrescripttaitappelpourtraiterleformulaire,lesinformationsseraientdisponiblesdelammemanire.
<?php
// initialisation de deux variables destines rcuprer
// l'information souhaite dans les tableaux $_POST
// et $_REQUEST
$nom_POST = "";
$nom_REQUEST = "";
// pour les deux tableaux :
// - tester si le tableau contient une valeur associe la
// cl portant le mme nom que la zone de saisie du
// formulaire
// - si oui, rcuprer cette valeur dans une variable et
// l'afficher
if ( isset($_POST["nom"]) ) {
$nom_POST = $_POST["nom"];
echo "\$_POST -> $nom_POST<BR>";
}
if ( isset($_REQUEST["nom"]) ) {
$nom_REQUEST = $_REQUEST["nom"];
echo "\$_REQUEST -> $nom_REQUEST<BR>";
}
?>
Rsultat
Les tableaux $_GET, $_POST et $_REQUEST sont apparus en version 4.1. Avant la version 4.1, $_GET et $_POST
s'appelaient $HTTP_GET_VARS et $HTTP_POST_VARS, et $_REQUEST n'avait pas d'quivalent. Pour des raisons de
compatibilit ascendante, ces variables "longues" sont toujours disponibles condition de positionner la directive de
configuration register_long_array on (off par dfaut). Cette directive de configuration est apparue en version 5 ; entre
la version 4.1 et la version 5, les variables longues taient disponibles par dfaut. Avant la version 4.0.3, il fallait que la directive
de configuration track_vars soit on pour que les tableaux $HTTP_GET_VARS et $HTTP_POST_VARS soient disponibles ;
depuis la version 4.0.3, cette directive est toujours on et les tableaux sont donc toujours disponibles.
Deuximemthode
Les informations saisies dans le formulaire peuvent tre automatiquement importes dans des variables PHP
grcelafonctionimport_request_variables.
types
Typed'informationdsire :
Goug :informationsenvoyesparlamthodeGET
Poup :informationsenvoyesparlamthodePOST
Couc :informationsenvoyesparuncookie(cf.chapitreGrerlessessionsUtiliserdescookies).
prfixe
Prfixeajouterdevantlenomdelavariable.
Lorsque cette fonction est appele dans le script de traitement d'un formulaire, PHP va crer une variable pour
chaque zone du formulaire : le nom de la variable est gal au nom de la zone dans le formulaire prcd du
prfixe,etlavaleurdelavariableestgalelavaleursaisiedansleformulaire.
LeprfixeestoptionnelmaisuneerreurdeniveauE_NOTICEestgnres'iln'estpasrenseign.
Vouspouvezutiliserunecombinaisondesdiffrenteslettresdetypespourimporterenunefoisdesinformations
d'origine diffrente. Par exemple, spcifier PG permet de rcuprer les informations envoyes par une mthode
POSTouunemthodeGET.
Exemple
<?php
// importer les informations du formulaire
// - mthode POST
// - prfixe form_
import_request_variables("P","form_");
// tester si la variable $form_nom existe
if ( isset($form_nom) ) {
// si oui, l'afficher
echo "\$form_nom = $form_nom<BR>";
} else {
// si non, l'initialiser
$form_nom = "";
}
// ensuite, affichage du formulaire : c'est du HTML
// noter l'utilisation de la variable $form_nom dans un petit
// bloc PHP pour initialiser la zone de saisie
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $form_nom?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Rsultat
Le fonctionnement est identique celui du premier exemple. Lors du premier appel, aucune variable n'est
importe dans le script (le formulaire n'a pas encore t affich). Lors du deuxime appel (traitement du
formulaire),unevariable$form_nomestbiencredanslescriptaveclavaleursaisie.
Troisimemthode(nonrecommande)
Latroisimemthodeestnonrecommandecarelleestdpendanted'unedirectivedeconfigurationetellepeut
poserdesproblmesdeperformanceetdescurit.Elleestnanmoinsprsentebrivementdanscettepartie
carvouspouvezlarencontrerdansducodePHP"ancien"(venantdelaversion3parexemple).
Si la directive de configuration register_globals est on, toutes les zones de formulaire sont automatiquement enregistres
dans des variables dans le script PHP qui traite le formulaire. Les variables hritent du nom (option NAME de la balise <INPUT>, <SELECT>
ou <TEXTAREA>) de la zone correspondante du formulaire. Ce comportement est valable quelle que soit la mthode (GET ou POST).
Exemple
<?php
// tester s'il existe une variable portant le mme nom
// que la zone de saisie du formulaire
if ( isset($nom) ) {
// si oui, l'afficher
echo "\$nom = $nom<BR>";
} else {
// si non, l'initialiser
$nom = "";
}
// ensuite, affichage du formulaire : c'est du HTML
// noter l'utilisation de la variable $nom dans un petit
//<+>bloc PHP pour initialiser la zone de saisie
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $nom ?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Le fonctionnement est identique celui des deux exemples prcdents. Lors du premier appel, la variable $nom
n'existe pas : rien n'est affich, ni en haut, ni dans la zone de saisie. Aprs saisie d'une valeur et clic sur le
boutonOK,lescriptestdenouveauappel :cettefois,lavariable$nomestdfinieetcontientlavaleursaisie.
Siladirectivedeconfigurationregister_globalsestoff,lesvariablesdeformulairenesontpascres.
Depuis la version 4.2, la directive register_globals est par dfaut off et cette mthode ne peut pas tre utilise sans
intervention dans le fichier php.ini.
Quechoisir ?
Unedesdeuxpremiresmthodes.
Les volutions successives de PHP vont dans le sens d'une utilisation des tableaux $_POST ou $_GET, ou de la
fonctionimport_request_variables.Dansunefutureversion,ladirectivedeconfigurationregister_globals
seradfinitivementpasse offetneserapasmodifiabledanslefichierphp.ini.Dansunetellehypothse,la
troisimemthodeneseraplusdisponible.
Les auteurs de PHP conseillent vivement d'utiliser l'une des deux premires mthodes pour des raisons de
scurit : en interrogeant le tableau adquat, ou en important explicitement les variables, on est certain que
l'information vient bien de l'endroit prvu et qu'il n'y a pas eu substitution par un utilisateur ventuellement mal
intentionn(cf.chapitreGrerlessessions).
Lesdeuxscriptssuivantsprsententunemanireclassiquedercuprerlesvaleurssaisiesdansunformulaireen
utilisantlesdeuxmthodes.
<?php
// rcupration dans des variables PHP des valeurs
// saisies dans le formulaire en utilisant un
// tableau $_* ($_POST ici)
$form_nom = (isset($_POST["nom"]))?$_POST["nom"]:"";
$form_prnom = (isset($_POST["prnom"]))?$_POST["prnom"]:"";
// etc. pour chaque zone
// ensuite, on utilise les variables dans les traitements
// et ventuellement dans le raffichage du formulaire
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $form_nom?>"><BR>
Prnom : <INPUT TYPE="text" NAME="prnom"
VALUE="<?php echo $form_prnom?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
<?php
// importation dans des variables PHP des valeurs
// saisies dans le formulaire
import_request_variables("P","form_");
// si les variables attendues n'existent pas, les initialiser
if (! isset($form_nom)) $form_nom = "";
if (! isset($form_prnom)) $form_prnom = "";
// etc. pour chaque zone
// ensuite, on utilise les variables dans les traitements
// et ventuellement dans le raffichage du formulaire
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $form_nom?>"><BR>
Prnom : <INPUT TYPE="text" NAME="prnom"
VALUE="<?php echo $form_prnom?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Danslasuitedecechapitre,nousutiliseronsdesformulairesPOSTetl'uneoul'autredesmthodes.
Quesepassetilsideuxzonesportentlemmenom ?
C'esttoutsimplementladernirezonerencontredansleformulairequifixelavaleur.
Exemple
Quesepassetils'ilyadeuxformulairesdanslapageHTML ?
Lesvariablesnesontcresetrenseignesquepourleformulairequiatvalid.
Exemple
Page saisie.htm
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Nom 1 : <INPUT TYPE="text" NAME="nom1"><BR>
<INPUT TYPE="submit" NAME="OK1" VALUE="OK1">
</FORM>
<FORM ACTION="saisie.php" METHOD="POST">
Nom 2 : <INPUT TYPE="text" NAME="nom2"><BR>
<INPUT TYPE="submit" NAME="OK2" VALUE="OK2">
</FORM>
</BODY>
</HTML>
<?php
$nom1 = (isset($_POST["nom1"]))?$_POST["nom1"]:"";
Rsultat
nom1 = Olivier
nom2 =
Utilisationd'untableaupourrcuprerleszonessaisies
Il est possible d'utiliser une notation de type tableau dans l'option NAME des balises <INPUT>, <SELECT> et
<TEXTAREA>.
Exemple
LasaisiedeHEURTELdanslapremirezoneetdeOlivierdansladeuxime,donneuneseulevariable$saisie,
detypetableau,quicontientleslignessuivantes :
Cl Valeur
0 HEURTEL
1 Olivier
PHPremplitletableauenajoutantunelignepourchaquezone,avecunindiceentierconscutifcommenant0
(commepourlanotation[]tudiedanslechapitreConstantes,variables,typesettableaux).
Cettetechniqueestintressante,mais,danslecode,ilfautsavoirquel'indice0correspondaunometl'indice1
auprnom.Parailleurs,unproblmepeutseprsentersil'ordredeszoneschange.
Pour amliorer cette technique, il est possible de fixer soimme la cl, soit avec un numro, soit avec une
chanedecaractres.
Exemple
La saisie de HEURTEL dans la premire zone et de Olivier dans la deuxime, donne le rsultat suivant dans le
tableau$saisie :
Exemple
La saisie de HEURTEL dans la premire zone et de Olivier dans la deuxime, donne le rsultat suivant dans le
tableau$saisie :
Cl Valeur
nom HEURTEL
prnom Olivier
Nousverronsultrieurementd'autressituationsocetypedenotationestobligatoire.
Lesdiffrentstypesdezones
PrenonsnotreformulairecompletdedpartetvoyonslesinformationsrcupresdanslescriptPHP.
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom :
<INPUT TYPE="text" NAME="nom" VALUE=""
SIZE="20" MAXLENGTH="20">
Mot de passe :
<INPUT TYPE="password" NAME="mot_de_passe" VALUE=""
SIZE="20" MAXLENGTH="20">
<BR>Sexe :
<INPUT TYPE="radio" NAME="sexe" VALUE="M"> Masculin
<INPUT TYPE="radio" NAME="sexe" VALUE="F"> Fminin
<INPUT TYPE="radio" NAME="sexe" VALUE="?"
CHECKED> Ne sait pas
<BR>Photo :
<INPUT TYPE="file" NAME="photo" VALUE="" SIZE="50">
<BR>Couleurs prfres :
<INPUT TYPE="checkbox" NAME="bleu"> Bleu
<INPUT TYPE="checkbox" NAME="blanc"> Blanc
<INPUT TYPE="checkbox" NAME="rouge"> Rouge
<INPUT TYPE="checkbox" NAME="nesaitpas" CHECKED> Ne sait pas
<BR>Langue :
<SELECT NAME="langue">
<OPTION VALUE="E">Espagnol
<OPTION SELECTED VALUE="F">Franais
<OPTION VALUE="I">Italien
</SELECT>
<BR>Fruits prfrs :<BR>
<SELECT NAME="fruits" MULTIPLE SIZE="8">
<OPTION VALUE="A">Abricots
<OPTION VALUE="C">Cerises
<OPTION VALUE="F">Fraises
<OPTION VALUE="P">Pches
<OPTION SELECTED VALUE="?">Ne sait pas
</SELECT>
<BR>Commentaire :<BR>
<TEXTAREA NAME="commentaire" ROWS="4" COLS="50"></TEXTAREA>
<BR>
<INPUT TYPE="hidden" NAME="invisible" VALUE="123"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
<INPUT TYPE="image" NAME="valider"
Script traitement.php
<?php
// inclusion d'un fichier contenant des fonctions gnriques
// (dont la fonction afficher_tableau dfinie dans le chapitre Fonctions et classes)
include("fonctions.inc") ;
afficher_tableau($_POST,"\$_POST :");
?>
Rsultat
$_POST :
nom = HEURTEL
mot_de_passe = olivier
sexe = M
photo = D:\Photos\identit.jpg
bleu = on
rouge = on
langue = F
fruits = F
commentaire = Consultant en systme d'information
invisible = 123
OK = OK
Zonecontenantdutexte
Pour les zones comprenant du texte, c'estdire les zones <INPUT> de type text (nom), password
(mot_de_passe), file (photo) et hidden (invisible), ainsi que pour la zone <TEXTAREA> (commentaire), les
Pour l'instant, avec la zone de type file, nous avons juste rcupr le nom du fichier, mais pas le fichier lui-mme (cf.
chapitre Gestion des fichiers).
Groupedeboutonsradio
Pouravoirungroupedeboutonsradio,leszonesdoiventporterlemmenom.
Exemple
Rsultat
$_POST :
sexe = M
Sil'optionVALUEestabsente,lavaleurpardfauteston.
Exemple
Rsultat
$_POST :
sexe = on
Avec le groupe de boutons radio, ne pas mettre d'option VALUE est gnant puisqu'il est alors impossible de
connatrel'optionslectionne.Danslapratique,ilfautmettrel'optionVALUE.
Casecocher
Pour des cases cocher, c'estdire pour des zones <INPUT> de type checkbox (sexe), la variable associe
contientlavaleurcontenuedansl'option VALUE de la baliseINPUT si l'option VALUEestabsente,lavaleurpar
dfauteston.Danslesdeuxcas,lavariableassocieestdfinieuniquementpourlescasescoches.
Exemple
$_POST :
bleu = on
rouge = on
Autre exemple
Rsultat
$_POST :
bleu = b
rouge = on
Avec la case cocher, l'option VALUE a gnralement moins d'importance, car il est possible de dterminer
qu'unecaseestcocheuniquementparlefaitquelavariableassocieaunevaleur(peuimportecettevaleur).
Danslecode,sivoussouhaitezrcuprerl'informationcorrespondantesouslaformed'unboolen,vouspouvez
crireuneinstructiondustyle:
$nom_case = isset($_POST["nom_case"])?TRUE:FALSE;
Plusieursapprochessontpossiblesvisvisdelavaleurdel'optionVALUE :
- L'option VALUE utilise la valeur souhaite au niveau de la logique applicative dans le cas o la case est coche (1,
oui ...), sachant que, si la case n'est pas coche, la variable n'existe pas.
- L'option VALUE est omise et le code interprte l'existence de la variable selon les besoins de la logique applicative.
Parcontre,ilestimportantquelesnomsdeszonessoientdiffrents.
Exemple
Rsultat
$_POST :
couleur = on
Autre exemple
$_POST :
couleur = rouge
Noussommesdanslecasoplusieurszonesportentlemmenom c'estalorsladernirerencontrequifixela
valeur.
Parcontre,ilestenvisageabled'utiliseruntableaupournepasavoirunevariableparcasecocher.
Exemple
Rsultat
$_POST :
couleur =
0 = on
1 = on
PHP ne met une ligne dans le tableau que lorsque la case est coche, en attribuant des indices entiers
conscutifscommenant0.Decefait,cesindicesnecorrespondentpaslapositiondelacasecocheparmi
l'ensembledescases.SansoptionVALUE,ilestimpossiblededterminerlescasescoches.
Rsultat
$_POST :
couleur =
0 = bleu
1 = rouge
C'estmieux,onsaitcequiatcoch.
Rsultat
Rsultat
$_POST :
couleur =
bleu = on
rouge = on
Siuntableauestutilispourl'ensembleduformulaire,unedessolutionslespluslisiblesestlasuivante :
Rsultat
$_POST :
saisie =
couleurs =
bleu = on
rouge = on
ou
<INPUT TYPE="checkbox" NAME="saisie[couleur][]"
VALUE="bleu"> Bleu
<INPUT TYPE="checkbox" NAME="saisie[couleur][]"
VALUE="blanc"> Blanc
<INPUT TYPE="checkbox" NAME="saisie[couleur][]"
VALUE="rouge"> Rouge
<INPUT TYPE="checkbox" NAME="saisie[couleur][]"
VALUE=" ?" CHECKED> Ne sait pas
Rsultat
$_POST :
saisie =
couleurs =
0 = bleu
1 = rouge
Listeslectionunique
Pour les listes slection unique, c'estdire pour une zone <SELECT> sans option MULTIPLE (langue dans
l'exemple suivant), la variable associe contient la valeur contenue dans l'option VALUE de la balise <OPTION>,
ou,s'iln'yapasd'optionVALUE,lavaleuraffichedanslaliste(c'estdirederrirelabalise<OPTION>).
<SELECT NAME="langue">
<OPTION VALUE="E">Espagnol
<OPTION SELECTED VALUE="F">Franais
<OPTION VALUE="I">Italien
</SELECT>
Rsultat
$_POST :
langue = F
<SELECT NAME="langue">
<OPTION>Espagnol
<OPTION SELECTED>Franais
<OPTION>Italien
</SELECT>
Rsultat
$_POST :
langue = Franais
L'une ou l'autre des possibilits peut tre choisie en fonction des besoins de la logique applicative. Souvent,
l'option VALUE est utilise pour mettre un code qui sera stock dans la base la place de la valeur affiche.
Cetteapprocheprsenteuninconvnient :lapartieinterfaceutilisateur(coucheprsentation)doitconnatreles
codes, ce qui n'est pas une bonne ide. La solution optimale consiste gnrer dynamiquement le formulaire
partirdelabase.
Listeslectionmultiple
Pour les listes slection multiple, c'estdire pour une zone <SELECT> avec option MULTIPLE (fruits dans
l'exemple ciaprs), la variable associe contient la valeur contenue dans l'option VALUE de la balise <OPTION>,
ou, s'il n'y a pas d'option VALUE, la valeur affiche dans la liste (c'estdire derrire la balise <OPTION>).
Attention, ceci est valable uniquement pour la dernire option slectionne, si la variable est une variable
scalaire.
Exemple
$_POST :
fruits = F
Lasolutionconsisteutiliseruntableau.
Exemple
Rsultat
$_POST :
fruits =
0 = A
1 = F
Comme nous l'avons dj vu avec la case cocher, PHP remplit le tableau avec une ligne pour chaque option
slectionne et numrote luimme les lignes. Dans le cas de la liste slection multiple, ce mode de
fonctionnementneposepasdeproblme.
$_POST :
fruits =
0 = Abricots
1 = Fraises
L'une ou l'autre des possibilits peut tre choisie en fonction des besoins de la logique applicative (mmes
principesquepourlalisteslectionunique).
Rsultat
$_POST :
saisie =
fruits =
0 = Abricots
1 = Fraises
Boutondevalidation
Pour un bouton de validation, c'estdire pour une zone <INPUT> de type submit (OK sur l'exemple ciaprs),
PHP cre une variable portant le nom du bouton (option NAME) et ayant comme valeur celle de l'option VALUE,
uniquementsileboutonestcliqu.
Exemple
$_POST :
OK = OK
$_POST :
soumettre = OK
Sileboutonneportepasdenom,aucunevariablen'estcre.Cen'estpasgravesi :
- Il n'est pas ncessaire de savoir comment le script est appel (affichage initial ou traitement du formulaire).
Danslesautrescas,ilfautnommerle(s)bouton(s).
Le script suivant montre comment faire la diffrence entre l'appel du script pour affichage initial et l'appel du
scriptpourtraitementduformulaire(cf.2.InteractionentreunformulaireetunscriptPHP,troisimemthode).
Exemple :
<?php
// inclure un fichier qui contient des dfinitions de
// constantes, dont le titre de la page (TITRE_PAGE_SAISIE)
require("constantes.inc");
// Tester comment le script est appel
if (isset($_POST["OK"])) {
// une ligne existe dans la variable $_POST
// correspondant au bouton nomm " OK " = le script
// est appel sur la validation du formulaire
// => traiter le formulaire
// gnralement, commencer par rcuprer les valeurs saisies
$nom = $_POST["nom"];
} else {
// le script n'est pas appel par le clic sur le bouton OK
// s'il n'y pas d'autre bouton "submit", le script est
// donc appel pour l'affichage initial
// => initialiser le formulaire
$nom = "X"; // par exemple
}
// dans le code HTML qui suit, inclusion de deux petits
//bouts de code PHP pour afficher respectivement le titre
// de la page et la valeur initiale de la zone de saisie
?>
<HTML>
<HEAD><TITLE><?php echo TITRE_PAGE_SAISIE ?></TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo $nom ?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Aveccescript,ladonnesaisieestbienraffichedansleformulaire.
Un problme se pose si le formulaire possde une seule zone de texte, aucun bouton et que l'utilisateur tape
ENTER ou RETURN. Dans ce cas, le formulaire est bien soumis mais il n'existe pas de bouton de validation pour
raliser le test dans le script PHP. La solution consiste tester si la variable $_* est vide ou pas (avec empty
maispasissetcarletableauexistetoujours).
Un problme similaire mais plus inattendu se pose si le formulaire prsente un bouton de validation, une seule
zone<INPUT>detypetext oufileetn'importequelautretypedezone(saufuneautrezone<INPUT>detype
text ou file). Dans ce cas, si l'utilisateur tape ENTER ou RETURN, alors qu'il est en train de saisir une
information dans la zone <INPUT> de type text ou file, le formulaire est bien soumis mais le bouton de
validation n'est pas considr comme cliqu : aucune variable ne lui est associe dans le formulaire. La solution
Si le formulaire contient deux boutons de validation nomms diffremment (option NAME), le premier OK et le
deuximeannuler,ilestpossiblededterminerdansquelcontextelescriptestappel.
Exemple
Si le formulaire contient deux boutons de validation portant le mme nom (option NAME="soumettre" par
exemple), mais des valeurs (option VALUE) diffrentes, le premier OK et le deuxime Annuler, il est possible de
dterminerdansquelcontextelescriptestappeldelamaniresuivante.
Exemple
Boutonimage
Pourunboutonimage,c'estdirepourunezone<INPUT>detypeimage (exemplevaliderciaprs),PHPcre
deux variables portant le nom du bouton (option NAME) suivi de _x et _y et donnant la position relative, en
pixels,duclicparrapportl'anglesituenhautgauchedel'image(uniquementsil'imageestclique).
Exemple
$_POST :
valider_x = 5
valider_y = 8
Sileboutonneportepasdenom,lesdeuxvariablessontappelesxety.
Exemple
$_POST :
x = 5
y = 8
Ilestalorspossibledetraiterlapositionduclicsielleestsignificativedupointdevuedelalogiqueapplicative.
Siplusieursboutonsimagesontprsentsdansleformulaire,ilestpossiblededterminerquelboutonaprovoqu
lasoumissionduformulaire.
Bouton"reset"ou"button"
Un clic sur des boutons correspondant des zones <INPUT> de type reset ou button ne provoque pas la
soumission du formulaire, ni l'appel du script de traitement. Ces boutons permettent de faire une simple action
ctnavigateur(enJavaScriptparexemple).
Synthse
Ilfautprendrel'habitudedebiendsigner(option NAME)toutesleszonesduformulaireavecdesnomsdistincts
oud'utiliserunnommagedetypetableau,pluttassociatif,pourfaciliterlamaintenanceetlalisibilitducode.
Pourlesgroupesdeboutonsradio,ilfautmettreuneoptionVALUEdistinctechaquebouton.
Pourlescasescocher,ilfautemployerdesnomsdistincts(option NAME),et/oudesvaleursdistinctes(option
VALUE), pour tre certain de pouvoir faire la diffrence l'arrive en cas d'utilisation d'un tableau, ne laissez
pasPHPeffectuerlanumrotation(pasde[]).
Pourleslistesslectionmultiple,ilfaututiliserunnommagedetypetableaupourpouvoirrcuprerlalistedes
valeursslectionnes employezl'option VALUEpourrcuprerunevaleurdiffrentedecellequiapparatdansla
liste.
Demme,Ilfautnommerle(s)bouton(s)devalidationpourtreenmesuredesavoircommentlescriptPHPest
appel. Si plusieurs boutons sont utiliss, il est possible d'employer le mme nom du moment que les valeurs
(optionVALUE)sontdiffrentes.
Exemple
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom :
<INPUT TYPE="text" NAME="nom" VALUE=""
SIZE="20" MAXLENGTH="20">
Mot de passe :
<INPUT TYPE="password" NAME="mot_de_passe" VALUE=""
SIZE="20" MAXLENGTH="20">
<BR>Sexe :
<INPUT TYPE="radio" NAME="sexe" VALUE="M"> Masculin
<INPUT TYPE="radio" NAME="sexe" VALUE="F"> Fminin
<INPUT TYPE="radio" NAME="sexe" VALUE="?"
CHECKED> Ne sait pas
<BR>Photo :
<INPUT TYPE="file" NAME="photo" VALUE="" SIZE="50">
<BR>Couleurs prfres :
<INPUT TYPE="checkbox" NAME="couleurs[bleu]"> Bleu
<INPUT TYPE="checkbox" NAME="couleurs[blanc]"> Blanc
<INPUT TYPE="checkbox" NAME="couleurs[rouge]"> Rouge
<INPUT TYPE="checkbox" NAME="couleurs[nesaitpas]" CHECKED>
Ne sait pas
<BR>Langue :
<SELECT NAME="langue">
<OPTION VALUE="E">Espagnol
<OPTION SELECTED VALUE="F">Franais
<OPTION VALUE="I">Italien
</SELECT>
<BR>Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<OPTION VALUE="A">Abricots
<OPTION VALUE="C">Cerises
<OPTION VALUE="F">Fraises
<OPTION VALUE="P">Pches
Rsultat
Rsultat
$_POST :
nom = HEURTEL
mot_de_passe = olivier
sexe = M
photo = D:\Photos\identit.jpg
couleurs =
bleu = on
rouge = on
langue = F
fruits =
0 = A
1 = F
commentaire = Consultant en systme d'information
invisible = 123
OK = OK
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom :
Rsultat
$_POST :
saisie =
nom = HEURTEL
mot_de_passe = olivier
sexe = M
photo = D:\Photos\identit.gif
couleurs =
bleu = on
rouge = on
langue = F
fruits =
0 = A
1 = F
commentaire = Consultant en systme d'information
invisible = 123
OK = OK
Comme tout le reste de la page, tout ou partie d'un formulaire peut tre construit dynamiquement. Trois cas
sontabordsdanscettesection :
Gnrerlatotalitduformulaire
Exemple
<?php
echo "<FORM ACTION=\"saisie.php\" METHOD=\"POST\">";
echo "Nom : <INPUT TYPE=\"text\" NAME=\"nom\"><BR>";
echo "<INPUT TYPE=\"submit\" NAME=\"OK\" VALUE=\"OK\">";
echo "</FORM>";
?>
Cetexempleneprsentepasungrandintrtcariln'yariendevraimentdynamiquedansleformulaire :autant
mettrelecodeHTMLdirectement,c'estpluslisible.
Unetelleapprochepeutnanmoinstrepratiques'ilexisteunedescriptionduformulairesousuneformeousous
uneautre.
En effet, dans l'exemple suivant, nous supposons que nous rcuprons (dans un fichier, dans une base...) une
description du formulaire sous la forme d'un tableau deux dimensions : chaque ligne du tableau contient une
descriptiondelazonesouslaformed'untableauavecletitre,letype,lenometlavaleur.
Exemple :
<?php
// tableau contenant la description du formulaire
$formulaire = array(
array("Nom : ","text","nom","HEURTEL"),
array("","submit","OK","OK") );
// gnration d'un formulaire l'aide d'une boucle sur le tableau
echo "<FORM ACTION=\"saisie.php\" METHOD=\"POST\">\n";
foreach($formulaire as $zone) {
echo "$zone[0]<INPUT TYPE=\"$zone[1]\"
NAME=\"$zone[2]\" VALUE=\"$zone[3]\"><BR>\n";
}
echo "</FORM>\n";
?>
Notez la prsence des squences \n, dans le code PHP, qui permettent d'avoir des retours la ligne dans le
sourcedelapage.
Gnrerdesvaleursinitialesdansleszonesdesaisie
Nousavonsdjtudicettepossibilitdansdiffrentsexemples.
Exemple
Ici,noussupposonsque$nomestunevariableinitialiseparailleursdanslescriptPHP.
Gnrerunelisted'options
Du code PHP peut tre utilis pour gnrer des listes d'options, soit dans une zone <SELECT> (liste slection
unique ou multiple), soit dans une zone <INPUT> de type radio (groupe de boutons radio), soit dans une zone
<INPUT>detypecheckbox(casecocher).
Les donnes affiches proviennent trs souvent d'une base de donnes et il est intressant de pouvoir
construirecettezoneduformulairedynamiquementpartirdesdonnesextraitesdelabase.
<?php
// liste des fruits afficher dans la liste, sous la forme d'un tableau
// associatif donnant le code du fruit (cl du tableau) et l'intitul
// du fruit ; nous verrons ultrieurement comment rcuprer ces informations
// dans une base
$fruits_du_march = array(
"A" => "Abricots",
"C" => "Cerises",
"F" => "Fraises",
"P" => "Pches",
"?" => "Ne sait pas");
// liste des fruits prfrs de l'utilisateur, sous la
// forme d'un tableau donnant le code des fruits concerns
// l encore, cette information pourra venir d'une base ou d'un autre cran
$fruits_prfrs = array("A","F");
?>
<!-- construction du formulaire -->
<FORM ACTION="saisie.php" METHOD="POST">
Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<?php
// code PHP gnrant la partie dynamique du formulaire
// parcourir la liste afficher et rcuprer le code et l'intitul
foreach($fruits_du_march as $code => $intitul) {
// dterminer si la ligne doit tre slectionne
// - oui si le code figure dans la liste des fruits
// prfrs de l'utilisateur => recherche de $code
// dans $fruits_prfrs avec la fonction in_array
// - si c'est le cas, mettre la clause SELECTED dans
// la balise OPTION, sinon ne rien mettre
$slection = in_array($code,$fruits_prfrs)?
"SELECTED":"";
// gnrer la balise OPTION avec la variable $code pour
// l'option VALUE, la variable $slection pour
// l'indication de slection et la variable $intitul
// pour le texte affich dans la liste
echo "<OPTION VALUE=\"$code\" $slection>$intitul\n";
}
?>
</SELECT>
<INPUT TYPE="submit" NAME="OK" VALUE="OK"><BR>
</FORM>
Cetexempleesttrsfacileadaptersil'optionVALUEn'estpasutilise.
<?php
// liste des langues afficher dans la liste, sous la
// forme d'un tableau associatif donnant le code de
// la langue (cl du tableau) et l'intitul de la langue
$langues_disponibles = array(
"E" => "Espagnol",
"F" => "Franais",
"I" => "Italien");
// code de la langue de l'utilisateur
$langue = "F";
?>
<!-- construction du formulaire -->
<FORM ACTION="saisie.php" METHOD="POST">
Langue :<BR>
<SELECT NAME="langue">
<?php
// code PHP gnrant la partie dynamique du formulaire
// parcourir la liste afficher et rcuprer le code
// et l'intitul
foreach($langues_disponibles as $code => $intitul) {
// dterminer si la ligne doit tre slectionne
// - oui si le code est gal au code de la langue de
// l'utilisateur
// - si c'est le cas, mettre la clause SELECTED dans
// la balise OPTION, sinon ne rien mettre
$slection = ($code == $langue)?"SELECTED":"";
// gnrer la balise OPTION avec la variable $code pour
// l'option VALUE, la variable $slection pour
// l'indication de slection et la variable $intitul
// pour le texte affich dans la liste
echo "<OPTION VALUE=\"$code\" $slection>$intitul\n";
}
?>
</SELECT>
<INPUT TYPE="submit" NAME="OK" VALUE="OK"><BR>
</FORM>
Des techniques similaires peuvent tre utilises pour construire une liste de cases cocher, un groupe de
boutonsradio...
Vued'ensemble
Danslapremirepartiedecechapitre,nousavonsvucommentrcuprerlesdonnessaisies.
Ensuite, il faut vrifier que les donnes saisies sont correctes, c'estdire qu'elles respectent les rgles de
gestiondfiniespourl'application.
L'objectif de cette partie est de vous fournir quelques pistes sur les techniques couramment utilises en PHP
pour cette vrification. Une autre approche possible consiste raliser un contrle en JavaScript dans le
navigateur,l'intrttantd'viterunalleretretouravecleserveur.
Pour illustrer les diffrents cas, nous allons utiliser le formulaire suivant, qui ne contient volontairement aucune
valeurpardfaut(notezlecasdelalanguepourlaquellelapremireoptionestunelignevide).
Exemple
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Nom :
<INPUT TYPE="text" NAME="nom" VALUE=""
SIZE="20" MAXLENGTH="20">
Mot de passe :
<INPUT TYPE="password" NAME="mot_de_passe" VALUE=""
SIZE="20" MAXLENGTH="20">
<BR>Date de naissance (JJ/MM/AAAA) :
<INPUT TYPE="text" NAME="date_naissance" VALUE=""
SIZE="10" MAXLENGTH="10">
<BR>Sexe :
<INPUT TYPE="radio" NAME="sexe" VALUE="M"> Masculin
<INPUT TYPE="radio" NAME="sexe" VALUE="F"> Fminin
<BR>Couleurs prfres :
<INPUT TYPE="checkbox" NAME="couleurs[bleu]"> Bleu
<INPUT TYPE="checkbox" NAME="couleurs[blanc]"> Blanc
<INPUT TYPE="checkbox" NAME="couleurs[rouge]"> Rouge
<BR>Langue :
<SELECT NAME="langue">
<OPTION>
<OPTION VALUE="E">Espagnol
<OPTION VALUE="F">Franais
<OPTION VALUE="I">Italien
</SELECT>
<BR>Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<OPTION VALUE="A">Abricots
<OPTION VALUE="C">Cerises
<OPTION VALUE="F">Fraises
<OPTION VALUE="P">Pches
</SELECT>
<BR>Commentaire :<BR>
<TEXTAREA NAME="commentaire" ROWS="4" COLS="50"></TEXTAREA>
<BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Rsultat
<?php
$nom = $_POST["nom"];
$mot_de_passe = $_POST["mot_de_passe"];
$date_naissance = $_POST["date_naissance"];
$sexe = $_POST["sexe"];
$couleurs = $_POST["couleurs"]; // tableau
$langue = $_POST["langue"];
$fruits = $_POST["fruits"]; // tableau
$commentaire = $_POST["commentaire"];
echo "\$nom = $nom<BR>";
echo "\$mot_de_passe = $mot_de_passe<BR>";
echo "\$date_naissance = $date_naissance<BR>";
echo "\$sexe = $sexe<BR>";
echo "\$couleurs = $couleurs<BR>";
echo "\$langue = $langue<BR>";
echo "\$fruits = $fruits<BR>";
echo "\$commentaire = $commentaire<BR>";
?>
Vrificationsclassiques
Nettoyagedesespacesquitranent
Exemple
$nom = trim($_POST["nom"]);
$mot_de_passe = trim($_POST["mot_de_passe"]);
$date_naissance = trim($_POST["date_naissance"]);
$commentaire = trim($_POST["commentaire"]);
Zonesobligatoires
Leformulaireprcdent,surunesaisievide,donnelersultatsuivant :
$nom =
$mot_de_passe =
Testersiunezoneobligatoireestsaisieservletrssimple :ilsuffitdetestersilavariableassociecontient
unevaleur.
Exemple
if ($variable == "") {
// $variable est non saisi, faire quelque chose
}
Il peut aussi tre tentant de raliser un test du type if (! $variable) en se souvenant qu'une chane vide est
quivalente FALSE. Cette approche n'est gnralement pas fiable, car une valeur saisie gale 0 sera aussi
considrecommemauvaise(car0estaussiquivalentFALSE).
Longueurmaximumd'unechane
Pour les zones en saisie libre, la longueur des informations saisies peut tre contrle avec la fonction strlen
(cf.Constantes,variables,typesettableauxManipulationdeschanesdecaractres).
Exemple
L'option MAXLENGTH de la balise INPUT permet un contrle complmentaire au moment de la saisie (c'est le
navigateurquis'encharge).
CaractresautorisspourunechaneFormat
Encasdebesoin,l'utilisationdesexpressionsrgulires(cf.chapitreConstantes,variables,typesettableaux
Manipulationdeschanesdecaractres)permetdecontrlertrsfacilementqueseulscertainscaractressont
prsentsetventuellementquelachanesaisierespecteunformatspcifique.
titre d'exemple, supposons que le mot de passe doit vrifier la rgle suivante : commencer par une lettre,
suiviedelettres,dechiffresoudescaractres_#*$avecunelongueurminimalede4.
Exemple
if (! eregi("^[a-z][a-z0-9_#*$]{3,}",$mot_de_passe)) {
// Mot de passe non valide
}
Quelquesexplicationssurl'expressionrgulireutilise(^[a-z][a-z0-9_#*$]{3,}) :
- [a-z] = une lettre entre a et z (ou A et Z car eregi est utilise) ...
- [a-z0-9_#*$]{3,} = suivi d'au moins 3 ({3,}) caractres parmi ceux indiqus: a z (et donc A Z), 0 9 et les
caractres _#*$.
D'autresexemplessontprsentsdanslasuitedecettepartieaveclesdatesetlesnombres.
Validitd'unedatePlagedevaleurs
Lavrificationdurespectduformatetdescaractresautorissesttrssimpleavecuneexpressionrgulire.
Exemple
if (! ereg("^[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}$",
$date_naissance)) {
// mauvais format pour la date
}
Quelquesexplicationssurl'expressionrgulireutilise(^([0-9]{1,2})/
([0-9]{1,2})/([0-9]{4})$) :
Pour vrifier la validit de la date, il est possible d'utiliser la fonction checkdate (cf. chapitre Constantes,
variables,typesettableauxManipulationdesdates).
Dansunpremiertemps,ilfautrcuprerlescomposantesdeladatesaisie.Plusieurssolutionssontutilisables :
$jma = explode("/",$date_naissance);
// $jma[0] contient le jour
// $jma[1] contient le mois
// $jma[2] contient l'anne
if (! checkdate($jma[1],$jma[0],$jma[2])) {
// date non valide
}
list($jour,$mois,$anne) = explode("/",$date_naissance);
// rcupration des composantes dans des variables indpendantes
if (! checkdate($mois,$jour,$anne)) {
// date non valide
}
- avec le troisime paramtre de la fonction ereg qui permet de rcuprer des portions de la chane, et cela
directement dans le test de conformit du format :
if (! ereg("^([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})$",
$date_naissance,$jma)) {
// mauvais format pour la date
Pour tester la plage de valeurs, le plus simple est de faire une comparaison numrique (ou alphabtique) sur un
nombre(ouunechane)construitsurlaformeAAAAMMJJ (20010828pourle28/08/2001).
Exemple
Validitd'unnombrePlagedevaleurs
Plusieurstechniquespeuventtreutilisespourvrifierqu'unnombreestbienform :
- la fonction is_numeric ;
Pourlaplagedevaleurs,unsimpletestdutypesuivantsuffit.
Exemple
Validitd'uneadresseemail
Unedesmeilleuressolutionssembletrelasuivante :
eregi("^[0-9a-z]([-_.]?[0-9a-z])*@
[0-9a-z]([-.]?[0-9a-z])*\.[a-z]{2,3}$",$adresse)
Quelquesexplicationssurl'expressionrgulireutilise :
- ([-_.]?[0-9a-z])* = suivi d'une ou plusieurs squences commenant chacune optionnellement par un tiret, un
soulign ou un point suivi de lettre ou de chiffres...
- @@ = suivi d'un @.
- ([-.]?[0-9a-z])* = suivi d'une ou plusieurs squences commenant chacune optionnellement par un tiret ou un
point suivi de lettres ou de chiffres.
L'expression rgulire permet de vrifier que l'adresse est syntaxiquement correcte, mais pas de contrler qu'elle existe
rellement.
Lafonctionnalitde"magicquotes"
PHPproposeunefonctionnalit,appele"magicquotes",dontl'objectifprincipalestdersoudreunproblmeli
l'enregistrement des donnes dans une base de donnes en effectuant un encodage sur les donnes saisies
dansunformulaire.
Cettefonctionnalitpeutrapidementdeveniruncassettesielleestmalpriseencompte.
Dequois'agitil ?
Siladirectivedeconfigurationmagic_quotes_gpceston,touteslesdonnesarrivantparunemthodeGETou
POST (ou encore, nous le verrons plus tard, par un cookie) sont automatiquement encodes avec un antislash
(\)devantlescaractresapostrophe('),guillemet(")etbiensrantislash(\).
ConsidronslescriptPHPsaisie.phpsuivantquisecontented'afficherunezonedesaisiepuis,derafficherla
valeursaisiedanslazoneduformulaireetdirectementdanslapage.
Exemple
<?php
// rcuprer la donnes saisie
$saisie = isset($_POST["saisie"])?$_POST["saisie"]:"";
// la rafficher ensuite dans la zone de saisie et directement dans la page...
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Saisie : <INPUT TYPE="text" NAME="saisie"
VALUE="<?php echo $saisie; ?>"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
<?php
echo $saisie;
?>
</BODY>
</HTML>
Rsultat
- Affichage initial :
Dans ce dernier cas, le problme de raffichage dans la zone de saisie n'est pas li la fonctionnalit "magic
quotes" mais un autre problme abord dans le prochain point (cf. 2. Autres problmes sur les donnes
saisies).
Ce principe d'encodage "magic quotes" est effectivement intressant, notamment devant l'apostrophe, si les
donnes sont destines tre enregistres dans une base SQL (Struc tured Query Language). En effet, en
SQL,ledlimiteurdechanedecaractresestl'apostrophe siunerequteenvoielachane'c'est l't'la
base,cettedernirevainterprter 'c'commeunechaneetnesaurapasquoifairedureste(est l't') :un
messaged'erreurseraretournparlabase.
Pourrglerceproblme,ilfautindiquerlabasequelesapostrophesl'intrieurdelachanenesontpasdes
dlimiteurs de la chane, gnralement en les faisant prcder d'un caractre "magique" ("d'chappement") : \
pour MySQL ou apostrophe (') pour d'autres bases comme Oracle, Sybase ou Microsoft SQL Server. Les bonnes
valeurs envoyer sont donc 'c\'est l\'t' pour MySQL ou 'c''est l''t' pour d'autres bases de
donnes.
La fonctionnalit "magic quotes" est intressante si la donne saisie est destine tre enregistre dans une
base MySQL (l'encodage est automatique), mais pose des problmes si la donne saisie est destine tre
enregistredansunebaseOracleouSQLServer(l'encodagen'estpaslebon)ousimplementaffichedansune
pageHTML(l'encodageestinutile).
Danslapratique,cettefonctionnalit"magicquotes"posedeuxproblmes :
- Si la donne est la fois destine tre affiche dans la page et enregistre dans une base, il y a un problme: avec
l'affichage si "magic quotes" est actif, avec l'enregis trement dans la base si "magic quotes" est inactif.
- Le dveloppeur ne matrise pas forcment la configuration de PHP dans l'environnement d'exploitation: il peut donc
crire du code qui fonctionne dans son environnement de dveloppement (avec une certaine configuration de "magic
quotes"), mais qui risque de ne plus fonctionner dans l'environnement d'exploitation o la configuration est peuttre
diffrente.
Nous allons donc voir comment grer correctement cette fonctionnalit et crire un code indpendant de la
configuration.
Pour grer les besoins contradictoires de l'affichage et de l'enregistrement dans la base, PHP propose deux
Lafonctionaddslashesprendenparamtreunechanedecaractresetretournecettechaneenajoutantun\
devant les caractres ', " et \ (si magic_quotes_sybase est off) ou le ' devant ' (si magic_quotes_sybase
eston).
Lafonctionstripslashesprendenparamtreunechanedecaractresetretournecettechaneensupprimant
le \ devant les caractres ', " et \ (si magic_quotes_sybase est off) ou le ' devant ' (si
magic_quotes_sybaseeston).
Exemple
<?php
echo addslashes("c'est l't")."<BR>";
echo stripslashes("c\'est l\'t")."<BR>";
?>
c\'est l\'t
c'est l't
Cesfonctionsvonttreutilesdanslesdeuxcassuivants :
- Si vous avez une donne dans une variable, qui n'a pas dj t encode, et que cette donne doive tre enregistre
dans la base, il est conseill d'appeler addslashes pour effectuer l'encodage adapt.
- Si vous avez une donne dans une variable, qui a t encode (manuellement ou automatiquement), et que vous
souhaitiez l'afficher dans une page HTML, il faut appeler stripslashes pour enlever l'encodage.
Il ne faut pas appeler addslashes ou stripslashes au hasard sur des variables dj encodes en ce qui concerne
addslashes ou non encodes en ce qui concerne stripslashes.
Exemple
<?php
// utilisation de la fonction addslashes sur une donne dj encode
echo addslashes("c\'est l\'t")."<BR>";
// utilisation de la fonction stripslashes sur une donne non encode
echo stripslashes("c'est l't")."<BR>";
// pas grave
echo stripslashes("d:\photos\identit.gif")."<BR>";
// mauvais
?>
c\\\'est l\\\'t
c'est l't
d:photosidentit.gif
Il est donc important de ne pas appeler addslashes systmatiquement avant un enregistrement dans la base,
oustripslashessystmatiquementavantunaffichagedansunepageHTML.Ilfautsavoird'ovientladonne
etsielleestounondjencodeparlafonctionnalit"magicquotes".
IlexistedeuxsituationssimplessivousmatrisezlaconfigurationdePHP :
- Vous tes certain que magic_quotes_gpc = off : dans ce cas, vous pouvez afficher les donnes issues des
formulaires sans soucis (pas besoin de la fonction stripslashes) et devez appeler addslashes avant tout
enregistrement dans la base.
- Vous tes certain que magic_quotes_gpc = on et que magic_quotes_sybase est adapt la base que vous
utilisez (off pour MySQL ou on pour Oracle, Sybase ou Microsoft SQL Server): dans ce cas, vous devez appeler
En effet, si vous initialisez une variable du type $valeur = "c'est l't", cette variable vacontenir une
information qui n'a pas subi l'encodage automatique de la fonctionnalit "magic quotes"; un moment ou un autre, il
faudra encoder la donne avec addslashes si elle doit tre enregistre dans la base...
Gestionintelligenteetportable
SivousnematrisezpaslaconfigurationdePHPetquevoussouhaitiezavoiruncodeportable,ilfautprocder
autrement.
Voicilasolutionlaplussimple :
- Dcider une fois pour toutes que toute variable PHP contient une donne qui est soit encode, soit non encode; la
version "toute variable PHP contient une donne non encode" est prconise.
- Faire le traitement ncessaire, lors de l'affectation d'une variable par une donne qui vient de l'extrieur pour s'assurer
qu'elle ne contient pas d'encodage "magic quotes".
- Ne rien faire visvis de l'encodage "magic quotes" (les variables ne contiennent pas de caractre \ superflu) lors de
l'affichage d'une variable dans une page HTML (directement ou dans un formulaire).
- Faire l'encodage ncessaire lors de l'enregistrement d'une variable dans une base.
Leschmasuivantprsentelessourcesdedonnesextrieuresqu'ilvafalloirgreraumomentdel'alimentation
desvariables :
Un tel traitement est possible grce la fonctionget_magic_quotes_gpc qui retourne 1 (quivalent TRUE) si
lafonctionnalit"magicquotes"estactiveet0(quivalentFALSE)sinon.
Ilestdoncpossibled'crireunefonctionquiserasystmatiquementappelelorsdelarcuprationd'unedonne
GPCpourenleverl'encodage"magicquotes"sicedernierestactif.
Exemple
<?php
function supprimer_encodage_MQ($valeur) {
// si magic quotes est actif, retourner
// la valeur aprs suppression de l'encodage
// (=> appel stripslashes), sinon, retourner
Appeler uniquement cette fonction sur des donnes GPC pour ne pas risquer d'enlever des caractres d'chappement qui ne
sont pas lis un encodage "magic quotes".
Larcuprationdesdonnesd'unformulaireprendalorslastructuresuivante :
<?php
// inclusion du fichier qui contient les dfinitions de nos
// fonctions gnrales
include("fonctions.inc");
// rcupration des valeurs saisies dans le formulaire
$nom = supprimer_encodage_MQ(trim($_POST["nom"]));
$mot_de_passe = supprimer_encodage_MQ(
trim($_POST["mot_de_passe"]));
$date_naissance = supprimer_encodage_MQ(
trim($_POST["date_naissance"]));
// ...
?>
Pourleszonesquinesontpasensaisielibre(listeslectionuniqueoumultiple,groupedeboutonsradio,cases
cocher),iln'estpasforcmentncessaired'appelerlafonctioncarladonneretourneestmatriseetvous
pouvez faire en sorte qu'elle ne contienne pas d'apostrophe dans le doute, appelezla systmatiquement (en
l'adaptantaucasolavariableestuntableau).
Ilesttrssimpled'crireunefonctiongnriquequiregroupel'appeltrimetsupprimer_encodage_MQ.
Exemple
<?php
function supprimer_encodage_MQ($valeur) {
// si magic quotes est actif, retourner
// la valeur aprs suppression de l'encodage
// (=> appel stripslashes), sinon, retourner la valeur
return (get_magic_quotes_gpc())?
stripslashes($valeur):$valeur;
}
function valeur_saisie($valeur) {
return supprimer_encodage_MQ (trim($valeur));
}
$nom = valeur_saisie($_POST["nom"]);
// ...
?>
Nous allons voir dans les chapitres Accder aux bases de donnes et Gestion des fichiers que les donnes en
provenance d'une base de donnes ou d'un fichier sont sous l'influence d'une autre directive, appele
magic_quotes_runtime,quiaunfonctionnementidentiquemagic_quotes_gpcetdoncunmodedetraitement
proche.
Pour l'enregistrement dans la base, nous verrons dans le chapitre Accder aux bases de donnes comment
traiterdemaniregnriquelesdonnesavantdelesenvoyerlabasepourviterlesproblmes.
Autresproblmessurlesdonnessaisies
Danslepointprcdent,nousavonsabordunproblmed'affichagedansunezonedeformulairesuitelasaisie
d'unguillemet(").
Rappel
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Saisie : <INPUT TYPE="text" NAME="saisie"
VALUE="il dit : \"bonjour !\""><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
il dit : \"bonjour !\"
</BODY>
</HTML>
EnHTML,danslesoptionsdesbalises(VALUE, NAME...),ledlimiteurdechaneestleguillemetetlecaractre\
n'est pas un caractre d'chappement : dans l'option VALUE="il dit : \"bonjour !\"", la squence "il
dit : \"estconsidrecommelavaleurdel'optionetlerestedelachaneestignor.
LasaisieOlivier <B>HeurteldonnelemotHeurtelengraslorsdel'affichagedanslapageHTML.
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Saisie : <INPUT TYPE="text" NAME="saisie"
VALUE="Olivier <B>Heurtel"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
Olivier <B>Heurtel
</BODY>
</HTML>
Lasquence <B>saisieparl'utilisateurseretrouvetellequelledanslesourcedelapageetestdoncinterprte
parlenavigateurcommelabalisedemiseengras.
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Saisie :<BR>
<TEXTAREA NAME="saisie" COLS="40" ROWS="6">Premire ligne.
Deuxime ligne.
Troisime ligne.</TEXTAREA><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
Premire ligne.
Deuxime ligne.
Troisime ligne.
</BODY>
</HTML>
Le texte est bien prsent avec des sauts de lignes dans le source de la page, mais le saut de ligne, en dehors
d'unezone<TEXTAREA>,n'estpasinterprtparlenavigateur :ilfautmettreunebalise<BR>.
Nous voyons donc apparatre trois problmes relatifs l'affichage dans la page HTML de donnes saisies par
l'utilisateur :
- prsence du caractre guillemet qui peut poser un problme lors de l'utilisation de la donne dans un formulaire (option
VALUE) ;
- prsence de balises HTML valides qui sont interprtes comme telles par le navigateur ;
Ledeuxime"problme"peutprsenterunintrtsivoussouhaitezoffrirlapossibilitunutilisateuravancde
saisiruntexteavecunpeudemiseenformepourunaffichageultrieurdansunepage.
Lafonctionhtmlspecialcharsprendunechanedecaractresetlaretourneenremplaantcertainscaractres
parleurquivalentHTML :
Syntaxe
texte
Chanetraiter.
Fonctionnementvisvisdescaractresguillemets(")etapostrophe(').
jeu
Jeudecaractresutiliserpourlaconversion.
Lescaractresconvertissontlessuivants :
Entre Sortie
& &
" "
' '
< <
> >
Le deuxime paramtre permet de prciser le fonctionnement visvis des caractres guillemets (") et
apostrophe(') :
Valeur Comportement
ENT_COMPAT Conversion du guillemet mais pas de l'apostrophe (par dfaut)
ENT_NOQUOTES Aucune conversion
ENT_QUOTES Conversion des deux caractres
Le troisime paramtre permet de dfinir le jeu de caractres utiliser pour la conversion : ISO-8859-1 (par
dfaut),ISO-8859-15,UTF-8,etc.
Lafonctionhtmlentitiesprsenteuncomportementidentiqueceluidehtmlspecialcharsmaispourtousles
caractresayantunquivalentenHTML(caractresaccentusnotamment).
Syntaxe
texte
Chanetraiter.
option
Fonctionnementvisvisdescaractresguillemets(")etapostrophe(').
jeu
Jeudecaractresutiliserpourlaconversion.
Lesdeuximeettroisimeparamtresontlammesignificationquepourlafonctionhtmlspecialchars.
Lafonctionnl2brprendunechaneetretournecettechaneaprsavoirinsrunebaliseHMTLdesautdeligne
devantchaquesautdeligne :labaliseest <br /><(compatibilitXHTML)partirdelaversion4.0.5dePHPet
<br> avant.
Syntaxe
texte
Chanetraiter.
Enfin, la fonction strip_tags prend une chane de caractres et la retourne aprs avoir supprim toutes les
balisesHTMLqu'ellecontient.
Syntaxe
texte
Chanetraiter.
balises_autorises
Listedesbalisesconserverdanslachane.
Undeuximeparamtrepermetd'indiquerlesbalisesconserver.
Exemple
<?php
echo "// premier texte<BR>\n";
$texte = "Olivier & Co. a dclar : \"c'est l't !\"";
echo $texte."<BR>\n";
echo "// htmlspecialchars<BR>\n";
echo "// - guillemet uniquement<BR>\n";
echo htmlspecialchars($texte,ENT_COMPAT)."<BR>\n";
echo "// - ni guillemet ni apostrophe<BR>\n";
echo htmlspecialchars($texte,ENT_NOQUOTES)."<BR>\n";
echo "// - guillemet et apostrophe<BR>\n";
echo htmlspecialchars($texte,ENT_QUOTES)."<BR>\n";
echo "// htmlsentities<BR>\n";
echo "// - guillemet et apostrophe<BR>\n";
echo htmlentities($texte,ENT_QUOTES)."<BR><BR>\n";
echo "// deuxime texte<BR>\n";
$texte = "<B>Olivier</B> & <U>Co.</U> <TT>a dclar</TT> :
<I>c'est l't !</I>";
echo $texte."<BR>\n";
echo "// strip_tags<BR>\n";
echo "// - toutes les balises<BR>\n";
echo strip_tags($texte)."<BR>\n";
echo "// - conserver <B> et <I><BR>\n";
echo strip_tags($texte,"<B><I>")."<BR><BR>\n";
echo "// troisime texte (avec sauts de ligne)<BR>\n";
$texte = "Premire ligne.\nDeuxime ligne.\n";
echo $texte."<BR>\n";
echo "// nl2br<BR>\n";
echo nl2br($texte)."<BR>\n";
?>
Rsultat
Par contre, les substitutions opres par les fonctions htmlentities et htmlspecialschars sont surtout
visiblesdanslesource.
// premier texte<BR>
Olivier & Co. a dclar : "c'est l't !"<BR>
// htmlspecialchars<BR>
// - guillemet uniquement<BR>
Olivier & Co. a dclar : "c'est l't !"<BR>
// - ni guillemet ni apostrophe<BR>
Olivier & Co. a dclar : "c'est l't !"<BR>
// - guillemet et apostrophe<BR>
Olivier & Co. a dclar : "c'est l't !"<BR>
// htmlsentities<BR>
// - guillemet et apostrophe<BR>
Olivier & Co. a déclaré : "c'est l'
été !"<BR><BR>
// deuxime texte<BR>
<B>Olivier</B> & <U>Co.</U> <TT>a dclar</TT> :
<I>c'est l't !</I><BR>
// strip_tags<BR>
// - toutes les balises<BR>
Olivier & Co. a dclar :
c'est l't !<BR>
// - conserver <B> et <I><BR>
<B>Olivier</B> & Co. a dclar :
<I>c'est l't !</I><BR><BR>
// troisime texte (avec sauts de ligne)<BR>
Premire ligne.
Deuxime ligne.
<BR>
// nl2br<BR>
Premire ligne.<br />
Deuxime ligne.<br />
<BR>
Cesfonctionsvontdoncpermettredegrerlesdiffrentsproblmesvoqusprcdemment.
Pour viter tout problme d'affichage dans le navigateur, il est conseill d'effectuer une transformation des
donnesavantoudansl'instructionecho.
<?php
// inclusion du script contenant la fonction valeur_saisie
Avec saisie
Correction
<?php
// inclusion du script contenant la fonction valeur_saisie
// dfinie dans le point 1. La fonctionnalit de "magic quotes"
include("fonctions.inc");
Rsultat
Aveccetteapproche,lasaisieestrestituetellequelle :sil'utilisateurasaisiunebalise,illaretrouve(celleci
n'estpasinterprteparlenavigateur).
Une autre approche possible pour les balises consiste les supprimer (notamment lors de la rcupration de la
donnesaisie).
Exemple
<?php
// inclusion du script contenant la fonction valeur_saisie
// dfinie dans le point 1. La fonctionnalit de "magic quotes"
include("fonctions.inc");
// rcuprer les donnes saisies sans les balises
if ( isset($_POST["OK"]) ) {
$saisie1 = valeur_saisie(
strip_tags($_POST["saisie1"]));
$saisie2 = valeur_saisie (
strip_tags($_POST["saisie2"]));
} else {
$saisie1 = "";
$saisie2 = "";
}
// les rafficher ensuite dans le formulaire et directement dans la page...
?>
La fonction nl2br doit tre appele aprs les fonctions htmlentities ou htmlspecialchar. Dans le cas contraire, la
balise <BR> ajoute par nl2br est encode (<BR>) avant d'tre insre dans le source de la page et n'est donc pas
interprte par le navigateur (le texte <BR> apparat dans la page affiche).
La fonction nl2br ne doit pas tre appele pour du texte destin une zone <TEXT-AREA> (sous peine, l encore, d'avoir le
texte <BR> dans la zone).
Synthse
Lagestiondesformulaires,avecl'affichageet/oul'enregistrementdesdonnessaisies,peutrapidementdevenir
uncassettecomptetenudesdiffrentsproblmespotentielsetdesdirectivesdeconfigurationassocies.
Nanmoins,avecunpeuderigueuretdeuxoutroisfonctionscritesunefoispourtoutes,cettegestionpeutse
fairesanssoucis.
Lastratgieprconiseestrsumeparleschmasuivant :
<?php
function supprimer_encodage_MQ($valeur) {
// si magic quotes est actif, retourner la valeur aprs suppression
// de l'encodage (=> appel stripslashes), sinon, retourner la valeur
return (get_magic_quotes_gpc())?
stripslashes($valeur):$valeur;
}
function valeur_saisie($valeur) {
return supprimer_encodage_MQ (trim($valeur));
}
?>
Une variante possible consiste supprimer les balises saisies par l'utilisateur dans ce cas, il suffit d'appeler la
fonctionstrip_tagsenplus.
Exemple de fonctions permettant d'afficher en scurit une donne dans une page HTML
<?php
function vers_formulaire($valeur) {
// affichage dans un formulaire
// encoder tous les caractres HTML spciaux
// - ENT_QUOTES : dont " et '
return htmlentities($valeur,ENT_QUOTES);
}
function vers_page($valeur) {
// affichage direct dans une page
// 1. encoder tous les caractres HTML spciaux
// - ENT_QUOTES : dont " et '
// 2. transformer les sauts de ligne en <BR>
return nl2br(htmlentities($valeur,ENT_QUOTES));
}
?>
<?php
// inclusion du script contenant les fonctions dfinies prcdemment
include("fonctions.inc");
// rcuprer la donne saisie
$saisie = isset($_POST["saisie"])?valeur_saisie($_POST["saisie"]):"";
// la rafficher ensuite dans le formulaire et directement dans la page...
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
lafindutraitementduformulaire,ilpeuttrencessaired'afficheruneautrepage,lasituationpouvantvarier
selonqueleformulaireesttraitparlescriptquil'afficheouparunscriptindpendant.
Variantes possibles:
Redirigerl'utilisateurversuneautrepageencoursdescriptestpossibleenutilisantlafonctionheader.
LafonctionheaderpermetdespcifierunechanequiestenvoyecommeentteHTTPaveclapageHTML.
Nousallonsutiliserl'enttelocationquiredirigelarequteversuneautreadresse.
Exemples
<?php
// affecter une valeur $nom si un nombre tir alatoirement
// entre 0 et 1 est gal 1
$nom = (rand(0,1)==1)?"Olivier":"";
// tester si $nom est renseign
if ($nom == "") {
// la variable $nom est vide, ce n'est pas normal
// => rediriger l'utilisateur vers une page d'erreur
header("location: erreur.htm");
// interrompre l'excution de ce script
exit;
}
// la variable $nom n'est pas vide, laisser le script se poursuivre
$message = "Bonjour $nom !"; // prparer un message
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<?php
// afficher le message
<HTML>
<HEAD><TITLE>Erreur</TITLE></HEAD>
<BODY>
Le site est actuellement indisponible ; essayez plus tard.<BR>
Merci de votre comprhension.<BR>
<!-- Lien pour une nouvelle tentative -->
<A HREF="info.php">Essayer de nouveau</A>
</BODY>
</HTML>
Statistiquement,unefoissurdeux,l'appelduscriptinfo.phpdonnelersultatsuivant :
Bonjour Olivier !
Etdonc,unefoissurdeux,lesuivant :
La fonction header doit tre appele avant toute instruction (PHP ou HTML) qui a pour effet de commencer construire la
page HTML (c'est en quelque sorte trop tard pour l'en-tte). Un simple espace, dans le script, ou dans un script inclus
(require ou include) provoque la mme erreur.
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<?php
// affecter une valeur $nom si un nombre tir alatoirement
// entre 0 et 1 est gal 1
$nom = (rand(0,1)==1)?"Olivier":"";
// tester si $nom est renseign
if ($nom == "") {
// la variable $nom est vide, ce n'est pas normal
// => rediriger l'utilisateur vers une page d'erreur
header("location: erreur.htm");
// interrompre l'excution de ce script
exit;
}
// la variable $nom n'est pas vide, laisser le script se poursuivre
echo "Bonjour $nom !"; // afficher un message
?>
</BODY>
</HTML>
Rsultat
Warning: Cannot modify header information - headers already sent by (output started at
d:\scripts php\info.php:5) in d:\scripts php\info.php on line 15
Si la fonctionnalit de mise en buffer de la page est active avec la directive de configuration output_buffering, le rsultat
du script n'est pas envoy au fur et mesure mais plac dans un buffer puis envoy d'un seul coup la fin (ou par morceaux si
le buffer est limit en taille). Dans ce cas, il est possible d'utiliser la fonction header sans provoquer d'erreur alors que le script
a commenc construire la page.
PHPproposed'autresfonctionsrelativesauxenttes :
Premierexempledelogiqued'enchanement
Un script saisie.php assure l'affichage initial du formulaire et son traitement. En cas d'erreur, le formulaire est
propos de nouveau pour correction (avec les valeurs saisies), accompagn d'un message d'erreur. En cas de
succsdutraitement,uneautrepageestappele.
<?php
// inclure un fichier qui contient des dfinitions de
// constantes, dont le titre de la page (TITRE_PAGE_SAISIE)
require("constantes.inc");
// inclure un fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// tester comment le script est appel
if (isset($_POST["OK"])) {
// traitement du formulaire ...
// rcuprer les valeurs saisies
$nom = valeur_saisie($_POST["nom"]);
$mail = valeur_saisie($_POST["mail"]);
// initialiser la variable du message
$message = "";
// contrler les valeurs saisies
if ($nom == "")
{ $message .= "Le nom est obligatoire.\n"; }
if ($mail == "")
{ $message .= "Le mail est obligatoire.\n"; }
if (! eregi("^[0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]
([-.]?[0-9a-z])*\.[a-z]{2,3}$",$mail))
{ $message .= "Le mail n'est pas valide.\n"; }
// tester s'il y a des erreurs
if ($message == "") {
// pas d'erreur
// enregistrer les informations quelque part
// et rediriger l'utilisateur vers une page d'accueil
header("location: accueil.php");
// interrompre l'excution du script
exit;
} else {
// erreur
// prparer le message pour l'affichage
$message = vers_page($message);
}
} else {
// affichage initial ...
// sur cet exemple simple, juste initialiser
// les variables
$nom = "";
$mail = "";
$message = "";
}
// dans le code HTML qui suit, inclusion de quatre petits
// bouts de code PHP pour afficher respectivement le titre
// de la page, la valeur des zones de saisie et le message
?>
<HTML>
<HEAD><TITLE><?php echo TITRE_PAGE_SAISIE ?></TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Veuillez saisir les informations suivantes
pour vous inscrire<BR><BR>
Nom : <INPUT TYPE="text" NAME="nom"
VALUE="<?php echo vers_formulaire($nom); ?>"><BR>
Mail : <INPUT TYPE="text" NAME="mail"
VALUE="<?php echo vers_formulaire($mail); ?>"><BR><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
<FONT COLOR="red"><?php echo $message; ?></FONT>
</BODY>
</HTML>
Deuximeexempledelogiqued'enchanement
Un script saisie.htm assure l'affichage initial du formulaire et un script traitement.php le traitement. En cas
Script saisie.htm
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="traitement.php" METHOD="POST">
Veuillez saisir les informations suivantes
pour vous inscrire<BR><BR>
Nom : <INPUT TYPE="text" NAME="nom" VALUE=""><BR>
Mail : <INPUT TYPE="text" NAME="mail" VALUE=""><BR><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
Script traitement.php
<?php
// inclure un fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// traitement du formulaire ...
// rcuprer les valeurs saisies
$nom = valeur_saisie($_POST["nom"]);
$mail = valeur_saisie($_POST["mail"]);
// initialiser la variable du message
$message = "";
// contrler les valeurs saisies
if ($nom == "")
{ $message .= "Le nom est obligatoire.\n"; }
if ($mail == "")
{ $message .= "Le mail est obligatoire.\n"; }
if (! eregi("^[0-9a-z]([-_.]?[0-9a-z])*@[0-9a-z]
([-.]?[0-9a-z])*\.[a-z]{2,3}$",$mail))
{ $message .= "Le mail n'est pas valide.\n"; }
// tester s'il y a des erreurs
if ($message == "") {
// pas d'erreur
// enregistrer les informations quelque part
// et rediriger l'utilisateur vers une page d'accueil
header("location: accueil.php");
// interrompre l'excution du script
exit;
} else {
// erreur
// prparer le message pour l'affichage
$message = vers_page($message);
}
// dans le code HTML qui suit, inclusion d'un petit bout
// de code PHP pour afficher le message
?>
<HTML>
<HEAD><TITLE>Erreur</TITLE></HEAD>
<BODY>
<FONT COLOR="red"><?php echo $message; ?></FONT>
<!-- Petit formulaire contenant un bouton permettant
---- de revenir en arrire (avec du JavaScript) pour corriger
-->
<FORM>
<<INPUT TYPE="button" VALUE="Corriger"
onClick="self.history.back()">
</FORM>
</BODY>
</HTML>
D'autres logiques d'enchanement peuvent exister, la fonction header permettant d'envisager diffrents cas de
figure(voirladocumentationPHP).
Le rsultat du traitement peut aussi tre affich dans une autre fentre grce l'option TARGET de la balise
<FORM>.
Exemple
Silafentren'existepas,elleseracreparlenavigateur.
Vued'ensemble
L'utilisationd'unebasededonnesSQLestsouventindispensablepourmettreenplaceunsiteWebdynamique.
C'esteneffetunmoyenstandardisdestockerdesdonnesutilespourlesite :
- catalogue de produits ;
PHP propose un support natif pour un grand nombre de bases de donnes, parmi lesquelles MySQL, Oracle,
Microsoft SQL Server, Informix, Sybase. Par ailleurs, PHP supporte ODBC (Open DataBase Connectivity) et peut
doncaccdertoutebasededonnessupportantODBC.
En complment, en version 5, PHP est livr avec SQLite, librairie qui implmente un moteur de base de donnes
SQL. SQLite peut tre utilis pour stocker des donnes dans une base SQL, sans avoir mettre en place la
partieserveurdelabasededonnes(commec'estlecasavecMySQL,Oracle,etc.).
Danscechapitre,noustudieronsMySQL,Oracle,MicrosoftSQLServeretSQLite.
Typiquement,lorsdel'utilisationd'unebasededonnes,lescriptPHPabesoind'effectueruneouplusieursdes
tchessuivantes :
- se connecter et se dconnecter ;
Cesdiffrentestchestypessonttudiesdanscechapitre.
Une connaissance minimale du langage SQL est ncessaire pour aborder ce chapitre.
Pour les diffrents exemples prsents ici, nous supposons l'existence d'une base contenant une table ARTICLE
prsentantlastructuresuivante :
Colonne Contenu
identifiant Identifiant de l'article (aliment automatiquement par le serveur)
libelle Libell de l'article
prix Prix de l'article
LecontenudecettetableARTICLEestlesuivant:
Lanotiondefetch
Quellequesoitlabase,l'instructiond'excutiond'unerequte SELECT(envuedeliredesdonnes)secontente
Pourrsumerlefonctionnement,l'instructiond'excutiond'unerequte SELECTidentifieunrsultatetpositionne
unpointeurinternesurlapremirelignedecersultat :
L'instructionFETCHpermetdelirelalignecourantedursultat,deramenerlesvaleursdansdesvariablesPHPet
defaireavancerlepointeursurlalignesuivante :
Prambule
Enversion5,PHPproposedeuxextensionspouraccderunebasededonnesMySQL :
L'extension MySQL est l'ancienne extension, prsente dans les versions antrieures de PHP cette extension
peut tre utilise pour accder n'importe quelle version de MySQL, mais elle ne supporte pas les nouvelles
fonctionnalitsdelaversion4.1deMySQL.
Pour utiliser les nouvelles fonctionnalits de la version 4.1 de MySQL, il faut utiliser l'extension MySQLi, apparue
en version 5 de PHP cette extension peut aussi tre employe pour accder une version plus ancienne de
MySQL,sousrservedenepasutiliserlesfonctionnalitsapparuesdanslaversion4.1deMySQL.
Mis part les nouvelles fonctionnalits de la version 4.1 de MySQL, les deux extensions sont trs proches en
termes de fonctionnalits. Trs souvent, elles proposent les mmes fonctions, avec des syntaxes identiques ou
compatibles. Sauf exception, pour passer de MySQL MySQLi, il suffit de remplacer le prfixe mysql_ dans le
nomdelafonctionparleprfixemysqli_.
l'heure o cet ouvrage est rdig, la version 4.1 de MySQL est encore en dveloppement (version 4.1.1
Alpha), et l'extension PHP la plus utilise est l'extension MySQL (pour accder des bases MySQL trs souvent
enversion3.2xou4.0).
En consquence, nous commencerons par prsenter de manire dtaille l'utilisation de l'extension MySQL.
Ensuite, nous tablirons une correspondance entre l'extension MySQLi et l'extension MySQL, en nous focalisant
surlesdiffrencesetlesprincipalesnouveauts.
Connexionetdconnexion
Lafonctionmysql_connectpermetd'tabliruneconnexionavecunebaseMySQL.
Syntaxe
serveur[:port]
Nomduserveurventuellementsuivid'unnumrodeport.
Valeurpardfaut :localhost:3306.
utilisateur
Nomdel'utilisateuremployerpourtablirlaconnexion.
Valeurpardfaut :lepropritaireduprocessusduserveurWeb.
mot_de_passe
Motdepasseutiliserpourtablirlaconnexion.
Valeurpardfaut :chanevide(pasdemotdepasse).
nouvelle
Permetdeforcerl'tablissementd'unenouvelleconnexion(TRUE).
Valeurpardfaut :FALSE.
Combinaisondesconstantessuivantes :
MYSQL_CLIENT_COMPRESS:utiliserunprotocoledecompression
MYSQL_CLIENT_IGNORE_SPACE :autoriserdesespacesaprslenomdesfonctions
MYSQL_CLIENT_INTERACTIVE : modifie la dure d'inactivit avant fermeture de la connexion pour un client de
typeinteractif.
La fonction mysql_connect retourne un identifiant de connexion ou, en cas d'erreur, la valeur FALSE
accompagned'unmessaged'alerteenvoyl'affichage(cf.chapitreGrerleserreursdansunscriptPHPpour
grercettesituationcorrectement).
Danslemmescript,appelerdeuxfois mysql_connectaveclesmmesparamtresn'ouvrepasdeuxconnexions
diffrentes : lors du deuxime appel, l'identifiant de la connexion dj ouverte est retourn. Pour modifier ce
comportement et forcer l'ouverture d'une nouvelle connexion, il faut donner la valeur TRUE au paramtre
nouvelle.
Exemple
<?php
// utilisation des valeurs par dfaut
$id1 = mysql_connect();
echo "\$id1 = $id1<BR>\n";
// spcification des paramtres
$id2 = mysql_connect("diane","oheu","rz245");
echo "\$id2 = $id2<BR>\n";
// exemple d'chec (" hermes " n'existe pas)
$id3 = mysql_connect("hermes","oheu","rz245");
echo "\$id3 = $id3<BR>\n";
// nouvel appel sans paramtre
$id4 = mysql_connect();
echo "\$id4 = $id4 (<B>= \$id1</B>)<BR>\n";
// gal $id1
?>
Rsultat
$id1 = Resource id #1
$id2 = Resource id #2
Warning: mysql_connect() [function.mysql-connect]: Unknown MySQL Server Host 'hermes' (11001) in
d:\scripts php\index.php on line 9
$id3 =
$id4 = Resource id #1 (= $id1)
Une valeur FALSE est convertie en chane vide dans un echo (d'ou la valeur de $id3).
Les connexions ouvertes dans un script sont automatiquement fermes la fin du script, sauf dconnexion
expliciteavantavecmysql_close(voirciaprs).
Lafonctionmysql_pconnectpermetd'obtenirunfonctionnementdiffrentetd'tabliruneconnexion"permanente"
qui ne sera pas ferme la fin du script et pourra tre rutilise dans ce script ou dans un autre script
ultrieurement.
Lasyntaxeestidentiquelasyntaxedelafonctionmysql_connect,sansleparamtrenouvelle.
Lorsdel'appellafonction mysql_pconnectdansunscript,PHPvrifiesiuneconnexionpermanenteadjt
ouverte avec les mmes paramtres (serveur, utilisateur et mot de passe) : si oui, l'identifiant de cette
connexion est retourn dans le cas contraire, une nouvelle connexion est tablie (et cette connexion ne sera
pasfermelafinduscript,autorisantainsisarutilisationultrieure).
La directive de configuration mysql.allow_persistent doit tre on pour pouvoir ouvrir des connexions
permanentes. Par ailleurs, les directives mysql.max_persistent et mysql.max_links permettent
respectivement de limiter le nombre de connexions permanentes et le nombre total de connexions. Grce
d'autres directives, vous pouvez dfinir des valeurs par dfaut (serveur, port, etc.) et modifier le timeout de
connexion.
Syntaxe
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Sinonprcis,fermeturedeladernireconnexionouverte.
Lafonctionmysql_closeretourneTRUEencasdesuccsetFALSEencasd'erreur(accompagnd'unealerte).
Lafonctionmysql_closeestsanseffetsuruneconnexionpermanente.
Toutes les connexions non permanentes sont automatiquement fermes la fin du script.
Exemple
<?php
// connexion
$id1 = mysql_connect();
echo "\$id1 = $id1<BR>\n";
// dconnexion
$ok = mysql_close($id1);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
// tentative de dconnexion d'une connexion dj close
$ok = mysql_close($id1);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
?>
Rsultat
$id1 = Resource id #1
$ok = TRUE
Warning: mysql_close(): 1 is not a valid MySQL-Link resource in
d:\scripts php\index.php on line 9
$ok = FALSE
Liredesdonnes
Liredesdonnesdansunebasencessitetroisoprations :
- slectionner la base de donnes laquelle envoyer la requte (un serveur MySQL pouvant abriter plusieurs bases
distinctes) ;
Slectionnerunebasededonnes
La fonctionmysql_select_dbpermetdeslectionnerlabasededonnesutiliserpourlaconnexionpasseen
paramtre.
Syntaxe
Avec
base
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Si non prcis, utilise la dernire connexion ouverte s'il n'y en a pas, tente d'ouvrir une connexion avec un
appellafonctionmysql_connectsansparamtre.
La fonction mysql_select_db retourne TRUE en cas de succs et FALSE en cas d'erreur. mysql_select_db ne
gnrepasd'alerteencasd'erreur.
Exemple
<?php
// connexion
$connexion = mysql_connect();
// slection d'une base qui existe
$rsultat1 = mysql_select_db("diane",$connexion);
echo "\$rsultat1 = ",($rsultat1)?'TRUE':'FALSE',"<BR>\n";
// slection d'une base qui n'existe pas
$rsultat2 = mysql_select_db("hermes",$connexion);
echo "\$rsultat2 = ",($rsultat2)?'TRUE':'FALSE',"<BR>\n";
?>
Rsultat
$rsultat1 = TRUE
$rsultat2 = FALSE
Excuterunerequte
Lafonctionmysql_querypermetd'envoyerunerequtepourexcutionlabasededonnesactiveduserveur.
Syntaxe
requte
Textedelarequteexcuter.
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Si non prcis, utilisation de la dernire connexion ouverte s'il n'y en a pas, tentative d'ouverture d'une
connexionavecunappellafonctionmysql_connectsansparamtre.
Dans le cas d'un ordre SELECT (ou SHOW, EXPLAIN, DESCRIBE), la fonction mysql_query retourne un identifiant
dersultatderequte,encasdesuccs,et FALSEencasd'checpourlesautresordresSQL,cettefonction
retourneTRUEencasdesuccs.mysql_querynegnrepasd'alerteencasd'erreur.
Exemple
<?php
// connexion et slection de la base (erreurs tester ...)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion) ;
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte
$rsultat1 = mysql_query($requte,$connexion);
echo "\$rsultat1 = ",
($rsultat1)? $rsultat1:'FALSE',"<BR>\n";
// dfinition d'une mauvaise requte
$requte = "SELECT * FROM article";
// excution de la requte
$rsultat2 = mysql_query($requte,$connexion);
Rsultat
$rsultat1 = Resource id #3
$rsultat2 = FALSE
Il existe une autre fonction, mysql_db_query, qui agit de manire similaire, en permettant de slectionner la
basechaqueexcution.Cettefonctionestdprcieetnedoitplustreutilise elleestconservepourdes
raisonsdecompatibilitascendante.
Dans le cas d'un ordre SELECT, le rsultat de la requte excute par mysql_query est mis en buffer. Il existe
une autre fonction, mysql_unbuffered_query, qui possde la mme syntaxe que mysql_query, et permet
aussi d'excuter une requte, mais sans placer le rsultat dans un buffer. Pour les requtes volumineuses,
mysql_unbuffered_query consomme beaucoup moins de mmoire que mysql_query et permet d'extraire la
premirelignebienplusrapidement :iln'yapasbesoind'attendrequelatotalitdursultatsoitmiseenbuffer.
Par contre, aprs excution de la requte avec mysql_unbuffered_query, il n'est pas possible de connatre le
nombredelignesdursultat(voir ciaprs),nid'excuteruneautrerequteavantd'avoirextraitlatotalitdes
lignes.
Connatrelenombredelignesdanslersultat
Lafonctionmysql_num_rowspermetdeconnatrelenombredelignesdanslersultat.
Syntaxe
rsultat
Identifiantdersultatderequteretournparlafonctionmysql_query.
Cette fonction est utilisable uniquement pour les requtes SELECT. Si la requte a t excute avec
mysql_unbuffered_query,cettefonctionretournelenombredelignesluescestade(0justeaprsl'excution
delarequte).
Exemple
<?php
// connexion et slection de la base (erreurs tester ...)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion) ;
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte
$rsultat = mysql_query($requte);
// rcupration du nombre de lignes
$nombre = mysql_num_rows($rsultat);
echo "Nombre d'articles : $nombre<BR>\n";
// dfinition de la requte
$requte = "SELECT * FROM articles WHERE prix > 40";
// excution de la requte
$rsultat = mysql_query($requte);
// rcupration du nombre de lignes
$nombre = mysql_num_rows($rsultat);
echo "Nombre d'articles dont le prix est suprieur 40 : $nombre<BR>\n";
?>
Rsultat
Lirelersultatdelarequte
Le rsultat de l'excution (avec succs) d'une requte SELECT peut tre lu par les fonctions
mysql_fetch_array,mysql_fetch_assoc, mysql_fetch_objectou mysql_ fetch_row.
Ces fonctions effectuent le mme traitement : lecture de la ligne courante du rsultat et avancement du
pointeursurlalignesuivante(voirl'introduction).
Cesfonctionsdiffrentsurletypededonnesutilispourretournerlersultat.
Syntaxe
rsultat
Identifiantdersultatderequteretournparlafonctionmysql_query.
type
Typedersultatgalunedesconstantessuivantes :MYSQL_ASSOC,MYSQL_NUM,MYSQL_BOTH.
Pourlafonctionmysql_fetch_assoc,ils'agitd'untableauassociatifdontlaclestlenomdelacolonne.Pourla
fonctionmysql_fetch_row,ils'agitd'untableauindicesentiers,l'indice0correspondantlapremirecolonne,
l'indice1ladeuxime,etc.Enfin,pourlafonctionmysql_fetch_array,letypedutableaudpenddudeuxime
paramtre :
MYSQL_NUM
Tableauindicesentiers(commelafonctionmysql_fetch_row).
MYSQL_ASSOC
Tableauassociatif(commelafonctionmysql_fetch_assoc).
MYSQL_BOTH
(valeur par dfaut)
Lesdeuxlafois.
Chaquecolonneestprsentedeuxfois.
Exemple:
Requte SELECT *
FROM articles
Colonnes identifiant libelle prix
1re ligne du 1 Abricots 35.5
rsultat
La fonction mysql_fetch_object retourne un objet, avec un attribut par colonne, le nom de l'attribut
correspondantaunomdelacolonne.
Exemple:
Attribut Valeur
identifiant 1
libelle Abricots
prix 35.5
En cas d'utilisation d'un alias de colonne dans la requte SELECT (exemple SELECT AVG(prix) prix_moyen
FROM articles),c'estl'aliasdecolonnequiestutiliscommeclounomd'attribut.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// connexion et slection de la base (erreurs tester...)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion) ;
// excution de la requte
$rsultat = mysql_query("SELECT * FROM articles");
// Premier fetch avec mysql_fetch_row
$ligne = mysql_fetch_row($rsultat);
afficher_tableau($ligne,"mysql_fetch_row");
// Deuxime fetch avec mysql_fetch_assoc
$ligne = mysql_fetch_assoc($rsultat);
afficher_tableau($ligne,"mysql_fetch_assoc");
// Troisime fetch avec mysql_fetch_array
// - sans deuxime paramtre = MYSQL_BOTH
$ligne = mysql_fetch_array($rsultat);
afficher_tableau($ligne,"mysql_fetch_array");
// Quatrime fetch avec mysql_fetch_object
$ligne = mysql_fetch_object($rsultat);
echo "<P><B>mysql_fetch_object</B><BR>";
echo "\$ligne->identifiant = $ligne->identifiant<BR>";
echo "\$ligne->libelle = $ligne->libelle<BR>";
echo "\$ligne->prix = $ligne->prix<BR>";
// Cinquime fetch de nouveau avec mysql_fetch_row
// - normalement, plus de ligne
$ligne = mysql_fetch_row($rsultat);
if (! $ligne) {
echo "<B>Cinquime fetch : plus rien</B>";
}
?>
Rsultat
mysql_fetch_row
0 = 1
mysql_fetch_object
$ligne->identifiant = 4
$ligne->libelle = Pches
$ligne->prix = 37.2
Cetexemplepermetd'observer:
- le fait qu' chaque fetch, le pointeur interne avance, et que le fetch suivant retourne donc la ligne suivante, jusqu'
avoir parcouru toutes les lignes.
En cas d'utilisation d'un identifiant de rsultat non valide, les fonctions mysql_fetch_* retournent FALSE et
affichentenplusunealertedutype :
Quellemthodeutiliser ?
Touteslesmthodessevalent,notammentdupointdevuedesperformances.Personnellement,nousavonsune
petite prfrence pour l'utilisation des fonctions mysql_fetch_assoc et mysql_fetch_object qui permettent
d'employerlenomdescolonnesdelarequteetderendrelecodepluslisible.
Exempledecodepourlalectured'uneligne
Un premier type de lecture consiste souvent lire une seule ligne d'information dans une table ou plusieurs
tablesavecjointure(s) :obtentiond'informationssurl'utilisateurquivientdeseconnecter,fichededescription
d'unarticle...
Exemple
<?php
// inclure un fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser les variables
$identifiant = "";
$libell = "";
$prix = "";
$message = "";
// Tester la faon dont le script est appel
if (! empty($_POST)) {
// traitement du formulaire ...
// rappel : lorsqu'un formulaire n'a qu'une zone de texte
// et que l'utilisateur tape return ou enter, le bouton de
// validation n'est pas considr comme cliqu. Pour savoir
// si le formulaire a t soumis, il faut tester si
// $_POST (ou $_GET) est vide ou non.
// rcuprer les valeurs saisies
$identifiant = valeur_saisie($_POST["identifiant"]);
// contrler les valeurs saisies
if ($identifiant == "") {
Exemple
<?php
function db_lire_ligne($requte) {
// la variable $ok est utilise pour savoir
// si tout se passe bien
// se connecter (par dfaut) et slectionner la base
$ok = ( ($connexion = mysql_connect()) != FALSE );
if ($ok) {
$ok = mysql_select_db("diane",$connexion);
}
// excuter la requte et tester le rsultat pour affecter
// la variable $ok
if ($ok) {
$ok = ( ($rsultat = mysql_query($requte)) != FALSE );
}
if ($ok) { // excution OK
// lire la ligne
$ligne = mysql_fetch_assoc($rsultat);
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Ilestpossible(souhaitable)d'amliorerlagestiondeserreurs(cf.Grerleserreurs).
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles WHERE identifiant= 1";
// lire le rsultat
$ligne = db_lire_ligne($requte);
if ($ligne) {
echo "$ligne[libelle] - $ligne[prix]";
}
?>
Abricots - 35.5
Exempledecodepourlalecturedetoutesleslignes
Un deuxime type de lecture consiste souvent afficher une liste d'lments extraits de la base (liste
d'utilisateurs,listed'articles...).
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter et slectionner la base (erreurs traiter)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
// excuter la requte de slection
$requte = "SELECT * FROM articles";
$rsultat = mysql_query($requte);
// fetch si la requte a bien t excute
if ($rsultat) {
// boucle jusqu' avoir un fetch FALSE
while ($article = mysql_fetch_assoc($rsultat)) {
// remplir un tableau avec chaque ligne extraite
// remarque : le tableau est multidimensionnel
Il est possible d'crire le mme exemple de manire plus compacte. Ce dernier sera alors plus conome en
mmoireetplusperformant :lefetchesteffectuaucoursdelaconstructiondelatableHTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter et slectionner la base (erreurs traiter)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
// excuter la requte de slection
// - le rsultat n'est pas mis en buffer
$requte = "SELECT * FROM articles";
$rsultat = mysql_unbuffered_query($requte);
// tester le rsultat
if (! $rsultat) { // requte pas OK
Pourpermettrel'utilisateurd'agirsurlaliste,ilestpossibled'imbriquerunformulaireoudesliensaveclatable
HTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter et slectionner la base (erreurs traiter)
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
Rsultat
Sur le lien, la place du code JavaScript, il est possible de mettre une vraie URL et d'enchaner sur une autre
page (cf. chapitre Grer les sessions pour comprendre comment placer un paramtre dans l'URL et pouvoir ainsi
passeruneinformation,icil'identifiantchoisi,uneautrepage).
Encequiconcerneletraitementduformulaire,toutestenvisageable.
Lencore,pourlalecturedeplusieurslignes,unefonctiongnriquepeuttreutilise.
Exemple
<?php
function db_lire_lignes_dans_tableau($requte) {
// la variable $ok est utilise pour savoir
// si tout se passe bien
// se connecter (par dfaut) et slectionner la base
$ok = ( ($connexion = mysql_connect()) != FALSE );
if ($ok) {
$ok = mysql_select_db("diane",$connexion);
}
// excuter la requte et tester le rsultat pour affecter
// la variable $ok
if ($ok) {
$ok = ( ($rsultat = mysql_query($requte)) != FALSE );
}
$tableau = array();
if ($ok) { // excution OK
// lire les lignes dans un tableau
while ($ligne = mysql_fetch_assoc($rsultat)) {
$tableau[] = $ligne;
}
}
// retourner $tableau ou FALSE en cas d'erreur
return ($ok)?$tableau:FALSE;
}
?>
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles";
// lire le rsultat dans un tableau
$articles = db_lire_lignes_dans_tableau($requte);
// afficher le premier article lu
if ($articles) {
echo count($articles)." articles<BR>";
echo "Premier article : ";
echo $articles[0]["libelle"]," - ",
$articles[0]["prix"];
}
?>
4 articles
Premier article : Abricots 35.5
Cettefonctiongnriquepeut,parexemple,treutilisepourconstruireuneliste<SELECT>>dansunformulaire.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// chargement de la liste des fruits
$requte = "SELECT identifiant,libelle FROM articles
ORDER BY libelle";
$fruits_du_march = db_lire_lignes_dans_tableau($requte);
?>
<!-- construction du formulaire -->
<FORM METHOD="POST">
Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<?php
// code PHP gnrant la partie dynamique du formulaire
// parcourir la liste afficher
foreach($fruits_du_march as $fruit) {
// gnrer la balise OPTION avec l'identifiant
// pour l'option VALUE et le libell pour le texte affich
// dans la liste
echo "<OPTION VALUE=\"$fruit[identifiant]\">
$fruit[libelle]\n";
}
?>
</SELECT>
<INPUT TYPE="submit" NAME="OK" VALUE="OK"><BR>
</FORM>
Rsultat
Mettrejourdesdonnes
MettrejourdesdonnesconsisteexcuterdesrequtesINSERT(cration),UPDATE(modification)ouDELETE
(suppression).
Encomplment,deuxfonctionssontintressantes :mysql_affected_rowsetmysql_insert_id.
Syntaxe
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Sinonprcis,utiliseladernireconnexionouverte.
Siladernirerequteachou,lafonctionmysql_affected_rowsretourne1.
La fonction mysql_affected_rows est cense ne pas fonctionner avec des requtes SELECT ; ce n'est pas vrai !
Dans le cas d'un ordre UPDATE, mysql_affected_rows ne compte pas les lignes non modifies lorsque les valeurs avant
et aprs sont les mmes.
La fonction mysql_insert_id retourne la valeur du dernier identifiant gnr pour une colonne ayant le type
AUTO_INCREMENTparunerequteINSERTdansunesession.
Syntaxe
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Sinonprcis,utiliseladernireconnexionouverte.
Siaucunidentifiantn'atgnrautomatiquement,lafonctionmysql_insert_idretournezro.
La requte INSERT n'a pas besoin d'tre la dernire requte excute dans la session.
Exemples
<?php
// inclusion du fichier qui contient la dfinition des
// fonctions gnrales
include("fonctions.inc");
// dfinition d'une petite fonction d'affichage de la liste
// des articles
function AfficherArticles() {
$requte = "SELECT * FROM articles";
$articles = db_lire_lignes_dans_tableau($requte);
if ($articles) {
echo "<B>Liste des articles :</B><BR>";
foreach($articles as $a) {
echo "$a[identifiant] - $a[libelle] - $a[prix]<BR>";
}
} else {
echo "<B>Plus d'articles.</B><BR>";
}
}
// affichage de contrle
AfficherArticles();
// la connexion a t tablie par la fonction
// db_lire_lignes_dans_tableau appele dans AfficherArticles
// requte INSERT
$requte = "INSERT INTO articles(libelle,prix)
VALUES('Poires',29.9)";
$rsultat = mysql_query("diane",$requte);
Rsultat
Crerdesformulairesquipermettentdemettrejourlesdonnesesttrssimple.
titred'exemple,nousallonsconstruireunformulairequipermetderaliserunesaisieenliste.
Prsentation du formulaire
Le formulaire propose le contenu actuel de la table qui peut tre modifi (saisie directe dans les zones) ou
supprim(parlescasescocher),pluscinqlignesvidesquipermettentdesaisirdenouvellesvaleurs.Danstous
lescas,l'identifiantnepeuttresaisi,c'estleserveurMySQLquival'attribuer.
Chaque ligne du tableau contient quatre zones de formulaire qui sont nommes (option NAME de la balise
<INPUT>)delamaniresuivante :
Colonne Nom
Identifiant saisie[i][modifier]
Libell saisie[i][libelle]
L'indice i est l'identifiant de l'article pour les lignes qui existent, et un numro compris entre 1 et 5 pour les
lignes vides. La zone de la colonne Identifiant est une zone masque (TYPE="hidden") qui va tre employe
pouridentifierleslignesdanslesquellesl'utilisateuraeffectuunemodification.
Avec ce processus de nommage, toute la saisie est rcupre dans le script PHP sous la forme d'un tableau
multidimensionnel nomm $lignes. Chaque ligne du tableau correspond une ligne du formulaire avec la cl
gale l'identifiant (ou 1 5 pour les nouvelles lignes) et la valeur gale un tableau associatif donnant les
lmentssaisis.
Pour identifier les lignes modifies par l'utilisateur, les zones de saisie du libell et du prix des lignes existantes
contiennentlecodeJavaScriptsuivant :
onChange="document.formulaire[$n].value=1"
CecodeJavaScriptapoureffet,chaquefoisquelazoneenquestionestmodifie,deplacerun1danslazone
masque associe la ligne. Le formulaire s'appelant formulaire (<FORM NAME = "formulaire"...),
l'expression document.formulaire[n] dsigne la nime zone du formulaire formulaire du document courant,
la premire zone du formulaire ayant le numro 0. Dans le source, la variable $n est calcule pour chaque ligne
$i du formulaire, par la formule $n = 4 * ($i - 1) : la zone cache de la ligne 1 a le numro 0 (c'est la
premireduformulaire),celledelaligne2lenumro4etainsidesuite.
Cetexemplepeut(doit)treamlior :
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter et slectionner la base
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
// traitement du formulaire
if (isset($_POST["OK"])) {
// rcuprer le tableau contenant la saisie
$lignes = $_POST["saisie"];
foreach($lignes as $identifiant => $ligne) {
// nettoyage de la saisie
$libell = valeur_saisie($ligne["libelle"]);
$prix = valeur_saisie($ligne["prix"]);
$prix = str_replace(",",".",$prix); // , => .
$prix = str_replace(" ","",$prix); // supprimer espaces
// ce niveau, il faudrait vrifier la saisie ...
$requte = "";
if ($identifiant < 0 and $libell.$prix != "") {
// identifiant ngatif et quelque chose de saisi
// = cration = INSERT
$requte = "INSERT INTO articles(libelle,prix)
VALUES('$libell',$prix)";
} elseif (isset($ligne["supprimer"])) {
// case " supprimer " coche = suppression = DELETE
$requte = "DELETE FROM articles
WHERE identifiant = $identifiant";
} elseif (isset($ligne["modifier"])) {
// zone " modifier " TRUE (1) = modification = UPDATE
$requte = "UPDATE articles
SET libelle = '$libell', prix = $prix
WHERE identifiant = $identifiant";
}
Grerleserreurs
Les fonctions mysql_errno etmysql_error permettent de rcuprer des informations sur l'erreur ventuelle de
ladernireoprationeffectuedansunesession.
Syntaxe
connexion
Identifiantdeconnexionretournparlafonctionmysql_connect.
Sinonprcis,utiliseladernireconnexionouverte.
Lafonctionmysql_errnoretourneunnumrod'erreuretlafonctionmysql_error,lemessageassoci.
Exemple
<?php
// se connecter un mauvais serveur
$connexion = mysql_connect('hermes');
echo "1 : ".mysql_errno()." - ".mysql_error()."<BR>";
// se connecter correctement (par dfaut)
$connexion = mysql_connect();
echo "2 : ".mysql_errno()." - ".mysql_error()."<BR>";
// slectionner une mauvaise base
$ok = mysql_select_db("hermes",$connexion);
echo "3 : ".mysql_errno()." - ".mysql_error()."<BR>";
// slectionner la bonne base
$ok = mysql_select_db("diane",$connexion);
echo "4 : ".mysql_errno()." - ".mysql_error()."<BR>";
// une bonne requte pour commencer
$requte = "SELECT * FROM articles";
$rsultat = mysql_query($requte);
echo "5 : ".mysql_errno()." - ".mysql_error()."<BR>";
// requte sur une table qui n'existe pas
$requte = "SELECT * FROM article";
$rsultat = mysql_query($requte);
echo "6 : ".mysql_errno()." - ".mysql_error()."<BR>";
// requte INSERT qui viole une cl primaire
$requte = "INSERT INTO articles(identifiant,libelle,prix)
VALUES(1,'Poires',29.9)";
$rsultat = mysql_query($requte);
echo "7 : ".mysql_errno()." - ".mysql_error()."<BR>";
// tentative de fetch sur un mauvais rsultat
$requte = "SELECT * FROM article";
$rsultat = mysql_query($requte);
echo "8 : ".mysql_errno()." - ".mysql_error()."<BR>";
$ligne = mysql_fetch_assoc($rsultat);
echo "9 : ".mysql_errno()." - ".mysql_error()."<BR>";
?>
Rsultat
Lepoint1illustrelefaitqu'encasd'erreurlorsdelaconnexion,unealerteestafficheencomplment.
Enpratique,lesfonctionsmysql_errnoetmysql_errornesontd'aucuneutilitsurlesfetch.
Par ailleurs, nous verrons au chapitre Grer les erreurs dans un script PHP comment supprimer l'affichage des
alertes.
Cesfonctionspeuventtremisesenuvretitred'exemplesurunedenosfonctionsgnriques.
Exemple
<?php
function db_lire_ligne($requte, &$erreur) {
// dans cette nouvelle version, db_lire_ligne prend un
// deuxime paramtre par rfrence dans lequel un numro et un message
// seront stocks en cas d'erreur (sous la forme d'un tableau)
// initialiser $erreur
$erreur = array(0,""); // numro = 0 message vide
// tablir la connexion
$ok = ($connexion = mysql_connect());
if ($ok) { // c'est bon
// slectionner la base de donnes
$ok = mysql_select_db("diane",$connexion);
}
if ($ok) { // c'est tojours bon
// excuter la requte et tester le rsultat pour
// affecter la variable $ok
$ok = ( ($rsultat = mysql_query($requte)) != FALSE );
}
if ($ok) { // tout est OK
// lire la ligne
$ligne = mysql_fetch_assoc($rsultat);
} else { // problme quelque part
// rcuprer les informations sur l'erreur
$erreur = array(mysql_errno(),mysql_error());
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// premier appel avec une erreur
$requte = "SELECT * FROM article WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
// deuxime appel correct
$requte = "SELECT * FROM articles WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
?>
Rsultat
Introduction
L'extensionMySQLipeuttreutilisesoitsousuneformeprocdurale(commel'extensionMySQL),soitsousune
formeobjet.
En cas d'utilisation sous une forme procdurale, l'extension MySQLi est trs proche de l'extension MySQL (mis
part les nouvelles fonctionnalits de la version 4.1 de MySQL, supportes par l'extension MySQLi mais pas par
l'extension MySQL). Trs souvent, les deux extensions proposent les mmes fonctions, avec des syntaxes
identiques ou compatibles. Sauf exception, pour passer de l'extension MySQL l'extension MySQLi, il suffit de
remplacerleprfixemysql_danslenomdelafonctionparleprfixemysqli_.
Parcontre,l'utilisationdel'extensionMySQLisousuneformeobjetestsensiblementdiffrentedel'utilisationde
l'extensionMySQL.Danssaformeorienteobjet,l'extensionMySQLipropose3classes :
mysqli
connexionentrePHPetMySQL.
mysqli_stmt
requteprpare.
mysqli_result
rsultatdel'excutiond'unerequte.
Cesdiffrentesclassesoffrentdesmthodesquipermettentd'effectuerlesdiffrentesactions(excutiond'une
requte,rcuprationdursultat,etc.).
Correspondanceavecl'extensionMySQL
Toutes les fonctions prsentes prcdemment dans l'extension MySQL, l'exception de la fonction
mysql_pconnect, ont un quivalent direct dans l'extension MySQLi il suffit de remplacer le prfixe mysql_ par
mysqli_ :
Remarques
Les premiers paramtres de mysql_connect et mysqli_connect sont identiques (serveur, utilisateur, mot de
MySQLi ne permet pas d'utiliser de connexion par dfaut dans les appels de fonctions. En consquence, un
identifiant de connexion valide doit tre pass en paramtre mysql_close, mysql_affected_rows,
mysql_insert_id,mysql_errnoetmysql_error.
Les fonctions mysqli_connect et mysqli_query> ne retournent plus des ressources mais des objets. Dans la
pratique, cela n'a aucune incidence car le rsultat de ces fonctions est simplement pass en paramtre
d'autresfonctions.
Endehorsdesfonctionsmysqli_errno et mysqli_error,MySQLioffrelesfonctionsmysqli_connect_error et
mysqli_connect_errnoquipermettentdercuprerdesinformationssuruneventuelleerreurdeconnexion.
MySQLineproposepasdefonctionsmysqli_unbuffered_query.Parcontre,lafonction mysqli_querypossde
un troisime paramtre qui permet d'indiquer si le rsultat doit tre mis en buffer (constante
MYSQLI_STORE_RESULT, valeur par dfaut) ou non (constante MYSQLI_USE_RESULT). Pour les requtes
volumineuses,l'utilisationdeMY-SQLI_USE_RESULTconsommebeaucoupmoinsdemmoireetpermetd'extrairela
premirelignebienplusrapidement :iln'yapasbesoind'attendrequelatotalitdursultatsoitmisenbuffer.
Par contre, aprs excution de la requte avec MY-SQLI_USE_RESULT, il n'est pas possible de connatre le
nombredelignesdursultat,nid'excuteruneautrerequteavantd'avoirextraitlatotalitdeslignesoulibr
lersultat(fonctionmysqli_free_result).
Exemple
<?php
// dfinir quelques variables
$serveur = "diane";
$utilisateur = "root";
$mot_de_passe = "";
$base="diane";
// connexion = mysqli_connect
// - pas de slection de la base dans cet appel
$connexion = mysqli_connect($serveur,$utilisateur,$mot_de_passe);
// vrifier le succs de la connexion
// - mysqli_connect_errno = numro de l'erreur de connexion
// - mysqli_connect_error = message de l'erreur de connexion
if (mysqli_connect_errno() != 0) {
echo sprintf(
"Erreur mysqli_connect : %d - %s<BR>",
mysqli_connect_errno(),
mysqli_connect_error());
exit;
}
// slectionner la base = mysqli_select_db
// - diffrences par rapport mysql_select_db
// > syntaxe inverse
// > identifiant de connexion obligatoire
// - inutile si base slectionne dans mysqli_connect
$ok = mysqli_select_db($connexion,$base);
if (! $ok) {
// rcuprer une erreur MySQLi = mysqli_errno & mysqli_error
// - diffrences par rapport mysql_errno & mysql_error
// > identifiant de connexion obligatoire
echo sprintf(
"Erreur mysqli_select_db : %d - %s<BR>\n",
mysqli_errno($connexion),
mysqli_error($connexion));
exit;
}
// excuter une requte = mysqli_query
// - diffrences par rapport mysql_query
// > syntaxe inverse
Rsultat
Nombre d'articles : 4
Premier article : Abricots - 35.5
Identifiant du nouvel article = 5
Nombre d'articles modifis = 5
Requtesprpares
LaprincipalenouveautdeMySQL4.1,utilisableavecl'extensionMySQLi,estlanotionderequteprpare.
Une requte paramtre est une requte qui contient des paramtres matrialiss par un point d'interrogation
Exemples
Un paramtre ne peut pas remplacer un nom de table, un nom de colonne ou toute une partie de la requte.
Exemples interdits
SELECT * FROM ?
SELECT * FROM articles WHERE ?
Lestapesd'utilisationd'unerequteparamtresontlessuivantes :
- associer des variables PHP aux paramtres de la requte (notion de "bind") = mysqli_stmt_bind_param ;
Danslecasd'unerequteSELECT,ilyadeuxtapessupplmentaires :
chaque excution de la requte prpare, la valeur courante des variables PHP associes aux paramtres est
utilise. L'intrt est de pouvoir employer plusieurs fois la mme requte avec des valeurs diffrentes des
paramtressansanalyserdenouveaularequte,cequipermetd'amliorerlesperformances.
Plusieursautresfonctionspeuventtreutilisesaveclesrequtesprpares :
mysqli_stmt_init
Creunerequteprpare.
mysqli_stmt_close
Fermeunerequteprpare.
mysqli_stmt_affected_rows
Retournelenombredelignesmisesjourparunerequteprpare.
mysqli_stmt_store_result
Metenbufferlersultatd'unerequteprpare.
mysqli_stmt_num_rows
Retournelenombredelignesslectionnesparunerequteprpare.
mysqli_stmt_free_result
Librelersultatd'unerequteprpare.
mysqli_stmt_errno
mysqli_stmt_error
Retournelemessaged'erreurd'unerequteprpare.
<?php
// dfinir quelques variables
$serveur="diane";
$utilisateur="root";
$mot_de_passe="";
$base="diane";
// connexion (avec slection de la base)
$connexion = mysqli_connect($serveur,$utilisateur,
$mot_de_passe,$base);
// dfinir la requte excuter
// - requte d'insertion avec deux paramtres
$requte = "INSERT INTO articles(libelle,prix) VALUES(?,?)";
// crer une requte prpare = mysqli_stmt_init
// - retourne un objet requte utiliser dans la suite
$stmt = mysqli_stmt_init($connexion);
// prparer la requte = mysqli_stmt_prepare
// - retourne simplement TRUE (succs) ou FALSE (erreur)
$ok = mysqli_stmt_prepare($stmt,$requte);
// associer des variables aux paramtres = mysqli_stmt_bind_param
// - le deuxime argument contient un ou plusieurs caractres
// indiquant le type des paramtres :
// i = entier, d = dcimal, s = chane
// - les arguments suivants sont les variables associer
// aux paramtres
// - l'association est positionnelle
// - retourne simplement TRUE (succs) ou FALSE (erreur)
// - sur notre exemple :
// > premier paramtre = chane = $libell
// > deuxime paramtre = dcimal = $prix
$ok = mysqli_stmt_bind_param($stmt,"sd",$libell,$prix);
// donner des valeurs aux variables
$libell = 'Bananes';
$prix = 15.35;
// excuter la requte prpare = mysqli_stmt_execute
// - retourne simplement TRUE (succs) ou FALSE (erreur)
$ok = mysqli_stmt_execute($stmt);
// rcuprer des informations sur l'excution d'une
// requte prpare
// - mysqli_stmt_affected_rows = nombre de lignes mises jour
// - mysqli_stmt_errno = numro d'erreur
// - mysqli_stmt_error = message d'erreur
// par contre, pas de mysqli_stmt_insert_id
// => utiliser mysqli_insert_id
echo sprintf(
"%s article insr - Identifiant = %s - Erreur = %s<BR>\n",
mysqli_stmt_affected_rows($stmt),
mysqli_insert_id($connexion),
mysqli_stmt_errno($stmt));
// il est alors possible de donner d'autre valeurs aux variables
// et d'xecuter de nouveau la requte
$libell = 'Pommes';
$prix = 24.5;
$ok = mysqli_stmt_execute($stmt);
echo sprintf(
"%s article insr - Identifiant = %s - Erreur = %s<BR>\n",
mysqli_stmt_affected_rows($stmt),
mysqli_insert_id($connexion),
mysqli_stmt_errno($stmt));
// il est aussi possible d'associer d'autres variables aux
// paramtres et d'xecuter de nouveau la requte
$ok = mysqli_stmt_bind_param($stmt,"sd",$libell_bis,$prix_bis);
$libell_bis = 'Oranges';
$prix_bis = 30;
$ok = mysqli_stmt_execute($stmt);
echo sprintf(
"%s article insr - Identifiant = %s - Erreur = %s<BR>\n",
mysqli_stmt_affected_rows($stmt),
mysqli_insert_id($connexion),
mysqli_stmt_errno($stmt));
Rsultat
Exemple de lecture
<?php
// dfinir quelques variables
$serveur="diane";
$utilisateur="root";
$mot_de_passe="";
$base="diane";
// connexion (avec slection de la base)
$connexion = mysqli_connect($serveur,$utilisateur,
$mot_de_passe,$base);
// dfinir la requte excuter
// - requte de slection avec un paramtre
$requte = "SELECT identifiant,libelle
FROM articles WHERE libelle LIKE ?";
// crer une requte prpare = mysqli_stmt_init
$stmt = mysqli_stmt_init($connexion);
// prparer la requte = mysqli_stmt_prepare
$ok = mysqli_stmt_prepare($stmt,$requte);
// associer des variables PHP aux paramtres =
// mysqli_stmt_bind_param
$ok = mysqli_stmt_bind_param($stmt,"s",$recherche);
// donner des valeurs aux variables
$recherche = 'P%';
// excuter la requte prpare = mysqli_stmt_execute
$ok = mysqli_stmt_execute($stmt);
// associer des variables aux colonnes du rsultat =
// mysqli_stmt_bind_result
// - une variable par colonne
mysqli_stmt_bind_result($stmt,$identifiant,$libell);
// extraire les lignes du rsultat = mysqli_stmt_fetch
// - retourne TRUE (succs), FALSE (erreur) ou NULL (plus de ligne)
// - les donnes de la ligne extraite sont charges dans les
// variables associes aux colonnes du rsultat
echo "<B> Premier appel = LIKE '$recherche'</B><BR>\n";
while (mysqli_stmt_fetch($stmt)) {
echo "$identifiant - $libell<BR>\n";
}
// librer le rsultat = mysqli_stmt_free_result
mysqli_stmt_free_result($stmt);
// excuter de nouveau la requte prpare avec une nouvelle valeur
$recherche = '%an%';
$ok = mysqli_stmt_execute($stmt);
// mettre le resultat en buffer = mysqli_stmt_store_result
$ok = mysqli_stmt_store_result($stmt);
// afficher le nombre de lignes slectionnes =
// mysqli_stmt_num_rows
// - impossible dans le premier cas car le rsultat n'avait pas
// t mis en buffer
echo "<B> Deuxime appel = LIKE '$recherche'</B><BR>\n";
echo sprintf("Nombre d'articles : %s<BR>\n",
mysqli_stmt_num_rows($stmt));
// extraire les lignes du rsultat = mysqli_stmt_fetch
// - utilise les variables lies prcdemment
while (mysqli_stmt_fetch($stmt)) {
echo "$identifiant - $libell<BR>\n";
}
// librer le rsultat = mysqli_stmt_free_result
mysqli_stmt_free_result($stmt);
// fermer une requte prpare = mysqli_stmt_close
$ok = mysqli_stmt_close($stmt);
// dconnexion = mysqli_close
mysqli_close($connexion);
?>
Prambule
PHP dispose de deux bibliothques pour accder Oracle : la bibliothque "Oracle" (prfixe des fonctions =
ora_)et"Oracle8"(prfixedesfonctions=oci).
La bibliothque "Oracle 8" est plus complte et plus puissante que la bibliothque "Oracle" elle permet
notammentd'utiliserlestypesLOBetROWIDetd'tablirdesliaisonsentredesvariablesPHPetdesvariablesdans
larequteSQL(processusde"bind variable").
Hormiscesdiffrences,l'utilisationdesdeuxbibliothquesestsimilaireetparatrafamilireauxpersonnesquiont
dj utilis les OCI Oracle, les prcompilateurs du type Pro*C ou des API (Application Programming Interface)
commeOLEDB(ObjectLinkingandEmbeddingDataBase)ouJDBC(JavaDataBaseConnectivity).
Danscetouvrage,nousavonschoisideprsenterlabibliothque"Oracle8".Contrairementcequelenomdela
bibliothque laisse penser, cette bibliothque peut tre utilise pour accder n'importe quelle version d'Oracle
(7,8,9).
En version 5, beaucoup de fonctions de cette bibliothque ont t renommes ; au prfixe prs, les fonctions portent
maintenant des noms identiques aux fonctions similaires des autres bases de donnes. Les anciens noms peuvent toujours
tre utiliss pour des raisons de compatibilit ascendante, mais sont dprcis. Cet ouvrage prsente les fonctions avec leur
nom de la version 5 mais rappelle l'ancien nom.
EnvironnementNLS
L'environnement NLS (National Language Support), utilis lors de l'excution des requtes, est dfini par les
variablesd'environnementhabituellespositionnessurleserveurquiexcutePHP :
- NLS_LANG
- NLS_DATE_FORMAT...
Sicesvariablesd'environnementnesontpaspositionnes,lesparamtrespardfautduserveurOraclesontpris
encompte.
Cette situation peut conduire des diffrences de fonctionnement d'un mme programme entre deux
environnements.Parexemple,sivousrcuprezdansunerequteunecolonnedetypeDATE,uneconversionen
chane est automatiquement effectue (car PHP ne supporte pas le type DATE en tant que tel) selon le
paramtreNLS_DATE_FORMATactif selonlaconfigurationetl'environnement,lachanercuprepeutavoirdes
formatsdiffrents(DD/MM/YYYY,DDMONYY...).
Desproblmesanaloguesseproduisentaveclesdonnesnumriquesquisont,ellesaussi,convertiesenchane
avecunsparateurdcimaletunsparateurdegroupequipeutvarierselonl'environnement.
Sil'environnementn'estpasmatris,ilestpossibled'agirauniveauducodePHPpourobteniruncodeportable
d'unenvironnementl'autre :
- soit en effectuant systmatiquement des conversions explicites dans les ordres SQL (TO_CHAR
(SYSDATE,'DD/MM/YYYY'), TO_DATE('31/08/2001','DD/MM/YYYY'), TO_CHAR(prix,'9999.99'),
TO_NUMBER('123.45','999.99') par exemple) ;
- soit en excutant, aprs chaque ouverture de session, des requtes ALTER SESSION (ALTER SESSION SET
NLS_DATE_FORMAT = 'DD/MM/YYYY' et/ou ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ', ' par
exemple).
Connexionetdconnexion
Lafonctionoci_connect(anciennementociLogon)permetd'ouvriruneconnexionavecunebaseOracle.
Avec
utilisateur
Nomdel'utilisateuremployerpourtablirlaconnexion.
mot_de_passe
Motdepasseutiliserpourtablirlaconnexion.
nom_de_service
Nom d'un service rseau valide, dfini dans le fichier tnsnames.ora, sur lequel tablir la connexion. Si non
spcifi, la fonction oci_connect utilise la variable d'environnement ORACLE_SID pour la connexion une
instancelocale,oulavariableTWO_TASK(linux)ouLOCAL(Windows),pourlaconnexionuneinstancedistante.
La fonction oci_connect retourne un identifiant de connexion en cas de succs ou, en cas d'erreur, la valeur
FALSE accompagne d'un message d'alerte envoy l'affichage (cf. chapitre Grer les erreurs dans un script
PHP).
Appeler deux fois la fonction oci_connect avec les mmes paramtres, dans le mme script, retourne deux
identifiants de connexion diffrents mais c'est en fait la mme connexion qui est partage. Ce point est
importantcarlesordresmissurlapremireconnexionetceuxmissurladeuximesontenfaitexcutsdans
lammetransaction :unCOMMITouROLLBACKsurl'unedesdeuxconnexionsagirasurlesdeux.
En cas de besoin, la fonction oci_new_connect anciennement ocinlogon peut tre utilise pour ouvrir deux
connexions indpendantes dans le mme script avec les mmes paramtres. La syntaxe de la fonction
oci_new_connectestlammequecelledelafonctionoci_connect.
Exemple
<?php
// connexion un nom de service rseau
$id1 = oci_connect("demeter","demeter","diane");
echo "\$id1 = $id1<BR>\n";
// connexion la variable d'environnement ORACLE_SID
$id2 = oci_connect("demeter","demeter");
echo "\$id2 = $id2<BR>\n";
// exemple d'chec (mauvais mot de passe)
$id3 = oci_connect("demeter","zeus","diane");
echo "\$id3 = $id3<BR>\n";
// nouvelle connexion avec les mmes paramtres que 1
$id4 = oci_connect("demeter","demeter","diane");
echo "\$id4 = $id4 (<B><> \$id1 mais c'est
trompeur</B>)<BR>\n";
// nouvelle connexion avec les mmes paramtres que 1
$id5 = oci_new_connect ("demeter","demeter","diane");
echo "\$id5 = $id5 (<B><> \$id1 et c'est rel</B>)<BR>\n";
?>
Rsultat
$id1 = Resource id #3
$id2 = Resource id #5
Warning: oci_connect() [function.oci-connect]:
OCISessionBegin: ORA-01017: nom d'utilisateur/mot de passe non valide;
connexion refuse in d:\scripts php\index.php on line 9
$id3 =
$id4 = Resource id #6 (<> $id1 mais c'est trompeur)
$id5 = Resource id #8 (<> $id1 et c'est rel)
Les connexions ouvertes dans un script sont automatiquement fermes la fin du script, sauf dconnexion
La fonction oci_pconnect (anciennement ocipLogon) permet d'obtenir une action diffrente et d'tablir une
connexiondite"permanente"quineserapasfermelafinduscriptetpourratrerutilisedanscescriptou
dansunautreultrieurement.
Lasyntaxeestidentiquelasyntaxedelafonctionoci_connect.
Lors de l'appel la fonction oci_pconnect dans un script, PHP regarde si une connexion permanente a dj t
ouverte avec les mmes paramtres (utilisateur, mot de passe et nom de service) : si oui, l'identifiant de cette
connexionestretourn sinon,unenouvelleconnexionesttablie(etcetteconnexionneserapasfermela
finduscript,autorisantainsisarutilisationultrieure).
Lafonctionoci_close(anciennementocilogoff)permetdefermeruneconnexionencoursdescript.
Syntaxe
Avec
connexion
Identifiantdeconnexionretournparlesfonctionsoci_connectouoci_new_connect.
En thorie (voir l'exemple ciaprs), la fonction oci_close retourne TRUE en cas de succs et FALSE en cas
d'erreur(accompagnd'unealerte).
Lafonctionoci_closeestsanseffetsuruneconnexionpermanente.
Toutes les connexions non permanentes sont automatiquement fermes la fin du script.
Exemple
<?php
// connexion
$id1 = oci_connect("demeter","demeter","diane");
echo "\$id1 = $id1<BR>\n";
// dconnexion
$ok = oci_close($id1);
echo "\$ok = ",var_dump($ok),"<B>(!)</B><BR>\n";
// tentative de dconnexion d'une connexion dj close
$ok = oci_close($id1);
echo "\$ok = ",var_dump($ok),"<B>(!)</B><BR>\n";
?>
Rsultat
$id1 = Resource id #3
$ok = NULL (!)
$ok = NULL (!)
Depuis la version 4 de PHP, la fonction oci_close qui est cense faire quelque chose ne fait rien et retourne
systmatiquement NULL ! Le source de la bibliothque semble indiquer que ce comportement est volontaire.
Liredesdonnes
Liredesdonnesdansunebasencessitetroisoprations :
- envoyer une requte (en l'occurrence un ordre SELECT) au serveur pour analyse (tape de "parse") ;
- excuter la requte ;
Lafonctionoci_parse(anciennementociparse)permetd'envoyerunerequtepouranalyseauserveur.
Syntaxe
Avec
connexion
Identifiantdeconnexionretournparlafonctionoci_connect(ouoci_new_connectouoci_pconnect).
requte
Textedelarequteanalyser.
La fonction oci_parse retourne un identifiant de curseur dans tous les cas (succs ou chec) le fait qu'un
curseur soit invalide, pour cause de requte incorrecte, n'est dtect qu'au moment de l'excution (voir ci
aprs).
Exemple
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// dfinition de la requte
$requte = "SELECT * FROM articles";
// analyse de la requte
$curseur1 = oci_parse($connexion,$requte);
echo "\$curseur1 = $curseur1<BR>\n";
// dfinition d'une mauvaise requte (table inexistante)
$requte = "SELECT * FROM article";
// analyse de la requte
$curseur2 = oci_parse($connexion,$requte);
echo "\$curseur2 = $curseur2<BR>\n";
?>
Rsultat
$curseur1 = Resource id #4
$curseur2 = Resource id #5
Excuterunerequte
La fonction oci_execute (anciennement ociexecute) permet d'excuter une requte prcdemment envoye
pouranalyseauserveur.
Syntaxe
curseur
Identifiantducurseurexcuter.
mode
Indique si un COMMIT automatique doit tre excut ou pas (sans objet pour une requte SELECT (cf. Mettre
jourdesdonnes)).
Lafonctionoci_executeretourneTRUEencasdesuccsetFALSEencasd'chec(accompagnd'unealerte).
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// dfinition de la requte
$requte = "SELECT * FROM articles";
// analyse de la requte
$curseur1 = oci_parse($connexion,$requte);
echo "\$curseur1 = $curseur1<BR>\n";
// excution de la requte
$ok1 = oci_execute($curseur1);
echo "\$ok1 = ".(($ok1)?"TRUE":"FALSE")."<BR>\n";
// dfinition d'une mauvaise requte
$requte = "SELECT * FROM article";
// analyse de la requte
$curseur2 = oci_parse($connexion,$requte);
echo "\$curseur2 = $curseur2<BR>\n";
// excution de la requte
$ok2 = oci_execute($curseur2);
echo "\$ok2 = ".(($ok2)?"TRUE":"FALSE")."<BR>\n";
?>
Rsultat
$curseur1 = Resource id #4
$ok1 = TRUE
$curseur2 = Resource id #5
Warning: oci_execute() [function.oci-execute]:
OCIStmtExecute: ORA-00942: Table ou vue inexistante in
d:\scripts php\index.php on line 18
$ok2 = FALSE
Nousallonsvoirdanslepointsuivantcommentrcuprer,danslescript,uncodeouunmessaged'erreur.
Commeindiquenintroduction,lafonctionoci_executeexcutelarequte,indiquesilarequtes'estexcute
correctementmaisnerenvoieaucunedonne.Ilvafalloirextraireleslignesdursultat.
La bibliothque "Oracle" (fonctions ora_*) possde une instruction, ora_do, qui regroupe l'analyse, l'excution et la lecture
de la premire ligne ; la bibliothque "Oracle 8" ne possde pas de fonction similaire.
Connatrelenombredelignesdanslersultat
ladiffrencedeMySQL,iln'yaaucunmoyen,avantlecture,deconnatrelenombredelignesdanslersultat.
Syntaxe
curseur
Identifiantducurseurdanslequellarequteatexcute.
Sil'excutiondelarequteachou,lafonctionoci_num_rowsretournezro.
Lirelersultatdelarequte
Le rsultat de l'excution (russie) d'une requte SELECT peut tre lu par les fonctions oci_fetch_array,
oci_fetch_assoc,oci_fetch_object,oci_fetch_rowetoci_fetch_all.
Syntaxe
Avec
curseur
Identifiantducurseurprcdemmentexcut.
type
Typedersultatdfiniparunecombinaisondesconstantessuivantes :
OCI_BOTH(valeurpardfaut)
OCI_ASSOC
OCI_NUM
OCI_RETURN_NULLS
S'iln'yaplusdeligneliredanslersultat,cesfonctionsretournentFALSE.
Pour la fonction oci_fetch_assoc, il s'agit d'un tableau associatif dont la cl est le nom de la colonne (en
majuscules).Pourlafonction oci_fetch_row,ils'agitd'untableauindicesentiers,l'indice0correspondantla
premire colonne, l'indice 1 la deuxime, etc. Enfin pour la fonction oci_fetch_array, le type du tableau
dpenddudeuximeparamtre :
OCI_NUM
Tableauindicesentiers(commelafonctionoci_fetch_row).
OCI_ASSOC
Tableauassociatif(commelafonctionoci_fetch_assoc).
OCI_BOTH
(valeur par dfaut)
Lesdeuxlafois.
Chaquecolonneestprsentedeuxfois.
quivalentOCI_NUM+OCI_ASSOC.
Les fonctions oci_fetch_object, oci_fetch_assoc et oci_fetch_row ne font pas figurer les colonnes ayant
une valeur NULL (mais les indices sont prservs dans le cas de la fonction oci_fetch_row). Par dfaut, le
comportementestidentiquepourlafonctionoci_fetch_array.
Desrsultatssimilairessontobtenusavecoci_fetch_assoc,oci_fetch_rowetoci_fetch_object.
Il n'y a aucun moyen de conserver les colonnes ayant une valeur NULL lors de l'utilisation des autres fonctions
oci_fetch_*.
Les constantes peuvent tre additionnes pour prciser plusieurs comportements. Par exemple,
OCI_ASSOC+OCI_RETURN_NULLSpermetd'obteniruntableauassociatifavecconservationdesvaleursNULL.
Exemple:
En cas d'utilisation d'un alias de colonne dans la requte SELECT (exemple SELECT AVG(prix) prix_moyen
FROM articles), c'est l'alias de colonne (en majuscules, sauf s'il est spcifi entre guillemets, auquel cas la
casseestrespecte)quiestutiliscommeclounomd'attribut.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
oci_fetch_row
0 = 1
1 = Abricots
2 = 35,5
1 ligne lue ce stade
oci_fetch_assoc
IDENTIFIANT = 2
LIBELLE = Cerises
PRIX = 48,9
2 lignes lue ce stade
oci_fetch_array
0 = 3
IDENTIFIANT = 3
1 = Fraises
LIBELLE = Fraises
2 = 29,95
PRIX = 29,95
3 lignes lue ce stade
oci_fetch_object
$ligne->IDENTIFIANT = 4
$ligne->LIBELLE = Pches
$ligne->PRIX = 37,2
4 lignes lue ce stade
Cinquime fetch : plus rien
4 lignes lue ce stade
Cetexemplepermetdevoir:
- Le fait qu' chaque fetch, le pointeur interne avance, et que le fetch suivant retourne donc la ligne suivante,
jusqu' avoir parcouru toutes les lignes.
LesfonctionsretournentFALSEetaffichentunealertedanslescassuivants :
La fonction oci_fetch_all (anciennement ocifetchstatement) lit toutes les lignes du rsultat dans un
tableau.
Syntaxe
Avec
curseur
Identifiantducurseurprcdemmentexcut.
rsultat
Variablequicontiendralersultatenretour.
Lecontenuinitialdelavariableestcras.
ignorer
Nombredelignesdudbutdursultatnepasramener.0pardfaut :lersultatdbutelapremireligne.
nombre
Nombre de lignes retourner, partir de la premire ligne retourne. 1 par dfaut : toutes les lignes sont
retournes.
type
Typedersultatdfiniparunecombinaisondesconstantessuivantes :
OCI_FETCHSTATEMENT_BY_ROW
OCI_FETCHSTATEMENT_BY_COLUMN(valeurpardfaut)
OCI_ASSOC(valeurpardfaut)
OCI_NUM
La fonctionoci_fetch_allretournelenombredelignesdursultatouFALSEsilersultatneprsenteaucune
ligne(ouencasd'erreur).
Letableauretourndansrsultatparlafonctionoci_fetch_allestuntableaumultidimensionnel.Pardfaut,
letableauprincipalestuntableauassociatifcontenantunelignepourchaquecolonnedelarequte :laclest
galeaunomdelacolonne, enmajuscules,etlavaleurestuntableauindicesentiersquicontientlesvaleurs
delacolonnepourl'ensembledeslignesdursultat(indice0pourla1re ligne,1pourla2e ,etc.).
La structure du tableau peut tre modifie en spcifiant une ou plusieurs des constantes suivantes pour le
paramtretype :
OCI_FETCHSTATEMENT_BY_ROW
Le tableau principal contient une ligne pour chaque ligne de la requte ce tableau est forcment indices
entiers.Letableausecondairecontientunelignepourchaquecolonnedelarequte.
OCI_FETCHSTATEMENT_BY_COLUMN
(valeur par dfaut)
Le tableau principal contient une ligne pour chaque colonne de la requte. Le tableau secondaire contient une
lignepourchaquelignedelarequte cetableauestforcmentindicesentiers.
OCI_ASSOC
(valeur par dfaut)
Letableaudescolonnesestuntableauassociatif.
OCI_NUM
Letableaudescolonnesestuntableauindicesentiers.
ladiffrencedesautresfonctionsoci_fetch_*,lafonctionoci_fetch_allretournelesvaleursNULL.
En cas d'utilisation, d'un alias de colonne dans la requte SELECT (exemple SELECT AVG(prix) prix_moyen
FROM articles),c'estl'aliasdecolonne(enmajuscules,saufs'ilestspcifientreguillemets,auquelcaslacasse
estrespecte)quiestutiliscommecl.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// dfinition de la requte
$requte = "SELECT * FROM articles";
// analyse de la requte
$curseur = oci_parse($connexion,$requte);
// excution de la requte
$ok = oci_execute($curseur);
// fetch de toutes les lignes
// - paramtres par dfaut
$nombre = oci_fetch_all($curseur,$rsultat);
afficher_tableau($rsultat,
'oci_fetch_all($curseur,$rsultat)');
echo ($nombre)?"$nombre lignes dans le rsultat":"FALSE";
// autre dtermination du nombre de lignes lues
$nombre = oci_num_rows($curseur);
echo "<BR>$nombre lignes dans le rsultat";
// excution de la requte
$ok = oci_execute($curseur);
Rsultat (en supposant que les prix ont t remis dans la table)
oci_fetch_all($curseur,$rsultat)
IDENTIFIANT =
0 = 1
1 = 2
2 = 3
3 = 4
LIBELLE =
0 = Abricots
1 = Cerises
2 = Fraises
3 = Pches
Les deux derniers exemples montrent ce qui se passe lorsque la requte ne retourne aucune ligne. Lors d'une
prsentation par colonnes (par dfaut), le tableau est initialis avec la liste des colonnes. Lors d'une
prsentationparlignes,letableauestvide.
Lafonctionoci_fetch_allretourneFALSEetafficheunealertedanslescassuivants :
Quellemthodeutiliser ?
Pour lire une seule ligne, les fonctions oci_fetch_array, oci_fetch_assoc, oci_fetch_object et
oci_fetch_row peuvent tre utilises indiffremment. C'est avant tout une affaire de got personnel il n'y a
aucune diffrence de performance entre les diffrentes fonctions. Personnellement, nous avons une petite
prfrencepourl'utilisationdutableauassociatifavecconservationdesvaleursNULL.
Pour lire toutes les lignes, vous pouvez utiliser la fonction oci_fetch_all si vous souhaitez passer par un
tableauetquelastructuredutableauvousconvienne.Sivousnesouhaitezpaspasserparuntableauouquela
structuredutableaunevousconviennepas,vouspouvezutiliserunedesautresfonctions oci_fetch_*etune
boucle.
Utiliserdesrequtesparamtres
Avec Oracle, il est possible d'employer des requtes paramtres, de les envoyer pour analyse au serveur puis
d'associer un paramtre de la requte une variable PHP (notion de "bind"). chaque excution, la valeur
courantedelavariablePHPestutilise.
L'intrt est de pouvoir rutiliser plusieurs fois la mme requte, avec des valeurs diffrentes de paramtres,
sansanalyserdenouveaularequte.Parailleurs,l'utilisationdevariables"bind"amliorelepartagedesrequtes
danslammoireOracle(dansla"sharedpool").
Auniveaudelarequte,unparamtreestunidentifiantprcdducaractredeuxpoints (:).
Exemple
Un paramtre ne peut pas remplacer un nom de table, un nom de colonne ou toute une partie de la requte.
Exemples interdits
Syntaxe
curseur
Identifiantducurseurprcdemmentanalys.
paramtre
Nomduparamtredanslarequte(aveclecaractre:)
Exemple ::p1
variable
longueur
Longueurmaximumdel'espaceutilispourlaliaison.
Valeurpardfaut :1(voirlesconsquencesciaprs).
type
Indiquesilaliaisonestd'untypeparticulierl'aided'unedesconstantessuivantes :
OCI_B_ROWID,OCI_B_CLOB,OCI_B_BLOB,OCI_B_BFILE
OCI_B_CFILE, OCI_B_NTY, OCI_B_CURSOR
La fonction oci_bind_by_name retourne TRUE si l'association a pu s'effectuer et FALSE dans le cas contraire
(accompagnd'unealerte).
L'unit du paramtre longueur n'est pas clairement dfinie dans la documentation l'usage, il semble que ce
soit un nombre de caractres (y compris pour les nombres). Si ce paramtre est gal 1 (soit explicitement,
soitpardfautlorsqu'iln'estpasrenseign),lalongueurestdfinieparlecontenudelavariableau moment de
l'appellafonction silavariablen'estpasdfinie,lalongueurestgale1.
Leparamtrelongueurdoittrepositionnavecsoincaruneerreurrisquedesurveniraumomentdel'appella
fonctionoci_execute,silalongueurdelavariablecetinstantestsuprieurelalongueurpriseencompteau
momentdel'appeloci_bind_by_name.
Exemple de message
Une des solutions, pour viter les problmes, consiste appeler systmatiquement la fonction
oci_bind_by_name sans paramtre juste avant chaque appel la fonction oci_execute. De cette manire,
voustescertaindeprendrelalongueuractuelledelavariable.Uneautreapprocheconsisteplacerunevaleur
avecunegrandemargedescurit.
Le paramtre type permet de grer des types de donnes particuliers, en l'occurrence les diffrents types LOB
(BLOB, CLOB et BFILE) et le type ROWID, les types de donnes dfinis par l'utilisateur et les curseurs. Si ce
paramtreestspcifi,ilfautmettreleparamtrelongueur1.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// dfinition d'une premire requte paramtre
$requte = "SELECT * FROM articles WHERE identifiant = :p1";
// analyse de la requte
$curseur = oci_parse($connexion,$requte);
// association entre le paramtre et la variable PHP
oci_bind_by_name($curseur,":p1",$identifiant,10);
// excution de la requte avec une premire valeur de la variable
$identifiant = 1;
$ok = oci_execute($curseur);
// lire le rsultat
$ligne = oci_fetch_assoc($curseur);
echo "$ligne[IDENTIFIANT] - $ligne[LIBELLE]<BR>";
// excution de la requte avec une deuxime valeur
// de la variable (utilisation du mme curseur)
$identifiant = 2;
$ok = oci_execute($curseur);
// lire le rsultat
$ligne = oci_fetch_assoc($curseur);
echo "$ligne[IDENTIFIANT] - $ligne[LIBELLE]<BR>";
Rsultat
1 - Abricots
2 - Cerises
1 - Abricots
Les types de donnes BLOB, CLOB, BFILE et ROWID se manipulent, en PHP, sous forme d'objets la fonction
oci_new_descriptor (anciennement OciNewDescriptor) permet de crer ces objets en cas de besoin. titre
d'illustration,unexemplepluscompletdel'utilisationduROWIDestdonndanslepointMettrejourdesdonnes
de ce chapitre. En cas de besoin, le ROWID peut tre converti dans la requte en chane (fonction SQL
ROWIDTOCHAR)etrciproquement(fonctionSQLCHARTOROWID) ilestalorsplusfacilemanipuler(parexemple,
pourleplacerdansunezonedeformulairecache).
Exempledecodepourlalectured'uneligne
Un premier type de lecture consiste souvent lire une seule ligne d'information dans une table ou plusieurs
tablesavecjointure(s) :obtentiond'informationssurl'utilisateurquivientdeseconnecter,fichededescription
d'unarticle...
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser les variables
$identifiant = "";
$libell = "";
$prix = "";
$message = "";
// Tester comment le script est appel
if (! empty($_POST)) {
// traitement du formulaire ...
// rappel : lorsqu'un formulaire n'a qu'une zone de texte
// et que l'utilisateur tape return ou enter, le bouton de
// validation n'est pas considr comme cliqu. Pour savoir
// si le formulaire a t soumis, il faut tester si
// $_POST (ou $_GET) est vide ou non.
// rcuprer les valeurs saisies
$identifiant = valeur_saisie($_POST["identifiant"]);
// contrler les valeurs saisies
if ($identifiant == "") {
$message .= "L'identifiant est obligatoire.\n";
}
if (! ereg("^[0-9]+$",$identifiant)) {
$message .=
"L'identifiant doit tre un nombre.\n";
}
// tester s'il y a des erreurs ce stade
if ($message == "") {
// pas d'erreur
Exemple
<?php
function db_lire_ligne($requte) {
// se connecter
$ok =($connexion =
oci_connect("demeter","demeter","diane"));
if ($ok) { // connexion OK
// analyser la requte
$ok = ($curseur = oci_parse($connexion,$requte));
}
if ($ok) { // analyse OK
// excuter la requte
$ok = oci_execute($curseur);
}
if ($ok) { // excution OK
// lire le rsultat
$ligne =
oci_fetch_array($curseur,OCI_ASSOC+OCI_RETURN_NULLS);
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Ilestpossible(souhaitable)d'amliorerlagestiondeserreurs(cf.Grerleserreurs).
Exemple d'utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles WHERE identifiant= 1";
// lire le rsultat
$ligne = db_lire_ligne($requte);
if ($ligne) {
// bien noter les cls en majuscules
echo "$ligne[LIBELLE] - $ligne[PRIX]";
}
?>
Abricots - 35.5
Exempledecodepourlalecturedetoutesleslignes
Un deuxime type de lecture consiste souvent afficher une liste d'lments extraits de la base (liste
d'utilisateurs,listed'articles...).
Exemple (en utilisant la fonction oci_fetch_all pour tout charger dans un tableau)
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// excuter la requte de slection
Il est possible d'crire le mme exemple de manire plus compacte. Ce dernier sera alors plus conome en
mmoireetplusperformant :lefetchesteffectuaucoursdelaconstructiondelatableHTML.
Exemple
Pourpermettrel'utilisateurd'agirsurlaliste,ilestpossibled'imbriquerunformulaireoudesliensaveclatable
HTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// excuter la requte de slection
// connexion
$ok =($connexion =
Sur le lien, la place du code JavaScript, il est possible de mettre une vraie URL et d'enchaner sur une autre
page(cf.chapitreGrerlessessionspourcomprendrecommentmettreunparamtredansl'URLetpouvoirainsi
passeruneinformation,icil'identifiantchoisi,uneautrepage).
Encequiconcerneletraitementduformulaire,toutestenvisageable.
Lencore,pourlalecturedeplusieurslignes,unefonctiongnriquepeuttreutilise.
<?php
function db_lire_lignes_dans_tableau($requte) {
// se connecter
$ok =($connexion =
oci_connect("demeter","demeter","diane"));
if ($ok) { // connexion OK
// analyser requte
$ok = ($curseur = oci_parse($connexion,$requte));
}
if ($ok) { // analyse OK
// excuter la requte
$ok = oci_execute($curseur);
}
if ($ok) { // excution OK
// lire le rsultat
$nombre = oci_fetch_all($curseur,$tableau);
}
// retourner $tableau ou FALSE en cas d'erreur
return ($ok)?$tableau:FALSE;
}
?>
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles";
// lire le rsultat dans un tableau
$articles = db_lire_lignes_dans_tableau($requte);
// afficher le premier article lu
if ($articles) {
echo count($articles['IDENTIFIANT'])." articles<BR>";
echo "Premier article : ";
echo "{$articles['LIBELLE'][0]} - {$articles['PRIX'][0]}";
}
?>
4 articles
Premier article : Abricots - 35.5
ladiffrencedeMySQL,letableaun'estpasvidesilersultatestvide.Cependant,ilestfaciledemodifierce
comportement,encasdebesoin,parappellafonctionarray().
Cettefonctiongnriquepeut,parexemple,treutilisepourconstruireuneliste<SELECT>dansunformulaire.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// chargement de la liste des fruits
$requte = "SELECT identifiant,libelle FROM articles
ORDER BY libelle";
$fruits_du_march = db_lire_lignes_dans_tableau($requte);
?>
<!-- construction du formulaire -->
<FORM METHOD="POST">
Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<?php
// code PHP gnrant la partie dynamique du formulaire
// parcourir la liste afficher
$nombre = count($fruits_du_march['IDENTIFIANT']);
for($i=0;$i<$nombre;$i++) {
// gnrer la balise OPTION avec l'identifiant
// pour l'option VALUE et le libell pour le texte affich dans la liste
echo "<OPTION VALUE=
\"{$fruits_du_march['IDENTIFIANT'][$i]}\">
Rsultat
Mettrejourdesdonnes
MettrejourdesdonnesconsisteexcuterdesrequtesINSERT(cration),UPDATE(modification)ouDELETE
(suppression).
L'excution de ce type de requte s'effectue avec les fonctions oci_parse et oci_execute, comme pour une
requteSELECT,aveclammepossibilitd'utiliserdesrequtesparamtres.
UnedesdiffrencesfondamentalesavecMySQLconcernelagestiondestransactions.
Par dfaut, la fonction oci_execute agit en "auto COMMIT" : si l'ordre de mise jour a russi, il est
immdiatementCOMMIT.PourgrerunetransactioncomposedeplusieursordresSQL,ilconvientd'excuterles
ordresindividuelssanslemode"autoCOMMIT"etd'excuter,lafin,unordreCOMMITouROLLBACK.
La fonction oci_execute accepte un deuxime paramtre qui permet d'indiquer le fonctionnement souhait vis
visduCOMMIT.
Cedeuximeparamtrepeutprendredeuxvaleurs :
OCI_COMMIT_ON_SUCCESS
(valeurpardfaut)
COMMITautomatiquesil'ordredemisejours'estcorrectementexcut.
OCI_DEFAULT
PasdeCOMMITautomatique.
PourexcuterunordreCOMMITouROLLBACK,deuxmthodessontdisponibles :
- La premire consiste excuter ces ordres, comme les autres ordres SQL, l'aide des fonctions oci_parse et
oci_execute.
Syntaxe
connexion
Identifiantdelaconnexionsurlaquelleexcuterl'ordreSQLCOMMITouROLLBACK.
<?php
// premire mthode
$ok = oci_execute(oci_parse($connexion,"COMMIT"));
$ok = oci_execute(oci_parse($connexion,"ROLLBACK"));
// deuxime mthode
$ok = oci_commit($connexion);
$ok = oci_rollback($connexion);
?>
La bibliothque "Oracle 8" ne propose par d'quivalent la fonction mysql_insert_id mais il est possible
d'utiliserlaclauseRETURNINGdesordresSQLINSERT, UPDATEouDELETE(voirciaprs).
Dans les requtes INSERT, UPDATE et DELETE, Oracle autorise (depuis la version 8i), de placer la fin des
requtesINSERT, UPDATEet DELETE,uneclauseRETURNINGquipermetdercuprerlavaleurd'uneouplusieurs
colonnes aprs l'insertion et la modification, ou avant la suppression. Pour rcuprer ces valeurs dans le code
PHP,ilsuffitd'utiliserdesparamtresetdelesassocierdesvariablesaveclafonctionoci_bind_by_name.
Syntaxe
Exemples
<?php
// inclusion du fichier qui contient la dfinition des fonctions gnrales
include("fonctions.inc");
// dfinition d'une petite fonction d'affichage de la liste des articles
function AfficherArticles() {
$requte = "SELECT * FROM articles";
$articles = db_lire_lignes_dans_tableau($requte);
if ($articles) {
echo "<B>Liste des articles :</B><BR>";
$nombre = count($articles['IDENTIFIANT']);
for($i=0;$i<$nombre;$i++) {
echo "{$articles['IDENTIFIANT'][$i]} _
{$articles['LIBELLE'][$i]} _
{$articles['PRIX'][$i]}<BR>";
}
} else {
echo "<B>Plus d'articles.</B><BR>";
}
}
// affichage de contrle
AfficherArticles();
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// requte INSERT (paramtre)
$requte = "INSERT INTO articles(libelle,prix)
VALUES(:p1,:p2)
RETURNING identifiant, ROWID, ROWIDTOCHAR(ROWID)
INTO :r1,:r2,:r3";
// analyse
$curseur = oci_parse($connexion,$requte);
// cration d'une variable pour le rowid
$rowid = oci_new_descriptor($connexion,OCI_D_ROWID);
// association entre les variables et les paramtres
oci_bind_by_name($curseur,":p1",$libell,50);
oci_bind_by_name($curseur,":p2",$prix,32);
oci_bind_by_name($curseur,":r1",$identifiant,32);
oci_bind_by_name($curseur,":r2",$rowid,-1,OCI_B_ROWID);
oci_bind_by_name($curseur,":r3",$rowid_chane,32);
// excution de la requte
$libell = "Poire"; // valeur du libell (sans s)
$prix = 0; // valeur du prix (0 pour l'instant)
$ok = oci_execute($curseur); // COMMIT automatique
echo "Identifiant du nouvel article = $identifiant.<BR>";
echo "ROWID du nouvel article = $rowid (objet !).<BR>";
echo "ROWID du nouvel article = $rowid_chane (chane).<BR>";
Rsultat
Cetexempleillustrelesdeuxtechniquesd'utilisationduROWID :
Crerdesformulairesquipermettentdemettrejourlesdonnesesttrssimple.
titred'exemple,nousallonsconstruireunformulairequipermetderaliserunesaisieenliste.
Prsentation du formulaire
Chaque ligne du tableau contient quatre zones de formulaire qui sont nommes (option NAME de la balise
<INPUT>)delamaniresuivante :
Colonne Nom
Identifiant saisie[i][modifier]
Libell saisie[i][libelle]
Prix saisie[i][prix]
Supprimer saisie[i][supprimer]
L'indice i est l'identifiant de l'article pour les lignes qui existent, et un numro compris entre 1 et 5 pour les
lignesvides.Lazonedelacolonne Identifiantestunezonemasque(TYPE="hidden")quivatreutilisepour
identifierleslignesdanslesquellesl'utilisateuraeffectuunemodification.
Avec ce processus de nommage, toute la saisie est rcupre dans le script PHP sous la forme d'un tableau
multidimensionnel nomm $lignes. Chaque ligne du tableau correspond une ligne du formulaire avec la cl
gale l'identifiant (ou 1 5 pour les nouvelles lignes) et la valeur gale un tableau associatif donnant les
lmentssaisis.
Pour identifier les lignes modifies par l'utilisateur, les zones de saisie du libell et du prix des lignes existantes
contiennentlecodeJavaScriptsuivant :
onChange="document.formulaire[$n].value=1"
CecodeJavaScriptapoureffet,chaquefoisquelazoneenquestionestmodifie,deplacerun1danslazone
masque associe la ligne. Le formulaire s'appelant formulaire (<FORM NAME = "formulaire"...>),
l'expression document.formulaire[n] dsigne la nime zone du formulaire formulaire du document courant,
la premire zone du formulaire ayant le numro 0. Dans le source, la variable $n est calcule pour chaque ligne
$i du formulaire, par la formule $n = 4 * ($i - 1) : la zone cache de la ligne 1 a le numro 0 (c'est la
premireduformulaire),celledelaligne2lenumro4etainsidesuite.
Cetexemplepeut(doit)treamlior :
Exemple
Appeleruneprocdurestocke
La bibliothque "Oracle 8" permet trs facilement d'excuter des blocs PL/SQL anonymes ou d'appeler des
procdures ou des fonctions stockes et des packages. Les procdures, fonctions et packages peuvent avoir
desparamtresenentre(IN)etensortie(OUT).
Le principe gnral consiste soumettre un bloc PL/SQL pour analyse et excution par l'intermdiaire des
fonctions oci_parse et oci_execute. L'appel la fonction oci_bind_by_name permet, en plus, d'associer des
variablesPHPauxventuelsparamtresdublocPL/SQL.
Si l'un des paramtres est un curseur (au sens REF CURSOR Oracle), il faut utiliser une variable PHP d'un type
Syntaxe
connexion
Identifiantdelaconnexionsurlaquellelecurseurdoittrecr.
Lafonctionoci_new_cursorretourneunidentifiantdecurseurouFALSEencasd'erreur.
Pour associer un paramtre de type curseur et une variable de type curseur, il faut utiliser la constante
OCI_B_CURSORendernierparamtredelafonctionoci_bind_by_name(avecunelongueurgale1).
Aprs excution du bloc, la variable de type curseur contient un identifiant de curseur qu'il faut excuter
(fonctionoci_execute)avantdepouvoirlireleslignes(fonctionoci_fetch_*).
Nousallonsillustrercesdiffrentesfonctionnalitsl'aidedupackageOraclesuivant :
BEGIN
SELECT COUNT(identifiant) INTO v_nombre
FROM articles;
RETURN v_nombre;
END;
-- procdure de lecture d'un article (si p_identifiant > 0)
-- ou de tous les articles (si p_identifiant = 0)
-- le rsultat est retourn sous la forme d'un curseur
PROCEDURE lire(
p_identifiant IN NUMBER,
p_curseur OUT curseur)
IS
BEGIN
IF p_identifiant = 0 THEN
OPEN p_curseur FOR
SELECT * FROM articles;
ELSE
OPEN p_curseur FOR
SELECT * FROM articles
WHERE identifiant = p_identifiant;
END IF;
Source PHP
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// insertion l'aide du package
// - la procdure est appele dans un bloc PL/SQL
$requte = "BEGIN pkg_articles.creer(:p1,:p2,:r1); END;";
// analyse
$curseur = oci_parse($connexion,$requte);
// association paramtres/variables
oci_bind_by_name($curseur,":p1",$libell,50);
oci_bind_by_name($curseur,":p2",$prix,32);
oci_bind_by_name($curseur,":r1",$identifiant,32);
// excution avec certaines valeurs
$libell = "Pommes";$prix = 10;
// Pas de COMMIT automatique de oci_execute (le package
// s'en charge)
$ok = oci_execute($curseur,OCI_DEFAULT);
// affichage de l'identifiant du nouvel article
echo "Identifiant du nouvel article = $identifiant.<BR>";
// comptage l'aide du package
// - la procdure est appele dans un bloc PL/SQL
$requte = "BEGIN :r1 := pkg_articles.compter; END;";
// analyse
$curseur = oci_parse($connexion,$requte);
// association paramtres/variables
oci_bind_by_name($curseur,":r1",$nombre,32);
// excution
$ok = oci_execute($curseur,OCI_DEFAULT);
echo "$nombre article(s) dans la base.<BR>";
// lecture d'un article l'aide du package
// - la procdure est appele dans un bloc PL/SQL
$requte = "BEGIN pkg_articles.lire(:p1,:r1); END;";
// analyse
$curseur = oci_parse($connexion,$requte);
// cration d'un curseur pour le rsultat
$curseur_rsultat = oci_new_cursor($connexion);
// association paramtres/variables
oci_bind_by_name($curseur,":p1",$identifiant,32);
oci_bind_by_name($curseur,":r1",$curseur_rsultat,
-1,OCI_B_CURSOR);
// excution avec la valeur actuelle de $identifiant
// => lecture de l'article insr prcdemment
$ok = oci_execute($curseur,OCI_DEFAULT);
// excution du curseur rsultat
$ok = oci_execute($curseur_rsultat,OCI_DEFAULT);
// fetch
$article = oci_fetch_array($curseur_rsultat,
OCI_ASSOC+OCI_RETURN_NULLS);
echo "Nouveau : $article[LIBELLE] - $article[PRIX]<BR>";
// lecture de tous les articles l'aide du package
// - le curseur $curseur peut tre rutilis
// - par contre, $curseur_rsultat est "inutilisable" : il faut
// le recrer et le r-associer
oci_free_cursor($curseur_rsultat); // libration du premier
$curseur_rsultat = oci_new_cursor($connexion);
oci_bind_by_name($curseur,":r1",$curseur_rsultat,
-1,OCI_B_CURSOR);
// excution avec $identifiant = 0
$identifiant = 0;
$ok = oci_execute($curseur,OCI_DEFAULT);
// excution du curseur rsultat
$ok = oci_execute($curseur_rsultat,OCI_DEFAULT);
// fetch de toutes les lignes
echo "Liste : <BR>";
while ($article = oci_fetch_array($curseur_rsultat,
OCI_ASSOC+OCI_RETURN_NULLS)) {
echo "  $article[LIBELLE] - $article[PRIX]<BR>";
}
?>
Rsultat
Les ressources utilises par les curseurs sont automatiquement libres la fin du script. En cas de besoin, les
fonctionsoci_free_cursoretoci_free_statementpeuventtreappelespourunelibrationanticipe.
Illustrationdesproblmeslisl'environnementNLS
Danscettepartie,nousallonsillustrerlanaturedesproblmesquipeuventseproduireavecl'environnementNLS
ettudierlesdiffrentessolutionspourrsoudrecesproblmes.
Exemple
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// rcupration de la date du serveur
$requte = "SELECT SYSDATE FROM dual";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$ligne = oci_fetch_assoc($curseur);
echo "SYSDATE = $ligne[SYSDATE]<BR>";
// augmentation des prix l'aide d'une requte paramtre
$requte = "UPDATE articles SET prix = prix * :p1";
$curseur = oci_parse($connexion,$requte);
oci_bind_by_name($curseur,":p1",$coefficient,32);
$coefficient = 1.05; // 5% d'augmentation
$ok = oci_execute($curseur);
echo oci_num_rows($curseur)." lignes modifies.";
?>
SYSDATE = 20-MAY-04
4 lignes modifies.
SYSDATE = 20/05/04
Warning: oci_execute() [function.oci-execute]:
OCIStmtExecute: ORA-01722: Nombre non valide in d:\scripts php\index.php
on line 16
0 lignes modifies.
Ques'estilpassentrelesdeux ?
Deuxproblmespeuventseproduire :
- Une donne attendue selon un certain format, et manipule dans le code selon ce format, peut changer de format en
fonction de l'environnement et donc poser des problmes dans le code.
- Une requte peut tre excute avec succs dans un environnement et pas dans l'autre.
L'erreursurladeuximerequteestlieaufaitque,dansunenvironnementfranais,lesparateurdcimalest
lavirgule(nonlepoint)etquelecoefficientd'augmentationpassenparamtreaunsparateurdcimalgalau
point.Labibliothquesemblepasserlesdonnesnumriquessousformedechane,cequiprovoqueunproblme
Dans le cas o l'environnement n'est pas matris et o vous souhaitez crire un code portable, ces problmes
peuventtretraitsdedeuxfaons :
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// rcupration de la date du serveur
// - la mise en forme attendue est obtenue par une
// conversion explicite
$requte = "SELECT TO_CHAR(SYSDATE, 'DD/MM/YYYY') d
FROM dual";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$ligne = oci_fetch_assoc($curseur);
echo "SYSDATE = $ligne[D]<BR>"; // utilisation de l'alias
// augmentation des prix l'aide d'une requte paramtre
// - la chane implicitement passe en paramtre est
// explicitement convertie l'aide du bon format
$requte = "UPDATE articles
SET prix = prix * TO_NUMBER(:p1,'9.99')";
$curseur = oci_parse($connexion,$requte);
oci_bind_by_name($curseur,":p1",$coefficient,32);
$coefficient = 1.05; // 5% d'augmentation
$ok = oci_execute($curseur);
echo oci_num_rows($curseur)." lignes modifies.";
?>
SYSDATE = 20/05/2004
4 lignes modifies.
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// dfinition de l'environnement souhait par
// deux requtes ALTER SESSION
$requte = "ALTER SESSION SET NLS_DATE_FORMAT='DD/MM/YYYY'";
$ok = oci_execute(oci_parse($connexion,$requte));
$requte = "ALTER SESSION SET NLS_NUMERIC_CHARACTERS='.,'";
$ok = oci_execute(oci_parse($connexion,$requte));
// rcupration de la date du serveur
$requte = "SELECT SYSDATE FROM dual";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$ligne = oci_fetch_assoc($curseur);
echo "SYSDATE = $ligne[SYSDATE]<BR>";
// augmentation des prix l'aide d'une requte paramtre
$requte = "UPDATE articles SET prix = prix * :p1";
$curseur = oci_parse($connexion,$requte);
oci_bind_by_name($curseur,":p1",$coefficient,32);
$coefficient = 1.05; // 5% d'augmentation
$ok = oci_execute($curseur);
echo oci_num_rows($curseur)." lignes modifies.";
?>
SYSDATE = 20/05/2004
4 lignes modifies.
Lafonctionoci_error (anciennementociError)permetdercuprerdesinformationssurl'erreurventuellede
ladernireoprationeffectuedansuncurseur.
Syntaxe
curseur
Identifiantducurseuroudelaconnexion.
Lafonction oci_errorretourneuntableauassociatifsiladernireoprationeffectuedanslecurseuragnr
une erreur : la ligne de cl code donne le numro de l'erreur Oracle et la ligne de cl message, le message
associ. Si la dernire opration effectue dans le curseur n'a pas gnr d'erreur, la fonction oci_error
retourneFALSE.
Si la fonction oci_error est appele sans paramtre, elle doit retourner l'erreur ventuelle, rencontre sur la
dernire opration ralise (tout curseur confondu). Dans la pratique, cette syntaxe ne fonctionne qu'aprs un
appeloci_connectetpermetdercuprerlemessaged'erreurventuel,relatiflaconnexion.
Exemple
<?php
// mauvaise connexion
$connexion = oci_connect("demeter","MotDePasseErron","diane");
$e = oci_error(); // noter l'appel sans paramtre
echo "1 : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// une bonne requte pour commencer
$requte = "SELECT * FROM articles";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$e = oci_error($curseur);
echo "<P>2 : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
// requte sur une table qui n'existe pas
$requte = "SELECT * FROM article";
$curseur = oci_parse($connexion,$requte);
$e = oci_error($curseur);
echo "<P>3.a : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
$ok = oci_execute($curseur);
$e = oci_error(); // appel sans paramtre pour voir
echo "3.b : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
$e = oci_error($curseur);
echo "3.c : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
// requte INSERT qui viole une cl primaire
$requte = "INSERT INTO articles(identifiant,libelle,prix)
VALUES(1,'Poires',29.9)";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$e = oci_error($curseur);
echo "<P>4 : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
// tentative de fetch sur un mauvais rsultat
$requte = "SELECT * FROM article";
$curseur = oci_parse($connexion,$requte);
$ok = oci_execute($curseur);
$e = oci_error($curseur);
echo "<P>5.a : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
$ligne = oci_fetch_assoc($curseur);
$e = oci_error($curseur);
echo "5.b : ".($e?"$e[code] - $e[message]":"OK")."<BR>";
?>
Rsultat
Quellequesoitl'erreur,unealerteestaffiche(cf.chapitreGrerleserreursdansunscriptPHPpoursupprimer
l'affichagedecesalertes).
Lersultat3fournitdeuxinformations :
- La fonction oci_error, sans paramtre, n'est d'aucune utilit, en dehors d'un appel aprs la fonction oci_connect.
- La fonction oci_parse, sur une mauvaise requte, ne gnre jamais d'erreur: la fonction oci_parse ne retourne
pas FALSE et la fonction oci_error retourne FALSE (donc pas d'erreur). L'erreur sera dtecte uniquement lors de
l'excution.
ContrairementMySQL,uneerreurestretournesiunetentativede fetchesteffectuesuruncurseurquin'a
pastexcut.
Dans la pratique, il convient d'appeler la fonction oci_error() aprs la fonction oci_connect, et oci_error
($curseur)aprslafonctionoci_execute.
Cesfonctionspeuventtremisesenuvre,titred'exemple,surunedenosfonctionsgnriques.
Exemple
<?php
function db_lire_ligne($requte, &$erreur) {
// dans cette nouvelle version, db_lire_ligne prend un
// deuxime paramtre par rfrence dans lequel un numro et un message
// seront stocks en cas d'erreur (sous la forme d'un tableau)
// initialiser $erreur
// code = 0, message vide
// le tableau est conforme la structure du tableau
// retourn par oci_error
$erreur = array("code" => 0, "message" => "");
// se connecter
$ok =($connexion =
oci_connect("demeter","demeter","diane"));
if ($ok) { // connexion OK
// analyser requte
$ok = ($curseur = oci_parse($connexion,$requte));
}
if ($ok) { // analyse OK
// excuter la requte
$ok = oci_execute($curseur);
}
if ($ok) { // excution OK
// lire le rsultat
$ligne = oci_fetch_array($curseur,
OCI_ASSOC+OCI_RETURN_NULLS);
}
if (! $ok) { // erreur quelque part
// si connexion OK, rcuprer l'erreur du curseur
// sinon, rcuprer l'erreur de la connexion
$erreur = $connexion?oci_error($curseur):oci_error();
}
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// premier appel avec une erreur
$requte = "SELECT * FROM article WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[code] - $erreur[message]<BR>";
} else {
echo "$ligne[LIBELLE] - $ligne[PRIX]<BR>";
}
// deuxime appel correct
$requte = "SELECT * FROM articles WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[code] - $erreur[message]<BR>";
} else {
echo "$ligne[LIBELLE] - $ligne[PRIX]<BR>";
?>
Rsultat
Le tableau retourn par la fonction oci_error offre deux lignes supplmentaires avec les cls offset et sqltext. La ligne
de cl offset donne la position de l'erreur dans le texte de la requte et la ligne de cl sqltext donne le texte de la requte.
Prambule
LejeudefonctionspropospourMicrosoftSQLServeresttrsprochedeceluideMySQL.
En rgle gnrale, il suffit de remplacer le prfixe mysql_ des fonctions de MySQL par mssql_ pour obtenir la
fonctionquivalentedeMicrosoftSQLServer.Leprfixe mssql_nedoitpastreconfonduavec msql_quiestle
prfixedesfonctionsdelabasemSQL.
Connexionetdconnexion
Lafonctionmssql_connectpermetd'tabliruneconnexionavecunebaseSQLServer.
Syntaxe
serveur
Nomduserveur.
utilisateur
Nomdel'utilisateuremployerpourtablirlaconnexion.
mot_de_passe
Motdepasseutiliserpourtablirlaconnexion.
La fonction mssql_connect retourne un identifiant de connexion ou, en cas d'erreur, la valeur FALSE
accompagned'unmessaged'alerteenvoyl'affichage(cf.chapitre GrerleserreursdansunscriptPHPpour
grercettesituationcorrectement).
Danslemmescript,appelerdeuxfois mssql_connectaveclesmmesparamtresn'ouvrepasdeuxconnexions
diffrentes :lorsdudeuximeappel,l'identifiantdelaconnexiondjouverteestretourn.
Exemple
<?php
// exemple de connexion correcte
$id1 = mssql_connect("diane","demeter","demeter");
echo "\$id1 = $id1<BR>\n";
// exemple d'chec (mauvais mot de passe)
$id2 = mssql_connect("diane","demeter","zeus");
echo "\$id2 = $id2<BR>\n";
// nouvelle connexion avec les mmes paramtres que 1
$id3 = mssql_connect("diane","demeter","demeter");
echo "\$id3 = $id3 (= $id1)<BR>\n";
// gal $id1
?>
Rsultat
$id1 = Resource id #1
Warning: mssql_connect() [function.mssql-connect]: message:
chec de la connexion de l'utilisateur 'demeter'. (severity 14)
in d:\scripts php\index.php on line 8
Warning: mssql_connect() [function.mssql-connect]: Unable to
connect to server: diane in d:\scripts php\index.php on line 8
$id2 =
$id3 = Resource id #1 (= Resource id #1)
La fonction mssql_pconnect permet d'obtenir un fonctionnement diffrent et d'tablir une connexion dite
"permanente"quineserapasfermelafinduscriptetpourratrerutilisedanscescriptouunautrescript
ultrieurement.
Lasyntaxeestidentiquelasyntaxedelafonctionmssql_connect.
Lors de l'appel la fonction mssql_pconnect dans un script, PHP regarde si une connexion permanente a dj
t ouverte avec les mmes paramtres (serveur, utilisateur et mot de passe) : si oui, l'identifiant de cette
connexionestretourn sinon,unenouvelleconnexionesttablie(etcetteconnexionneserapasfermela
finduscript,autorisantainsisarutilisationultrieure).
Implicitement, la connexion est tablie sur la base par dfaut associe l'utilisateur toutes les requtes qui
sontexcutessurcetteconnexion,s'effectuentimplicitementsurcettebasepardfaut.
Lafonctionmssql_select_dbpermetdechangerlabaseactivedelaconnexion.
Syntaxe
base
Nomdelabaseactiver.
connexion
Identifiantdeconnexionretournparlafonctionmssql_connect.
Sinonprcis,s'appliqueladernireconnexionouverte.
La fonction mssql_select_db retourne TRUE si la base a pu tre change et FALSE autrement (accompagn
d'unealerte).
Exemple
<?php
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
// changement de base
$ok = mssql_select_db("pubs",$connexion);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
// tentative de changement pour une base qui n'existe pas
$ok = mssql_select_db("pub",$connexion);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
?>
Rsultat
$ok = TRUE
Warning: mssql_select_db() [function.mssql-select-db]:
message: Impossible de trouver l'entre dans sysdatabases pour la base de donnes 'pub'. Aucune
entre ne porte ce nom. Assurez-vous que le nom est correctement saisi. (severity 16)
in d:\scripts php\index.php on line 8
Warning: mssql_select_db() [function.mssql-select-db]:
Unable to select database: pub in d:\scripts php\index.php on line 8
$ok = FALSE
Lafonctionmssql_closepermetdefermeruneconnexionencoursdescript.
connexion
Identifiantdeconnexionretournparlafonctionmssql_connect.
Sinonprcis,fermeturedeladernireconnexionouverte.
Lafonctionmssql_closeretourneTRUEencasdesuccsetFALSEencasd'erreur(accompagnd'unealerte).
Lafonctionmssql_closeestsanseffetsuruneconnexionpermanente.
Toutes les connexions non permanentes sont automatiquement fermes la fin du script.
Exemple
<?php
// connexion
$id1 = mssql_connect("diane","demeter","demeter");
echo "\$id1 = $id1<BR>\n";
// dconnexion
$ok = mssql_close($id1);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
// tentative de dconnexion d'une connexion dj close
$ok = mssql_close($id1);
echo "\$ok = ".(($ok)?"TRUE":"FALSE")."<BR>\n";
?>
Rsultat
$id1 = Resource id #1
$ok = TRUE
$ok = TRUE
Cetexemplemontrequefermeruneconnexiondjclosenegnrepasd'erreur.
Liredesdonnes
Liredesdonnesdansunebasencessitedeuxoprations :
- envoyer, pour excution, une requte (en l'occurrence un ordre SELECT) au serveur ;
Excuterunerequte
Lafonctionmssql_querypermetd'envoyerunerequtepourexcutionauserveur.
Syntaxe
requte
Textedelarequteexcuter.
connexion
Identifiantdeconnexionretournparlafonctionmssql_connect.
Sinonprcis,utilisationdeladernireconnexionouverte.
La fonction mssql_query retourne un identifiant de rsultat de requte, en cas de succs, et FALSE en cas
Rappel : la requte s'excute sur la base active de la connexion (base par dfaut de l'utilisateur ou base prcdemment
slectionne par la fonction mssql_select_db).
Exemple
<?php
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte sur la base actuelle
$rsultat1 = mssql_query($requte,$connexion);
echo "\$rsultat1 = $rsultat1<BR>\n";
// dfinition d'une mauvaise requte
$requte = "SELECT * FROM article";
$rsultat2 = mssql_query($requte,$connexion);
echo "\$rsultat2 = $rsultat2<BR>\n";
// excution de la bonne requte sur une mauvaise base
$ok = mssql_select_db("msdb",$connexion);
$requte = "SELECT * FROM articles";
$rsultat3 = mssql_query($requte,$connexion);
echo "\$rsultat3 = $rsultat3<BR>\n";
?>
Rsultat
rsultat1 = Resource id #2
Warning: mssql_query() [function.mssql-query]: message:
'article' : nom d'objet incorrect. (severity 16) in
d:\scripts php\index.php on line 10
Warning: mssql_query() [function.mssql-query]: Query failed
in d:\scripts php\index.php on line 10
$rsultat2 =
Warning: mssql_query() [function.mssql-query]: message:
'articles' : nom d'objet incorrect. (severity 16)
in d:\scripts php\index.php on line 15
Warning: mssql_query() [function.mssql-query]: Query failed in
d:\scripts php\index.php on line 15
$rsultat3 =
Commeindiquenintroduction,lafonctionmssql_queryexcutelarequte,indiquesilarequtes'estexcute
correctementmaisnerenvoieaucunedonne.Ilvafalloirextraireleslignesdursultat.
Connatrelenombredelignesdanslersultat
Lafonctionmssql_num_rowspermetdeconnatrelenombredelignesdanslersultat.
Syntaxe
rsultat
Identifiantdersultatderequteretournparlafonctionmssql_query.
CettefonctionestutilisableuniquementpourlesrequtesSELECT.
Exemple
<?php
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte (avec la connexion courante)
$rsultat = mssql_query($requte);
// rcupration du nombre de lignes
Rsultat
Nombre d'articles : 4
Nombre d'articles dont le prix est suprieur 40 : 1
Lirelersultatdelarequte
Ces fonctions effectuent le mme traitement : lecture de la ligne courante du rsultat et avancement du
pointeursurlalignesuivante(voirl'introduction).
Cesfonctionsdiffrentsurletypededonnesutilispourretournerlersultat.
Syntaxe
rsultat
Identifiantdersultatderequteretournparlafonctionmssql_query.
type
Typedersultatgalunedesconstantessuivantes :
MSSQL_ASSOC, MSSQL_NUM, MSSQL_BOTH
S'iln'yaplusdeligneliredanslersultat,cesfonctionsretournentFALSE.
Pourlafonctionmssql_fetch_assoc,ils'agitd'untableauassociatifdontlaclestlenomdelacolonne.Pourla
fonctionmssql_fetch_row,ils'agitd'untableauindicesentiers,l'indice0correspondantlapremirecolonne,
l'indice1ladeuxime,etc.Enfin,pourlafonctionmysql_fetch_array,letypedutableaudpenddudeuxime
paramtre :
MSSQL_NUM
Tableauindicesentiers(commelafonctionmssql_ fetch_row).
MSSQL_ASSOC
Tableauassociatif(commelafonctionmssql_fetch_assoc).
MSSQL_BOTH
(valeur par dfaut)
Lesdeuxlafois.
Exemple:
Requte SELECT *
FROM articles
Colonnes identifiant libelle prix
1re ligne du 1 Abricots 35.5
rsultat
mssql_fetch_row mssql_fetch_assoc
ou ou
mssql_fetch_array mssql_fetch_array mssql_fetch_array
(...,MSSQL_NUM) (...,MSSQL_ASSOC) (...,MSSQL_BOTH)
Indice/Cl Valeur Indice/Cl Valeur Indice/Cl Valeur
0 1 identifiant 1 identifiant 1
1 Abricots libelle Abricots 0 1
2 35.5 prix 35.5 libelle Abricots
1 Abricots
prix 35.5
2 35.5
La fonction mssql_fetch_object retourne un objet, avec un attribut par colonne, le nom de l'attribut
correspondantaunomdelacolonne.
En cas d'utilisation d'un alias de colonne dans la requte SELECT (exemple SELECT AVG(prix) prix_moyen
FROM articles),c'estl'aliasdecolonnequiestutiliscommeclounomd'attribut.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
// excution de la requte sur la connexion courante
$rsultat = mssql_query("SELECT * FROM articles");
// Premier fetch avec mssql_fetch_row
$ligne = mssql_fetch_row($rsultat);
afficher_tableau($ligne,"mssql_fetch_row");
// Deuxime fetch avec mssql_fetch_assoc
$ligne = mssql_fetch_assoc($rsultat);
afficher_tableau($ligne,"mssql_fetch_assoc");
// Troisime fetch avec mssql_fetch_array
// - sans deuxime paramtre = MSSQL_BOTH
$ligne = mssql_fetch_array($rsultat);
afficher_tableau($ligne,"mssql_fetch_array");
// Quatrime fetch avec mssql_fetch_object
$ligne = mssql_fetch_object($rsultat);
echo "<P><B>mssql_fetch_object</B><BR>";
echo "\$ligne->identifiant = $ligne->identifiant<BR>";
echo "\$ligne->libelle = $ligne->libelle<BR>";
echo "\$ligne->prix = $ligne->prix<BR>";
// Cinquime fetch de nouveau avec mssql_fetch_row
// - normalement, plus de ligne
$ligne = mssql_fetch_row($rsultat);
if (! $ligne) {
echo "<P><B>Cinquime fetch : plus rien</B>";
}
?>
Rsultat
Vousobservezgrcecetexemple :
- le fait qu' chaque fetch, le pointeur interne avance, et que le fetch suivant retourne donc la ligne suivante, jusqu'
avoir parcouru toutes les lignes.
En cas d'utilisation d'un identifiant de rsultat non valide, les fonctions mysql_fech_* retournent FALSE et
affichent,enplus,unealertedutype :
Quellemthodeutiliser ?
Touteslesmthodessevalent,notammentdupointdevuedesperformances.Personnellement,nousavonsune
petite prfrence pour l'utilisation des fonctions mssql_fetch_assoc, mssql_fetch_array et
mssql_fetch_object qui permettent d'employer le nom des colonnes de la requte et de rendre le code plus
lisible.
Exempledecodepourlalectured'uneligne
Unpremiertypedelectureconsistesouventenvisageruneseuleligned'informationdansunetableouplusieurs
tablesavecjointure(s) :obtentiond'informationssurl'utilisateurquivientdeseconnecter,fichededescription
d'unarticle...
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
//initialiser les variables
$identifiant="";
$libell="";
$prix="";
$message="";
// Tester comment le script est appel
if (! empty($_POST)) {
// traitement du formulaire ...
// rappel : lorsqu'un formulaire n'a qu'une zone de texte
// et que l'utilisateur tape return ou enter, le bouton de validation
// n'est pas considr comme cliqu. Pour savoir
// si le formulaire a t soumis, il faut tester si
// $_POST (ou $_GET) est vide ou non.
// rcuprer les valeurs saisies
$identifiant = valeur_saisie($_POST["identifiant"]);
// contrler les valeurs saisies
if ($identifiant == "") {
$message .= "L'identifiant est obligatoire.\n";
Ilestrelativementsimpled'crireunefonctiongnriquepermettantdelireuneligne.
<?php
function db_lire_ligne($requte) {
// se connecter
$connexion = mssql_connect("diane","demeter","demeter");
// excuter la requte et tester le rsultat pour affecter
// la variable $ok
$ok = (($rsultat = mssql_query($requte)) != FALSE);
if ($ok) { // excution OK
// lire la ligne
$ligne = mssql_fetch_array($rsultat);
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Ilestpossible(souhaitable)d'amliorerlagestiondeserreurs(cf.Grerleserreurs).
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles WHERE identifiant= 1";
// lire le rsultat
$ligne = db_lire_ligne($requte);
if ($ligne) {
echo "$ligne[libelle] - $ligne[prix]";
}
?>
Abricots - 35.5
Exempledecodepourlalecturedetoutesleslignes
Un deuxime type de lecture consiste souvent afficher une liste d'lments extraits de la base (liste
d'utilisateurs,listed'articles...).
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter
$connexion = mssql_connect("diane","demeter","demeter");
// excuter la requte de slection
$requte = "SELECT * FROM articles";
$rsultat = mssql_query($requte);
// fetch si la requte a bien t excute
if ($rsultat) {
// boucle jusqu' avoir un fetch FALSE
while ($article = mssql_fetch_array($rsultat)) {
// remplir un tableau avec chaque ligne extraite
// remarque : le tableau est multidimensionnel
// puisque $article est lui-mme un tableau
$articles[] = $article;
}
}
// tester le rsultat
if (! $rsultat) { // requte pas OK
$message .= "Erreur.\n";
} elseif (empty($articles)) { // rsultat vide
$message .=
"Aucun article dans la base.\n";
On peut crire le mme exemple de manire plus compacte, un peu plus conome en mmoire et peuttre un
peuplusperformante :lefetchesteffectuaucoursdelaconstructiondelatableHTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter
$connexion = mssql_connect("diane","demeter","demeter");
// excuter la requte de slection
$requte = "SELECT * FROM articles";
$rsultat = mssql_query($requte);
// tester le rsultat
if (! $rsultat) { // requte pas OK
// message d'erreur
$message .= "Erreur.\n";
// prparer le message pour l'affichage
$message = vers_page($message);
}
// Affichage de la page ...
?>
<HTML>
<HEAD><TITLE>Liste des articles</TITLE></HEAD>
<BODY>
<!-- construction d'une table HTML -->
<TABLE BORDER="1" CELLPADDING="4" CELLSPACING="0">
Pourpermettrel'utilisateurd'agirsurlaliste,ilestpossibled'imbriquerunformulaireoudesliensaveclatable
HTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// se connecter
$connexion = mssql_connect("diane","demeter","demeter");
// excuter la requte de slection
$requte = "SELECT * FROM articles";
$rsultat = mssql_query($requte);
// tester le rsultat
if (! $rsultat) { // requte pas OK
// message d'erreur
$message .= "Erreur.\n";
// prparer le message pour l'affichage
$message = vers_page($message);
}
// Affichage de la page ...
?>
<HTML>
<HEAD><TITLE>Liste des articles</TITLE></HEAD>
<BODY>
<!-- construction d'une table HTML l'intrieur d'un
---- formulaire -->
<FORM METHOD="POST">
<TABLE BORDER="1" CELLPADDING="4" CELLSPACING="0">
<!-- ligne de titre -->
<TR ALIGN=\"center\">
<TH>Libell</TH><TH>Prix</TH><TH>Case</TH><TH>Lien</TH>
</TR>
<!-- code PHP pour les lignes du tableau -->
<?php
if ($rsultat) { // s'il y a un rsultat afficher
// boucle de fetch
while ($article = mssql_fetch_array($rsultat)) {
// mise en forme des donnes
$article["libelle"] = vers_page($article ["libelle"]);
$article["prix"] = vers_page(
number_format($article["prix"],2,"," ," "));
// gnration de la ligne de la table HTML
// - une case cocher dans une colonne
// - un lien dans une autre colonne
printf(
Rsultat
Encequiconcerneletraitementduformulaire,toutestenvisageable.
Lencore,pourlalecturedeplusieurslignes,unefonctiongnriqueestutilisable.
Exemple
<?php
function db_lire_lignes_dans_tableau($requte) {
// se connecter
$connexion = mssql_connect("diane","demeter","demeter");
// excuter la requte et tester le rsultat pour affecter
// la variable $ok
$ok = (($rsultat = mssql_query($requte)) != FALSE);
if ($ok) { // excution OK
// lire les lignes dans un tableau
while ($ligne = mssql_fetch_array($rsultat)) {
$tableau[] = $ligne;
}
}
// retourner $tableau ou FALSE en cas d'erreur
return ($ok)?$tableau:FALSE;
}
?>
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles";
// lire le rsultat dans un tableau
$articles = db_lire_lignes_dans_tableau($requte);
// afficher le premier article lu
if ($articles) {
echo count($articles)." articles<BR>";
echo "Premier article : ";
echo "{$articles[0]['libelle']} - {$articles[0]['prix']}";
}
?>
4 articles
Premier article : Abricots - 35.50
Cettefonctiongnriquepeut,parexemple,treutilisepourconstruireuneliste<SELECT>dansunformulaire.
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// chargement de la liste des fruits
$requte = "SELECT identifiant,libelle FROM articles
ORDER BY libelle";
$fruits_du_march = db_lire_lignes_dans_tableau($requte);
?>
<!-- construction du formulaire -->
<FORM METHOD="POST">
Fruits prfrs :<BR>
<SELECT NAME="fruits[]" MULTIPLE SIZE="8">
<?php
// code PHP gnrant la partie dynamique du formulaire
// parcourir la liste afficher
foreach($fruits_du_march as $fruit) {
// gnrer la balise OPTION avec l'identifiant pour l'option
// VALUE et le libell pour le texte affich dans la liste
echo "<OPTION VALUE=\"$fruit[identifiant]\">
$fruit[libelle]\n";
}
?>
</SELECT>
<INPUT TYPE="submit" NAME="OK" VALUE="OK"><BR>
</FORM>
Rsultat
Mettrejourdesdonnes
MettrejourdesdonnesconsisteexcuterdesrequtesINSERT(cration),UPDATE(modification)ouDELETE
(suppression).
L'excutiondecetypederequtes'effectueaveclafonctionmssql_query,commepourunerequteSELECT.
Il n'y a pas d'quivalent, avec Microsoft SQL Server, la fonction MySQL mysql_effected_rows et la fonction
mssql_num_rows ne fonctionne pas pour une requte INSERT, UPDATE ou DELETE. Par contre, il est possible
d'excuterunerequteSELECT @@ROWCOUNTpourobteniruneinformationsurlenombredelignesaffectesparle
dernierordredemisejour(voirlesexemplesdelapagesuivante).
Il n'y a pas d'quivalent non plus la fonction MySQL mysql_insert_id mais il est possible d'excuter une
requte SELECT SCOPE_IDENTITY() ou SELECT @@IDENTITY pour rcuprer la dernire valeur de type auto
incrmentgnre(voirlesexemplesdelapagesuivante).
Pardfaut,lesordressontautomatiquement COMMITs.Pourregrouperplusieursordresdemisejourdansune
transaction, il faut excuter, avec la fonction mssql_query, la requte BEGIN TRANSACTION avant le premier
ordre,etlarequteCOMMIT TRANSACTION(ouROLLBACK TRANSACTION)aprsledernierordre.
Exemples
<?php
// inclusion du fichier qui contient la dfinition des fonctions gnrales
include("fonctions.inc");
// dfinition d'une petite fonction d'affichage de la liste des articles
function AfficherArticles() {
$requte = "SELECT * FROM articles";
$articles = db_lire_lignes_dans_tableau($requte);
if ($articles) {
echo "<B>Liste des articles :</B><BR>";
Rsultat
Crerdesformulairesquipermettentdemettrejourlesdonnesesttrssimple.
titred'exemple,nousallonsconstruireunformulairepourraliserunesaisieenliste.
Prsentation du formulaire
Chaque ligne du tableau contient quatre zones de formulaire qui sont nommes (option NAME de la balise
<INPUT>)delamaniresuivante :
Colonne Nom
Identifiant saisie[i][modifier]
Libell saisie[i][libelle]
Prix saisie[i][prix]
Supprimer saisie[i][supprimer]
L'indice i est l'identifiant de l'article pour les lignes qui existent, et un numro compris entre 1 et 5 pour les
lignesvides.Lazonedelacolonne Identifiantestmasque(TYPE="hidden")ellevatreutilisepouridentifier
leslignesdanslesquellesl'utilisateuraeffectuunemodification.
Avec ce processus de nommage, toute la saisie est rcupre dans le script PHP sous la forme d'un tableau
multidimensionnel nomm $lignes. Chaque ligne du tableau correspond une ligne du formulaire avec la cl
gale l'identifiant (ou 1 5 pour les nouvelles lignes) et la valeur gale un tableau associatif donnant les
lmentssaisis.
Pour identifier les lignes modifies par l'utilisateur, les zones de saisie du libell et du prix des lignes existantes
contiennentlecodeJavaScriptsuivant :
onChange="document.formulaire[$n].value=1"
Ce code JavaScript a pour effet, chaque fois que la zone en question est modifie, de mettre un 1 dans la
zone masque associe la ligne. Le formulaire s'appelant formulaire (<FORM NAME = "formulaire"...),
l'expression document.formulaire[n] dsigne la nime zone du formulaire formulaire du document courant,
la premire zone du formulaire ayant le numro 0. Dans le source, la variable $n est calcule pour chaque ligne
$i du formulaire, grce la formule $n = 4 * ($i - 1) : la zone cache de la ligne 1 a le numro 0 (c'est la
premireduformulaire),celledelaligne2lenumro4etainsidesuite.
Cetexemplepeut(doit)treamliorpour :
Exemple
Appeleruneprocdurestocke
La bibliothque Microsoft SQL Server permet trs facilement d'excuter des blocs TransactSQL, d'appeler des
procduresstockesquiretournentventuellementdesvaleurs.
Nousallonsillustrercesdiffrentesfonctionnalitsl'aidedesprocduressuivantes :
Source PHP
<?php
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
// insertion l'aide de la procdure
$requte = "EXECUTE CreerArticle 'Pommes', 10";
// excution
$rsultat = mssql_query($requte);
// rcupration de l'identifiant du nouvel article
$ligne = mssql_fetch_row($rsultat);
$identifiant = $ligne[0];
echo "Identifiant du nouvel article = $identifiant.<BR>";
// comptage l'aide de la procdure
$requte = "EXECUTE CompterArticles";
// excution
$rsultat = mssql_query($requte);
// rcupration du rsultat
$ligne = mssql_fetch_row($rsultat);
$nombre = $ligne[0];
echo "$nombre article(s) dans la base.<BR>";
// lecture d'un article l'aide de la procdure
// => celui insr prcdemment ($identifiant)
$requte = "EXECUTE LireArticles $identifiant";
// excution
$rsultat = mssql_query($requte);
// rcupration du rsultat
$article = mssql_fetch_array($rsultat);
echo "Nouveau : $article[libelle] - $article[prix]<BR>";
// lecture de tous les articles l'aide de la procdure
// => appel sans paramtre
$requte = "EXECUTE LireArticles";
// excution
$rsultat = mssql_query($requte);
// rcupration du rsultat
echo "Liste : <BR>";
// fetch de toute les lignes
while ($article = mssql_fetch_array($rsultat)) {
echo "  $article[libelle] - $article[prix]<BR>";
}
?>
Rsultat:
Grerleserreurs
Lagestiondeserreursproposeparlabibliothquen'estpastrspratique.
Syntaxe
chane mssql_get_last_message()
mssql_min_message_severity()&
Exemples
<?php
// mauvaise connexion
$connexion = mssql_connect("diane",
"demeter","MotDePasseErron");
$message = mssql_get_last_message();
echo "1 : $message<BR>";
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
$message = mssql_get_last_message();
echo "<P>2 : $message<BR>";
// une bonne requte pour commencer
$requte = "SELECT * FROM articles";
$rsultat = mssql_query($requte);
$message = mssql_get_last_message();
echo "<P>3 : $message<BR>";
// requte sur une table qui n'existe pas
$requte = "SELECT * FROM article";
$rsultat = mssql_query($requte);
$message = mssql_get_last_message();
echo "<P>4 : $message<BR>";
// requte UPDATE qui viole une contrainte NOT NULL
$requte = "UPDATE articles SET prix = NULL";
$rsultat = mssql_query($requte);
$message = mssql_get_last_message();
echo "<P>5 : $message<BR>";
// tentative de fetch sur un mauvais rsultat
$requte = "SELECT * FROM article";
$rsultat = mssql_query($requte);
$message = mssql_get_last_message();
echo "<P>6.a : $message<BR>";
$ligne = mssql_fetch_row($rsultat);
$message = mssql_get_last_message();
echo "<P>6.b : $message<BR>";
?>
Rsultat
Plusieursremarques :
- La fonction mssql_get_last_message ne retourne pas uniquement des messages d'erreur, comme en tmoigne le
message rcupr suite une connexion russie (rsultat2) qui indique la base courante.
- Le rsultat 3 montre que la fonction mssql_get_last_message retourne le dernier message mis par le serveur,
mme si ce message est ancien et que des ordres SQL ont t excuts depuis.
- Les rsultats 4 et surtout 5 montrent que les messages rcuprs lors d'une erreur sont plutt succincts et ne donnent
pas d'information trs prcise sur la nature de l'erreur.
Quellequesoitl'erreur,uneouplusieursalertessontaffiches.Parailleurs,nousallonsvoirauchapitreGrerles
erreurs dans un script PHP comment supprimer l'affichage des alertes la fonction
mssql_min_message_severitypermetd'enliminerunepartie.
Surcetexemple,unmoinsgrandnombred'alertessontaffiches.Apriori,iln'estpaspossibledefairemieux,car
lesniveauxdegravitdeMicrosoftSQLServervontjusqu'25 :100estdoncdjlargementaudessus.
UneautresolutionconsisteexcuterlarequteSELECT @@ERRORpourrcuprer,surleserveur,lenumrode
l'erreurdudernierordreSQLexcut(0sipasd'erreur).Cettesolutionncessiteuneconnexionrussie.
Exemples
<?php
// limiter la quantit de message
mssql_min_message_severity(100);
// connexion
$connexion = mssql_connect("diane","demeter","demeter");
$erreur = mssql_fetch_row(mssql_query("SELECT @@ERROR"));
$numro = $erreur[0];
echo "1 : numro de l'erreur = $numro<BR>";
// requte sur une table qui n'existe pas
$requte = "SELECT * FROM article";
$rsultat = mssql_query($requte);
$erreur = mssql_fetch_row(mssql_query("SELECT @@ERROR"));
$numro = $erreur[0];
echo "<P>2 : numro de l'erreur = $numro<BR>";
// requte UPDATE qui viole une contrainte NOT NULL
$requte = "UPDATE articles SET prix = NULL";
$rsultat = mssql_query($requte);
$erreur = mssql_fetch_row(mssql_query("SELECT @@ERROR"));
$numro = $erreur[0];
echo "<P>3 : numro de l'erreur = $numro<BR>";
Rsultat
1 : numro de l'erreur = 0
Warning: mssql_query() [function.mssql-query]: Query failed
in d:\scripts php\index.php on line 10
2 : numro de l'erreur = 208
Warning: mssql_query() [function.mssql-query]: Query failed
in d:\scripts php\index.php on line 16
3 : numro de l'erreur = 515>
Lesnumrosretournscorrespondentbienaunumrod'erreurMicrosoftSQLServersousjacent(515=violation
d'unecontrainteNOT NULLnotamment).
Cesfonctionspeuventtremisesenuvretitred'exemplesurunedenosfonctionsgnriques.
Source PHP
<?php
function db_lire_ligne($requte, &$erreur) {
// dans cette nouvelle version, db_lire_ligne prend un deuxime paramtre
// par rfrence dans lequel un numro et un message seront stocks
// en cas d'erreur (sous la forme d'un tableau) initialiser $erreur
$erreur = array(0,""); // numro = 0, message vide
// se connecter
if (! ($ok = mssql_connect("diane","demeter","demeter"))) {
// -1 = numro d'erreur interne l'application
$erreur = array(-1,mssql_get_last_message());
};
// excuter la requte et tester le rsultat pour affecter la variable $ok
if ($ok) { // connexion OK
$ok = (($rsultat = mssql_query($requte)) != FALSE);
if (! $ok) {
$erreur[1] = mssql_get_last_message(); // message
// rcuprer le numro de l'erreur dans @@ERROR
$temp = mssql_fetch_row(
mssql_query("SELECT @@ERROR"));
$erreur[0] = $temp[0]; // numro
}
}
if ($ok) { // excution OK
// lire la ligne
$ligne = mssql_fetch_array($rsultat);
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions gnrales
require("fonctions.inc");
// premier appel avec une erreur
$requte = "SELECT * FROM article WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
// deuxime appel correct
$requte = "SELECT * FROM articles WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
?>
Rsultat
Prambule
SQLiteestunelibrairiequiimplmenteunmoteurdebasededonnesSQL.
SQLite peut tre utilise pour stocker des donnes dans une base SQL, sans avoir mettre en place la partie
serveurdelabasededonnes(commec'estlecasavecMySQL,Oracle,etc.).
SQLitelitetcritdirectementdanslesfichiersdelabasededonnes.
Pourplusd'informationsurSQLite,vouspouvezvisiterlesiteWebsuivant :http://sqlite.org/.
Ouvriretfermerunebase
Lafonctionsqlite_openpermetd'ouvrirunebaseSQLite.
Syntaxe
Avec
fichier
Cheminverslefichierdelabasededonnes.
mode
Non utilis actuellement. Prvu pour le mode d'ouverture de la base. Valeur par dfaut : 666 (seule valeur
autoriseactuellement).
erreur
Variablepasseparrfrencepermettantdercuprerunventuelmessaged'erreur.
Lafonctionsqlite_openretourneunidentifiantdebasededonnesouFALSEencasd'erreur,accompagnd'un
message d'alerte envoy l'affichage nous verrons, dans le chapitre Grer les erreurs dans un script PHP,
commentgrercettesituationcorrectement.
Silabase(i.e.lefichier)n'existepasdj,SQLitetenteradelacrer.
Exemple
<?php
// ouverture d'une base qui existe dj
$id1 = sqlite_open('diane.dbf', 666, $erreur);
echo "\$id1 = $id1<BR>\n";
echo "\$erreur = $erreur<BR>\n";
// tentative d'ouverture d'une base avec un mauvais chemin
$id2 = sqlite_open('d:/base/diane.dbf', 666, $erreur);
echo "\$id2 = $id2<BR>\n";
echo "\$erreur = $erreur<BR>\n";
?>
Rsultat
$id1 = Resource id #2
$erreur =
Warning: sqlite_open() [function.sqlite-open]: unable to open database: d:\base\diane.dbf in
d:\scripts php\index.php on line 7
$id2 =
$erreur = unable to open database: d:\base\diane.dbf
Les bases ouvertes dans un script sont automatiquement fermes la fin du script, sauf fermeture explicite
avantavecsqlite_close(voirciaprs).
La fonction sqlite_popen permet d'obtenir un fonctionnement diffrent et d'ouvrir une base de faon
"permanente"quineserapasfermelafinduscriptetpourratrerutilisedanscescriptoudansunautre
scriptplustard.
Lasyntaxeestidentiquelasyntaxedelafonctionsqlite_open.
Lors de l'appel la fonction sqlite_popen dans un script, PHP regarde si la base a dj t ouverte : si oui,
l'identifiantdecettebasededonnesestretourn autrement,labaseestouverte(etcettebaseneserapas
fermelafinduscript,cequiautoriseainsisarutilisationultrieure).
Lafonctionsqlite_closepermetdefermerunebasededonnes.
Syntaxe
sqlite_close([ressource base])
Avec
base
Identifiantdebasededonnesretournparlafonctionsqlite_open.
Lafonctionmysql_closeretourneTRUEencasdesuccsetFALSEencasd'erreur(accompagnd'unealerte).
Tenterdefermerunebasedjfermeprovoquel'affichaged'unealerte.
Toutes les bases ouvertes de faon non permanente sont automatiquement fermes la fin du script.
Exemple
<?php
// ouverture
$id1 = sqlite_open('diane.dbf');
echo "\$id1 = $id1<BR>\n";
// fermeture
sqlite_close($id1);
// tentative de fermeture d'une base dj ferme
sqlite_close($id1);
?>
Rsultat
id1 = Resource id #2
Warning: sqlite_close(): 2 is not a valid sqlite database resource
in d:\scripts php\index.php on line 8
Liredesdonnes
Liredesdonnesdansunebasencessitedeuxoprations :
Excuterunerequte
Lafonctionsqlite_querypermetd'excuterunerequtesurunebase.
Avec
base
Identifiantdebasededonnesretournparlafonctionsqlite_open.
requte
Textedelarequteexcuter.
Danslecasd'unordreSELECT,lafonctionsqlite_queryetourneunidentifiantdersultatderequteencasde
succs et FALSE en cas d'chec (avec affichage d'un message d'alerte) pour les autres ordres SQL, cette
fonctionretourneTRUEencasdesuccs.
Exemple
<?php
// ouverture
$base = sqlite_open('diane.dbf');
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte
$rsultat1 = sqlite_query($requte,$base);
echo "\$rsultat1 = ",
($rsultat1)? $rsultat1:'FALSE',"<BR>\n";
// dfinition d'une mauvaise requte
$requte = "SELECT * FROM article";
// excution de la requte
$rsultat2 = sqlite_query($requte,$base);
echo "\$rsultat2 = ",
($rsultat2)? $rsultat2:'FALSE',"<BR>\n";
?>
Rsultat
$rsultat1 = Resource id #3
Warning: sqlite_query() [function.sqlite-query]: no such table:
article in d:\scripts php\index.php on line 12
$rsultat2 = FALSE
Comme indiqu en introduction, la fonction sqlite_query excute la requte, indique si la requte s'est
excutecorrectementmaisnerenvoieaucunedonne.Ilvafalloirextraireleslignesdursultat.
Il existe une variante de sqlite_query, nomme sqlite_array_query, qui excute une requte et retourne
directementlersultatdansuntableau(prsenteciaprs).
Danslecasd'unordreSELECT,lersultatdelarequteexcuteparsqlite_queryestmisenbuffer.Ilexiste
une autre fonction, sqlite_unbuffered_query, qui possde la mme syntaxe que sqlite_query et permet
aussi d'excuter une requte, mais sans mettre le rsultat dans un buffer. Pour les requtes volumineuses,
sqlite_unbuffered_query consomme beaucoup moins de mmoire que sqlite_query et permet d'extraire la
premirelignebienplusrapidement :iln'yapasbesoind'attendrequelatotalitdursultatsoitmisenbuffer.
Parcontre,aprsexcutiondelarequteavec sqlite_unbuffered_query,iln'estpaspossibledeconnatrele
nombredelignesdursultat(voirciaprs).
Connatrelenombredelignesdanslersultat
Lafonctionsqllite_num_rowspermetdeconnatrelenombredelignesdanslersultat.
Syntaxe
Avec
rsultat
Identifiantdersultatderequteretournparlafonctionsqlite_query.
CettefonctionestutilisableuniquementpourlesrequtesSELECT.
Exemple
<?php
// ouverture
$base = sqlite_open('diane.dbf');
// dfinition de la requte
$requte = "SELECT * FROM articles";
// excution de la requte
$rsultat = sqlite_query($requte,$base);
// rcupration du nombre de lignes
$nombre = sqlite_num_rows($rsultat);
echo "Nombre d'articles : $nombre<BR>\n";
// dfinition de la requte
$requte = "SELECT * FROM articles WHERE prix > 40";
// excution de la requte
$rsultat = sqlite_query($requte,$base);
// rcupration du nombre de lignes
$nombre = sqlite_num_rows($rsultat);
echo "Nombre d'articles dont le prix est suprieur 40 : $nombre<BR>\n";
?>
Rsultat
Nombre d'articles : 4
Nombre d'articles dont le prix est suprieur 40 : 1
Lirelersultatdelarequte
Lersultatdel'excution(russie)d'unerequteSELECTpeuttreluparlafonctionsqlite_fetch_array.
Syntaxe
Avec
rsultat
Identifiantdersultatderequteretournparlafonctionsqlite_query.
type
Typedersultatgalunedesconstantessuivantes :
SQLITE_ASSOC,SQLITE_NUM,SQLITE_BOTH
Lafonction sqlite_fetch_arrayretournelalignecourantedursultatsouslaformed'untableau,chaqueligne
dutableaucorrespondantunecolonnedursultat.
S'iln'yaplusdeligneliredanslersultat,lafonctionretourneFALSE.
Letypedutableau(numriqueouassociatif)dpenddudeuximeparamtre :
SQLITE_NUM
Tableauindicesentiers.
Tableauassociatif.
SQLITE_BOTH
(valeur par dfaut)
Lesdeuxlafois.
Chaquecolonneestprsentedeuxfois.
Exemple:
Rsultatd'unfetchavec :
En cas d'utilisation, d'un alias de colonne dans la requte SELECT (exemple SELECT AVG(prix) prix_moyen
FROM articles),c'estl'aliasdecolonnequiestutiliscommecl.
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// ouverture
$base = sqlite_open('diane.dbf');
// excution de la requte
$rsultat = sqlite_query("SELECT * FROM articles",$base);
// Premier fetch sans deuxime paramtre
$ligne = sqlite_fetch_array($rsultat);
afficher_tableau($ligne,"sans deuxime paramtre");
// Deuxime fetch avec SQLITE_BOTH
$ligne = sqlite_fetch_array($rsultat,SQLITE_BOTH);
afficher_tableau($ligne,"SQLITE_BOTH");
// Troisime fetch avec SQLITE_ASSOC
$ligne = sqlite_fetch_array($rsultat,SQLITE_ASSOC);
afficher_tableau($ligne,"SQLITE_ASSOC");
// Quatrime fetch avec SQLITE_NUM
$ligne = sqlite_fetch_array($rsultat,SQLITE_NUM);
afficher_tableau($ligne,"SQLITE_NUM");
// Cinquime fetch de nouveau sans deuxime paramtre
// - normalement, plus de ligne
$ligne = sqlite_fetch_array($rsultat);
if (! $ligne) {
echo "<P><B>Cinquime fetch : plus rien</B>";
}
?>
Cetexemplepermetdevoir:
- chaque fetch, le pointeur interne avance, et que le fetch suivant retourne donc la ligne suivante, jusqu' avoir
parcouru toutes les lignes.
En cas d'utilisation d'un identifiant de rsultat non valide, la fonction sqlite_fech_array retourne FALSE et
affiche,enplus,unealertedutype :
Encasdebesoin,lafonctionsqlite_has_morepeuttreutilisepourdterminers'ilrestedeslignesextraire
dansunrsultat.
Syntaxe
Avec
rsultat
Identifiantdersultatderequteretournparlafonctionsqlite_query.
SQLite propose aussi une fonction, sqlite_array_query, qui permet d'excuter une requte et de retourner le
rsultat dans un tableau. Cette fonction est l'quivalent de l'appel la fonction sqlite_query suivi d'une srie
d'appelslafonctionsqlite_fetch_array(pourchaquelignedursultat),enbeaucoupplusperformant.
Syntaxe
Avec
Identifiantdebasededonnesretournparlafonctionsqlite_open.
requte
Textedelarequteexcuter.
type
Typedersultatgalunedesconstantessuivantes :
SQLITE_ASSOC,SQLITE_NUM,SQLITE_BOTH
Exemple
<?php
// inclusion du fichier qui contient la dfinition de
// afficher_tableau
include("fonctions.inc");
// ouverture
$base = sqlite_open('diane.dbf');
// dfinition de la requte
// - deux articles seulement
$requte = "SELECT * FROM articles LIMIT 2";
// excution de la requte et rcupration du
// rsultat dans un tableau
// - pas de troisime paramtre => SQLITE_BOTH
$rsultat = sqlite_array_query($requte,$base);
afficher_tableau($rsultat);
?>
Rsultat
0 =
0 = 1
identifiant = 1
1 = Abricots
libelle = Abricots
2 = 35.5
prix = 35.5
1 =
0 = 2
identifiant = 2
1 = Cerises
libelle = Cerises
2 = 48.9
prix = 48.9
Exempledecodepourlalectured'uneligne
Un premier type de lecture consiste souvent lire une seule ligne d'information dans une table (ou plusieurs
tablesavecjointure) :informationssurl'utilisateurquivientdeseconnecter,fiched'informationd'unarticle...
Exemple
<?php
// inclure un fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser les variables
$identifiant = "";
$libell = "";
$prix = "";
$message = "";
// Tester la faon dont le script est appel
Ilestrelativementsimpled'crireunefonctiongnriquepermettantdelireuneligne.
Exemple
<?php
function db_lire_ligne($requte) {
// la variable $ok est utilise pour savoir
// si tout se passe bien
// ouvrir la base
$ok = ( ($base = sqlite_open('diane.dbf')) != FALSE );
// excuter la requte et tester le rsultat pour affecter
// la variable $ok
if ($ok) {
$ok = ( ($rsultat = sqlite_query($requte,$base))
!= FALSE );
}
if ($ok) { // excution OK
// lire la ligne
$ligne = sqlite_fetch_array($rsultat);
}
// retourner $ligne ou FALSE en cas d'erreur
return ($ok)?$ligne:FALSE;
}
?>
Ilestpossible(souhaitable)d'amliorerlagestiondeserreurs(cf.Grerleserreurs).
Exemple d'utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// dfinir la requte
$requte = "SELECT * FROM articles WHERE identifiant= 1";
// lire le rsultat
$ligne = db_lire_ligne($requte);
if ($ligne) {
echo "$ligne[libelle] - $ligne[prix]";
}
?>
Abricots - 35.5
Exempledecodepourlalecturedetoutesleslignes
Un deuxime type de lecture consiste souvent afficher une liste d'lments extraits de la base (liste
d'utilisateurs,listed'articles...).
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// ouvrir la base
$ok = ( ($base = sqlite_open('diane.dbf')) != FALSE );
// excuter la requte de slection et charger directement
// les donnes dans un tableau
Le mme exemple peut tre crit de manire plus compacte, plus conome en mmoire et plus performante : le
fetchesteffectuaucoursdelaconstructiondelatableHTMLsurunerequtedontlersultatn'apastmis
enbuffer.
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// ouvrir la base
$ok = ( ($base = sqlite_open('diane.dbf')) != FALSE );
// excuter la requte de slection
// - le rsultat n'est pas mis en buffer
$requte = "SELECT * FROM articles";
$rsultat = sqlite_unbuffered_query($requte,$base);
// tester le rsultat
if (! $rsultat) { // requte pas OK
// message d'erreur
$message .= "Erreur.\n";
// prparer le message pour l'affichage
$message = vers_page($message);
}
Pourpermettrel'utilisateurd'agirsurlaliste,ilestpossibled'imbriquerunformulaireoudesliensaveclatable
HTML.
Exemple
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// initialiser la variable de message
$message = "";
// ouvrir la base
$ok = ( ($base = sqlite_open('diane.dbf')) != FALSE );
// excuter la requte de slection
// - le rsultat n'est pas mis en buffer
$requte = "SELECT * FROM articles";
$rsultat = sqlite_unbuffered_query($requte,$base);
// tester le rsultat
if (! $rsultat) { // requte pas OK
// message d'erreur
$message .= "Erreur.\n";
// prparer le message pour l'affichage
$message = vers_page($message);
}
// Affichage de la page ...
?>
<HTML>
<HEAD><TITLE>Liste des articles</TITLE></HEAD>
<BODY>
<!-- construction d'une table HTML l'intrieur d'un
---- formulaire -->
<FORM METHOD="POST">
<TABLE BORDER="1" CELLPADDING="4" CELLSPACING="0">
<!-- ligne de titre -->
<TR ALIGN=\"center\">
<TH>Libell</TH><TH>Prix</TH><TH>Case</TH><TH>Lien</TH>
</TR>
<!-- code PHP pour les lignes du tableau -->
<?php
Rsultat
Sur le lien, la place du code JavaScript, il est possible de mettre une vraie URL et d'enchaner sur une autre
page (voir le chapitre Grer les sessions pour comprendre comment placer un paramtre dans l'URL et pouvoir
ainsipasseruneinformation,icil'identifiantchoisi,uneautrepage).
Encequiconcerneletraitementduformulaire,toutestenvisageable.
Lencore,pourlalecturedeplusieurslignes,unefonctiongnriqueestpossible.
Exemple
<?php
function db_lire_lignes_dans_tableau($requte) {
// la variable $ok est utilise pour savoir
// si tout se passe bien
// ouvrir la base
$ok = ( ($base = sqlite_open('diane.dbf')) != FALSE );
// excuter la requte et rcuprer le rsultat directement
// dans un tableau
if ($ok) {
$tableau = sqlite_array_query($requte,$base);
// tester le rsultat pour affecter la variable $ok
$ok = ( $tableau != FALSE );
}
// retourner $tableau ou FALSE en cas d'erreur
return ($ok)?$tableau:FALSE;
}
?>
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
4 articles
Premier article : Abricots - 35.5
Mettrejourdesdonnes
MettrejourdesdonnesconsisteexcuterdesrequtesINSERT(cration),UPDATE(modification)ouDELETE
(suppression).
L'excutiondecetypederequtes'effectueaveclafonctionsqlite_query,commepourunerequteSELECT.
Encomplment,deuxfonctionssontintressantes :sqlite_changesetsqlite_last_insert_rowid.
Syntaxe
Avec
base
Identifiantdebasededonnesretournparlafonctionsqlite_open.
Siladernirerequteachou,lafonctionsqlite_changesretourne0.
Lafonction sqlite_last_insert_rowidretournelavaleurdudernieridentifiantgnrparunerequteINSERT
surunebase,pourunecolonnedclareenINTEGER PRIMARY KEY.
Syntaxe
Avec
base
Identifiantdebasededonnesretournparlafonctionsqlite_open.
Siaucunidentifiantn'atgnrautomatiquement,lafonctionsqlite_last_insert_rowidretourne0.
La requte INSERT n'a pas besoin d'tre la dernire requte excute sur la base.
Exemples
<?php
Rsultat
Crerdesformulairesquipermettentdemettrejourlesdonnesesttrssimple.
titred'exemple,nousallonsconstruireunformulairequipermetderaliserunesaisieenliste.
Prsentation du formulaire
Chaquelignedutableaucontient4zonesdeformulairequisontnommes(optionNAMEdelabalise<INPUT>)de
lamaniresuivante :
Colonne Nom
Identifiant saisie[i][modifier]
Libell saisie[i][libelle]
Prix saisie[i][prix]
Supprimer saisie[i][supprimer]
L'indice i est l'identifiant de l'article pour les lignes qui existent et un numro compris entre 1 et 5 pour les
lignesvides.Lazonedelacolonne Identifiantestunezonemasque(TYPE="hidden")quivatreutilisepour
identifierleslignesdanslesquellesl'utilisateuraeffectuunemodification.
Avec ce processus de nommage, toute la saisie sera rcupre dans le script PHP sous la forme d'un tableau
multidimensionnel nomm $lignes. Chaque ligne du tableau correspond une ligne du formulaire avec la cl
gale l'identifiant (ou 1 5 pour les nouvelles lignes) et la valeur gale un tableau associatif donnant les
lmentssaisis.
Pour identifier les lignes modifies par l'utilisateur, les zones de saisie du libell et du prix des lignes existantes
contiennentlecodeJavaScriptsuivant :
onChange="document.formulaire[$n].value=1"
Ce code JavaScript a pour effet, chaque fois que la zone en question est modifie, de mettre un 1 dans la
zone masque associe la ligne. Le formulaire s'appelant formulaire (<FORM NAME = "formulaire"...),
l'expression document.formulaire[n] dsigne la nime zone du formulaire formulaire du document courant,
la premire zone du formulaire ayant le numro 0. Dans le source, la variable $n est calcule pour chaque ligne
$i du formulaire par la formule $n = 4 * ($i - 1) : la zone cache de la ligne 1 a le numro 0 (c'est la
premireduformulaire),celledelaligne2lenumro4etainsidesuite.
Cetexemplepeut(doit)treamliorpour :
Source
Grerleserreurs
Syntaxe
Avec
base
Identifiantdebasededonnesretournparlafonctionsqlite_open.
numro
Numrod'erreurSQLite.
La fonctionsqlite_last_errorretournelenumrod'erreurdeladernireoprationeffectuesurunebase.La
fonctionsqlite_error_stringretournelemessaged'erreurassociunnumrod'erreur.
Exemple
<?php
// ouverture
$base = sqlite_open('diane.dbf');
// une bonne requte pour commencer
$requte = "SELECT * FROM articles";
$rsultat = sqlite_query($requte,$base);
$code = sqlite_last_error($base);
$message = sqlite_error_string($code);
echo "1 : $code - $message<BR>";
Rsultat
1 : 0 - not an error
Warning: sqlite_query() [function.sqlite-query]: no such table:
article in d:\scripts php\index.php on line 12
2 : 1 - SQL logic error or missing database
Warning: sqlite_query() [function.sqlite-query]: PRIMARY KEY
must be unique in d:\scripts php\index.php on line 19
3 : 19 - constraint failed
Warning: sqlite_query() [function.sqlite-query]: no such table:
article in d:\scripts php\index.php on line 25
4 : 1 - SQL logic error or missing database
Warning: mysql_fetch_assoc(): supplied argument is not a valid
MySQL result resource in d:\scripts php\index.php on line 29
5 : 1 - SQL logic error or missing database
Le point 5 illustre le fait que les erreurs lies l'utilisation d'une ressource de rsultat non valide n'est pas une
erreur SQLite. Dans ce cas, la fonction sqlite_last_error n'est pas rinitialise et ne retourne donc pas
d'erreurspcifique :lecodeetlemessagedupoint 5sontenfaitceuxdupoint4.
En pratique, les fonctions sqlite_last_error et sqlite_error_string sont employes aprs l'excution des
requtes mais ne sont d'aucune utilit sur l'ouverture de la base et sur les "fetch". Pour l'ouverture de la base,
nousavonsvuquelafonctionsqlite_openpermettaitdercupreruneerreurventuelledansunevariable.
Par ailleurs, nous verrons au chapitre Grer les erreurs dans un script PHP comment supprimer l'affichage des
alertes.
Cesfonctionspeuventtremisesenuvretitred'exemplesurunedenosfonctionsgnriques.
Source
<?php
function db_lire_ligne($requte, &$erreur) {
// dans cette nouvelle version, db_lire_ligne prend un
// deuxime paramtre par rfrence dans lequel un numro
// et un message seront stocks en cas d'erreur (sous la
// forme d'un tableau)
// initialiser $erreur
$erreur = array(0,""); // numro = 0, message vide
// ouvrir la base et tester le rsultat pour affecter
// la variable $ok
$base = sqlite_open('diane.dbf',666,$erreur_ouverture);
$ok = empty($erreur_ouverture);
// en cas d'erreur, affecter $erreur
if (! $ok ) {
// un code d'erreur fictif est utilis
$erreur = array(-1,$erreur_ouverture);
}
Utilisation
<?php
// inclure le fichier qui contient les diffrentes fonctions
// gnrales
require("fonctions.inc");
// premier appel avec une erreur
$requte = "SELECT * FROM article WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
// deuxime appel correct
$requte = "SELECT * FROM articles WHERE identifiant = 1";
if (! ($ligne = db_lire_ligne($requte,$erreur))) {
echo "$erreur[0] - $erreur[1]<BR>";
} else {
echo "$ligne[libelle] - $ligne[prix]<BR>";
}
?>
Rsultat
Prambule
Nous avons vu dans le chapitre Gestion des formulaires que PHP proposait une fonctionnalit, appele "magic
quotes", dont l'objectif principal est de rsoudre un problme li l'enregistrement des donnes, dans une base
dedonnes,eneffectuantunencodagesurlesdonnessaisiesdansunformulaire.
<?php
// donne qui pose problme (peut tre saisie dans un formulaire)
$libell = "Pomme d'api";
$prix = 10;
// requte
$requte = "INSERT INTO articles(libelle,prix)
VALUES('$libell',$prix)";
echo "$requte<BR>";
// Excution avec MySQL
echo "<P><B>MySQL</B><BR>";
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
$rsultat = mysql_query($requte);
echo mysql_error()."<BR>"; // MySQL ne gnre pas d'alerte
// Excution avec Oracle
echo "<P><B>Oracle</B><BR>";
$connexion = oci_connect("demeter","demeter","diane");
$rsultat = oci_execute(oci_parse($connexion,$requte));
// Excution avec SQL Serveur
echo "<P><B>SQL Serveur</B><BR>";
$connexion = mssql_connect("diane","demeter","demeter");
$rsultat = mssql_query($requte);
// Excution avec SQLite
echo "<P><B>SQLite</B><BR>";
$base = sqlite_open('diane.dbf');
$rsultat = sqlite_query($requte,$base);
?>
Rsultat
Pour rgler ce problme, il faut indiquer la base que les apostrophes l'intrieur de la chane ne sont pas les
dlimiteurs de la chane, gnralement en faisant prcder l'apostrophe d'un caractre
"magique" ("d'chappement") : c'est le caractre antislash (\) pour MySQL ou apostrophe (') pour MySQL et
d'autresbasescommeOracle,SybaseouMicrosoftSQLServer.
<?php
// donne corrige (valable pour toutes les bases)
$libell = "Pomme d''api";
$prix = 10;
// requte
$requte = "INSERT INTO articles(libelle,prix)
VALUES('$libell',$prix)";
echo "$requte<BR>";
// Excution avec MySQL
echo "<P><B>MySQL</B><BR>";
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
$rsultat = mysql_query($requte);
echo mysql_error()."<BR>"; // MySQL ne gnre pas d'alerte
// Excution avec Oracle
echo "<P><B>Oracle</B><BR>";
$connexion = oci_connect("demeter","demeter","diane");
$rsultat = oci_execute(oci_parse($connexion,$requte));
// Excution avec SQL Serveur
echo "<P><B>SQL Serveur</B><BR>";
$connexion = mssql_connect("diane","demeter","demeter");
$rsultat = mssql_query($requte);
// Excution avec SQLite
echo "<P><B>SQLite</B><BR>";
$base = sqlite_open('diane.dbf');
$rsultat = sqlite_query($requte,$base);
?>
Rsultat
EncequiconcerneMySQL,unencodageaveclecaractreantislash(\)auraitaussifonctionne(maispasavec
lesautresbases).
La fonctionnalit "magic quotes" d'encodage automatique rpond cette problmatique : si elle est active
(directive de configuration magic_quotes_gpc = on), toutes les donnes issues d'un formulaire (mthodes GET
ouPOST),d'uneURL(mthodeGET)oud'uncookiesontautomatiquementencodesaveclecaractreantislash
(\),ouapostrophe(')siladirectivedeconfigurationmagic_quotes_sybaseeston.
Malheureusement,nousavonsvuquecettefonctionnalit"magicquotes"posaitd'autresproblmesvisvis :
Pour mmoire, la solution propose consiste s'assurer que les donnes sont charges dans des variables sans
encodageetfairecequ'ilfautaumomentdel'enregistrementdanslabase c'estcequenousallonsvoirdans
cechapitre.
Chargementdesdonnesenprovenanced'unebase
Unencodage"magicquotes"automatiqueestpossiblesurlesdonnesluesdansunebase,maisuniquementpour
MySQLetSQLServer.
Si la directive de configuration magic_quotes_runtime est on, toutes les donnes lues dans une base (ou
dans un fichier) ont automatiquement un encodage avec un anti slash (\) sur les caractres apostrophe ('),
guillemet(")etbiensrantislash(\).
Siladirectiveestoff,aucunencodageneseproduit.
<?php
// requte
$requte = "SELECT libelle FROM articles
WHERE identifiant = 5";
// Excution avec MySQL
echo "<B>MySQL</B><BR>";
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
$rsultat = mysql_query($requte);
$article = mysql_fetch_row($rsultat);
echo "$article[0]<BR>";
// Excution avec Oracle
echo "<B>Oracle</B><BR>";
$connexion = oci_connect("demeter","demeter","diane");
oci_execute($rsultat = oci_parse($connexion,$requte));
$article = oci_fetch_row($rsultat);
echo "$article[0]<BR>";
// Excution avec SQL Serveur
echo "<B>SQL Serveur</B><BR>";
$connexion = mssql_connect("diane","demeter","demeter");
$rsultat = mssql_query($requte);
$article = mssql_fetch_row($rsultat);
echo "$article[0]<BR>";
// Excution avec SQLite
echo "<B>SQLite</B><BR>";
$base = sqlite_open('diane.dbf');
$rsultat = sqlite_query($requte,$base);
$article = sqlite_fetch_array($rsultat);
echo "$article[0]<BR>";
?>
MySQL
Pomme d'api
Oracle
Pomme d'api
SQL Serveur
Pomme d'api
SQLite
Pomme d'api
MySQL
Pomme d\'api
Oracle
Pomme d'api
SQL Serveur
Pomme d\'api
SQLite
Pomme d'api
MySQL
Pomme d''api
Oracle
Pomme d'api
SQL Serveur
Pomme d''api
SQLite
Pomme d'api
Syntaxe
entier get_magic_quotes_runtime()
boolen set_magic_quotes_runtime(entier valeur)
valeur
Nouvellevaleurdeladirectivemagic_quotes_runtime
0 =dsactiv(off),1=activ(on
Lafonctionset_magic_quotes_runtimeretourneTRUEsilechangements'esteffectuetFALSEautrement.
Lafonctionget_magic_quotes_runtimeretourne0sil'optionestdsactiveet1sielleestactive.
Exemple
<?php
// requte
$requte = "SELECT libelle FROM articles
WHERE identifiant = 5";
// Excution avec MySQL : magic_quotes_runtime = 1
echo "<B>set_magic_quotes_runtime(1)</B><BR>";
set_magic_quotes_runtime(1);
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
$rsultat = mysql_query($requte);
$article = mysql_fetch_row($rsultat);
echo "$article[0]<BR>";
// Excution avec MySQL : magic_quotes_runtime = 0
echo "<B>set_magic_quotes_runtime(0)</B><BR>";
set_magic_quotes_runtime(0);
$connexion = mysql_connect();
$ok = mysql_select_db("diane",$connexion);
$rsultat = mysql_query($requte);
$article = mysql_fetch_row($rsultat);
echo "$article[0]<BR>";
?>
set_magic_quotes_runtime(1)
Pomme d\'api
set_magic_quotes_runtime(0)
Pomme d'api
La fonction set_magic_quotes_runtime sera particulirement intressante avec MySQL et SQL Server pour
crireuncodeindpendantdelaconfiguration :avantchaqueexcutiond'unerequteSELECT,ilsuffitd'appeler
cettefonctionaveclavaleur0ou1correspondantlastratgiequevousavezadopte.
La fonction db_lire_ligne (ciaprs)peutainsitreadapte,suivantlastratgiedenepasavoirdedonnes
encodesdanslesvariables.
Exemple
<?php
function db_lire_ligne($requte, &$erreur) {
// initialiser $erreur
$erreur = array(0,""); // numro = 0 message vide
// pas d'encodage sur les donnes lues dans la base
$ok = set_magic_quotes_runtime(0);
// tablir la connexion
$ok = ($connexion = mysql_connect());
if ($ok) { // c'est bon
// slectionner la base de donnes
$ok = mysql_select_db("diane",$connexion);
}
if ($ok) { // c'est toujours bon
// excuter la requte et tester le rsultat pour
// affecter la variable $ok
$ok = ( ($rsultat = mysql_query($requte)) != FALSE );
Misejourdesdonnesdanslabase
Pour la mise jour des donnes dans la base, il faut s'assurer que toutes les donnes de type "texte" ont le
caractred'chappementadapt(\ou'pourMySQL,'pourlesautresbases)devantchaqueapostrophe.
Sivousavezadoptunestratgiedanslaquelletouteslesvariablescontiennentdesdonnesencodes,iln'ya
rienfaire.
l'inverse,sivousavezadoptunestratgie(plusnaturelle ?)danslaquelletouteslesvariablesnecontiennent
pasdedonnesencodes,ilconvientd'assurerl'chappementdesapostrophesdanslesdonnesenvoyesla
base.
Lesfonctionsaddslashesetmysql_escape_stringpeuventtreutilises.
Syntaxe
valeur
Chanedecaractreschapper.
La fonction mysql_escape_stringajouteunantislash (\) devant tous les caractres apostrophe ('), guillemet
(") et antislash (\) trouvs dans la chane valeur, quelle que soit la valeur de la directive de configuration
magic_quotes_sybase.
Lafonction addslashesajouteunantislash(\)devanttouslescaractresapostrophe('),guillemet(")etanti
slash (\) trouvs dans la chane valeur, si la directive de configuration magic_quotes_sybase est off. Par
contre, si la directive de configuration magic_quotes_sybase est on, la fonction addslashes se contente
d'ajouteruneapostrophe(')devantlescaractresapostrophe(')trouvsdanslachanevaleur.
Exemple
<?php
$valeur = " ' \ \" "; // c'est pour tester ...
echo addslashes($valeur)."<BR>";
echo mysql_escape_string($valeur)."<BR>";
?>
\' \\ \"
\' \\ \"
Aucunediffrenceentrelesdeuxfonctions.
'' \ "
\' \\ \"
Il n'y a pas de changement pour la fonction mysql_escape_string mais un comportement diffrent pour la
fonctionaddslashes.Conclusions :
- La fonction mysql_escape_string est intressante, car indpendante de la configuration, mais elle est valable
uniquement pour MySQL.
- La fonction addslashes est intressante car elle est valable pour toutes les bases, mais elle est dpendante de la
configuration.
La solution, si vous souhaitez avoir un code qui fonctionne avec toutes les bases et qui soit indpendant de la
configuration,estd'criresaproprefonction.
Exemple
<?php
function vers_base($valeur) {
// le seul caractre qui pose vraiment problme est l'apostrophe (') ;
// c'est donc le seul qui est chapp par cette fonction
// une solution valable pour toutes les bases consiste
// l'chapper par lui-mme => remplacement de ' par ''
return str_replace("'","''",$valeur);
}
$valeur = " ' \ \" "; // c'est pour tester ...
echo vers_base($valeur)."<BR>";
?>
Rsultat
'' \ "
Unetellefonctionpeutfacilementtreappelelorsdelaconstructiond'unerequte.
Exemple
<?php
function vers_base($valeur) {
// le seul caractre qui pose vraiment problme est l'apostrophe (') ;
// c'est donc le seul qui est chapp par cette fonction une solution
// valable pour toutes les bases consiste
// l'chapper par lui-mme => remplacement de ' par ''
return str_replace("'","''",$valeur);
}
$libell = "Pomme d'api";
$prix = 10;
// l'utilisation du sprintf rend plus lisible la construction de la requte
$requte = sprintf(
"INSERT INTO articles(libelle,prix) VALUES('%s',%s)",
vers_base($libell),
$prix);
echo "$requte<BR>";
?>
Rsultat
<?php
function construire_requte($requte) {
// rcuprer le nombre de paramtres
$nombre_param = func_num_args();
// boucler sur tous les paramtres partir du deuxime
// (le premier contient la requte de base)
for($i=1;$i<$nombre_param;$i++) {
// rcuprer la valeur du paramtre
$valeur = func_get_arg($i);
// si c'est une chane, remplacer ' par ''
if (is_string($valeur)) {
$valeur = str_replace("'","''",$valeur);
}
// mettre la valeur son emplacement %n (n = $i)
$requte = str_replace("%$i",$valeur,$requte);
}
// retourner la requte
return $requte;
}
// des variables contiennent des valeurs venant de quelque part ...
$libell = "Pomme d'api";
$prix = 10;
// construction de la requte
$requte = construire_requte(
"INSERT INTO articles(libelle,prix) VALUES('%1',%2)",
$libell,
$prix);
echo "$requte<BR>";
?>
Rsultat
Il n'y a pas de problme de ce type lors de l'utilisation de requtes paramtres avec Oracle.
Exemple
<?php
// connexion
$connexion = oci_connect("demeter","demeter","diane");
// requte INSERT (paramtre)
$requte = "INSERT INTO articles(libelle,prix)
VALUES(:p1,:p2)";
// analyse
$curseur = oci_parse($connexion,$requte);
// association entre les variables et les paramtres
oci_bind_by_name($curseur,":p1",$libell,50);
oci_bind_by_name($curseur,":p2",$prix,32);
// excution de la requte
$libell = "Pomme d'api"; // pas de problme avec d'api /$prix = 10;
$ok = oci_execute($curseur); // COMMIT automatique
$nombre = oci_num_rows($curseur);
echo "$nombre article insr.<BR>";
?>
Rsultat
1 article insr.
Le protocole HTTP (HyperText Transfer Protocol) est un protocole "sans tat" : rien ne permet d'identifier que
c'estlemmeutilisateurquitaitprcdemmentsurlapageAetqui,maintenant,accdelapage B.
En ce qui concerne PHP, nous savons maintenant qu'une variable a une porte gale au script dans lequel elle
estdfinie,etqu'elleexisteuniquementletempsdel'excutionduscript.
Exemple
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="accueil.php" METHOD="POST">
Nom : <INPUT TYPE="text" NAME="nom" VALUE=""><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
</BODY>
</HTML>
<?php
// traitement du formulaire
if (! empty($_POST)) {
// rcupration de la valeur saisie
$nom = $_POST["nom"];
}
// Affichage de la page d'accueil
?>
<HTML>
<HEAD><TITLE>Accueil</TITLE></HEAD>
<BODY>
Bonjour <?php echo $nom; ?> !<BR>
<!-- lien vers une autre page -->
<A HREF="action.php">Action</A>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Action</TITLE></HEAD>
<BODY>
<!-- affichage du nom de l'utilisateur -->
Bonjour <?php echo $nom; ?> !<BR>
Action...
</BODY>
</HTML>
Rsultat
- Rsultat du clic sur le lien (si les erreurs de niveau E_NOTICE ne sont pas affiches) :
Leproblmeestlemmesilescriptaccueil.phpestappeldenouveauparlelien.
Exemple
<?php
// traitement du formulaire
if (! empty($_POST)) {
// rcupration de la valeur saisie
$nom = $_POST["nom"];
}
// Affichage de la page d'accueil
?>
<HTML>
<HEAD><TITLE>Accueil</TITLE></HEAD>
<BODY>
Bonjour <?php echo $nom; ?> !<BR>
<!-- lien vers une autre page -->
<A HREF="accueil.php">Accueil</A>
</BODY>
</HTML>
Rsultat
- Rsultat du clic sur le lien (si les erreurs de niveau E_NOTICE ne sont pas affiches) :
Lersultatestlemme :lavaleurdelavariablelafindelapremireexcutionduscriptn'estpasconserve
lafinduscript(problmededuredevie).
Or,unsiteinteractifquinesecontentepasd'afficherdespageslesunesderrirelesautres,asouventbesoin,
du point de vue de la logique applicative, d'identifier un utilisateur d'une page l'autre et de conserver des
informations relatives cet utilisateur d'une page l'autre (typiquement, un panier lectronique constitu par
l'utilisateursurunepagedoittoujourstredfinisurlapagepermettantlepaiement).
Le terme "session" dsigne la priode de temps correspondant la navigation continue d'un utilisateur sur un
site. "Grer les sessions" signifie donc tre en mesure d'identifier l'instant o un nouvel utilisateur accde une
pagedusiteetdeconserverdesinformationsrelativescetutilisateurjusqu'cequ'ilquittelesite.L'utilisateur
n'est pas forcment un utilisateur authentifi par un nom et un mot de passe mais peut trs bien tre un
"anonyme",nonrfrencparlesite,quieffectueunachat.Deplusenplus,lessitesinteractifsproposentdes
fonctionnalitsd'identification(membre,abonn...)carcelapermetdeconserverdesinformationssurl'utilisateur
d'unevisitel'autre(prfrencesparexemple).Cettepossibilitestgalementtudiedanscechapitremaisdu
pointdevuedelanotiondesession,lavisitedel'utilisateurlevendredicorrespondraunesessiondiffrentede
savisitedulundi,mmesicertainesinformationssaisieslelundisontsusceptiblesd'trerestitueslevendredi.
Cechapitreapourobjectifdeprsenterlesdiffrentestechniquesquivontpermettre,d'unepartd'identifierun
utilisateuret,d'autrepart,de"suivre"cetutilisateuretlesdonnesquiluisontassocies,d'unepagel'autre.
Nous allons aussi tudier une variante qui consiste identifier un utilisateur et conserver des informations
d'unevisiteuneautre.
Nous allons ensuite aborder pour la gestion des sessions, les mthodes "artisanales" puis les nouvelles
fonctionnalitsoffertesparPHPdepuislaversion4.
Enfin, nous allons terminer ce chapitre en voquant les techniques permettant de conserver des informations
d'unevisitel'autre.
Vued'ensemble
Certains sites ont besoin d'authentifier les utilisateurs qui accdent au site afin de vrifier que ces derniers sont
bieninscrits.
Cetteauthentificationcomprendgnralementdeuxtapes :
Saisiedel'identification
L'identificationpeuttresaisiededeuxmanires :
Formulaire
Ilesttrssimpledecrerunpetitformulairepermettantl'utilisateurdesaisirunnometunmotdepasse.
Exemple de script PHP (login.php) qui affiche ce formulaire (fonction de vrification utilisateur existe, pour l'instant non
dfinie)
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie est correcte
// alatoire, en attendant mieux...
return (bool) rand(0,1);
}
// initialisation des variables
$identifiant = "";
$mot_de_passe = "";
$message = "";
// traitement du formulaire
if (isset($_POST["connexion"])) {
// rcuprer les informations saisies
$identifiant =
valeur_saisie($_POST["identifiant"]);
$mot_de_passe =
valeur_saisie($_POST["mot_de_passe"]);
// vrifier que l'utilisateur existe
if (utilisateur_existe($identifiant,$mot_de_passe)) {
// l'utilisateur existe ...
// typiquement, partir sur une autre page et interrompre le script
header("location: accueil.php");
exit;
} else {
// l'utilisateur n'existe pas ...
// typiquement, afficher un message et proposer de
// nouveau l'identification
$message = "Identification incorrecte. ";
$message .= "Essayez de nouveau.";
// laisser le formulaire s'afficher de nouveau ...
}
}
?>
<HTML>
<HEAD><TITLE>MonSite.com</TITLE></HEAD>
<BODY>
<FORM ACTION="login.php" METHOD="POST">
<TABLE BORDER=0>
<TR>
Rsultat
- Affichage initial :
- Saisie :
L'utilisationd'unezonedetypepasswordpermetdemasquerlasaisiedumotdepasse.
Si la saisie est incorrecte, la page est propose de nouveau. Dans le cas contraire, une page d'accueil est
affiche.
AuthentificationHTTP
l'aide de la fonction header, il est possible de demander au navigateur d'afficher une fentre de dialogue
invitantl'utilisateursaisirunnometunmotdepasse.Lemessaged'entteenvoyerest :
Sil'utilisateurcliquesurleboutonOK,lescriptestappeldenouveauaveclesvaleurssaisiesdisponiblesdansles
Par scurit, il est prfrable de rcuprer ces informations via le tableau associatif $_SERVER, avec les cls
PHP_AUTH_USER et PHP_AUTH_PW. Dans la pratique, ce n'est pas une obligation, car nous vrifierons ensuite que
l'utilisateurexistebien.Sicetutilisateur nousaenvoyl'informationsanspasserparledialogue,nouslesaurons.
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie est correcte
// alatoire, en attendant mieux...
return (bool) rand(0,1);
}
function Authentification($message) {
header("WWW-Authenticate: Basic realm=\"$message\"");
// si l'utilisateur clique sur le bouton annuler,
// les lignes suivantes s'excutent (sinon, le script est
// de nouveau appel mais avec $PHP_AUTH_USER renseign
// et le script ne passera plus par ici)
// typiquement, afficher un message et proposer
// l'utilisateur d'essayer de nouveau
echo "<FONT COLOR=\"red\">Vous devez saisir un nom et
un mot de passe pour accder au site.</FONT><BR>";
echo "<A HREF=login.php>Essayer de nouveau</A>";
exit;
}
if (! isset($_SERVER["PHP_AUTH_USER"])) {
// pas de variable $PHP_AUTH_USER = premier appel du script
// demande d'identifiation
Authentification("MonSite.com");
} else {
// variable $PHP_AUTH_USER existe = appel aprs saisie
// rcuprer les information saisies
$identifiant =
valeur_saisie($_SERVER["PHP_AUTH_USER"]);
$mot_de_passe =
valeur_saisie($_SERVER["PHP_AUTH_PW"]);
// vrifier que l'utilisateur existe
if (utilisateur_existe($identifiant,$mot_de_passe)) {
// l'utilisateur existe ...
// typiquement, partir sur une autre page et interrompre le script
header("location: accueil.php");
exit;
} else {
// l'utilisateur n'existe pas ...
// Essayer de nouveau
Authentification
("MonSite.com : identification incorrecte");
}
}
?>
Rsultat
Pour l'instant, sur les deux exemples, l'accs la page d'accueil n'est pas protg : un utilisateur qui demande cette page y
accde sans problme.
Vrifierl'identificationsaisie
Quelle que soit la mthode d'identification utilise au point prcdent, il convient ensuite de vrifier que les
informationssaisiescorrespondentbienunutilisateur"connu".
Typiquement,cecontrleestralisl'aided'unebasededonnesquicontientlalistedesutilisateurs,ainsique,
sansdouted'autresinformations.
Nousallonsprendrecommehypothsedetravail,pourlasuite,l'utilisationd'unebasemySQL,etdanscettebase,
l'existenced'unetableutilisateursprsentantdeuxcolonnes,identifiantetmot_de_passe.
Exemple
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifieque l'identification saisie est correcte
// dfinition et excution de la requte
$requte = sprintf(
"SELECT * FROM utilisateurs WHERE identifiant = '%s'",
vers_base($identifiant));
$erreur = "";
$utilisateur = db_lire_ligne($requte,$erreur);
// l'identification est bonne s'il existe un utilisateur ayant
// l'identifiant saisi (! empty...) et que le mot de passe corresponde
// ($utilisateur...== ...)
$existe = ((! empty($utilisateur)) and
($utilisateur["mot_de_passe"] == $mot_de_passe));
// rsultat
return $existe;
}
?>
D'autres mthodes d'authentification, qui ne s'appuient pas sur une base de donnes sont envisageables (simple
fichierparexemple).
Dans de nombreuses situations, dont celles relatives la gestion des sessions, il est ncessaire de gnrer des
identifiantsuniques.
Eneffet,danslecontextedelagestiondessessions,cetidentifiantestsouventutilecarilpermet,commeson
noml'indique,d'identifierlessessionsetdonc,depouvoirlesdiffrencier.
PHPproposelafonctionuniqidpourgnrerdesidentifiantsuniques.
Syntaxe
prfixe
Prfixeajouterl'identifiant.
Mettreunechanevideounerienmettresivousnesouhaitezpasdeprfixe.
La fonction uniqid retourne une chane de treize caractres (sans compter le prfixe) calcule partir de
l'heurecouranteenmicrosecondes.
Exemple
<?php
echo uniqid()."<BR>";
echo uniqid()."<BR>";
echo uniqid("abc")."<BR>";
?>
Rsultat
3b9651f96756f
3b9651f9675b7
abc3b9651f9675e5
Cet exemple montre que l'identifiant gnr est unique, mme si la diffrence entre deux appels successifs est
faible.Parcontre,l'identifiantgnrpeuttrejuginsuffisammentalatoireetunpeutropfaciledterminer.
Une technique classique consiste alors crypter l'identifiant gnr. La fonction md5 permet de le faire trs
facilement,enutilisantunemthodeMD5.
Syntaxe
Valeur
Chanecrypter.
Lafonctionmd5retournelachanecrypte.
Exemple
<?php
echo md5("olivier");
?>
Rsultat
d3ca5dde60f88db606021eeba2499c02
<?php
echo md5(uniqid())."<BR>";
echo md5(uniqid())."<BR>";
echo md5(uniqid())."<BR>";
?>
Rsultat
7de6a154b916f6f96e3031dd002d0a3e
d45dd6c61405f3462219c2b0b8ec6865
790bcbaf32a4fcb76f6ee8fdf8b1ecfd
Lenouvelidentifiantcomprend32caractresilest,maintenant,plusalatoireetmoinsfaciledterminer.
Pour les paranoaques de la scurit, il est possible d'aller encore plus loin en utilisant, en plus, un prfixe
alatoire.
Exemple
<?php
// gnration d'identifiants prfixe alatoire crypts
echo md5(uniqid(rand()))."<BR>";
echo md5(uniqid(rand()))."<BR>";
echo md5(uniqid(rand()))."<BR>";
?>
Rsultat
7b8d690bd713a6486d1bea0b0444da66
85d53b9cf512f40484d9c5eecd2f9978
cb7b9243a45ff2beb5a57fde09a9d7a5
Unefonctiongnriquepeuttrecritepourdfinirunidentifiantunique.
Exemple
<?php
function identifiant_unique() {
// gnration de l'identifiant
return md5(uniqid(rand()));
}
?>
Principe
L'URL(UniformResourceLocator)peuttreutilisepourpasserdesinformationsd'unepageuneautre.
Syntaxe
url_classique?nom=valeur[&...]
Le point d'interrogation (?) introduit la liste des paramtres de l'URL spars par le caractre perluette (&)
chaqueparamtreestconstituparuncouplenom/valeursouslaformenom=valeur.
Exemples
www.monsite.com/info/accueil.php?prenom=Olivier
chercher.php?prenom=Olivier&nom=HEURTEL
En PHP, les paramtres passs l'URL correspondant un script, sont disponibles dans ce script sous la forme
devariablessansavoirbesoind'effectuerlamoindreanalysedel'URL.
Lesprincipesdercuprationdelavariablessontlesmmesquepourlesvaleurssaisiesdansunformulaire(cf.
chapitreGestiondesFormulaires).
Tous les paramtres de l'URL sont automatiquement enregistrs dans le tableau associatif $_GET : la cl du
tableauestgaleaunomduparamtre.
Exemple
- Script page1.php :
<?php
// initialisation d'une variable
$nom="Olivier";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=<?php echo $nom; ?>">Page 2</A>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=Olivier">Page 2</A>
</BODY>
</HTML>
- Script page2.php
<?php
// rcupration des informations passes dans l'URL
$nom=$_GET["nom"];
echo $nom;
?>
Rsultat
Ainsi, des variables dfinies dans un script peuvent tre transmises un autre script. C'est la valeur qui est
transmise, pas la variable ellemme rien n'interdit dans le script cible de rcuprer la valeur pour la mettre
dansunevariableportantunautrenom.
Silavaleurtransmettrenecontientpasdecaractresspciaux(espace,perluette(&),pointd'interrogation
(?), etc.), elle peut tre place directement dans l'URL comme indiqu prcdemment. Dans le cas contraire, il
estncessairedel'encoderpourviterquecescaractresparticulierssoientmalinterprts.
Sur l'exemple prcdent, si la variable contient "Olivier & Xavier", seul "Olivier" sera rcupr dans la variable
$noml'arrivecarle&estinterprtcommelesparateurdeparamtre.
Cetencodagepeuttreralistrsfacilementgrceauxfonctionsurlencodeouraw-urlencode.
Syntaxe
valeur
Chaneencoder.
Ces deux fonctions retournent la chane aprs encodage. L'encodage consiste remplacer tous les caractres
nonalphanumriquesparunesquence%xy, xytantunnombrehexadcimalgalaucodeASCIIducaractre.
Ladiffrenceentrelesdeuxfonctionsestsubtileetconcernejustelecaractreespace :lafonctionurlencode
remplace les espaces par le caractre "plus" (+), le vrai caractre "plus" tant luimme encod, alors que la
fonction rawurlencoderemplacelesespacesparlasquence%20(codeASCII32enhexadcimal).Lafonction
urlencode est conforme au type MIME application/xwwwformurlencoded (type utilis pour transmettre les
valeurs des formulaires) alors que la fonction rawurlencode est conforme la RFC1738 a priori, il faut plutt
employerlafonctionrawurlencode.
Exemple
<?php
// initialisation d'une variable
$nom="Olivier & Xavier";
echo urlencode($nom)."<BR>";
Rsultat
Olivier+%26+Xavier
Olivier%20%26%20Xavier
Lescriptpage1.phppeuttremodifidelamaniresuivante :
<?php
// initialisation d'une variable
$nom="Olivier & Xavier";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=<?php echo rawurlencode($nom); ?>">
Page 2</A>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=Olivier%20%26%20Xavier">
Page 2</A>
</BODY>
</HTML>
Lachanedelarequtepeutaussitreconstruitel'aidedelafonctionhttp_build_queryapparueenversion
5.
Syntaxe
Avec
donnes
Tableau contenant les donnes utiliser pour construire la chane de la requte. L'indice ou la cl du tableau
sontutilisscommenomduparamtrepourlavaleurassocie.
prfixe
Prfixe utiliser pour le nom des paramtres, lorsqu'il s'agit d'un indice numrique. Permet d'avoir l'arrive un
nomexploitablecommenomdevariable(unnomdevariablePHPnepeutpascommencerparunchiffre).
Cette fonction construit, puis encode, une chane de requte sous la forme cl1=valeur1&cl2=valeur2&...
enutilisantlescls(ouindices)etvaleurstrouvesdansletableaudonnes.S'ilestsaisi,leparamtreprfixe
estajoutdevantlesindicesnumriques.
Exemple
<?php
Rsultat
nom=Olivier+%26+Xavier&0=David+%2B+Thomas
nom=Olivier+%26+Xavier&v_0=David+%2B+Thomas
Il existe deux fonctions, urldecode et rawurldecode, qui permettent de dcoder une chane pralablement encode,
respectivement par urlencode ou rawurlencode. Ces fonctions de dcodage n'ont pas besoin d'tre appeles lorsque des
donnes encodes sont transmises par l'URL. En effet, ces donnes sont automatiquement dcodes l'arrive.
"magicquotes" :leretour
Comme nous l'avons expliqu dans le chapitre 7, la valeur rcupre dans le script d'arrive peut par contre,
subir l'encodage "magic quotes" si la directive de configuration magic_quotes_gpc (souvenezvous que gpc
signifieGet/Post/Cookie)eston.
Exemple
<?php
// initialisation d'une variable avec apostrophe
$nom="c'est l't";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=<?php echo rawurlencode($nom); ?>">
Page 2</A>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 en passant la valeur de $nom
dans l'URL -->
<A HREF="page2.php?nom=c%27est%20l%27%E9t%E9">
Page 2</A>
</BODY>
</HTML>
c\'est l\'t
En consquence, lors de la rcupration d'une information transmise par URL, il convient ventuellement
d'appeler la fonction stripslashes ou notre fonction gnrique valeur_saisie pour supprimer l'encodage
"magicquotes".
Applicationlagestiondessessions
Cette technique de transmission de donnes par l'URL peut tre utilise pour la gestion des sessions, en
transmettantlesinformationsdesessiondansl'URL.
Lesprincipessontlessuivants :
- Cet identifiant de session est systmatiquement intgr dans les URL qui permettent de naviguer entre les diffrentes
pages du site.
- Dans chaque script (page) concern par la gestion des sessions, commencez par tester si le script a t appel avec
une URL contenant un identifiant de session; si ce n'est pas le cas, l'utilisateur n'a pas encore de session (c'est la
premire page qu'il visite) et il faut ouvrir la session. Cette ouverture de session peut se matrialiser par la simple
attribution d'un identifiant unique ou par la redirection vers une page d'identification, si le site n'accepte pas les
utilisateurs anonymes.
- Script page1.php:
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// tester si la session est ouverte, c'est dire si une
// variable " session " a t transmise par l'URL
if (! isset($_GET["session"]) ) {
// variable " session " vide = pas de session
// => ouvrir la session
// pour cet exemple :
// - identifiant de session
$session = identifiant_unique();
// - date/heure d'ouverture de la session
$date = date("\l\e d/m/Y H:i:s");
// - message
$message = "Nouvelle session : $session - $date";
} else {
// variable " session " non vide = session ouverte
// => rcuprer les informations de l'URL
$session = $_GET["session"];
$date = $_GET["date"]; // message
$message = "Session dj ouverte: $session - $date";
}
// construction des paramtres de l'url : $session + $date
// $session n'a pas besoin d'tre encod
$url = "?session=$session&date=".rawurlencode($date);
// dtermination de la date et de l'heure actuelle (pas celle
// de l'ouverture de la session
$actuel = "Nous sommes le ".date("d/m/Y").
" ; il est ".date("H:i:s");
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages -->
<A HREF="page2.php<?php echo $url; ?>">Page 2</A>
</BODY>
</HTML>
<?php
...
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages -->
<A HREF="page1.php<?php echo $url; ?>">Page 1</A>
</BODY>
</HTML>
Rsultat
>
La page n'a pas t mise jour car elle est dans le cache du navigateur. Une solution ce problme est
proposeaupoint4Remarquesetconclusion.
L'utilisation de cette technique peut tre illustre sur une gestion de sessions avec authentification des
utilisateurs.
Exemple
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie est correcte
$requte = sprintf(
"SELECT * FROM utilisateurs WHERE identifiant = '%s'",
vers_base($identifiant));
$erreur = "";
$utilisateur = db_lire_ligne($requte,$erreur);
// l'identification est bonne s'il existe un utilisateur
// ayant l'identifiant saisi (! empty ...) et que le mot
// de passe correspond ($utilisateur ... == ...)
$existe = ((! empty($utilisateur)) and
($utilisateur["mot_de_passe"] == $mot_de_passe));
return $existe;
}
// initialisation des variables
$identifiant = "";
$mot_de_passe = "";
$message = "";
// traitement du formulaire
if (isset($_POST["connexion"])) {
// rcuprer les informations saisies
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// tester si la session est ouverte, c'est--dire si une
// variable " session " a t transmise par l'URL
if (! isset($_GET["session"]) ) {
// variable " session " vide = pas de session
// => rediriger l'utilisateur vers la page de login
header("location: login.php");
exit;
} else {
// variable " session " non vide = session ouverte
// => rcuprer les autres informations de l'URL pour cet exemple :
// - identifiant de session
$session = $_GET["session"];
// - date/heure d'ouverture de la session
$date = $_GET_["date"];
// - identifiant de l'utilisateur
$identifiant =
valeur_saisie($_GET_["identifiant"]);
// message
$message = "Session : $session - $identifiant - $date";
}
// construction des paramtres de l'url : $session + $date
L'accsauxpagesdusiteestmaintenantprotg,ouplutt,sembleprotg(dtaildanslasectionsuivante).
Le script login.php montre la possibilit de placer des paramtres derrire l'URL passe la fonction header.
Remarquesetconclusion
Lesutilisateursmalinset/oumalintentionns
Pour les deux exemples donns, un utilisateur (malin et/ou mal intentionn) qui appelle une URL
http://.../page1.php?session=abcaccdesansproblmelapagedemandeenoutrepassantlemcanisme
d'ouverturedesessionet,notamment,lepassageparlapaged'identificationdansledeuximeexemple :
En effet, actuellement, le script se contente de tester l'existence d'une valeur pour le paramtre session dans
l'URL, sans vrifier que la valeur en question correspond une vraie session. Pour cela, il faut conserver, ct
serveur, dans un fichier ou dans une base, la trace des sessions rellement ouvertes, c'estdire la trace des
identifiants de session rellement attribus par l'application. En complment, il faut prvoir un mcanisme de
dure de vie (30 minutes , 1 heure, 6 heures...) qui fasse en sorte qu'un utilisateur n'emploie pas un identifiant
desessionattribuprcdemment.
Nepastouttransmettredansl'URL
Lemcanismeemploypourconserver,ctserveur,latracedessessionsouvertes,peutaussitreutilispour
conserver des informations complmentaires sur la session et ne pas tre oblig ainsi de passer toutes les
valeurs par l'URL : seul l'identifiant de session peut l'tre. Il suffit alors, au dbut de chaque script, d'utiliser
l'identifiant de session pour rcuprer les informations complmentaires de la session, et, en fin de script, de
renregistrer,ctserveur,lesinformationsdesessionquionttmodifies.
Casdutraitementd'unformulaire
La technique de transmission des informations de session par l'URL peut tre utilise dans l'URL de l'option
ACTION.
Exemple
Le script appel (page1.php sur notre exemple) peut rcuprer l'identifiant de la session dans le tableau $_GET
etlesvaleursduformulairedansletableau$_POST.
Nous allons voir dans la partie E (Passer des informations par une zone de formulaire cache), que l'information
desessionpeutaussi,danscecas,tretransmisedansleformulaire.
Forcerlerafrachissementd'unepage
Pourrsoudreleproblmedespagesnonmisesjourcartoujoursprsentesdanslecachedunavigateur,ilfaut
envoyerdesenttescomplmentairesdanslapageHTMLl'aidedelafonctionheader.
Exemple
// HTTP 1.0
header("Pragma: no-cache");
// HTTP 1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
Conclusion
Utiliser l'URL pour transmettre des informations de session est envisageable mais ncessite beaucoup de code
pourconstruirequelquechosedesolide.
Nous n'indiquons volontairement pas d'exemple plus complet pour la gestion des sessions avec cette technique
car,depuisPHP4,lesfonctionnalitsdegestiondessessionsonttintroduitespoursimplifierledveloppement
et apporter des solutions simples aux diffrentes problmatiques voques prcdemment : autant les utiliser
(cf.GrerlessessionsUtiliserlagestiondessessionsdePHP).
La technique prsente dans cette partie doit tre vue comme une mthode permettant de transmettre des
informationssimplesd'unepageuneautre,sanschercherunescuritimportante.
Principe
Nous avons vu dans le chapitre 7 que les informations saisies dans un formulaire taient transmises au script
chargdutraitementetpouvaient,ensuite,treaffichesdansunenouvellepage.
Cettemthodepeuttreutilisepourtransmettre,aupassage,d'autresinformationsnonsaisiesparl'utilisateur,
typiquementenlesplaantdansunezonedeformulairecache.
Exemple
- Script page1.php :
<?php
// initialisation d'une variable
$nom="Olivier";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 avec un bouton de formulaire -->
<FORM ACTION="page2.php" METHOD="POST">
<!-- l'information transmettre est cache -->
<INPUT TYPE="hidden" NAME="nom" VALUE="<?php echo $nom; ?>">
<INPUT TYPE="submit" NAME="page2" VALUE="Page 2">
</FORM>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<!-- lien vers la page 2 avec un bouton de formulaire -->
<FORM ACTION="page2.php" METHOD="POST">
<!-- l'information transmettre est cache -->
<INPUT TYPE="hidden" NAME="nom" VALUE="Olivier">
<INPUT TYPE="submit" NAME="page2" VALUE="Page 2">
</FORM>
</BODY>
</HTML>
Scriptpage2.php:
<?php
// rcupration des informations passes dans l'URL
$nom=$_POST["nom"];
echo $nom;
?>
Rsultat
- Affichage de la page 1 :
Avecleformulaire,iln'yapasdeproblmed'encodage(effectuautomatiquement).
Pas contre, dans le chapitre 7, nous avons vu (et rsolu) les diffrents problmes qui pouvaient se produire,
avec la fonctionnalit "magic quotes" ou l'intgration dans le formulaire de caractres spciaux. Il ne faut donc
pasoublierd'utiliserlesfonctions stripslashes et htmlspecialcharsoulesfonctionsgnriquescresdans
lesexemplesprcdentsvers_formulaireetvaleur_saisie.
Applicationlagestiondessessions
Cettetechniquedetransmissiondedonnesparunformulairepeuttreutilisepourlagestiondessessions,en
transmettantlesinformationsdesessiondansleszonescachesd'unformulaire.
Lesprincipesmisenuvresontlesmmesqu'avecl'URL.
- Script page1.php :
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// tester si la session est ouverte, c'est--dire si une
// variable " session " a t transmise par le formulaire
if (! isset($_POST["session"]) ) {
// variable " session " vide = pas de session
// => ouvrir la session
// pour cet exemple :
// - identifiant de session
$session = identifiant_unique();
// - date/heure d'ouverture de la session
$date = date("\l\e d/m/Y H:i:s");
// - message
$message = "Nouvelle session : $session - $date";
} else {
// variable " session " non vide = session ouverte
// => rcuprer les informations caches du formulaire
$session = $_POST["session"];
$date = $_POST["date"];
// message
$message = "Session dj ouverte: $session - $date";
}
<?php
...
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages avec un formulaire -->
<FORM ACTION="page1.php" METHOD="POST">
<INPUT TYPE="hidden" NAME="session"
VALUE="<?php echo $session; ?>">
<INPUT TYPE="hidden" NAME="date"
VALUE="<?php echo $date; ?>">
<INPUT TYPE="submit" NAME="page1" VALUE="Page 1">
</FORM>
</BODY>
</HTML>
Rsultat
L'ouverture de session, par passage dans une page d'identification, peut s'effectuer sur le mme principe qu'au
point D Passer des informations par l'URL. La seule difficult rsoudre concerne la redirection de la page
d'identification vers une autre page du site, aprs une connexion russie : l'utilisation de la fonction header ne
permet pas de transmettre des informations par la mthode du formulaire. Le plus simple consiste, alors,
inverserlgrementlalogiqueetfairetraiterleformulaired'identificationparlescriptdelapage1 cedernier
sechargeantderenvoyerl'utilisateursurlapaged'identificationencasd'checdeconnexion.Danslapratique,
cetteapprochen'estpastrslgantedupointdevuedel'organisationducode.
Remarquesetconclusion
Lesutilisateursmalinset/oumalintentionns
Unutilisateur(malinet/oumalintentionn)peutconstruireunepageavecsonpropreformulaire,comprenantune
zone nomme "session", contenant une valeur quelconque et qui appelle le script page1.php il accde alors
sansproblmelapage1,enoutrepassantlemcanismed'ouverturedesessionet,notamment,lepassagepar
lapaged'identificationdansledeuximeexemple.
CommedanslepointDPasserdesinformationsparl'URL,lasolutionconsistegardertrace,ctserveur,des
sessionsrellementouvertes.
Nepastouttransmettredansleformulaire
CommedanslepointD Passerdesinformationsparl'URL,lemcanismeutilispourconserver,ctserveur,la
trace des sessions ouvertes, peut aussi tre utilis pour conserver des informations complmentaires sur la
sessionet,ainsi,nepastreobligdepassertouteslesvaleursdansleformulaire.
Casdelanavigationparbalise<AHREF...>
Latechniqueproposedanscettesectionn'estpasfacilecombineraveclanavigationparbalise<A HREF...>.
Plusieurssolutionssontenvisageables :
- Mettre en place une navigation uniquement base de boutons; ce n'est pas trs lgant et, surtout, pas dans l'esprit
de la navigation sur le Web.
- Utiliser les deux techniques; cela risque d'alourdir la programmation, sauf si l'on utilise systmatiquement la mthode
GET pour le traitement des formulaires: que les donnes soient transmises par URL ou par formulaire, elle sont
rcuprables dans $_GET.
Conclusion
Utiliser les formulaires pour transmettre des informations de session est envisageable mais ceci ncessite
beaucoup de code pour construire quelque chose de solide et peut conduire une interface de navigation qui
n'estpasdansl'espritduWeb.
Comme pour la gestion des sessions par l'URL, nous n'allons pas plus loin dans les exemples : autant utiliser les
fonctionnalitsdegestiondessessionsdePHP(cf.GrerlessessionsUtiliserlagestiondessessionsdePHP).
La technique prsente dans cette partie doit tre vue comme une technique permettant de transmettre
ponctuellement des informations complmentaires dans un formulaire dj prsent. Par contre, crer un
Principe
Un cookie est un petit fichier dpos, par un site, sur le poste de l'internaute et qui peut contenir des
informations.
LescookiessontautomatiquementrenvoysauserveurWeb,parlenavigateur,lorsquel'internautenaviguedans
lespagesdusiteenquestion.
PHPpermetdercuprertrsfacilement,dansdesvariables,lesdonnesstockesdanslecookie.
Lafonctionsetcookiepermetdedposeruncookiesurlepostedel'internaute.
Syntaxe simplifie
boolen setcookie(chane nom [, chane valeur [, entier expiration [, chane chemin [, chane domaine
[, entier securis]]]]])
Avec
nom
Nomducookie.
valeur
Valeurstockedanslecookie.
expiration
Dated'expirationducookie(timestampUnix).
chemin
Chemin sur le serveur dans lequel le cookie est disponible. Mettre / pour rendre le cookie disponible sur le
domaineentierou /rep/pourrendrelecookiedisponibledanslerpertoire /rep/dudomaineettoussessous
rpertoires.Pardfaut,galaurpertoirepartirduquellecookieatdpos.
domaine
Domaineauquellecookieestrenvoy. .monSite.com(avecunpointaudbut)permetparexemplederendrele
cookiedisponiblepourtouslessousdomainesdemonSite.com.
scuris
Mettre1pourindiquerquelecookienedoittretransmisquesuruneconnexionscurise(0pardfaut).
Si la fonction n'est appele qu'avec le paramtre nom, le cookie portant ce nom est supprim du poste de
l'internaute. Si les paramtres domaine et chemin avaient t spcifis lors du dpot du cookie, il faut les
spcifierl'identiquepoursupprimerlecookie(mettreunedated'expirationdanslepass).
Sileparamtrevaleurestspcifi,uncookieportantlenom nometcontenantlavaleurvaleurestenvoysur
le poste de l'utilisateur s'il existe dj un cookie portant ce nom, ce dernier est mis jour avec la nouvelle
valeur.
Leparamtreexpirationpermetdedterminerladated'expirationducookie(etdoncladatedesasuppression
du poste de l'utilisateur) si ce paramtre est non spcifi (ou gal 0) le cookie expire la fin de la session,
c'estdirelorsquel'utilisateurquittelesite.
Lescookiessontenvoysdansl'enttedelapage.l'instardelafonctionheader,lafonction setcookiedoit
donc tre appele avant toute instruction (PHP ou HTML), cette dernire ayant pour effet de commencer
construirelapageHTML.Encasdeproblme,unmessagedutypesuivantestaffich :
La fonction setcookie retourne TRUE si l'instruction a pu tre excute (pas de donnes dj transmises), et
FALSEdanslecascontraire. Parcontre,lecodederetourdelafonctionnedonneaucuneinformationsurlefait
que le cookie a rellement pu tre dpos sur le poste de l'utilisateur : si ce dernier refuse les cookies, la
fonctionsetcookieretournequandmmeTRUEbienquelecookien'aitpastdpos.
Les cookies sont grs par site ; deux cookies de sites diffrents peuvent porter le mme nom. Le cookie est dpos sur le
poste de l'internaute par la fonction setcookie puis renvoy ultrieurement lors de la visite de n'importe quelle page du site.
Exemple
<?php
// dpt d'un cookie nomm " nom " contenant
// la valeur " Olivier " et expirant la fin de la session
$ok = setcookie("nom","Olivier");
// idem mais expirant date du jour (time() en secondes)
// plus 30 fois 24 fois 3600 secondes (soit 30 jours)
$ok = setcookie("nom","Olivier",time()+(30*24*3600));
// suppression du cookie nomm " nom "
$ok = setcookie("nom");
?>
Lorsque le cookie est renvoy au serveur Web, par le navigateur, lors de la demande d'une page PHP, la valeur
du cookie est accessible dans une variable PHP selon un mcanisme identique celui mis en uvre pour les
formulairesetlesURL.
La valeur de chaque cookie envoy, par le navigateur, est automatiquement enregistre dans le tableau
associatif$_COOKIE :lacldutableauestgaleaunomducookie.
Les variables de cookie sont aussi disponibles dans le tableau associatif $_REQUEST ou peuvent tre importes dans le
script par appel la fonction import_request_variables (cf. Gestion des formulaires - Contrler les donnes saisies -
Rcuprer les donnes saisies dans le formulaire).
Exemple
<?php
// premier cookie expirant la fin de la session
$ok1 = setcookie("prnom","Olivier");
// deuxime cookie expirant dans 30 jours
$ok2 = setcookie("nom","HEURTEL",time()+(30*24*3600));
// rsultat
if ($ok1 and $ok2) {
$message = "Cookies dposs (du moins, a priori)";
} else {
$message = "L'un des cookies n'a pas pu tre dpos";
}
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1</B><BR>
<?php echo $message; ?><BR>
<A HREF="page2.php">Page 2</A>
</BODY>
</HTML>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<?php
if ( isset($_COOKIE["prnom"]) ) {
echo "\$_COOKIE[\"prnom\"] = {$_COOKIE['prnom']}<BR>";
} else {
Rsultat
- Affichage de la page 1 :
Page 1
Cookies dposs (du moins, a priori)
Page 2
$_COOKIE["prnom"] = Olivier
$_COOKIE["nom"] = HEURTEL
- Rsultat d'un retour, avant trente jours, sur la page 2 du mme site:
$_COOKIE["prnom"] =
$_COOKIE["nom"] = HEURTEL
Le cookie de dure de vie gale la session n'existe plus la sortie de la session et l'information est perdue
l'informationstockedansl'autrecookierestedisponible(danslalimitedesaduredevie).
Il est possible de stocker n'importe quelle chane dans le cookie sans avoir se soucier d'un ventuel
encodage/dcodage :l'encodageetledcodagesonteffectusautomatiquement.
Exemple
<?php
// valeur du cookie avant
$avant = (isset($_COOKIE ["heure"]))?$_COOKIE ["heure"]:"";
// dpt du cookie expirant la fin de la session
$ok = setcookie("heure",date("H:i:s"));
// valeur du cookie aprs
$aprs = (isset($_COOKIE ["heure"]))?$_COOKIE ["heure"]:"";
// heure actuelle
$actuel = date("H:i:s");
// affichage
echo "Actuel : $actuel<BR>";
echo "Avant : $avant<BR>";
echo "Aprs : $aprs<BR>";
?>
Actuel : 14:53:18
Avant :
Aprs :
Lors du premier appel, le cookie n'existe pas avant (c'est normal) et n'existe toujours pas aprs, car il a
simplementtenvoymaisn'estpasencore"revenu"(manireimagedeprsenterleschoses).
Lors du deuxime appel, la valeur du cookie est disponible ds le dbut du script (le cookie est revenu avec la
requtepourlapage),etabienunevaleurquicorrespondl'instantoilatdpos parcontre,savaleur
aprsnerefltepasimmdiatementlaralit(mmeprincipequepourledptinitial :lecookien'estpasencore
"revenu").
Actuel : 14:53:41
Avant : 14:53:30
Aprs : 14:53:30
Lorsdutroisimeappel,lecookieabienunevaleurquicorrespondsamisejourlorsdudeuximeappel.
Une des consquences de ce mode de fonctionnement est qu'il n'est pas possible, tout de suite aprs avoir
dposlecookie,detestersilecookieatacceptounonparleposte.
Pour savoir si un poste accepte les cookies, il faut dposer un cookie et recharger une page dans laquelle la
prsenceounonducookiepermettradedterminersileposteacceptelescookies.
<?php
// tester si c'est le deuxime appel de la page
if (! isset($_GET["retour"])) {
// non ...
// dposer le cookie
setcookie("test","test");
// et recharger la page avec une information dans
// l'URL indiquant que c'est le deuxime passage
header("Location: tester_cookie.php?retour=1");
} else {
// oui ...
// tester si le cookie est revenu
if (isset($_COOKIE["test"])) { // oui ...
echo "Cookie accept";
} else { // non ...
echo "Cookie refus";
}
}
?>
Il est possible de rcuprer un tableau comme valeur de cookie sous rserve d'utiliser une notation de type
tableaulorsdudptducookie.
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// tester si c'est le deuxime appel de la page
if (! isset($_GET["retour"])) {
// non ...
// dposer le cookie
setcookie("test[0]","zro");
setcookie("test[1]","un");
// et recharger la page avec une information dans
// l'URL indiquant que c'est le deuxime passage
header("Location: tester_cookie.php?retour=1");
} else {
// oui ...
// tester si le cookie est revenu
if (isset($_COOKIE["test"])) { // oui ...
echo "Cookie accept<BR>";
afficher_tableau($_COOKIE["test"]);
} else { // non ...
echo "Cookie refus";
Rsultat
Cookie accept
0 = zro
1 = un
Dans la pratique, il y a en fait plusieurs cookies dposs sur le poste de l'utilisateur, mais les valeurs sont bien
rcupres dans le script PHP sous la forme d'un tableau. Pour dposer un seul cookie contenant plusieurs
valeurs, vous pouvez procder par concatnation, ou utiliser une fonction comme implode (et explode au
retourducookie).
"magicquotes" :leretour
CommepourlesdonnesGETetPOST,lavaleurrcupredansuncookiepeutsubirl'encodage"magicquotes"si
ladirectivedeconfigurationmagic_quotes_gpc(Get/Post/Cookie)eston.
<?php
// tester si c'est le deuxime appel de la page
if (! isset($_GET["retour"])) {
// non ...
// dposer le cookie
setcookie("test","c'est l't");
// et recharger la page avec une information dans
// l'URL indiquant que c'est le deuxime passage
header("Location: tester_cookie.php?retour=1");
} else {
// oui ...
// tester si le cookie est revenu
if (isset($_COOKIE["test"])) { // oui ...
echo "Valeur du cookie = $_COOKIE[test]";
} else { // non ...
echo "Cookie refus";
}
}
?>
En consquence, lors de la rcupration d'une information transmise par cookie, il convient ventuellement
d'appeler la fonction stripslashes ou notre fonction gnrique valeur_saisie pour supprimer l'encodage
"magicquotes".
Applicationlagestiondessessions
Les cookies prsentent l'immense avantage, par rapport aux techniques tudies jusqu' maintenant, d'tre
parfaitement indpendants la fois de la navigation par balise <A HREF=...> et de la gestion des formulaires :
grer les sessions l'aide des cookies permet donc de s'affranchir des inconvnients lis aux deux autres
mthodes.
Ilsprsentent,parcontre,ungrosinconvnient :ilspeuventtrerefussparlesinternautes.
Lesprincipesdemiseenuvresontlesmmesquepourlagestionparl'URL.
Nousallonsillustrercesprincipesl'aidede2pages(enmettantl'hypothsequelescookiessontaccepts).
Exemple (avec deux pages et partant de l'hypothse que les cookies sont accepts)
- Script page1.php :
<?php
...
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages -->
<A HREF="page1.php">Page 1</A>
</BODY>
</HTML>
Rsultat
EncasdeclicsurleboutonPrcdentedunavigateur,lapagen'estpasmisejourcarelleestdanslecache
dunavigateur.UnesolutionceproblmeestproposedanslepointD4.Remarquesetconclusion.
Avec les cookies, il est possible de naviguer entre les pages et de grer des formulaires sans se soucier des informations de
session : elles sont transmises en parallle.
L'utilisation de cette technique peut tre illustre sur une gestion de session avec authentification des
utilisateurs.
Exemple
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie est correcte
$requte = sprintf(
"SELECT * FROM utilisateurs WHERE identifiant = '%s'",
vers_base($identifiant));
$erreur = "";
$utilisateur = db_lire_ligne($requte,$erreur);
// l'identification est bonne s'il existe un utilisateur
// ayant l'identifiant saisi (! empty ...) et que le mot
// de passe correspond ($utilisateur ... == ...)
$existe = ((! empty($utilisateur)) and
($utilisateur["mot_de_passe"] == $mot_de_passe));
return $existe;
}
// initialisation des variables
$identifiant = "";
$mot_de_passe = "";
$message = "";
// traitement du formulaire
if (isset($_POST["connexion"])) {
// rcuprer les informations saisies
$identifiant =
valeur_saisie($_POST["identifiant"]);
$mot_de_passe =
valeur_saisie($_POST["mot_de_passe"]);
// vrifier que l'utilisateur existe
if (utilisateur_existe($identifiant,$mot_de_passe)) {
// l'utilisateur existe ...
// => ouvrir la session
$session = identifiant_unique();
$date = date("\l\e d/m/Y H:i:s");
// dposer trois cookies pour stocker ces informations
// dure de vie = la session justement !
setcookie("session",$session);
setcookie("date",$date);
setcookie("identifiant",$identifiant);
header("location: page1.php ");
exit;
} else {
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// tester si la session est ouverte, c'est--dire si une
// variable "session" a t transmise par le cookie
if (! isset($_COOKIE["session"]) ) {
// variable " session " vide = pas de session
// => rediriger l'utilisateur vers la page de login
header("location: login.php");
exit;
} else {
// variable "session" non vide = session ouverte
// => rcuprer les autres informations des cookies
// pour cet exemple :
// - identifiant de session
$session = $_COOKIE["session"];
// - date/heured'ouverture de la session
$date = $_COOKIE["date"];
// - identifiant de l'utilisateur
$identifiant =
valeur_saisie($_COOKIE["identifiant"]);
// message
$message = "Session : $session - $identifiant - $date";
}
// dtermination de la date et de l'heure actuelles (pas celles
// de l'ouverture de la session
$actuel = "Nous sommes le ".date("d/m/Y").
" ; il est ".date("H:i:s");
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages -->
<A HREF="page2.php">Page 2</A>
</BODY>
</HTML>
Remarquesetconclusion
Lesutilisateursmalinset/oumalintentionns
Bien que ce soit un peu plus complexe mettre en uvre, un utilisateur (malin et/ou mal intentionn) peut
accder la page 1, en outrepassant le mcanisme d'ouverture de session et, notamment, le passage par la
paged'identificationdansledeuximeexemple.
Comme dans les deux autres cas (URL et formulaire), la solution consiste garder trace, ct serveur, des
sessionsrellementouvertes.
Nepastouttransmettredanslescookies
Lescookiespossdentleurslimites :
L encore, le mcanisme utilis pour conserver, ct serveur, la trace des sessions ouvertes, peut aussi tre
employpourconserverdesinformationscomplmentairessurlasession.Ainsi,vousn'tespasobligdepasser
touteslesvaleursdansdescookies.
Conclusion
Les cookies sont trs pratiques pour grer les sessions mais ne sont pas forcment accepts par tous les
utilisateurs.
Pour un site destin des utilisateurs identifis (abonns, inscrits), il est possible d'imposer l'acceptation des
cookiespourtremembredusite,l'importanttantdebieninformerlesutilisateursquelecookienerestequele
tempsdelasession.
Pour un site "grand public", il n'est sans doute pas acceptable de fonder une gestion des sessions sur les
cookies.
De toutes les mthodes abordes jusqu' prsent, la technique "cookie" et la technique "URL" peuvent tre
considrescommelesmoinscontraignantes.Unegestiondessessions,danslaquelleseull'identifiantdesession
doittretransmisd'unepagel'autre(lesautresinformationstantstockessurleserveur)peuttremiseen
place relativement facilement en employant les cookies, si l'utilisateur les accepte et en utilisant l'URL dans le
cascontraire.C'estexactementcequeproposelagestiondessessionsdePHPquenousallonsvoirmaintenant :
nenousamusonsdoncpasredveloppercequiexistedj !
Nous allons galement voir dans ce chapitre (cf. G rer les sessions Conserver des informations d'une visite
une autre), que le cookie est un bon outil (sous rserve toujours de l'accord de l'utilisateur) pour stocker une
informationd'unesessionl'autre(enutilisantdoncuncookieayantuneduredeviespcifielacration).
Principes
Depuis la version 4, PHP propose un ensemble de fonctions qui facilitent la gestion des sessions. Les principes
sontlessuivants :
- Cet identifiant unique est transmis d'une page l'autre, soit par cookie (si le poste accepte les cookies), soit par l'URL
dans le cas contraire; en tout tat de cause, c'est PHP qui choisit automatiquement la bonne mthode et assure ce
transfert ( quelques rserves prs, lies la configuration).
- Les variables, dont vous souhaitez conserver la valeur d'une page l'autre pendant la dure de la session, sont
indiques PHP qui se charge automatiquement de restituer leurs valeurs au dbut du script, et de les sauvegarder
la fin du script. Par dfaut, la sauvegarde s'effectue sur disque, dans des fichiers temporaires, mais il est possible,
moyennant un peu de dveloppement, de faire sauvegarder ces valeurs par PHP dans une base. Ces variables sont
dsignes sous le terme "variables de session".
Enbref,PHPsechargedetoutelagestion.
Lesfonctions
Lesprincipalesfonctionsdumoduledegestiondessessionssontlessuivantes :
Nom Rle
session_start Ouvre une nouvelle session ou ractive la session
courante.
session_id Retourne (ou ventuellement modifie) l'identifiant de la
session.
session_name Retourne (ou ventuellement modifie) le nom de la
variable utilise pour stocker l'identifiant de la session.
session_register Enregistre une variable dans la session courante.
session_is_registered Indique si une variable est enregistre dans la session.
session_unregister Supprime l'enregistrement de la variable dans la session.
session_unset Supprime l'enregistrement de toutes les variables de la
session.
session_destroy Supprime la session.
session_start
Syntaxe
boolen session_start()
La fonction session_start va interroger l'environnement pour dtecter si une session a dj t ouverte pour
l'utilisateur actuel. Si oui, les variables enregistres dans la session sont restitues. Autrement, une nouvelle
sessionestouverteavecattributiond'unidentifiant.
Lafonctionsession_startretournetoujoursTRUE.
Toutscriptconcernparlagestiondessessionsdoitappeler session_startpouravoiraccsauxvariablesde
session.
Exemple
<?php
// ouvrir/ractiver la session
session_start();
?>
session_id
Syntaxe
nouvelle_valeur
Nouvellevaleurattribuel'identifiantdesession.
Appelesansparamtre,lafonction session_idretournelavaleurdel'identifiantdesession.Cettevaleursera
toujoursvidesisession_startn'apastappeledanslescript.
Appele avec un paramtre, la fonction session_id modifie la valeur attribue l'identifiant de session. En
pratique,danslamajoritdescas,celaneprsentepasungrandintrt.
Exemple
<?php
// rcuprer la valeur de session_id avant
$avant = session_id();
// ouvrir/ractiver la session
session_start();
// rcuprer la valeur de session_id aprs
$aprs = session_id();
// affichage
$actuel = date("H:i:s");
echo "Heure : $actuel<BR>";
echo "Avant : $avant<BR>";
echo "Aprs : $aprs<BR>";
?>
Rsultat
- Premier appel :
Heure : 16:48:23
Avant :
Aprs : 5367261e1325076530d5f4c756b55e07
Heure : 16:48:37
Avant :
Aprs : 5367261e1325076530d5f4c756b55e07
Heure : 16:49:33
Avant :
Aprs : 124b271be50112948ae2279dbb28e43d
Les trois exemples montrent qu'avant appel la fonction session_start, la fonction session_id retourne une
session_name
Syntaxe
nouvelle_valeur
Nouvellevaleurattribueaunomdelavariablequistockel'identifiantdesession.
Appele sans paramtre, la fonction session_name retourne le nom de la variable dans laquelle l'identifiant de
session est stock. La fonction session_nameretourneunrsultatmmesilafonction session_start n'a pas
tappeledanslescript.
Appele avec un paramtre, la fonction session_name modifie le nom de la variable. En pratique, dans la
majoritdescas,celaneprsentepasungrandintrt(ilestremissavaleurpardfautlafinduscript).
Exemple
<?php
// rcuprer la valeur de session_name avant
$avant = session_name();
// ouvrir/ractiver la session
session_start();
// rcuprer la valeur de session_name aprs
$aprs = session_name();
// affichage
echo "Avant : $avant<BR>";
echo "Aprs : $aprs<BR>";
// affichage de la valeur en utilisant la technique de variable variable
echo "$aprs = ${$aprs}<BR>";
?>
Rsultat
Avant : PHPSESSID
Aprs : PHPSESSID
PHPSESSID = 4f7acd051136cafc0464d44583f7ff68
Le nom de la variable est dfini par la directive de configuration session.name. Vous pouvez modifier cette
directivepourutiliserunautrenom.
session_register
Syntaxe
nom_variable
Chane(outableau)contenantlenomdela(oudes)variable(s)enregistrerdanslasession.Danslesdeuxcas,
lesnomsdevariablesontindiqussanslecaractre$.
Cette fonction est conserve pour des raisons de compatibilit ascendante et ne fonctionne que lorsque la directive de
configuration register_globals est on (rappel : elle est off par dfaut depuis la version 4.2 et passera dfinitivement
off dans une prochaine version). la place, il est conseill de travailler directement avec le tableau $_SESSION (voir ci-aprs).
Lafonctionsession_registeraccepteplusieursparamtrespermettantainsid'enregistrerplusieursvariablesen
unseulappel.
La fonction session_register fait un appel implicite la fonction session_start pour ouvrir ou ractiver la
session.
Tout type de variable est accept (notamment les tableaux). Des exemples sont donns dans la section
suivante.
Manipulerlesvariablesenregistresdanslasession
Lorsdel'appellafonctionsession_start,touteslesvariablesenregistresdanslasessionsontrestaureset
accessibles selon des mcanismes identiques ceux dj tudis pour les donnes GET et POST ou pour les
cookies.
La valeur de chaque variable enregistre est notamment automatiquement restitue dans le tableau associatif
$_SESSION($HTTP_SESSION_VARSavantla4.1) :lacldutableauestgaleaunomdelavariableenregistre.
N'oubliez pas que la directive de configuration register_globals est off par dfaut depuis la version 4.2 et qu'elle
passera dfinitivement off dans une prochaine version.
Le tableau $_SESSION prsente une fonctionnalit supplmentaire intressante : toutes les entres stockes
dans ce tableau sont automatiquement enregistres en tant que donnes de session si la fonction
session_start a t appele au pralable, sans avoir besoin d'appeler la fonction session_register.
$_SESSIONnesertdoncpasuniquementrcuprerlesdonnesdesessionmaisaussilesenregistrer.
- Script page1.php qui ouvre une session et enregistre des variables dans la session :
<?php
// ouvrir/ractiver la session
session_start();
// initialiser deux variables
$prnom = "";
$informations = "";
// enregistrer les deux variables dans la session
session_register("prnom");
session_register("informations");
// donner des valeurs aux variables
$prnom = "Olivier";
$informations = array("prnom"=>"Olivier","nom"=>"HEURTEL");
// c'est un tableau associatif
// autre variable non enregistre
$nom = "HEURTEL";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1</B><BR>
<A HREF="page2.php">Page 2</A>
</BODY>
</HTML>
<?php
// appel session_start
session_start();
// affichages
echo '$prnom = ',isset($prnom)?$prnom:'','<BR>';
echo '$_SESSION["prnom"] = ',
isset($_SESSION["prnom"])?$_SESSION["prnom"]:'',
'<BR>';
echo '$nom = ',isset($nom)?$nom:'','<BR>';
echo '$_SESSION["nom"] =',
isset($_SESSION["nom"])?$_SESSION["nom"]:'',
'<BR>';
echo '$informations["nom"] = ',
$prnom = Olivier
$_SESSION["prnom"] = Olivier
$nom =
$_SESSION["nom"] =
$informations["nom"] = HEURTEL
$_SESSION["informations"]["nom"] = HEURTEL
Lavariable$nomn'apasdevaleur,carellen'estpasdfiniedanslescriptpage2.php,nienregistreentantque
variabledesessiondanslescript page1.php.Parcontre,lenomestprsentdansletableauassociatifqui,lui,a
bientenregistr.
$prnom =
$_SESSION["prnom"] =
$nom =
$_SESSION["nom"] =
$informations["nom"] =
$_SESSION["informations"]["nom"] =
Lesvariablesdesessionnesontpasrestaures.
$prnom =
$_SESSION["prnom"] =
$nom =
$_SESSION["nom"] =
$informations["nom"] =
$_SESSION["informations"]["nom"] =
Les variables de session n'ont pas t restaures ... car elles n'ont, en fait, pas t enregistres. Si
register_globalsestoff,session_registernefaitrien(etneditrien).
Remarques:
- La fonction session_register indique PHP le nom des variables sauvegarder dans la session; la valeur
proprement dite de la variable est sauvegarde lorsque le script se termine et non lors de l'appel la fonction
session_register.
- partir du moment o une variable est enregistre, il n'est plus ncessaire d'appeler session_register lorsque la
variable est modifie, quel que soit le script (celui dans lequel la variable a t enregistre ou un autre).
- Script page1.php qui ouvre une session et enregistre des variables dans la session :
<?php
// ouvrir/ractiver la session
session_start();
// enregistrer deux "variables" dans la session
$_SESSION["prnom"] = "Olivier";
$_SESSION["informations"] =
array("prnom"=>"Olivier","nom"=>"HEURTEL");
?>
<HTML>
<?php
// appel session_start
session_start();
// affichages
echo '$_SESSION["prnom"] = ',
isset($_SESSION["prnom"])?$_SESSION["prnom"]:'',
'<BR>';
echo '$_SESSION["informations"]["nom"] = ',
isset($_SESSION["informations"]["nom"])?
$_SESSION["informations"]["nom"]:'',
'<BR>';
?>
$_SESSION["prnom"] = Olivier
$_SESSION["informations"]["nom"] = HEURTEL
Cettemthodefonctionnequellequesoitlaconfiguration c'estlamthoderecommande.
Il n'y a aucun encodage (ni mme de "magic quotes" !) sur les donnes stockes dans une variable de session.
Par contre, il existe des diffrences de fonctionnement, premire vue troublantes, selon la valeur de la
directivedeconfigurationregister_globals :
- Si register_globals est off, la variable de session $x n'existe pas a priori; il faut aller la lire dans $_SESSION
["x"]. Pour la mise jour, utiliser $x (mme aprs l'avoir initialis avec $_SESSION ["x"]) est sans effet; pour
PHP, ce n'est pas $x qui contient la valeur sauvegarder; c'est $_SESSION["x"] (qu'il faut donc modifier
directement).
- Si register_globals est on, la variable de session $x existe et rfrence la mme valeur (mme zone mmoire)
que $_SESSION["x"]. Modifier l'une modifie l'autre (et vice versa).
Pour terminer, il existe un problme similaire si les variables de session sont manipules, non pas directement
danslescript,maisdansunefonctionappeledanslescript.Lesvariablesdesessionsont,enfait,implicitement
desvariablesdfiniesdanslescript,c'estdiredesvariablesglobalesvisvisdelafonctionenquestion.
Pour manipuler des variables de session l'intrieur d'une fonction, il faut les traiter en tant que variables
globales, tout en tant confront au mme problme visvis de la valeur de la directive de configuration
register_globals : dclarer la variable $x comme variable (global $x;) dans la fonction, et la lire ou la
modifieralorsqueregister_globalsestoff,esterron.
Heureusement, le tableau $_SESSION est une variable "super globale" : elle est disponible dans la totalit du
script,mmel'intrieurdesfonctions,sansdevoirladclarerglobale(global $_SESSIONestinutile).
L'exemple ciaprs, compos de trois scripts, illustre diverses utilisations du tableau $_SESSION. Ce code
fonctionne quelle que soit la configuration, est facile crire et respecte bien les recommandations de la
communautPHPsurlagestiondessessions.
Script page1.php
<?php
// ouvrir/ractiver la session
Script page2.php
<?php
// dfinir une fonction qui "manipule" la session
function manipuler_session() {
// ouvrir/ractiver la session
session_start();
// modifier la valeur de la variable de session
$_SESSION["prnom"] = "Xavier";
}
// appeler la fonction qui manipule la session
manipuler_session();
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2</B><BR>
<A HREF="page2.php">Page 3</A><BR>
<?php
// afficher un message
echo "Bonjour ". $_SESSION["prnom"];
?>
</BODY>
</HTML>
Script page3.php
<?php
// dfinir une fonction qui ouvre la session
function activer_session() {
// ouvrir/ractiver la session
session_start();
}
// dfinir une fonction qui affiche l'information de session
function afficher_information_session() {
// afficher un message
echo "Bonjour ". $_SESSION["prnom"];
}
// appeler la fonction qui ouvre la session
activer_session();
?>
<HTML>
<HEAD><TITLE>Page 3</TITLE></HEAD>
<BODY>
<B>Page 3</B><BR>
<A HREF="page1.php">Page 1</A><BR>
<?php
Page 1
Page 2
Bonjour Olivier
Page 2
Page 3
Bonjour Xavier
Page 3
Page 1
Bonjour Xavier
Si $_SESSION est utilis, il est dconseill d'employer session_register (et nous allons le voir
session_is_registered et session_unregister).
session_is_registered
Syntaxe
nom_variable
Nomdelavariable(sousformedechanesanslecaractre$)tester.
Cette fonction est conserve pour des raisons de compatibilit ascendante. la place, il est conseill d'utiliser la fonction
isset pour tester la valeur dans le tableau $_SESSION.
La fonction session_is_registered retourne TRUE ou FALSE selon que la variable, dont le nom est pass en
paramtre,estenregistreounon.
Exemple
- Script page1.php :
<?php
// ouvrir/ractiver la session
session_start();
// enregistrer une variable dans la session
$_SESSION["nom"] = "Olivier";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1</B><BR>
<?php echo $_SESSION["nom"]; ?><BR>
<A HREF="page2.php">Page 2</A>
</BODY>
</HTML>
<?php
// rcuprer la valeur avant appel session_start
$avant = session_is_registered("nom");
// ouvrir/ractiver la session
session_start();
// rcuprer la valeur aprs appel session_start
$aprs = session_is_registered("nom");
// affichage
echo "Avant : ".($avant?"TRUE":"FALSE")."<BR>";
echo "Aprs : ".($aprs?"TRUE":"FALSE")."<BR>";
?>
<?php
// rcuprer la valeur avant appel session_start
$avant = session_is_registered("nom");
// ouvrir/ractiver la session
session_start();
// rcuprer la valeur aprs appel session_start
$aprs = session_is_registered("nom");
// affichage
echo "Avant : ".($avant?"TRUE":"FALSE")."<BR>";
echo "Aprs : ".($aprs?"TRUE":"FALSE")."<BR>";
?>
Avant : FALSE
Aprs : TRUE
session_unregister
Syntaxe
nom_variable
Nomdelavariable(sousformedechanesanslecaractre$)neplusenregistrerdanslasession.
Cette fonction est conserve pour des raisons de compatibilit ascendante. la place, il est conseill d'utiliser la fonction
unset pour supprimer la valeur dans le tableau $_SESSION.
Lafonctionsession_unregisterretourneTRUE,encasdesuccs,etFALSE,encasd'chec.
Lafonctionsession_unregisterestsanseffetsielleestappeleavantlafonctionsession_start.
Lafonctionsession_unregisternesupprimepaslavariabledanslescriptencours.
- Script page2.php :
<?php
// ouvrir/ractiver la session
session_start();
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2</B><BR>
<?php
// variables avant
echo 'Avant :','<BR>';
echo '$nom = ', isset($nom)?$nom:'','<BR>';
echo '$_SESSION[nom] = ',
isset($_SESSION["nom"])?$_SESSION["nom"]:'','<BR>';
// supprimer l'enregistrement de la variable
session_unregister("nom");
// que sont devenues les variables dans le script ?
echo 'Aprs :','<BR>';
echo '$nom = ', isset($nom)?$nom:'','<BR>';
echo '$_SESSION[nom] = ',
isset($_SESSION["nom"])?$_SESSION["nom"]:'','<BR>';
?>
<A HREF="page3.php">Page 3</A>
</BODY>
- Script page3.php :
<?php
// ouvrir/ractiver la session
session_start();
?>
<HTML>
<HEAD><TITLE>Page 3</TITLE></HEAD>
<BODY>
<B>Page 3</B><BR>
<?php
// que sont devenues les variables dans le script ?
echo '$nom = ', isset($nom)?$nom:'','<BR>';
echo '$_SESSION[nom] = ',
isset($_SESSION["nom"])?$_SESSION["nom"]:'','<BR>';
?>
</BODY>
</HTML>
- Page 2 :
Page 2
Avant :
$nom = Olivier
$_SESSION[nom] = Olivier
Aprs :
$nom = Olivier
$_SESSION[nom] =
Page 3
- Page 3 :
Page 3
$nom =
$_SESSION[nom] =
- Page 2 :
Page 2
Avant :
$nom =
$_SESSION[nom] = Olivier
Aprs :
$nom =
$_SESSION[nom] =
Page 3
- Page 3 :
Page 3
$nom =
$_SESSION[nom] =
Danscecas,lavariable$nomn'existaitpas(effetderegister_globals = off).
- Script page2.php :
Lersultatestidentique.
session_unset
Syntaxe
session_unset()
Cette fonction est conserve pour des raisons de compatibilit ascendante. la place, il est conseill d'utiliser la fonction
unset pour supprimer les valeurs dans le tableau $_SESSION, ou de lui affecter un tableau vide (array()).
Lafonction session_unsetsupprimel'enregistrementdetouteslesvariablesdelasessionainsiquelesvariables
ellesmmes(ladiffrencedelafonctionsession_unregister).
Lafonctionsession_unsetestsanseffetsielleestappeleavantlafonctionsession_start.
session_destroy
Syntaxe
boolen session_destroy()
Aprs un appel la fonction session_destroy, la session n'existe plus un appel la fonction session_id
retourneunechanevide,etunappelultrieurlafonctionsession_startvaouvrirunenouvellesession.Par
contre, la fonction session_destroy ne supprime pas les variables de session dans le script en cours. Pour
supprimer immdiatement toutes les donnes de session, appelez la fonction session_unset ou affectez un
tableauvide$_SESSION.
Lafonctionsession_destroyretourneTRUE,encasdesuccs,etFALSE,encasd'chec.
La fonction session_destroy retourne FALSE et affiche une alerte, si elle est appele avant la fonction
session_start.
Exemple
- Script page2.php :
- Script page3.php :
<?php
// ouvrir/ractiver la session
session_start();
?>
<HTML>
<HEAD><TITLE>Page 3</TITLE></HEAD>
<BODY>
<B>Page 3</B><BR>
<?php
Rsultat
- Page 2 :
Page 2
session_id aprs =
$_SESSION[nom] = Olivier
Page 3
- Page 3 :
Page 3
$_SESSION[nom] =
Dans la deuxime page, les donnes de sessions ne sont pas encore supprimes. Par contre, dans la troisime
page,lesvariablessontvides(enfait,unenouvellesessionatouverte).
Lescriptpage2.phpsuivantsupprimetoutdesuitelesdonnes :
<?php
// ouvrir/ractiver la session
session_start();
// supprimer l'enregistrement des variables
session_destroy();
// supprimer les donnes de session
$_SESSION = array();
// rcuprer l'identifiant de la session aprs
$aprs = session_id();
?>
Grersoimmelatransmissiondel'identifiantdesession
Normalement, l'identifiant de session est automatiquement transmis par PHP, soit par cookie soit par l'URL (si
l'utilisateurn'acceptepaslescookies).
Nanmoins,troisdirectivesdeconfigurationpilotentcecomportement :
- session.use_cookie ;
- session.use_trans_id ;
- session.use_only_cookie.
Siladirectivesession.use_cookieestgale0,PHPnetentemmepasd'utiliserlescookiespourtransmettre
l'identifiant de session. Par contre, si la directive est gale 1 (valeur par dfaut), PHP tente d'utiliser les
cookies.
Si la directive session.use_trans_sid est gale 0 (valeur par dfaut), PHP n'utilise pas l'URL pour
transmettre l'identifiant de session. Par contre, si la directive est gale 1 et que l'identifiant de session ne
puisse pas tre transmis par cookie (du fait de la configuration ou d'un refus de l'utilisateur), alors PHP utilise
l'URLpourtransmettrel'identifiantdesession.
Siladirectivesession.use_only_cookieest1,seulslescookiessontutilisspourtransmettrel'identifiantde
session.Pardfaut,ladirectiveest0(compatibilitascendante).
La consquence principale est la suivante : si la directive session.use_trans_sid est gale 0 (valeur par
dfaut) et si l'identifiant de session ne peut pas tre transmis par cookie (du fait de la configuration ou d'un
refusdel'utilisateur),lagestionnefonctionneplus.
En terme de scurit, il est dconseill de permettre la transmission de l'identifiant de session par l'URL. Il est
prfrable d'utiliser des cookies, mais cela ncessite que l'internaute les acceptent. Les valeurs par dfaut des
directivesdeconfigurationvontdanscesens.
Exemple
- Script page1.php :
<?php
// ouvrir/ractiver la session
session_start();
// enregistrer une variable dans la session
$_SESSION["nom"] = "Olivier";
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1</B><BR>
<?php
// afficher l'ID de la session
echo 'session_id = ',session_id(),'<BR>';
// afficher la donne de session
echo 'nom = ',
- Script page2.php :
<?php
// ouvrir/ractiver la session
session_start();
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2</B><BR>
<?php
// afficher l'ID de la session
echo 'session_id = ',session_id(),'<BR>';
// afficher la donne de session
echo 'nom = ',
isset($_SESSION["nom"])?$_SESSION["nom"]:'','<BR>';
?>
</BODY>
</HTML>
Page 1
session_id = d726fe0c341a5318e23ce8fa458f6b2b
nom = Olivier
Page 2
- Affichage de la page 2 aprs un clic sur le lien Page 2 (si l'utilisateur refuse les cookies et que session.use_trans_sid =
0) :
Page 2
session_id = 7ea06105fcd63c888171925e59c973f2
nom =
Les informations de session n'ont pas t transmises et l'appel la fonction session_start a ouvert une
nouvellesession.
Page 1
session_id = 508036f27cbd7a7bac0317288c1a2ce0
nom = Olivier
Page 2
- Affichage de la page 1 aprs un clic sur le lien Page 2 si l'utilisateur refuse les cookies et que session.use_trans_sid =
1:
Page 2
session_id = 508036f27cbd7a7bac0317288c1a2ce0
nom = Olivier
Danscecas,lasessionestbienconserve.
RegardonslesourceHMTLdelapremirepagepourcomprendrecequis'estpass :
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
La balise <A HREF> >a t automatiquement rcrite par PHP, pour intgrer la transmission de l'identifiant de
session (nomm PHPSESSID par dfaut). Si un paramtre avait t prsent dans l'URL, PHP aurait ajout le
paramtrePHPSESSIDdansl'URL(&PHPSESSID=...).
Parcontre,unproblmeseposeencasderetoursurlapage1,parleboutonPrcdentedunavigateur :
Page 1
session_id = e0d99af15c40395379681f47a27393af
nom = Olivier
Page 2
Comme l'identifiant de session n'est pas retransmis lors de l'appel cette page, une nouvelle session est
ouverte.
De la mme manire, si une page propose un formulaire, une zone cache est automatiquement ajoute par
PHP,pourtransmettrel'identifiantdesessionlorsdelasoumissionduformulaire.
Exemple
Parcontre,l'informationn'estpastransmiselorsd'uneredirectionaveclafonctionheader.
Sil'identifiantn'estpasautomatiquementtransmisparPHP,ilconvientd'assurersoimmecettetransmission,le
plussimpletantdelefaireparl'URL(commePHPlefaitquandl'optionestactive).
Le nom de l'identifiant de session est dfini par une directive de configuration et utiliser "en dur" la valeur
PHPSESSIDpeutconduireducodenonportable.
Une premire possibilit consiste employer les fonctions session_name et session_id, pour construire le
paramtreinsrerdansl'URLsouslaformenom_identifiant=valeur_identifiant.
La deuxime possibilit (plus simple), consiste utiliser une constante, nomme SID, qui est automatiquement
initialiseparPHP,avecunechanenom_identifiant=valeur_identifiant.
<?php
// ouvrir/ractiver la session
session_start();
// construire la chane soi-mme
echo "Mon SID : ".session_name()."=".session_id()."<BR>";
// afficher la constante SID
echo "SID : ".SID;;
?>
Rsultat
Silenomdelavariableestmodifidanslefichierphp.ini,laconstanteSIDentientcompte.
Rsultat
SID : ID_SESSION=af15b302ccf0e48620ac7ab8b0b6b671
Exemples
- Dans une zone cache du formulaire (dans ce cas, il faut utiliser les fonctions session_name et session_id) :
header("Location: page2.php?".SID);
La constante SID n'est pas renseigne si le cookie est accept, sauf dans le script qui vient juste d'ouvrir la session (car PHP
ne sait pas encore si le cookie est accept par le client).
Intgrer un SID vide dans une URL n'est pas trs lgant mais ne pose pas de problme (<A HREF="page2.php?"> est
valide).
Si vous intgrez systmatiquement le SID dans les URL et que la transmission automatique fonctionne (soit par cookie, soit
par l'URL), ce n'est pas non plus trs lgant mais cela ne pose pas de problme.
Exemple
<?php
function url($url) {
// si la directive de configuration session.use_trans_sid
// est 0 (pas de transmission automatique par l'URL) et
// si SID est non vide (le poste a refus le cookie) alors
// il faut grer soi-mme la transmission
if ((get_cfg_var("session.use_trans_sid") == 0)
and (SID != "")) {
// ajouter la constante SID derrire l'URL avec un ?
// s'il n'y a pas encore de paramtre ou avec un & dans le cas contraire
$url .= ((strpos($url,"?") === FALSE)?"?":"&").SID;
}
return $url;
}
// ouvrir/ractiver la session
session_start();
// quelques tests
echo url("page2.php")."<BR>";
echo url("page3.php?nom=Olivier")."<BR>";
?>
Rsultat
page2.php?PHPSESSID=27c63e18284afaffb658d3495149d295
page3.php?nom="Olivier"&PHPSESSID=
27c63e18284afaffb658d3495149d295
page2.php?PHPSESSID=5a32506a14cc7d42a88fc7f4fec7ede0
page3.php?nom=Olivier&PHPSESSID=
5a32506a14cc7d42a88fc7f4fec7ede0
page2.php
page3.php?nom=Olivier
page2.php
page3.php?nom=Olivier
Danslederniercas,lorsquelecookieestrefus,c'estPHPquiajouteautomatiquementleSIDdansl'URL(carla
directivesession.trans_ideston).
Cette fonction peut ensuite tre appele partout o il faut construire une URL susceptible de transmettre
l'identifiantdesession.
Quelle que soit la configuration, cette fonction doit tre utilise lors d'une redirection avec la fonction header (car PHP ne
rcrit jamais les URL appeles par cette fonction).
Quelquesdirectivesdeconfigurationsupplmentaires
Encomplmentdecellesdjcites,ilestbondeconnatrelesdirectivesdeconfigurationsuivantes :
session.save_path
Rpertoiredanslequellesfichierstemporairescontenantlesinformationsdesessionsontenregistrs.
session.auto_start
Sielleestpositionne1,lafonction session_startestautomatiquementappeleaudbutdechaquescript
(pouruncodeportable,ilestprfrabled'appelerexplicitementlafonctionsession_start).
session.cookie_lifetime
Duredeviedescookiesdposssurlepostedel'utilisateur.Lavaleur0proposepardfaut,estbienadapte
pouruncookiedesession.
session.cache_limiter
Dtermine le comportement visvis du cache de toutes les pages concernes par la gestion des sessions
envoyes au navigateur. Valeurs possibles : nocache, private, public. Cette information est transmise dans
l'enttedelarponseduserveurWeb. nocachepardfaut.
session.cookie_path
Cheminsurleserveurdanslequellecookiedesessionestdisponible(voirlafonctionsetcookie)./pardfaut.
session.cookie_domain
Domaineauquellecookieestrenvoy(voirlafonctionsetcookie).Videpardfaut.
session.cookie_secure
Duredevieenminutesdespagesdanslecache.180pardfaut.Sanseffetsilavaleur nocacheestspcifie
danssession.cache_limiter.
Applicationlagestiondessessions
Les principes dfinis avec les autres techniques vont s'appliquer de manire similaire, lors de l'utilisation de la
fonctionnalitdegestiondessessionsdePHP4.
Le principe essentiel est de systmatiquement appeler la fonction session_start au dbut de chaque script,
soit pour ouvrir une session lors d'une premire visite, soit pour ractiver un contexte de session lors de la
poursuitedelanavigation.
- Script page1.php :
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// ouvrir/ractiver la session
session_start();
// tester si la session est nouvelle (i.e. ouverte par
// l'appel session_start ci-dessus) ou ancienne (i.e ouverte
// par un appel antrieur session_start)
// le mieuxest de tester si une de nos variables de session
// est dj enregistre
if (! isset($_SESSION["date"])) {
// variable " date " pas encore enregistre
// => nouvelle session
// => ouvrir la session au niveau applicatif
// pour cet exemple :
// - dterminer la date/heure d'ouverture
// de la session
$date = date("\l\e d/m/Y H:i:s");
// - enregistrer la date/heure d'ouverture
// de la session
$_SESSION["date"] = $date;
// - rcuprer l'identifiant de la session (pour info)
$session = session_id();
// - message
$message = "Nouvelle session : $session - $date";
} else {
// variable " date " dj enregistre
// => ancienne session
// => rcuprer les variables de session (uniquement
// celles utilises dans ce script)
// pour cet exemple :
// - date/heure d'ouverture de la session
$date = $_SESSION["date"];
// - rcuprer l'identifiant de la session (pour info)
$session = session_id();
// message
$message = "Session dj ouverte: $session - $date";
}
// dtermination de la date et de l'heure actuelle (pas celle
// de l'ouverture de la session
$actuel = "Nous sommes le ".date("d/m/Y").
" ; il est ".date("H:i:s");
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages
utiliser notre fonction gnrique url() pour tre
certain que l'identifiant de session est transmis
quelles que soient les conditions -->
<A HREF="<?php echo url("page2.php"); ?>">Page 2</A>
</BODY>
</HTML>
<?php
...
?>
<HTML>
<HEAD><TITLE>Page 2</TITLE></HEAD>
<BODY>
<B>Page 2 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages -->
<A HREF="<?php echo url("page1.php"); ?>">Page 1</A>
</BODY>
</HTML>
Rsultat
Le fait que cette page soit mise jour est li la directive de configuration session.cache_limiter qui est
gale nocache sur l'exemple : les pages concernes par la gestion des sessions ne sont pas mises dans le
cachedunavigateuretsontdoncsystmatiquementrafrachies.
Le code commun toutes les pages est bien entendu dfini dans une fonction, appele par les diffrents scripts.
L'utilisation de cette technique peut tre illustre sur une gestion de sessions avec authentification des
utilisateurs.
Exemple
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie est correcte
$requte = sprintf(
"SELECT * FROM utilisateurs WHERE identifiant = '%s'",
vers_base($identifiant));
$erreur = "";
$utilisateur = db_lire_ligne($requte,$erreur);
// l'identification est bonne s'il existe un utilisateur
// ayant l'identifiant saisi (! empty ...) et que le mot
// de passe corresponde ($utilisateur ... == ...)
$existe = ((! empty($utilisateur)) and
($utilisateur["mot_de_passe"] == $mot_de_passe));
return $existe;
}
// traitement du formulaire
if (isset($_POST["connexion"])) {
// rcuprer les informations saisies
$identifiant =
valeur_saisie($_POST["identifiant"]);
$mot_de_passe =
valeur_saisie($_POST["mot_de_passe"]);
// vrifier que l'utilisateur existe
if (utilisateur_existe($identifiant,$mot_de_passe)) {
// l'utilisateur existe ...
// => ouvrir la session au niveau applicatif
// pour cet exemple :
// - ouvrir la session
session_start();
// - enregistrer les donnes de session
$_SESSION["date"] = date("\l\e d/m/Y H:i:s");
$_SESSION["identifiant"] = $identifiant;
// puis rediriger l'utilisateur vers la page1 en
// appelant la fonction gnrique url pour tre
// certain que l'identifiant de session est transmis
// quelles que soient les conditions
header("location: ".url("page1.php"));
exit;
} else {
// l'utilisateur n'existe pas ...
// typiquement, afficher un message et proposer de nouveau
// l'identification
$message = "Identification incorrecte.
Essayez de nouveau.";
// laisser le formulaire s'afficher de nouveau ...
}
}
?>
<HTML>
<HEAD><TITLE>Login</TITLE></HEAD>
<BODY>
<FORM ACTION="login.php" METHOD="POST">
<TABLE BORDER=0>
<TR>
<TD ALIGN="right">Identifiant :</TD>
<TD><INPUT TYPE="text" NAME="identifiant" VALUE=
"<?php echo vers_formulaire($identifiant); ?>"></TD>
</TR>
<TR>
<TD ALIGN="right">Mot de passe :</TD>
<TD><INPUT TYPE="password" NAME="mot_de_passe" VALUE=
"<?php echo vers_formulaire($mot_de_passe); ?>"></TD>
</TR>
<TR>
<TD></TD>
<TD ALIGN="right"><INPUT TYPE="submit" NAME="connexion"
VALUE= "Connexion"></TD>
</TR>
</TABLE>
</FORM>
<FONT COLOR="red"><?php echo $message; ?></FONT>
</BODY>
</HTML>
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// ouvrir/ractiver la session
session_start();
// tester si la session est nouvelle (i.e. ouverte par
// l'appel session_start ci-dessus) ou ancienne (i.e ouverte
// par un appel antrieur session_start)
// le mieux est de tester si l'une de nos variables de session
// est dj enregistre
if (! isset($_SESSION["identifiant"])) {
// variable " identifiant " pas encore enregistre
// => l'utilisateur n'est pas connect
// => rediriger l'utilisateur vers la page de login
header("location: login.php");
exit;
} else {
// variable " identifiant" dj enregistre
// => l'utilisateur est connect
// => rcuprer les variables de session (uniquement
// celles utilises dans ce script)
// pour cet exemple :
// - date/heure d'ouverture de la session
$date = $_SESSION ["date"];
// - identifiant de l'utilisateur
$identifiant = $_SESSION["identifiant"];
// - rcuprer l'identifiant de la session (pour info)
$session = session_id();
// message
$message = "Session : $session - $identifiant - $date";
}
// dtermination de la date et de l'heure actuelle (pas celle
// de l'ouverture de la session
$actuel = "Nous sommes le ".date("d/m/Y").
" ; il est ".date("H:i:s");
?>
<HTML>
<HEAD><TITLE>Page 1</TITLE></HEAD>
<BODY>
<B>Page 1 - <?php echo $actuel; ?></B><BR>
<?php echo $message; ?><BR>
<!-- lien vers les autres pages
utiliser notre fonction gnrique url() pour tre
certain que l'identifiant de session est transmis
quelles que soient les conditions -->
<A HREF="<?php echo url("page2.php"); ?>">Page 2</A>
</BODY>
</HTML>
Remarquesetconclusion
Lesutilisateursmalinsoumalintentionns
Lepassagedel'identifiantdesessionparl'URLpeutposerdesproblmesdescurit.
Considronslescriptpage.phpsuivant :
<?php
// ouvrir/ractiver la session
session_start();
// afficher l'id de session
echo 'session_id = ',session_id();
?>
session_id : abc
La valeur donne la variable PHPSESSID dans l'URL a t prise comme identifiant de session. Cela peut
permettreunutilisateur(malinet/oumalintentionn)defairecroirevotreapplicationqu'iladjunesession
ouverte,oud'utiliserunesessionouverteparunautreutilisateur.
Pourempchercephnomne,ilfautmettreladirectivedeconfiguration session.use_only_cookies1,afin
de forcer l'utilisation d'un cookie pour la transmission de l'identifiant de session. L'inconvnient est que
l'utilisateurpeutrefuserlescookiesetquecettemthoden'est,detoutesfaons,pascompltementscurise
laseulesolutionvraimentsreconsisteutiliseruneconnexionscurise.
Indpendamment de cela, il est relativement simple de se prmunir contre l'emploi d'un faux identifiant de
session,soitenmmorisantctserveurlesidentifiantsdessessionsouvertes,soitentestantl'existenced'une
donnedesessiondans$_SESSION.
<?php
// ouvrir/ractiver la session
session_start();
if (! isset($_SESSION["identifiant"])) {
// si la donne de session "identifiant"
// n'existe pas, c'est que la session n'a
// pas t rellement ouverte par l'application
// faire ce qu'il faut ...
// pour cet exemple :
// - afficher un message
echo "Session non ouverte","<BR>";
// - simuler l'ouverture applicative de la session
$_SESSION["identifiant"] = "123";
} else {
// si la donne de session "identifiant" existe,
// c'est que la session a rellement t ouverte
// par l'application
echo "Session ouverte","<BR>";
echo "identifiant = ",$_SESSION["identifiant"],"<BR>";
}
// afficher l'id de session
echo 'session_id = ',session_id(),'<BR>';
?>
Rsultat:
Session ouverte
identifiant = 123
session_id = abc
PHP a conserv l'identifiant de session initial. En cas de besoin, la fonction session_regenerate_id peut tre
appelepourrgnrerunidentifiantdesession.
Exemple:
<?php
// ouvrir/ractiver la session
session_start();
if (! isset($_SESSION["identifiant"])) {
// si la donne de session "identifiant"
Rsultat:
Session ouverte
identifiant = 123
session_id = 69r09ddjnjjo5c5227rp2kls22
Cettetechniquenemetpasl'abridel'utilisationabusive,paruninternaute,d'unidentifiantdesessiond'unautre
internaute.
Rsultat:
- Un deuxime utilisateur russit rcuprer l'identifiant de session du premier utilisateur et effectue un appel du type :
http://_/page.php?PHPSESSID=ed63nvl9mbtv11muljg826r3q7
Session ouverte
identifiant = 123
session_id = ed63nvl9mbtv11muljg826r3q7
Si vous avez besoin d'un haut niveau de scurit, utilisez une connexion scurise.
Conclusion
Moyennantunpeuderigueurdanslecode,lafonctionnalitdegestiondessessionsdePHPestfacilemettre
en uvre et indpendante des techniques de navigation utilises (liens, formulaires). Pour des besoins de
scurit avance, elle peut tre facilement employe dans le cadre d'une connexion scurise dans ce cas, il
s'agitsurtoutd'uneproblmatiquedeconfigurationduserveurwebetiln'yariendeparticulierfaireauniveau
dePHP.
Si vous souhaitez conserver des informations sur un utilisateur d'une visite l'autre (ventuellement trs
loignesdansletemps),ilexistedeuxsolutionsprdominantes :
- dposer un cookie sur son poste (si possible avec son accord pralable) ;
- stocker les informations ct serveur (le plus pratique tant d'utiliser une base de donnes), et associer ces
informations une identification (typiquement un nom et un mot de passe) que l'utilisateur devra saisir chaque
visite.
Une solution intermdiaire, lgante et respectueuse de l'utilisateur, est employe par certains sites cette
solution consiste proposer l'utilisateur de dposer sur son poste un cookie qui ne contient qu'une ou deux
informations permettant la connexion automatique au site (sans saisir de nom et de mot de passe), les
informationscomplmentairestantrcupresdansunebase.
Nousallonsillustrercettesolutionl'aidededeuxpages :
- une page de personnalisation (script personnaliser.php) qui permet l'utilisateur d'activer ou de dsactiver la
connexion automatique ;
- une page d'identification (script login.php) qui, selon le cas, effectue la connexion automatique ou demande
l'utilisateur de se connecter.
Chaqueconnexiondel'utilisateurestunesession.
Exemple
- Script personnaliser.php :
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
// ouvrir/ractiver la session
session_start();
// initialisation des variables
$message = "";
// la session a-t'elle t ouverte au niveau applicatif ?
if (isset($_SESSION["identifiant"])) { // oui
// rcuprer les variables de session
$identifiant = $_SESSION["identifiant"];
$mot_de_passe = $_SESSION["mot_de_passe"];
// le script est-il appel en traitement du formulaire ?
if (isset($_POST["activer"])) { // oui
// activer la connexion automatique
// dposer deux cookies d'une dure de vie de 30 jours
// un pour l'identifiant de l'utilisateur et un pour son mot de passe
$expiration = time()+ (30 * 24 * 3600);
setcookie("identifiant",$identifiant,$expiration);
setcookie("mot_de_passe",$mot_de_passe,$expiration);
// prparer un message
$message = "Connexion automatique active";
} elseif (isset($_POST["dsactiver"])) { // oui
// dsactiver la connexion automatique
// supprimer les deux cookies
setcookie("identifiant");
setcookie("mot_de_passe");
// prparer un message
$message = "Connexion automatique dsactive";
}
} else { // session non ouverte au niveau applicatif
// rdiriger l'utilisateur vers la page de login
header("Location: login.php");
exit;
}
?>
<?php
// inclusion du fichier contenant les fonctions gnrales
include("fonctions.inc");
function utilisateur_existe($identifiant,$mot_de_passe) {
// fonction qui vrifie que l'identification saisie
// est correcte
$requte = sprintf(
"SELECT * FROM utilisateurs WHERE identifiant = '%s'",
vers_base($identifiant));
$erreur = "";
$utilisateur = db_lire_ligne($requte,$erreur);
// l'identification est bonne s'il existe un utilisateur
// ayant l'identifiant saisi (! empty _) et que le mot
// de passe correspond ($utilisateur _ == _)
$existe = ((! empty($utilisateur)) and
($utilisateur["mot_de_passe"] == $mot_de_passe));
return $existe;
}
// initialisation des variables
$message = "";
$identifiant = "";
$mot_de_passe = "";
$action = "";
// le script est-il appel en validation du formulaire
if (isset($_POST["connexion"])) { // oui
// => connexion manuelle
// rcuprer les information saisies
$identifiant =
valeur_saisie($_POST["identifiant"]);
$mot_de_passe =
valeur_saisie($_POST["mot_de_passe"]);
Rsultat
- Premier appel :
- Quitter puis revenir sur une des deux pages: arrive directe sur la page de personnalisation (une connexion
>
- Quitter puis revenir sur une des deux pages: la page d'identification est propose (plus de connexion automatique) :
- Refaire la squence d'activation puis revenir sur l'une des deux pages, aprs avoir supprim le compte de l'utilisateur
(la connexion automatique choue) :
Il est prfrable de stocker le mot de passe de l'utilisateur sous forme crypte ou d'utiliser un identifiant de connexion
automatique associ l'utilisateur. De cette manire, dans les deux cas, le mot de passe de l'utilisateur n'est pas expos aux
regards indiscrets.
Depuis le dbut de cet ouvrage, nous avons rencontr des variables "particulires" : celles associes des
donnes de formulaire, des donnes transmises par une URL, des donnes d'un cookie ou encore, des
donnesdesessions.
CesdiffrentstypesdevariablessontdsignssousletermedevariablesGPCS(Get/Post/Cookie/Session).
Nousavonsvuquecesvariablesfonctionnaientselonlesmmesprincipes :
- Elles sont accessibles directement sous la forme $x, si la directive de configuration register_globals est on.
- Les variables Get/Post/Cookie peuvent aussi tre explicitement importes dans le script grce la fonction
import_request_variables (utile si register_ globals est off).
- Elle sont aussi accessibles par l'intermdiaire de tableaux associatifs $_GET, $_POST, $_COOKIE et $_SESSION. En
complment, le tableau associatif $_REQUEST regroupe le contenu des tableaux $_GET, $_POST et $_COOKIE.
Pourchaquetype,leconseilestlemme :utiliserdeprfrencel'accsparletableauassociatifcorrespondant.
Deuxraisonsjustifientceconseil :
- C'est la seule manire d'tre certain que l'information lue arrive bien par le moyen attendu.
- La directive de configuration register_globals est off par dfaut et passera dfinitivement off dans une
prochaine version de PHP.
Eneffet,quesepassetilsi,danslemmescript,ilexistedesvariablesGPCSportantlemmenom ?
Exemple
- Script page1.php :
<?php
// ouvrir une session et enregistrer une variable de
// session nomme " x " de valeur " SESSION "
session_start();
session_register("x"); // dconseill
$x = "SESSION";
// dposer un cookie nomm " x " de valeur " COOKIE "
setcookie("x","COOKIE");
?>
<!-- Dans le formulaire, mettre une variable nomme " x " de
valeur " GET " dans l'URL de ACTION -->
<FORM ACTION="page2.php?x=GET" METHOD="POST">
<!-- et une zone nomme " x " de valeur " POST " -->
- Script page2.php :
<?php
// ractiver la session
session_start();
// afficher $x directement
echo '$x = ',isset($x)?$x:'','<BR>';
// afficher les valeurs de " x " partir des tableaux
echo '$_GET["x"] = ',
isset($_GET["x"])?$_GET["x"]:'','<BR>';
echo '$_POST["x"] = ',
isset($_POST["x"])?$_POST["x"]:'','<BR>';
echo '$_COOKIE["x"] = ',
$x = SESSION
$_GET["x"] = GET
$_POST["x"] = POST
$_COOKIE["x"] = COOKIE
$_SESSION["x"] = SESSION
$_REQUEST["x"] = COOKIE
$x =
$_GET["x"] = GET
$_POST["x"] = POST
$_COOKIE["x"] = COOKIE
$_SESSION["x"] =
$_REQUEST["x"] = COOKIE
Cetexemplepermettroisconstatations :
- Les valeurs des diffrentes variables x sont bien accessibles simultanment, sans ambigut dans leur tableau
respectif. La seule exception concerne la donne de session enregistre avec session_register lorsque
register_globals est off: dans ce cas, nous avons dj vu que session_register ne faisait rien. Si la
donne avait t enregistre sous la forme $_SESSION["x"] = "SESSION", le problme ne se produirait pas et la
donne serait prsente l'arrive dans $_SESSION.
- La variable $x n'est pas forcment initialise et, lorsqu'elle l'est, elle est gale la valeur de la variable de session.
Mais estce toujours le cas?
- Le tableau $_REQUEST contient uniquement la valeur COOKIE. Mais estce toujours le cas?
Si nous refaisons la manipulation sans la variable de session, nous obtenons le rsultat suivant (si
register_globalseston) :
$x = COOKIE
$_GET["x"] = GET
$_POST["x"] = POST
$_COOKIE["x"] = COOKIE
$_SESSION["x"] =
$_REQUEST["x"] = COOKIE
Cette fois, c'est la valeur du cookie qui est prise en compte. Si nous enlevons le cookie, le rsultat est le
suivant :
$x = POST
$_GET["x"] = GET
$_POST["x"] = POST
$_COOKIE["x"] =
$_SESSION["x"] =
$_REQUEST["x"] = POST
Ici, c'est la valeur de la zone formulaire (POST) qui est prise en compte. Si nous enlevons cette dernire, le
rsultatestlesuivant :
$x = GET
$_GET["x"] = GET
$_POST["x"] =
$_COOKIE["x"] =
Ilneresteplusquelavaleurtransmiseparl'URL.
Ceuxquilesouhaitentpeuventraliserletest,lersultatobtenun'estpasliunquelconqueordred'apparition
desinformations,nidanslapage1nidanslapage2.
Enfait,encasdeconflit,letypedevariablequialaprioritetquicraselesautresestdfiniparladirectivede
configuration variables_order. Cette directive est une chane compose des caractres G, P, C et S,
correspondant aux types dj voqus, et d'un cinquime caractre, E, correspondant aux variables
d'environnement.
Les variables d'environnement correspondent aux variables d'environnement du systme d'exploitation qui sont
rendues disponibles dans l'environnement PHP, soit directement sous la forme $x, soit travers le tableau
associatf$_ENV.
L'ordred'apparitiondeslettresEGPCSdansladirective,correspondunordredeprioritcroissant.
Lersultatobtenuprcdemmentestdlavaleursuivantedeladirective :
variables_order="GPCS"
Lavariable$xestbiend'abordgalelavaleurdelavariabledesession,puiscelleducookie,etc.
Unproblmesimilairepeutseproduirelorsdel'utilisationdelafonction import_request_variables.Lepremier
paramtre de cette fonction indique les types de variables importer, sous la forme d'une combinaison des
lettresG, PetC : PCparexemple.Lesvariablessontimportesdansl'ordreindiquetcrasentlesvariablesde
mmenomprcdemmentimportes.Dansnotreexemple,lesvariables COOKIEcraserontlesvariablesPOST de
mme nom pralablement importes. Pour viter ce genre de problme, il est possible d'appeler plusieurs fois la
fonction,enindiquantchaquefoisunprfixediffrentpourlenomdelavariable(deuximeparamtre).
Ce n'est pas une bonne habitude de programmation d'utiliser le mme nom pour plusieurs informations ; un dveloppeur sens
ne sera pas confront ce problme.
Cette situation carte, il faut avoir conscience qu'un utilisateur (malin et/ou mal intentionn) peut assez facilement fournir une
valeur, par un moyen donn (GPC en l'occurrence), une variable dont vous pensez contrler l'origine.
crire du code dont le fonctionnement est li une certaine valeur de la directive variables_order n'est sans doute pas,
non plus, une bonne ide du point de vue de la portabilit et de la maintenabilit.
Leconseilavis,donnparl'quipededveloppementdePHP,estdonclesuivant :
Rcuprez les valeurs "EGPCS" par les tableaux associatifs pour viter tout problme.
Un site interactif a souvent besoin d'envoyer des messages lectroniques aux utilisateurs, par exemple pour
confirmerunachat,uneinscriptionouenvoyerunelettred'information.
La fonction mail, propose par PHP, permet de rpondre simplement ce genre de besoin. Cette fonction est
dtaille dans ce chapitre, d'abord, pour envoyer des messages textes (sans pice jointe), puis pour envoyer
desmessagesauformatMIME(MultipurposeInternetMailExtensions).
En complment, PHP propose une bibliothque puissante, mais plus complexe d'utilisation, pour grer des
messages selon le protocole IMAP (Internet Message Access Protocol). Cette bibliothque ne sera pas aborde
danscetteouvragecarellen'estpasindispensablepourrpondreaubesoinvoquprcdemment.
Lafonctionmailpermetd'envoyerunmessagelectronique.
Syntaxe
destinataire
Adresse email du destinataire. Des destinataires multiples peuvent tre indiqus en les sparant par des
virgules.
objet
Objetdumessage.
message
Textedumessage.
entte
Enttessupplmentaires.
La fonction mail envoie le message caractris par les diffrents paramtres un serveur de messagerie dfini
parlesdirectivesdeconfigurationsuivantes :
LafonctionmailretourneTRUEsilemessageaputreenvoyauserveur(cequinegarantitpasquecedernier
apul'envoyeravecsuccs)et FALSEdanslecascontraire.Iln'yaaucunmoyendesavoirsilemessageat
envoyavecsuccs cettevrificationdoittreraliseendehorsdePHP.
Le quatrime paramtre permet de spcifier des informations supplmentaires qui sont envoyes dans l'entte
dumessage desinformationsmultiplesdoiventtresparesparlasquence\r\n.
La squence utiliser comme sparateur d'en-tte est souvent source de problme (et de dbat dans les forums de
discussion). Trs souvent, la squence \n seule fonctionne ; parfois, la squence \r\n ne fonctionne pas.
<?php
// destinataire
$destinataire = "contact@olivier-heurtel.fr";
// objet
$objet = "Inscription monSite.com";
// message
$message =
"Monsieur Heurtel,
Nous vous remercions pour votre inscription sur note site monSite.com.
Nous esprons que ce site rpondra vos attentes.
Le webmaster.";
Cet exemple montre que le message peut tre directement crit sur plusieurs lignes il est aussi possible de le
construireparconcatnation.
<?php
// deux destinataires spars par une virgule
$destinataires = "olivier@diane.com,xavier@zeus.fr";
// objet
$objet = "Rservation d'un court de squash";
// message
$message .= "";
$message .= "Olivier, Xavier,\r\n";
$message .= "Nous vous confirmons votre rservation pour\r\n";
$message .= "un court de squash le lundi 10 septembre de\r\n";
$message .= "18h30 19h30.\r\n\r\n";
$message .= "Le CSM.\r\n";
// en-ttes supplmentaires
$enttes .= "";
$enttes .= "From: \"Rservation CSM\" <resa@csm.fr>\r\n";
$enttes .= "Reply-To: \"Rservation CSM\" <resa@csm.fr>\r\n";
$enttes .= "X-Priority: 1\r\n";
// envoi
$ok = mail($destinataires,$objet,$message,$enttes);
?>
Lesenttessupplmentairessontspcifissouslaformemot_cl: valeur.
Lesentteslespluscourantssontlessuivants :
Dans le paramtre destinataire, il n'est pas possible de spcifier une adresse sous la forme ["nom en clair"]
<adresse e-mail>. Par contre, il est possible d'indiquer des adresses sous cette forme en les envoyant dans l'en-tte To:,
en doublon du paramtre destinataire.
Prambule
Danscettepartie,nousallonstudiercommentenvoyerdesmessagesauformatMIMEouplusgnralementau
formatMultipartMIME.
LeformatMIMEpermetd'envoyerunmessageayantunautreformatquedutexte :formatHTML,image...
Le format Multipart MIME permet d'envoyer un message compos de plusieurs parties ayant chacune un format
diffrent(dutexteplusuneimage,parexemple),unedes"parties"pouvanttreunepicejointe.
L'objectif de ce point, sans rentrer dans le dtail du format MIME (les amateurs peuvent se pencher sur les
nombreuses RFC qui traitent du sujet), est de montrer concrtement comment procder sur deux cas typiques,
l'envoid'unmessageauformatHTMLetl'envoid'unmessageavecunepicejointe.
MessageauformatHTML
Lecasdel'envoid'unmessageauformatHTMLpermetd'illustrerl'utilisationduformatMIMEsimple.
Exemple(sourced'unmessageMIMEauformatHTML):
Un message MIME simple comprend d'abord les enttes standard d'un message, puis, trois lignes d'enttes
supplmentaires (en gras) indiquant que le message est au format MIME, et enfin, le corps du message
proprementdit.
Lestroislignesd'enttessupplmentairessontlessuivantes :
MIME-Version
IndiquequelemessageestauformatMIMEetprciselaversion.
Content-Type
IndiqueletypeMIMEducontenu.
Content-Transfer-Encoding
Indiqueletyped'encodage.
QuelquestypesMIMEusuels :
text/plain
Textesimple.Lejeudecaractresutilispeuttrespcifiparl'optioncharset(parexempleiso88591).
text/html
image/jpeg
ImageauformatJPEG.
application/octet-stream
Donnesbinaires.
Quelquestypesd'encodagesusuels :
7bit
Encodagedutextesur7bits.
8bit
Encodagedutextesur8bits(utiliserpourconserverlescaractresaccentus).
base64
Encodagepourlesdonnesbinaires(voirfonctionbase64_encode).
Classiquement, pour les types MIME text/*, un type d'encodage 7bit ou 8bit est utilis et le corps du
message contient le texte en clair. Il est aussi possible d'employer un encodage base64 et de placer dans le
corpsdumessagedesdonnesencodesenconsquence(voirlafonctionbase64_encodeplusloin).
PourlestypesMIMEcorrespondantdesdonnesbinaires(image,son,documentPDF...),unencodagebase64
est utilis et le corps du message contient les donnes encodes en consquence (voir la fonction
base64_encodeplusloin).
EnvoyerunmessageauformatHTMLaveclafonctionmailestrelativementsimple.
Ilfaut :
Exemple
<?php
// destinataires
$destinataires = "xavier@zeus.fr";
// objet
$objet = "Bonjour !";
// en-ttes supplmentaires
$enttes .= "";
$enttes .= "From: \"Olivier\" <olivier@diane.com>\r\n";
$enttes .= "MIME-Version: 1.0\r\n";
$enttes .= "Content-Type: text/html; charset=iso-8859-1\r\n";
$enttes .= "Content-Transfer-Encoding: 8bit\r\n";
// message (HTML)
$message .= "";
$message .= "<HTML>\r\n";
$message .= "<HEAD><TITLE>Bonjour !</TITLE></HEAD>\r\n";
$message .= "<BODY>\r\n";
$message .= "<FONT COLOR=\"green\">Bonjour !</FONT>\r\n";
$message .= "</BODY>\r\n";
$message .= "</HTML>\r\n";
// envoi
$ok = mail($destinataires,$objet,$message,$enttes);
?>
Sivousutilisezunencodage base64,vouspouvezappelerlafonctionbase64_encodepoureffectuerl'encodage
Syntaxe
donnes
Donnesencoder.
Cettefonctionretournelesdonnesencodes.
En complment, pour se conformer aux spcifications, il faut dcouper les donnes encodes en base64 en
morceauxde76octetssparsparunesquence\r\n.
Cetteoprationseraralisetrssimplementgrcelafonctionchunk_split.
Syntaxe
donnes
Donnesdcouper.
longueur
Longueurdesmorceaux(76pardfaut).
sparateur
Sparateurdesmorceaux(\r\npardfaut).
Lafonctionchunk_splitretournelachanedcoupe.
Exemple
<?php
// message
$message .= "";
$message .= "<HTML>\n";
$message .= "<HEAD><TITLE>Bonjour !</TITLE></HEAD>\n";
$message .= "<BODY>\n";
$message .= "<FONT COLOR=\"green\">Bonjour !</FONT>\n";
$message .= "</BODY>\n";
$message .= "</HTML>\n";
// encodage et dcoupage du message
$message = chunk_split(base64_encode($message));
// affichage du message
echo $message;
?>
Rsultat
PEhUTUw+CjxIRUFEPjxUSVRMRT5Cb25qb3VyICE8L1RJVExFPjwvSEVBRD4KPEJPRFk+CjxGT05U
IENPTE9SPSJncmVlbiI+Qm9uam91ciAhPC9GT05UPgo8L0JPRFk+CjwvSFRNTD4K
Exemple
<?php
// lecture d'une image
$fichier = fopen("logo.gif","r");
$donnes = fread($fichier,filesize("logo.gif"));
fclose($fichier);
// encodage et dcoupage des donnes
Rsultat
R0lGODlhCgEkAPcAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwMDcwKbK8EAgAGAgAIAgAKAgAMAg
AOAgAABAACBAAEBAAGBAAIBAAKBAAMBAAOBAAABgACBgAEBgAGBgAIBgAKBgAMBgAOBgAACAACCA
AECAAGCAAICAAKCAAMCAAOCAAACgACCgAECgAGCgAICgAKCgAMCgAOCgAADAACDAAEDAAGDAAIDA
...
AAj/AP8JHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmyZUp7
CchJI0BAWjsEC2EeILfNpc+fQIO2I0DO3kB75IgitEezKbmgGw80nap0oFSqNHv+u4q1a82B27wS
MMi16YGtYqWRS3CQqdiu0tC+pQ==
<?php
// destinataires
$destinataires = "xavier@zeus.fr";
// objet
$objet = "Bonjour !";
// en-ttes supplmentaires
$enttes = "";
$enttes .= "From: \"Olivier\" <olivier@diane.com>\r\n";
$enttes .= "MIME-Version: 1.0\r\n";
$enttes .= "Content-Type: text/html; charset=iso-8859-1\r\n";
$enttes .= "Content-Transfer-Encoding: base64\r\n";
// message
$message = "";
$message .= "<HTML>\n";
$message .= "<HEAD><TITLE>Bonjour !</TITLE></HEAD>\n";
$message .= "<BODY>\n";
$message .= "<FONT COLOR=\"green\">Bonjour !</FONT>\n";
$message .= "</BODY>\n";
$message .= "</HTML>\n";
// encodage et dcoupage
$message = chunk_split(base64_encode($message));
// envoi
$ok = mail($destinataires,$objet,$message,$enttes);
?>
Messageavecpicejointe
Lecasdel'envoid'unmessageavecpicejointepermetd'illustrerl'utilisationduformatMultipartMIME.
Exemple (source d'un message avec pice jointe au format Multipart MIME)
--=O=L=I=V=I=E=R=
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
--=O=L=I=V=I=E=R=--
Un message Multipart MIME contient d'abord les enttes standards d'un message, puis, deux lignes d'enttes
supplmentaires(engras)indiquantquelemessageestauformatMultipartMIME,etenfinlesdiffrentesparties
Dans l'entte du message, nous retrouvons les deux lignes MIME-Version et Content-Type. Pour un message
Multipart MIME, Content-Type est gal multipart/mixed suivi d'une option boundary qui donne la chane
utilisepourmarquerledbutdesdiffrentespartiesdumessage(=O=L=I=V=I=E=R=surnotreexemple).
Chaque partie du message commence par deux signes "moins" suivis de la chane donne par boundary (
=O=L=I=V=I=E=R=,surnotreexemple).
Dansl'enttedechaquepartie,nousretrouvonslesdeuxlignesContent-TypeetContent-Transfer-Encoding
quiprcisentletypeMIMEetl'encodagedelapartie.
Lesdonnesdelapartieviennentensuite.
Lafindumessageestmarquepardeuxsignes"moins",suivisdelachanedonneparboundarysuiviededeux
signes"moins"(--=O=L=I=V=I=E=R=--,surnotreexemple).
La chane donne par boundary doit tre choisie avec soin pour viter d'tre confondue avec des donnes, ce
quiconduiraitunemauvaiseinterprtationdumessage.
Dans l'entte de chaque partie, il est possible d'indiquer une ligne d'entte supplmentaire (Content-
Disposition)quivasuggrerauclientdemessagerieunemaniredeprsenterlesdonnescorrespondantes
l'utilisateur :lesdeuxvaleurspossiblessontinline(lesdonnessontprsentesdirectementdanslemessage)
ou attachment (les donnes sont prsentes en picejointe) dans ce cas, un nom de fichier peut tre
suggrgrcel'optionfilename.
Exemple
Pour envoyer un message Multipart MIME avec la fonction mail, il faut construire les diffrentes parties du
message dans le paramtre message, en respectant la structure indique prcdemment le paramtre entte
de la fonction mail contient les enttes standard, y compris l'entte indiquant qu'il s'agit d'un message au
formatMultipartMIME.
Les diffrentes parties du message doivent tre spares par une ligne vide (\r\n). Au sein de chaque partie, il en est de
mme entre l'en-tte de la partie et les donnes. Voir la remarque dans le chapitre Envoyer un courrier lectronique - Envoyer un
message texte sans pice jointe au sujet de la squence \r\n.
<?php
// destinataires
$destinataires = "xavier@zeus.fr";
// objet
$objet = "Bonjour !";
// en-ttes supplmentaires
$enttes = "";
// - origine du message
$enttes .= "From: \"Olivier\" <olivier@diane.com>\r\n";
// - message au format Multipart MIME
$enttes .= "MIME-Version: 1.0\r\n";
$enttes .= "Content-Type: multipart/mixed; ";
$enttes .= "boundary=\"=O=L=I=V=I=E=R=\"\r\n";
// message
$message = "";
// - premire partie du message (texte proprement dit)
// - en-tte de la partie
$message .= "--=O=L=I=V=I=E=R=\r\n";
$message .= "Content-Type: text/plain; ";
$message .= "charset=iso-8859-1\r\n ";
$message .= "Content-Transfer-Encoding: 8bit\r\n";
$message .= "\r\n"; // ligne vide
// - donnes de la partie
$message .= "Voir la pice jointe.\r\n";
$message .= "\r\n"; // ligne vide
// - deuxime partie du message (pice-jointe)
Plusieurs pices jointes peuvent tre envoyes en rptant, autant de fois que ncessaire, les lignes de code
correspondantes.
En thorie, la totalit du message pourrait tre construite dans l'en-tte (paramtre message gal une chane vide). Dans la
pratique, et en rgle gnrale, cela fonctionne sur plate-forme Linux, mais pas sur plate-forme Windows.
PHPproposeungrandnombredefonctionspermettantdemanipulerlesfichierssurleserveur.
Lesfonctionslesplusutilessontlessuivantes:
Nom Rle
fopen Ouvrir un fichier
fclose Fermer un fichier
fread Lire le contenu d'un fichier (dans une chane)
file Lire le contenu d'un fichier (dans un tableau)
fwrite crire dans un fichier
file_get_contents Ouvrir, lire et fermer un fichier
file_put_contents Ouvrir, crire et fermer dans un fichier
copy Copier un fichier
unlink Supprimer un fichier
rename Renommer un fichier
file_exists Tester l'existence d'un fichier
filesize Lire la taille d'un fichier
chdir Changer de rpertoire courant
opendir Ouvrir un rpertoire
closedir Fermer un rpertoire
readdir Lire le contenu d'un rpertoire
Certaines de ces fonctions vont prendre comme paramtre un nom de fichier ou de rpertoire. Sur une plate
forme Windows, pour spcifier un chemin d'accs dans une chane de caractres dlimite par des guillemets,
vousdevezchapperl'antislash(parunantislash=\\)ouvouspouvezutiliserunenotationtype"Unix",avec
des slashs (/). Par exemple, le chemin c:\temp\info.txt peut tre crit "c:\\temp\\info.txt" ou
"c:/temp/info.txt".Siaucuncheminn'estindiqu,c'estlerpertoirecourantquiestutilis.Desnomsrelatifs
peuvent tre spcifis en utilisant le caractre .(point)pourdsignerlerpertoirecourant,et .. (deux points)
pourdsignerlerpertoiresuprieur.
La constante prdfinie DIRECTORY_SEPARATOR donne le caractre de sparation utilis dans les noms de
rpertoirepourlaplateformesurlaquellePHPestinstall.
Parailleurs,plusieursfonctionspossdentunparamtre(appel utiliser_inclusiondanslessyntaxesdecet
ouvrage) qui permet de rechercher le fichier dans les rpertoires spcifis par la directive de configuration
include_path.
fopen
Lafonctionfopenpermetd'ouvrirunfichier.
Syntaxe
nom_fichier
Chemind'accsaufichierouvrir.
mode
Moded'ouverturedufichier
r=lectureseule
utiliser_inclusion
Mettre 1 (ou TRUE) pour rechercher le fichier dans les rpertoires spcifis par la directive de configuration
include_path.
LafonctionfopenretourneunpointeurdefichierencasdesuccsetFALSEencasd'chec.
fclose
Lafonctionfclosepermetdefermerunfichier.
Syntaxe
fichier
Pointeurdefichierpralablementouvert.
LafonctionfcloseretourneTRUEencasdesuccsetFALSEencasd'chec.
fread
Lafonctionfreadpermetdelirelecontenud'unfichier(dansunechane).
Syntaxe
fichier
Pointeurdefichierpralablementouvert.
longueur
Nombred'octetsliredanslefichier.
LafonctionfreadretournelesdonnesluesouFALSEencasd'chec.
file
Lafonctionfilepermetdelirelecontenud'unfichier(dansuntableau).
Syntaxe
nom_fichier
Chemind'accsaufichierlire.
Mettre1 (ou TRUE) pour rechercher le fichier dans les rpertoires spcifis par la directive de configuration include_path.
La fonction file ouvre le fichier dont le nom est pass en paramtre, et le retourne dans un tableau, chaque
lignedutableaucorrespondantunelignedufichier.LafonctionretourneFALSEencasd'erreur.
fwrite
Lafonctionfwritepermetd'criredansunfichier.
Syntaxe
fichier
Pointeurdefichierpralablementouvert.
donnes
Donnescriredanslefichier.
longueur
Siprcis,indiquelenombred'octetscrire(toutelachanedonnespardfaut).
Lafonctionfwriteretournelenombred'octetscritsouFALSEencasd'chec.
file_get_contents
Lafonctionfile_get_contentspermetdelirelecontenud'unfichier(dansunechane).
Syntaxe
Avec
nom_fichier
Chemind'accsaufichierlire.
utiliser_inclusion
Mettre 1 (ou TRUE) pour rechercher le fichier dans les rpertoires spcifis par la directive de configuration
include_path.
La fonction file_get_contents ouvre le fichier dont le nom est pass en paramtre et le retourne dans une
chane.LafonctionretourneFALSEencasd'erreur.
Utiliser cette fonction se rvle plus performant qu'ouvrir le fichier (fopen), le lire (fread) et le refermer
(fclose).
file_put_contents
La fonction file_put_contents permet d'crire le contenu d'une chane dans un fichier. Cette fonction est
apparueenversion5.
Syntaxe
Avec
nom_fichier
Chemind'accsaufichierlire.
donnes
Donnescriredanslefichier.
mode
Constante FILE_USE_INCLUDE_PATH pour crire dans le premier rpertoire spcifi dans la directive de
configurationinclude_path.
ConstanteFILE_APPENDpourajouterlesdonneslafindufichier,s'ilexistedj.
Spcifierlasommedesdeuxconstantespourcombinerlesdeuxoptions.
La fonction file_put_contents ouvre le fichier dont le nom est pass en paramtre, crit le contenu de la
chanepasseenparamtrepuisfermelefichier.
Si le fichier n'existe pas, il est cr. Si le fichier existe, son contenu est remplac, sauf si la constante
FILE_APPENDestspcifieentroisimeparamtre auquelcaslesdonnessontajouteslafindufichier.
Lafonctionretournelenombred'octetscritsdanslefichier,ouFALSEencasd'erreur.
copy
Lafonctioncopypermetdecopierunfichier.
Syntaxe
source
Emplacementdufichiersource.
destination
Emplacementdufichierdestination.
LafonctioncopyeffectuelacopieetretourneTRUEencasdesuccsetFALSEencasd'chec.
unlink
Lafonctionunlinkpermetdesupprimerunfichier.
Syntaxe
nom_fichier
Emplacementdufichiersupprimer.
Lafonctionunlinksupprimelefichier,retourneTRUEencasdesuccsetFALSEencasd'chec.
rename
Syntaxe
ancien_nom
Emplacementdufichierrenommer.
nouveau_nom
Nouveaunomdufichier.
LafonctionrenamerenommelefichieretretourneTRUEencasdesuccsetFALSEencasd'chec.
file_exists
Lafonctionfile_existspermetdetesterl'existenced'unfichier.
Syntaxe
nom_fichier
Emplacementdufichiertester.
Lafonctionfile_existsretourneTRUEsilefichierexisteetFALSEdanslecascontraire.
filesize
Lafonctionfilesizepermetdelirelatailled'unfichier.
Syntaxe
nom_fichier
Emplacementdufichier.
LafonctionfilesizeretournelatailledufichierouFALSEencasd'chec.
chdir
Lafonctionchdirpermetdechangerderpertoirecourant.
Syntaxe
chemin
Rpertoiresouhait.
LafonctionchdirretourneTRUEencasdesuccsetFALSEencasd'chec.
opendir
Lafonctionopendirpermetd'ouvrirunrpertoire.
chemin
Rpertoireouvrir.
Lafonctionopendirouvreunrpertoireenvuedelirecequ'ilcontientetretourneunpointeursurledossier,ou
FALSEencasd'chec.
closedir
Lafonctionclosedirpermetdefermerunrpertoire.
Syntaxe
closedir(ressource rpertoire)
rpertoire
Pointeurderpertoirepralablementouvert.
Lafonctionclosedirfermeunpointeurderpertoirepralablementouvert.
readdir
Lafonctionreaddirpermetdelirelecontenud'unrpertoire.
Syntaxe
rpertoire
Pointeurderpertoirepralablementouvert.
La fonction readdir retourne le nom du fichier suivant dans le rpertoire (sans ordre particulier), ou FALSE s'il
n'yaplusdenomdefichierliredanslerpertoire.
Exemplesd'utilisation
<?php
// ouvrir un fichier
$f = fopen("e:/info.txt","w");
// crire dans le fichier
fwrite($f, "Olivier HEURTEL");
// fermer le fichier
fclose($f);
// copier un fichier
copy("e:/info.txt","e:/temp/info.txt");
// supprimer un fichier
unlink("e:/info.txt");
// renommer un fichier
rename("e:/temp/info.txt","e:/temp/auteur.txt");
// ouvrir un fichier
$f = fopen("e:/temp/auteur.txt","r");
// lire dans le fichier
$texte = fread($f, filesize("e:/temp/auteur.txt"));
// fermer le fichier
fclose($f);
// afficher les informations lues
echo $texte;
Rsultat
Olivier HEURTEL
<?php
// ouvrir le rpertoire
$dir = opendir("e:/temp");
// parcourir le rpertoire en lisant le nom d'un fichier chaque itration
while($fichier = readdir($dir)) {
echo "$fichier<BR>";
}
// ferme le rpertoire
closedir($dir);
?>
Rsultat
.
..
lisez-moi.txt
auteur.txt
La fonctionreaddirpermetdercuprerlenomdesfichiersetdesrpertoirescontenusdansunrpertoire.Le
rpertoire courant et le rpertoire suprieur sont aussi retourns avec les symboles . (point) et .. (deux
points).
Si la directive de configuration magic_quotes_runtime est on, les donnes lues dans les fichiers subiront le
dsormaistraditionnelencodage"magicquotes".
Exemple
<?php
// criture d'une information dans un fichier
$f = fopen("e:/temp/info.txt","w");
fwrite($f, "C'est l't");
fclose($f);
// lecture du contenu du fichier
$f = fopen("e:/temp/info.txt","r");
$texte = fread($f, filesize("e:/temp/info.txt"));
fclose($f);
// affichage des informations lues
echo $texte;
?>
C'est l't
C\'est l\'t
Comme nous l'avons vu dans le chapitre sur l'accs aux bases de donnes (Accder aux bases de donnes), il
esttrsfaciledemodifierlavaleurdeladirectivemagic_quotes_runtimeencoursdescriptgrcelafonction
set_magic_quotes_runtime.
Exemple
<?php
// criture d'une information dans un fichier
$f = fopen("e:/temp/info.txt","w");
fwrite($f, "C'est l't");
fclose($f);
// mettre magic_quotes_runtime off (0)
set_magic_quotes_runtime(0);
// lecture du contenu du fichier
$f = fopen("e:/temp/info.txt","r");
$texte = fread($f, filesize("e:/temp/info.txt"));
fclose($f);
// affichage des informations lues
echo $texte;
?>
C'est l't
Ilestdonctrsfaciled'crireuncodequisoitindpendantdelaconfigurationetafinquetoutedonneluedans
unfichiersoitencode"magicquotes"ounon.
Encomplment,lafonctionstripslashespeuttreutiliseencasdebesoinpoursupprimerl'encodage.
Les donnes lues dans une base et les donnes lues dans un fichier ont le mme comportement visvis de la
fonctionnalit"magicquotes".
magic_quotes_runtime
on off
Si ce comportement n'est pas dsir, il convient donc de mettre magic_quotes_runtime off (dans le script
oudansladirectivedeconfiguration)oudesystmatiquementappelerfwriteenspcifiantlalongueur.
CertainssitespeuventproposerauxutilisateursdetransfrerdesdocumentsdeleurposteversleserveurWeb :
dposer un CV sur un site (site de recherche d'emploi), mettre une pice jointe dans un message (site de
messagerie)ousimplementstockerledocumentsurleserveur(sitedestockage).
Dans la terminologie anglosaxonne, cette fonctionnalit s'appelle le "file upload" ( opposer au "download" qui
permetdetlchargerundocumentduserveurverssonposte).
Cettefonctionnalit,trssimplemettreenuvreenPHP,prsentedeuxexigences :
- dans un formulaire, proposer une zone permettant l'utilisateur de dsigner l'emplacement du fichier sur son poste ;
- dans le script de traitement du formulaire, rcuprer le fichier envoy par l'utilisateur et en faire quelque chose.
DanslechapitreGestiondesformulaires,nousavonsvoqulapossibilitdemettredansunformulaireunezone
permettantd'indiquerl'emplacementd'unfichiersursonposte(TYPE="file") :
Exemple :
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// traitement du formulaire
$fichier = "";
if (isset($_POST["fichier"])) {
$fichier = valeur_saisie($_POST["fichier"]);
}
?>
<HTML>
<HEAD><TITLE>Saisie</TITLE></HEAD>
<BODY>
<FORM ACTION="saisie.php" METHOD="POST">
Fichier : <INPUT TYPE="file" NAME="fichier"><BR>
<INPUT TYPE="submit" NAME="OK" VALUE="OK">
</FORM>
<?php
echo vers_page($fichier);
?>
</BODY>
</HTML>
Rsultat
- Affichage initial :
Cette technique ne fonctionne qu'avec les formulaires qui utilisent la mthode POST.
Encomplment,ilestpossibled'ajouterunezonecachedansleformulaireafindelimiterlatailledesfichiersqui
peuvent tre envoys vers le serveur. Cette zone cache, obligatoirement situe avant la zone de type file
doits'appelerMAX_FILE_SIZE(optionNAME)etprciserlataillemaximumenoctetsdansl'optionVALUE:
La valeur prcise dans cette zone ne peut pas tre suprieure la valeur de la directive de configuration
upload_max_filesize (2 Mo par dfaut). Si la zone cache n'est pas prsente, c'est la taille spcifie dans la
directiveupload_max_filesizequis'applique.
Parailleurs,letlchargementn'estpossiblequesiladirectivedeconfigurationfile_uploadseston.
Lorsqu'un fichier est envoy avec un formulaire, des informations sur ce fichier sont accessibles, dans le script
PHP,grcelavariable$_FILES etlavaleursaisieparl'utilisateurn'estplusdisponibledans$_POST.
Cl Valeur
Sur le serveur, le fichier transfr est un fichier temporaire portant un nom du type php*.tmp, situ dans le
rpertoiredfiniparladirectivedeconfigurationupload_tmp_dir.
La structure de $_FILES permet d'avoir plusieurs zones de type file dans le formulaire et donc d'autoriser le
chargementdeplusieursfichiers.
Exemple (le formulaire contient deux zones de type file nommes fichier1 et fichier2 :
Silefichiertemporairecrsurleserveurn'estpasexploit(renomm/copi/dplac)parlescriptPHPquitraite
leformulaire,ilestsupprimautomatiquementlafinduscript.DanslescriptPHP,ilconvientdoncdemanipuler
lefichiertemporaireselonlesbesoinsdel'application.
Exemple complet
<?php
// inclusion du fichier qui contient les fonctions gnrales
include("fonctions.inc");
// initialisation de la variable de message
$message = "";
// traitement du formulaire
if (isset($_POST["OK"])) {
// rcuprer les informations sur le fichier
$informations = $_FILES["fichier"];
// en extraire
// - son nom
$nom = valeur_saisie($informations["name"]);
// - son type MIME
$type_mime = $informations["type"];
// - sa taille
$taille = $informations["size"];
// - l'emplacement du fichier temporaire
$fichier_temporaire = $informations["tmp_name"];
// - le code d'erreur
$code_erreur = $informations["error"];
// contrles et traitement
switch ($code_erreur) {
case UPLOAD_ERR_OK :
// fichier bien reu
// dterminer sa destination finale
$destination = "e:/temp/$nom";
// copier le fichier temporaire (tester le rsultat)
if (copy($fichier_temporaire,$destination)) {
// copie OK => mettre un message de confirmation
$message = "Transfert termin - Fichier = $nom ";
$message .= "Taille = $taille octets ";
$message .= "Type MIME = $type_mime.";
} else {
// problme de copie => mettre un message d'erreur
$message = "Problme de copie sur le serveur.";
}
break;
case UPLOAD_ERR_NO_FILE :
// pas de fichier saisi
Pourtlchargerunfichierpartirduserveur,ilestpossibled'utiliserlamthodeclassiquequiconsisteutiliser
unlien(balise<A>).
Exemple
<A HREF="cv.pdf">Tlcharger</A>
Cettetechniquepeutposerdesproblmes :
- C'est le navigateur qui dcide de proposer l'utilisateur un dialogue d'enregistrement ou d'afficher directement le
document s'il sait comment faire.
- Les fichiers qui sont interprts par le serveur (.php par exemple) ou par le navigateur (.htm par exemple) ne
peuvent pas tre chargs de cette manire.
Une autre technique est utilisable, si vous souhaitez forcer le navigateur proposer l'utilisateur un dialogue
d'enregistrement,etce,pourn'importequeltypededocument.
Cette technique consiste envoyer certains enttes particuliers l'aide de la fonction header, suivie du
documentproprementdit.
Il n'est pas garanti que la technique dcrite prcdemment fonctionne correctement, ou de la mme manire, avec tous les
navigateurs. En effet, elle est base sur une fonctionnalit non standard du protocole HTTP qui est implmente par les
navigateurs. C'est aussi la raison pour laquelle, vous trouverez de nombreuses variantes de cette mthode dans les forums de
discussion.
Lesenttesminimumsenvoyersontlessuivants :
QuelquestypesMIMEcourants :
Aprs l'envoi des enttes, il ne reste plus qu' envoyer le document "directement" dans la page, soit par une
lecture(fread)suivied'unecho,soitplussimplementl'aidedelafonctionreadfilequilitunfichieretl'envoie
directementverslasortie.
Syntaxe
nom_fichier
Chemind'accsaufichierlire.
utiliser_inclusion
Mettre 1 (ou TRUE) pour rechercher le fichier dans les rpertoires spcifis par la directive de configuration
include_path.
Lafonctionreadfileretournelenombred'octetslusouFALSEencasd'erreur.
Cette technique va tre illustre l'aide d'un script download.php qui propose une liste de documents en
tlchargement.Cescriptgnreunformulairequioffreunboutondetype"image"(TYPE="image")pourchaque
fichierproposentlchargement,lenomduboutontantgalaunumrodudocument.
Comme nous l'avons vu dans le chapitre Constantes, variables, types et tableaux, nous allons rcuprer dans
$_POST deux variables n_x et n_y donnant respectivement la position relative horizontale et verticale du clic
l'intrieurdel'image(ntantlenomdel'imageclique,dansnotrecas,unnumro).
Exemple
<?php
// liste des documents (viendrait sans doute d'une
// base de donns dans une vraie application)
$documents = array("cv.pdf","photo.gif");
// traitement du formulaire si $_POST nom vide
if (! empty($_POST)) {
// rcuprer le numro du document
// - prendre la cl de la premire ligne de
// $_POST (normalement du type n_x,
// n tant le numro du document)
list($numro) = each($_POST);
// - convertir la chane en entier => seul le n reste
$numro = (integer) $numro;
// en dduire le nom du document
$NomFichier = $documents[$numro];
// envoyer l'en-tte d'attachement
$header = "Content-Disposition: attachment; ";
$header .= "filename=$NomFichier\n" ;
header($header);
// envoyer l'en-tte du type MIME (ici, " inconnu ")
header("Content-Type: x/y\n");
// envoyer le document
// - pas d'encodage magic quotes
set_magic_quotes_runtime(0);
// - lire le document
readfile($NomFichier);
}
?>
<HTML>
<HEAD><TITLE>Download</TITLE></HEAD>
<BODY>
<FORM ACTION="download.php" METHOD="POST">
<TABLE BORDER=1 CELLPADDING=4 CELLSPACING=0>
<TR ALIGN="center" BGCOLOR="lemonchiffon">
<TH>Document</TH><TH>Tlcharger</TH>
</TR>
<?php
// un petit bout de code PHP pour gnrer les lignes du