Académique Documents
Professionnel Documents
Culture Documents
Programmation Web
Coté serveur : PHP, PDO, MVC, DAL, Front Controller
Rémy Malgouyres
LIMOS UMR 6158, IUT, département info
Université Clermont 1
B.P. 86
63172 AUBIERE cedex
http://malgouyres.org/
http://malgouyres.org/programmation-html-css
http://malgouyres.org/tutoriel-drupal
http://malgouyres.org/programmation-php
http://malgouyres.org/programmation-javascript
Cours sur l’administration de serveurs (Serveurs WEB avec apache, SSL, LDAP...) :
http://malgouyres.org/administration-reseau
Table des matières
1
TABLE DES MATIÈRES
7 Sessions 114
7.1 Concept de Session et Problèmes de Sécurité . . . . . . . . . . . . . . . . . . . 114
7.2 Cycle de vie d’une Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
7.3 Gestion de l’Identifiant de Session (SID) . . . . . . . . . . . . . . . . . . . . . 118
7.4 Login/Password : Exemple de Politique de Sécurité . . . . . . . . . . . . . . . 122
2
TABLE DES MATIÈRES
3
Première partie
4
Table of Contents
1 PHP procédural 7
1.1 Notion de CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Générer du code HTML avec un CGI en PHP . . . . . . . . . . . . . . . . . . 8
1.3 Exemple de fonction en PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4 Inclure un fichier PHP dans un autre . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Arithmétique : types int et float . . . . . . . . . . . . . . . . . . . . . . . . 10
1.6 Tableaux indexés : avec une clé de type int . . . . . . . . . . . . . . . . . . . 11
1.7 Tableaux associatifs : avec une clé de type String . . . . . . . . . . . . . . . . 12
1.8 Passage de paramètre à un script PHP . . . . . . . . . . . . . . . . . . . . . . 13
1.9 Variables Locales ou Globales, Références . . . . . . . . . . . . . . . . . . . . 17
6
Chapitre 1
PHP procédural
7
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
4
5 i n t main ( v o i d )
6 {
7 int i ;
8 p r i n t f ( ”%s%c%c \n” , ” Content−Type : t e x t / html ; c h a r s e t=i s o −8859−1” , 1 3 , 1 0 ) ;
9
10 p r i n t f ( ”<html>” ) ;
11 p r i n t f ( ”<head>” ) ;
12 p r i n t f ( ”< t i t l e >Exemple de CGI</ t i t l e >” ) ;
13 p r i n t f ( ”</head>” ) ;
14 p r i n t f ( ”<body>” ) ;
15 p r i n t f ( ”<h1>V a r i a b l e s d ’ Environnement d ’ un <i >CGI</i ></h1>” ) ;
16
17 fo r ( i =0 ; e n v i r o n [ i ] !=NULL ; i ++){
18 p r i n t f ( ”%s<b r />\n” , e n v i r o n [ i ] ) ;
19 }
20
21 p r i n t f ( ”</body>” ) ;
22 p r i n t f ( ”</html>” ) ;
23 return 0 ;
24 }
8
Chapitre 1 : PHP procédural
7 <body>
8 <p>
9 < ?php // d é b u t du s c r i p t PHP
10 echo ” H e l l o World ! ” ;
11 // On a f f i c h e du code HTML s i l a s o r t i e
12 ?> < !−− f i n du s c r i p t PHP −−>
13 </p>
14 </body>
15 </html>
9
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
10
Chapitre 1 : PHP procédural
type ou d’accéder au nom du type d’une variable. Nous en verrons par la suite.
11
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
2
3 < ?php
4 outputEnTeteHTML5 ( ’ Tableaux 1 ’ , ’UTF−8 ’ , ’ my S t y l e . c s s ’ ) ;
5 ?>
6 <p>
7 <h1>Tableaux avec c l é e n t i è r e s </h1>
8 <p>
9 < ?php
10 $ t a b l e a u = array ( 2 3 , 4 5 , 4 1 , 6 , 0 4 ) ;
11 echo ” ( ” ;
12 fo r ( $ i =0 ; $ i < count ( $ t a b l e a u ) ; $ i ++) {
13 echo $ t a b l e a u [ $ i ] ;
14 i f ( $ i + 1 < count ( $ t a b l e a u ) )
15 echo ” , ” ;
16 }
17 echo ” ) \n” ;
18 ?>
19 </p>
20 < ?php
21 outputFinFichierHTML5 ( ) ;
22 ?>
12
Chapitre 1 : PHP procédural
http://www.remysprogwebtuto.org/exemples/php1/\
13
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
ex08_passages_parametres2.php?texte=Bonjour&titre=monTitre
Le second script peut alors récupérer les paramètres texte et titre dans un tableau as-
sociatif $_GET. On peut vérifier que les variables texte et titre ont bien été utilisées via la
fonction isset.
Code Source 1.10 : exemples/php1/ex08_passages_parametres2.php
1 < ?php r e q u i r e _ o n c e ’ . / commonFunctions . php ’ ; ?>
2 < ?php
3 $ t i t r e = ’Mon t i t r e par d é f a u t ’ ;
4 i f ( i s s e t ($_GET[ ’ t i t r e ’ ] ) ) {
5 $ t i t r e = $_GET[ ’ t i t r e ’ ] ;
6 }
14
Chapitre 1 : PHP procédural
Certains navigateurs ne supportant pas les URL avec des caractères comme des accents ou
autres caractères UTF-8 quelconques (notamment le & !!!), si on veut passer une chaîne un peu
générale en paramètre, on la codera en une string simple via la fonction htmlentities.
Dans l’exemple suivant, l’URL du second script est :
http://www.remysprogwebtuto.org/exemples/php1/ex10_passages_parametres4.php?\
texte=L%27%C3%A9t%C3%A9%20va%20%C3%AAtre%20chaud%20cette%20ann%C3%A9e\
&titre=Passage%20de%20param%C3%A8tres%20avec%20accents%20et%20espaces
15
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
5 $ t i t r e = $_GET[ ’ t i t r e ’ ] ;
6 }
7 outputEnTeteHTML5 ( $ t i t r e , ’UTF−8 ’ , ’ myS ty l e . c s s ’ ) ;
8 ?>
9 <p>
10 Pour l a n c e r l ’ a u t r e s c r i p t s a v e c comme t e x t e
11 < ?php
12 $ t e x t e =”L ’ é t é va ê t r e chaud c e t t e ann é e ” ;
13 echo ’ ” ’ . $ t e x t e . ’ ” ’ ;
14 echo ”<br/> e t comme t i t r e ” ;
15 $ t i t r e = ” Passage de p a r a m è t r e s avec a c c e n t s e t e s p a c e s ” ;
16 echo ’ ” ’ . $ t i t r e . ’ ” ’ ;
17 echo ” \n<a h r e f= \ ” ” ;
18 echo ’ . / ex10_passages_parametres4 . php ? t e x t e= ’
19 . htmlentities ( $ t e x t e , ENT_COMPAT, ”UTF−8” )
20 . ”& t i t r e =”
21 . htmlentities ( $ t i t r e , ENT_COMPAT, ”UTF−8” )
22 . ”\”>\n\ t c l i q u e z i c i \n</a>” ;
23 ?>.
24 </p>
25 < ?php
26 outputFinFichierHTML5 ( ) ;
27 ?>
16
Chapitre 1 : PHP procédural
21 outputFinFichierHTML5 ( ) ;
22 ?>
17
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
18
Chapitre 2
1. Robustesse : les classes de base du framework doivent être testées et doivent être conçus
pour réduire le risque de bugs lorsqu’un développer utilise les classes du framework, ou
d’attaques lorsqu’un utilisateur malveillant utilise un site construit à partir du framework.
2. Généricité et versatilité : Le code doit pouvoir s’adapter, sans le retoucher, au plus grand
nombre d’applications possibles.
3. Facilité de maintenance du framework lui-même, avec une modularité interne. Les grand
outils (librairies, frameworks externes, etc.) utilisés par le framework doivent etre circons-
crits à des sous-modules avec des wrappers ou helpers de manière à pouvoir changer l’un
de ces outils sans revoir l’ensemble du code.
4. Une bonne lisibilité et une bonne documentation, notamment parce que les développeurs
qui utilisent le framework ne sont pas nécessairement les mêmes que les développeurs du
framework lui-même.
19
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Par rapport à ces quatre objectifs, des outils sont à disposition des développeurs du frame-
work :
2. Généricité : les patrons de conception (ou design patterns) permettent de développer des
interfaces pour le framework qui rendent les code similaire d’une application à l’autre,
suivant des principes d’organisation éprouvés, et qui permet de séparer différents aspects
du développement d’une application.
4. Lisibilité : une forme stéréotypée pour l’interface des classes, les identificateurs, etc. rend
le code plus lisible. De plus, des outils permettent de générer automatiquement une
documentation (HTML, LATEX, PDF, etc.) des classes à partir de commentaires dans
le code. C’est le cas par exemple de Doxygen pour le PHP.
20
Chapitre 2 : Les classes en PHP
(voir le chapitre 9). Ces patrons de conception visent à garantir la modularité par le découplage
des différentes parties d’une application, permettant de faciliter les évolutions (par exemple un
changement de technologie pour l’interface homme-machine IHM ), du fait de l’indépendance
logique des parties.
21
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Voici maintenant un exemple avec une classe contenant le numéro de téléphone d’une per-
sonne. Les commentaires ont une forme spéciale pour pouvoir générer la documentation du
code avec l’outil Doxygen. Les attributs sont privés et sont toujours initialisés via les setters,
qui sont des méthodes spacialement conçues qui testent les condition que doivent satisfaire les
attributs (ici être non null) avant des les initialiser. Le constructeur utilise les setters ce qui a
l’avantage de factoriser le code, c’est à dire que les tests sur les valeurs des attributs ne sont
réalisés qu’une seule fois.
22
Chapitre 2 : Les classes en PHP
Nous allons maintenant voir une classe un peu plus complexe, au moins en ce sens qu’elle
possède plus d’attributs. Nous allons voir comment nous pouvons, dès ce stade de la conception,
respecter un certain nombre de bonnes pratiques, à la fois dans l’organisation du code et pour
sa division en fichiers, mais aussi, au niveau de la Conception Objet dans la séparation du
modèle de données (objetsMétier) et de la mise en forme de ces données pour l’affichage vers
l’utilisateur (vues).
La classe Adresse représentera le modèle de données pour une adresse postale et la classe
AdresseView implémentera (en l’occurrence) deux vues HTML d’une Adresse, l’une dévelop-
pée et l’autre compacte. Comme toujours, notre modélisation n’est pas cannonique et plusieurs
choix seraient possibles.
Par ailleurs, pour limiter la longueur des fichiers sources, nous utilisons un trait. Un trait
permet de regrouper dans un fichiers séparé un ensemble de méthodes qui font partie d’une
classe. Un trait peut meme définir une parte de plusieurs classes, mais les méthodes de ces
classes doivent avoir exactement le meme code. (c’est une manière un peu “bricole” de faire
de la programmation générique en PHP. Dans notre exemple, le trait AdresseProperties
contient tous les getters et setters de la classe Adresse. Le trait et ses méthodes sont insérés
dans la classe Adresse avec le mot clé use.
23
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Vue
PersonneView AdresseView
uses
+ getHtmlDevelopped(personne : Personne) : string + getHtmlDevelopped(adresse : Adresse) : string
+ getHtmlCompact(personne : Personne) : string + getHtmlCompact(adresse : Adresse) : string
uses
uses
Metier
Personne
- idPersonne : string {id}
- nom : string
- prenom : string
Adresse
+ Personne(idPersonne : string, nom : string, prenom : string, adresse : string,
telephones : Telephone 0..*) {throws Invalid Arg} - idAdresse : string {id}
+ getIdPersonne() : string - numeroRue : string
+ setIdPersonne(id : string) : void {throws Invalid Arg} - rue : string
+ getNom() : string - complementAddr : string
+ setNom(nom : string) : void {throws Invalid Arg} - codePostal : string
+ getPrenom() : string adresse - ville : string
+ setPrenom(prenom : string) : void {throws Invalid Arg} 1 1 - pays : string
+ getAdresse() : Adresse + Adresse(idAdresse : string, numeroRue : string, rue : string,
+ setAdresse(adresse : Adresse) : void {throws Invalid Arg}
complementAddr : string, codePostal : string,
+ getTelephones() : Telephone 0..*
ville : string, pays : string) {throws Invalid Arg}
+ getTelephone(libelle : string) : Telephone {throws Invalid Arg}
+ getIdAdresse() : string
+ setTelephones(telephones : Telephone 0..*) : void {throws Invalid Arg}
+ setIdAdresse(idAdresse : string) : void {throws Invalid Arg}
+ addTelephone(libelle : string, numero : string) : void {throws Invalid Arg}
+ getNumeroRue() : string
+ removeTelephone(libelle : string) : void
+ setNumeroRue(numeroRue : string) : void {throws Invalid Arg}
+ getRue() : string
+ setRue(rue : string) : void {throws Invalid Arg}
+ getComplementAddr() : string
+ setComplementAddr(complementAddr : string) : void {throws Invalid Arg}
telephones
+ getCodePostal() : string
0..*
24
Chapitre 2 : Les classes en PHP
20 private $ v i l l e ;
21 /* * nom du pays . ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
22 private $pays ;
23
24 // I n c l u s i o n du t r a i t A d r e s s e P r o p e r t i e s d é f i n i s s a n t l e s a c c e s s e u r s e t s e t t e r s
25 use A d r e s s e P r o p e r t i e s ;
26
27 /* * @ b r i e f C o n s t r u c t e u r : i n i t i a l i s e l e s a t t r i b u t s à p a r t i r d e s p a r a m è t r e s .
28 * Les p a r a m è t r e s c o r r e s p o n d e n t aux v a l e u r s à m e t t r e dans l e s a t t r i b u t s .
29 * Tout o b j e t d o i t ê t r e i n i t i a l i s é a v e c l e c o n s t r u c t e u r ( a p p e l à new) .
30 * I c i , l e s p a r a m è t r e s p e u v e n t ê t r e n u l l . Les a t t r i b u t s s o n t a l o r s i n i t i a l i s é s
31 * à une cha î ne v i d e , p e r m e t t a n t l a coh é r e n c e de l a c l a s s e . */
32 public function __construct ( $ i d A d r e s s e , $numeroRue , $rue , $complementAddr ,
33 $ c o d e P o s t a l , $ v i l l e , $pays ) {
34 $ t h i s −>s e t I d A d r e s s e ( $ i d A d r e s s e ) ;
35 $ t h i s −>setNumeroRue ( $numeroRue ) ;
36 $ t h i s −>setRue ( $ r u e ) ;
37 $ t h i s −>setComplementAddr ( $complementAddr ) ;
38 $ t h i s −>s e t C o d e P o s t a l ( $ c o d e P o s t a l ) ;
39 $ t h i s −>s e t V i l l e ( $ v i l l e ) ;
40 $ t h i s −>s e t P a y s ( $pays ) ;
41 }
42 } // end o f c l a s s Adresse
43 ?>
25
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
29 public function g e t C o d e P o s t a l ( ) {
30 return $ t h i s −>c o d e P o s t a l ;
31 }
32
33 /* * @ b r i e f A c c e s s e u r : permet d ’ o b t e n i r l e nom l a v i l l e . */
34 public function g e t V i l l e ( ) {
35 return $ t h i s −> v i l l e ;
36 }
37
38 /* * @ b r i e f A c c e s s e u r : permet d ’ o b t e n i r l e pays . */
39 public function getPays ( ) {
40 return $ t h i s −>pays ;
41 }
42
43 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom de l a rue .
44 * @param $NumeroRue l e numé ro à u t i l i s e r . p e u t ê t r e n u l l . */
45 public function s e t I d A d r e s s e ( $ i d A d r e s s e ) {
46 $ t h i s −>i d A d r e s s e = empty( $ i d A d r e s s e ) ? ” ” : $ i d A d r e s s e ;
47 }
48
49 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom de l a rue .
50 * @param $NumeroRue l e numé ro à u t i l i s e r . p e u t ê t r e n u l l . */
51 public function setNumeroRue ( $numeroRue ) {
52 $ t h i s −>numeroRue = ( $numeroRue == n u l l ) ? ” ” : $numeroRue ;
53 }
54
55 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e numé ro dans l a rue .
56 * @param $Rue l e nom de l a rue ou de l a p l a c e à u t i l i s e r . p e u t ê t r e n u l l . */
57 public function setRue ( $ r u e ) {
58 $ t h i s −>r u e = ( $ r u e == n u l l ) ? ” ” : $ r u e ;
59 }
60
61 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r / m o d i f i e r l e compl é ment d ’ a d r e s s e .
62 * @param $ComplementAddr l e compl é ment d ’ a d r e s s e à u t i l i s e r . */
63 public function setComplementAddr ( $complementAddr ) {
64 $ t h i s −>complementAddr = ( $complementAddr == n u l l ) ? ” ” : $complementAddr ;
65 }
66
67 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e code p o s t a l .
68 * @param $Cod e P os ta l l e numé ro à u t i l i s e r . p e u t ê t r e n u l l */
69 public function s e t C o d e P o s t a l ( $ c o d e P o s t a l ) {
70 $ t h i s −>c o d e P o s t a l = ( $ c o d e P o s t a l == n u l l ) ? ” ” : $ c o d e P o s t a l ;
71 }
72
73 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom de l a v i l l e .
74 * @param $ V i l l e l e nom de l a v i l l e à u t i l i s e r . p e u t ê t r e n u l l */
75 public function s e t V i l l e ( $ v i l l e ) {
76 $ t h i s −> v i l l e = ( $ v i l l e == n u l l ) ? ” ” : $ v i l l e ;
77 }
78
79 /* * @ b r i e f s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom du Pays
80 * @param $pays l e nom du Pays à u t i l i s e r . p e u t ê t r e n u l l */
81 public function s e t P a y s ( $pays ) {
82 $ t h i s −>pays = ( $pays == n u l l ) ? ” ” : $pays ;
83 }
84 }
26
Chapitre 2 : Les classes en PHP
85 ?>
27
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
52 $htmlCode .= $ a d r e s s e −>g e t C o d e P o s t a l ( ) . ” ” ;
53 $htmlCode .= $ a d r e s s e −>g e t V i l l e ( ) ;
54 i f ( !empty( $ a d r e s s e −>g e t V i l l e ( ) ) )
55 $htmlCode .= ” , ” ;
56 $htmlCode .= $ a d r e s s e −>getPays ( ) ;
57
58 return $htmlCode ;
59 }
60 } // end o f c l a s s AdresseView
61 ?>
28
Chapitre 2 : Les classes en PHP
Notons que l’on peut aussi importer une classe par la directive use, et pas seulement un
namespace.
29
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
filtrage. Dans cette partie, nous réalisons un filtrage sommaire, pour illustrer le mecanisme de
gestion des erreurs par exceptions.
30
Chapitre 2 : Les classes en PHP
7 return $ t h i s −>i d P e r s o n n e ;
8 }
9
10 /* * @ b r i e f a c c e s s e u r : permet d ’ o b t e n i r l e nom de l ’ employ é */
11 public function getNom ( ) {
12 return $ t h i s −>nom ;
13 }
14
15 /* * @ b r i e f a c c e s s e u r : permet d ’ o b t e n i r l e pr énom de l ’ employ é */
16 public function getPrenom ( ) {
17 return $ t h i s −>prenom ;
18 }
19
20 /* * @ b r i e f a c c e s s e u r : permet d ’ o b t e n i r l ’ a d r e s s e de l ’ employ é */
21 public function g e t A d r e s s e ( ) {
22 return $ t h i s −>a d r e s s e ;
23 }
24
25 /* * @ b r i e f a c c e s s e u r : permet d ’ o b t e n i r l e t a b l e a u d e s t é l é phones */
26 public function g e t T e l e p h o n e s ( ) {
27 return $ t h i s −>t e l e p h o n e s ;
28 }
29
30 /* * @ b r i e f a c c e s s e u r : permet d ’ o b t e n i r un numé ro de t é l é phone de l ’ employ é
31 * @param l i b e l l e Le l i b e l l é du numé ro s o u h a i t é */
32 public function g e t T e l e p h o n e ( $ l i b e l l e ) {
33 i f (empty( $ t h i s −>t e l e p h o n e s [ $ l i b e l l e ] ) ) {
34 throw new \ E x c e p t i o n ( ’Dé s o l é , Le t é l é phone ” ’ . $ l i b e l l e . ’ ” n \ ’ e x i s t e pas .
Have a t r y i n t h e phonebook . . . ’ ) ;
35 }
36 return $ t h i s −>t e l e p h o n e s [ $ l i b e l l e ] ;
37 }
38
39 /* * s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l ’ i d e n t i f i a n t de l a p e r s o nn e
40 * @param $ i d P e r s o n n e l ’ i d e n t i f i a n t de l a p e r s o n n e . Doit ê t r e non v i d e */
41 public function s e t I d P e r s o n n e ( $ i d P e r s o n n e ) {
42 i f (empty( $ i d P e r s o n n e ) | | s t r l e n ( $ i d P e r s o n n e ) != 1 0 ) {
43 throw new \ E x c e p t i o n ( ’Dé s o l é , t o u t e p er s o n n e d o i t a v o i r un i d e n t i f i a n t de
10 c a r a c t è r e s ! ’ ) ;
44 } else {
45 $ t h i s −>i d P e r s o n n e= $ i d P e r s o n n e ;
46 }
47 }
48
49 /* * s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom de l a pe r s o n n e
50 * @param $Nom l e nom de l a per s on n e . Doit comporter au moins 1 c a r a c t è r e */
51 public function setNom ( $nom ) {
52 i f (empty( $nom ) | | s t r l e n ( $nom ) > 1 0 0 ) {
53 throw new \ E x c e p t i o n ( ’Dé s o l é , t o u t e p er s o n n e d o i t a v o i r un nom e t l e nom a
au p l u s 100 c a r a c t è r e s ! ’ ) ;
54 } else {
55 $ t h i s −>nom = $nom ;
56 }
57 }
58
59 /* * s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e nom de l a pe r s o n n e */
31
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
32
Chapitre 2 : Les classes en PHP
7 * Les a t t r i b u t s d o i v e n t ê t r e non n u l l .
8 * ( mais normalement ç a ne r i s q u e pas d ’ a r r i v e r c a r l e s a t t r i b u t s s o n t p r i v é s
9 * donc l ’ u t i l i s a t e u r de l a c l a s s e n ’ a pas pu l e s m e t t r e à n u l l .
10 * Les s e t t e r s e t l e c o n s t r u c t e u r e s t a i n s i con ç u que l e s a t t r i b u t s
11 * ne p e u v e n t pas ê t r e n u l l . ) */
12 public s t a t i c function getHtmlDevelopped ( $ p e r s o n n e ) {
13 $htmlCode = ” ” ;
14 $htmlCode .= ”nom : ” . $personne −>getNom ( ) . ”<b r />\n” ;
15 i f ( s t r l e n ( $personne −>getPrenom )>=1)
16 $htmlCode .= ”Pr énom : ” . $personne −>getPrenom ( ) . ”<b r />\n” ;
17 $htmlCode .= AdresseView : :getHtmlDevelopped ( $personne −>g e t A d r e s s e ( ) ) ;
18 $count = 0 ;
19 foreach ( $personne −>g e t T e l e p h o n e s ( ) a s $ t e l e p h o n e ) {
20 i f ( $count != 0 ) {
21 $htmlCode .= ”<b r/>” ;
22 }
23 $count++ ;
24 $htmlCode .= $ t e l e p h o n e −>toHTML( ) ;
25 }
26 $htmlCode .= ”<b r />\n” ;
27 return $htmlCode ;
28 }
29
30 /* * @ b r i e f Mé t h o d e de g éné r a t i o n d ’ une l i g n e de tableHTML .
31 * Permet d ’ a f f i c h e r d e s Personnes dans une t a b l e HTML. */
32 public s t a t i c function getHtmlTableRow ( $ p e r s o n n e ) {
33 $htmlCode = ”<t r >” ;
34 $htmlCode .= ”<td>” . $personne −>getNom ( ) . ”</td>” ;
35 $htmlCode .= ”<td>” . $personne −>getPrenom ( ) . ”</td>” ;
36 $htmlCode .= ”<td>” . AdresseView : :getHtmlCompact ( $personne −>g e t A d r e s s e ( ) ) . ”</
td>” ;
37 $htmlCode .= ”<td>” ;
38 $count = 0 ;
39 foreach ( $personne −>g e t T e l e p h o n e s ( ) a s $ t e l e p h o n e ) {
40 i f ( $count != 0 ) {
41 $htmlCode .= ”<b r/>” ;
42 }
43 $count++ ;
44 $htmlCode .= $ t e l e p h o n e −>toHTML( ) ;
45 }
46 $htmlCode .= ”</td>” ;
47 $htmlCode .= ”</t r >” ;
48
49 return $htmlCode ;
50 }
51
52 /* * Permet d ’ o b t e n i r une l i g n e de t a b l e HTML a v e c l e s en−t ê t e s de c o l o n n e s
53 * pour a f f i c h a g e d ’ une t a b l e de Personnes . */
54 public s t a t i c function getHtmlTableHeads ( ) {
55 $htmlCode = ”<t r >” ;
56 $htmlCode .= ”<th>Nom</th>” ;
57 $htmlCode .= ”<th>Pr énom</th>” ;
58 $htmlCode .= ”<th>Adresse </th>” ;
59 $htmlCode .= ”<th>Té l é phone ( s )</th>” ;
60 $htmlCode .= ”</t r >” ;
61 return $htmlCode ;
33
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
62 }
63 } // end o f c l a s s PersonneView
64 ?>
34
Chapitre 2 : Les classes en PHP
1 < ?php
2 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / VueHtmlUtils . php ’ ) ;
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / AdresseView . php ’ ) ;
4 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / PersonneView . php ’ ) ;
5
6 use CoursPHP\Vue\ PersonneView ;
7
8 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 (
9 ’ C o n s t r u c t i o n e t a f f i c h a g e d \ ’ une Personne ’ , ’UTF−8 ’ , ’ m y S t y l e . c s s ’ ) ;
10
11 echo ”<p>” ;
12 echo PersonneView : :getHtmlDevelopped ( $ p e r s o n n e ) ;
13 echo ”</p>” ;
14
15 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
16 ?>
Voyons maintenant le test d’une vue affichant plusiers personnes dans une table HTML.
35
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
36
Chapitre 2 : Les classes en PHP
Voyons enfin ce qui se passe lorsqu’une erreur dans les données déclenche une exception au
niveau du setter, alors que notre récupération de l’exception nous permet d’afficher un message
d’erreur intelligible, évitant le crash complet du site.
Dans l’exemple suivant, nous créons deux personnes en récupérant, pour chacune, une
exception. Nous accumulons les éventuels messages exceptions dans un tableau associatifs. Dans
la vue qui suit, nous testons la présence d’erreurs dans ce tableau associatif avant d’afficher
soit la personne, soit le message d’erreur concernant cette instance (le cas échéant).
37
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
38
Chapitre 2 : Les classes en PHP
39
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
29 public function s e t C a t e g o r i e ( $ c a t e g o r i e ) {
30 i f ( ! self : :isValidCategorie ( $categorie ) ){
31 throw new \ E x c e p t i o n ( ” Erreur , c a t é g o r i e d ’ employ é \” ” . $ c a t e g o r i e
32 . ” \” i n v a l i d e . ” ) ;
33 } else {
34 $ t h i s −>c a t e g o r i e = $ c a t e g o r i e ;
35 }
36 }
37
38 /* * s e t t e r : permet d ’ i n i t i a l i s e r ou de m o d i f i e r l e s a l a i r e de l a pe r s o n n e
39 * @param $ s a l a i r e s a l a i r e mensuel en e u r o s / mois */
40 public function s e t S a l a i r e M e n s u e l ( $ s a l a i r e ) {
41 i f ( $ s a l a i r e == n u l l | | ! is_numeric ( $ s a l a i r e ) ) {
42 $ t h i s −>s a l a i r e M e n s u e l = 0 . 0 ;
43 } else {
44 $ t h i s −>s a l a i r e M e n s u e l = $ s a l a i r e ;
45 }
46 }
47 }
48 ?>
40
Chapitre 2 : Les classes en PHP
41
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
16 echo ”<p>” ;
17 i f (empty( $ d a t a E r r o r [ ” employe1 ” ] ) ) {
18 echo EmployeView : :getHtmlDevelopped ( $employe1 ) ;
19 } else {
20 echo $ d a t a E r r o r [ ” employe1 ” ] ;
21 }
22 echo ”</p>” ;
23
24 echo ”<p>” ;
25 i f (empty( $ d a t a E r r o r [ ” employe2 ” ] ) ) {
26 echo EmployeView : :getHtmlDevelopped ( $employe2 ) ;
27 } else {
28 echo $ d a t a E r r o r [ ” employe2 ” ] ;
29 }
30 echo ”</p>” ;
31
32 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
33 ?>
42
Deuxième partie
43
44
Table of Contents
3 Formulaires HTML/PHP 47
3.1 Formulaires HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.1 Premier Formulaire HTML . . . . . . . . . . . . . . . . . . . . . . . . 47
3.1.2 Exemple de style CSS pour formulaire . . . . . . . . . . . . . . . . . . 48
3.1.3 Réception des données en PHP . . . . . . . . . . . . . . . . . . . . . . 53
3.2 Validation pour la sécurité : Appel de filter_var . . . . . . . . . . . . . . . . 54
3.3 Appel des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.4 Tableaux $_POST $_GET $_REQUEST . . . . . . . . . . . . . . . . . . . . . . . . 57
3.5 Formulaires dynamiques an javascript . . . . . . . . . . . . . . . . . . . . . . . 59
46
Chapitre 3
Formulaires HTML/PHP
Les formulaires HTML permettent de faire saisir des données par l’utilisateur via son naviga-
teur. Ces données sont saisies dans des champs appelés inputs, qui sont définis avec la balise
<input>. Les données sont ensuite récupérées dans un script, ici un script PHP. Ces données
doivent impérativement être testées et filtrées pour des raisons de sécurité.
47
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
48
Chapitre 3 : Formulaires HTML/PHP
4 f o n t −s i z e : 18 pt ;
5 background−c o l o r : # f f f ;
6 c o l o r : #222 ;
7 }
8
9 /* s t y l e du t i t r e */
10 h1 {
11 f o n t −w e i g h t : b o l d ;
12 f o n t −s i z e : 150% ;
13 c o l o r : white ;
14 t e x t −a l i g n : c e n t e r ;
15 background−c o l o r : #999 ;
16 padding : 15 px ;
17 }
18
19 /* *****************************************
20 | mise en forme du f o r m u l a i r e |
21 \**************************************** */
22
23 /* Largeur minimale pour que l a mise en page ” ne c a s s e pas ” */
24 form {
25 width : 800 px ;
26 }
27
28 form span . f o r m F i e l d {
29 width : i n h e r i t ;
30 d i s p l a y : i n l i n e −b l o c k ;
31 margin : 5px 0 ;
32 }
33
34 /* t o u s l e s l a b e l s ont l a même l a r g e u r pour a l i g n e r l e s i n p u t s */
35 form l a b e l {
36 float : left ;
37 width : 400 px ;
38 t e x t −a l i g n : r i g h t ;
39 padding : 6px ;
40 f o n t −w e i g h t : b o l d ;
41 }
42
43 form i n p u t {
44 padding : 6px ;
49
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
45 margin− l e f t : 20 px ;
46 background−c o l o r : #ddd ;
47 border −s t y l e : g r o o v e ;
48 border −width : 5px ;
49 border −c o l o r : #444 ;
50 border −r a d i u s :10px ;
51 }
52
53 form s e l e c t {
54 padding : 1px 6px ;
55 margin− l e f t : 20 px ;
56 background−c o l o r : #ddd ;
57 border −s t y l e : g r o o v e ;
58 border −width : 5px ;
59 border −c o l o r : #444 ;
60 border −r a d i u s :10px ;
61 f o n t −s i z e : 110% ;
62 }
63
64 /* i n p u t sp é c i a l pour l e b o u t t o n s u b m i t */
65 form i n p u t . s a n s L a b e l {
66 margin− l e f t : 432 px ; /* 400+6+6+20 : a l i g n é s u r l e s a u t r e s i n p u t s */
67 f o n t −s i z e : 130% ;
68 f o n t −w e i g h t : b o l d e r ;
69 background−c o l o r :#333333 ;
70 c o l o r :w h i t e ;
71 }
72
73 form p {
74 background−c o l o r : # f f f ;
75 padding : 0px ;
76 }
77
78 form span . errorMsg {
79 f o n t −s i z e : 90% ;
80 f o n t −s t y l e : i t a l i c ;
81 c o l o r :r e d ;
82 }
83
84 /* ************************************** */
85
86
87 /* s t y l e par d é f a u t d e s l i e n s */
88 a :l i n k {
89 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
90 c o l o r : #00 e ;
91 }
92
93 /* s t y l e d e s l i e n s v i s i t é s */
94 a :visited {
95 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
96 c o l o r : #00 c ;/* b l e u c l a i r */
97 }
98
99 /* s t y l e d e s l i e n s v i s i t é s */
100 a :hover {
50
Chapitre 3 : Formulaires HTML/PHP
101 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
102 c o l o r : #e40 ;/* r o u g e v i f */
103 }
104
105 /* s t y l e d e s é l é ments i m p o r t a n t s */
106 s t r o n g {
107 f o n t −v a r i a n t : s m a l l −c a p s ;
108 f o n t −w e i g h t : b o l d e r ;
109 color : black ;
110 }
111
112 /* s t y l e d e s é l é ments mis en é v i d e n c e */
113 em {
114 f o n t −s t y l e : i t a l i c ;
115 color : black ;
116 }
117
118 p {
119 background−c o l o r : #ddd ;
120 t e x t −a l i g n : j u s t i f y ;
121 padding : 5 pt ;
122 }
51
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
32 }
33
34 /* t o u s l e s l a b e l s ont l a même l a r g e u r pour a l i g n e r l e s i n p u t s */
35 form l a b e l {
36 float : left ;
37 width : 400 px ;
38 t e x t −a l i g n : r i g h t ;
39 padding : 6px ;
40 f o n t −w e i g h t : b o l d ;
41 }
42
43 form i n p u t {
44 padding : 6px ;
45 margin− l e f t : 20 px ;
46 background−c o l o r : #ddd ;
47 border −s t y l e : g r o o v e ;
48 border −width : 5px ;
49 border −c o l o r : #444 ;
50 border −r a d i u s :10px ;
51 }
52
53 form s e l e c t {
54 padding : 1px 6px ;
55 margin− l e f t : 20 px ;
56 background−c o l o r : #ddd ;
57 border −s t y l e : g r o o v e ;
58 border −width : 5px ;
59 border −c o l o r : #444 ;
60 border −r a d i u s :10px ;
61 f o n t −s i z e : 110% ;
62 }
63
64 /* i n p u t sp é c i a l pour l e b o u t t o n s u b m i t */
65 form i n p u t . s a n s L a b e l {
66 margin− l e f t : 432 px ; /* 400+6+6+20 : a l i g n é s u r l e s a u t r e s i n p u t s */
67 f o n t −s i z e : 130% ;
68 f o n t −w e i g h t : b o l d e r ;
69 background−c o l o r :#333333 ;
70 c o l o r :w h i t e ;
71 }
72
73 form p {
74 background−c o l o r : # f f f ;
75 padding : 0px ;
76 }
77
78 form span . errorMsg {
79 f o n t −s i z e : 90% ;
80 f o n t −s t y l e : i t a l i c ;
81 c o l o r :r e d ;
82 }
83
84 /* ************************************** */
85
86
87 /* s t y l e par d é f a u t d e s l i e n s */
52
Chapitre 3 : Formulaires HTML/PHP
88 a :l i n k {
89 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
90 c o l o r : #00 e ;
91 }
92
93 /* s t y l e d e s l i e n s v i s i t é s */
94 a : v i s i t e d {
95 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
96 c o l o r : #00 c ;/* b l e u c l a i r */
97 }
98
99 /* s t y l e d e s l i e n s v i s i t é s */
100 a :hover {
101 t e x t −d e c o r a t i o n : u n d e r l i n e ; /* s o u l i g n é */
102 c o l o r : #e40 ;/* r o u g e v i f */
103 }
104
105 /* s t y l e d e s é l é ments i m p o r t a n t s */
106 s t r o n g {
107 f o n t −v a r i a n t : s m a l l −c a p s ;
108 f o n t −w e i g h t : b o l d e r ;
109 color : black ;
110 }
111
112 /* s t y l e d e s é l é ments mis en é v i d e n c e */
113 em {
114 f o n t −s t y l e : i t a l i c ;
115 color : black ;
116 }
117
118 p {
119 background−c o l o r : #ddd ;
120 t e x t −a l i g n : j u s t i f y ;
121 padding : 5 pt ;
122 }
53
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
54
Chapitre 3 : Formulaires HTML/PHP
14 $filter = FILTER_VALIDATE_BOOLEAN ;
15 break ;
16 case ” i p ” :
17 $filter = FILTER_VALIDATE_IP ;
18 break ;
19 case ” u r l ” :
20 $filter = FILTER_VALIDATE_URL ;
21 break ;
22 default : // important ! ! !
23 $filter = f a l s e ; // S i t y p e e s t faux , l a v a l i d . é choue .
24 }
25 return $ f i l t e r ;
26 }
27
28 // Mé t h o d e r e t o u r n a n t l e f i l t r e de n e t t o y a g e à u t i l i s e r
29 // dans l a f o n c t i o n f i l t e r _ v a r
30 function g e t S a n i t i z e F i l t e r ( $type )
31 {
32 switch ( $type ) {
33 case ” s t r i n g ” :
34 $ f i l t e r = FILTER_SANITIZE_STRING ;
35 break ;
36 case ” t e x t ” :
37 $ f i l t e r = FILTER_SANITIZE_FULL_SPECIAL_CHARS ;
38 break ;
39 case ” u r l ” :
40 $ f i l t e r = FILTER_SANITIZE_URL ;
41 break ;
42 default : // i m p o r t a n t ! ! !
43 $ f i l t e r = f a l s e ; // S i t y p e e s t faux , l a v a l i d . é choue .
44 }
45 return $ f i l t e r ;
46 }
47
48 ?>
55
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
56
Chapitre 3 : Formulaires HTML/PHP
Dans tous les cas, seuls les scripts implémentant des vues envoie du code HTML
sur la sortie standard.
57
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
58
Chapitre 3 : Formulaires HTML/PHP
13 }
14 foreach ($_POST a s $key => $ v a l ) {
15 echo htmlentities ( ” \$_POST[ ’ ” . $key . ” ’ ] = ” . $val , ENT_COMPAT, ”UTF−8” ) . ”<b r
/>” ; ;
16 }
17 foreach ($_REQUEST a s $key => $ v a l ) {
18 echo htmlentities ( ” \$_REQUEST[ ’ ” . $key . ” ’ ] = ” . $val , ENT_COMPAT, ”UTF−8” ) . ”
<b r/>” ; ;
19 }
20 ?>
21 </body>
22 </html>
59
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
17 </s e l e c t>
18 </p>
19 <div id=” a t t r i b u t S u p p l e m e n t a i r e ”>
20
21 </div>
22 <p>
23 <i nput type=” s u b m i t ” value=”−− OK −−” />
24 </p>
25 </form>
26 <s c r i p t>
27 function anneeChange ( ) {
28 var pa ra gr a p h e = document . getElementById ( ” a t t r i b u t S u p p l e m e n t a i r e ” ) ;
29 p a r a g ra p h e . innerHTML=document . getElementById ( ” annee ” ) . value+” ann é e . ” ;
30 i f ( document . getElementById ( ” annee ” ) . value == ” deuxième ” ) {
31 par a g r aph e . innerHTML+=”<l a b e l>O r i e n t a t i o n pr é vue pour l ’ ann é e p r o c h a i n e
:</ l a b e l>”
32 +’<s e l e c t name=” o r i e n t a t i o n ” id=” o r i e n t a t i o n ”>’
33 +’<option value=”LP”>LP</option>’
34 +’<option value=” master ”>master</option>’
35 +”<option value= \” i n g e \”>E c o l e d ’ i n g é</option>”
36 +’<option value=” b o u l o t ”>Boulot</option>’
37 +’<option value=” a u t r e ”>Autre</option>’
38 +’</s e l e c t>’ ;
39
40 }
41 }
42 anneeChange ( ) ;
43 </s c r i p t>
44 </body>
45 </html>
60
Chapitre 4
61
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Figure 4.2 : Le site affiche en HTML les données saisies dans le gentil formulaire
62
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
17 </p>
18 </body>
19 </html>
Figure 4.4 : L’affichage des données du formulaire sort le code HTML entré par le pirate
63
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Ça n’est pas très joli mais c’est inoffensif sauf si l’utilisateur fait vraiment exprès de copier
l’adresse du lien dans sa barre d’adresse. Pour éviter complètement l’apparition de code, HTML
ou autre, ou plus généralement de données non conforme à un format attendu, nous veroons
plus loin comment utiliser des expressions régulières.
64
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
7 </head>
8 <body>
9 <h1>Post de deux cha î nes </h1>
10 <form method=” p o s t ” a c t i o n=” e x 0 3 _ e s c a p e T e s t R e q u e s t . php ”>
11 <i n p u t type=” h i d d e n ” name=” c h a i n e 1 ” v a l u e=” Ceci e s t l ’ exemple de cha î ne a v e c
a p o s t r o p h e ”/>
12 <i n p u t type=” h i d d e n ” name=” c h a i n e 2 ” v a l u e=” Ceci e s t s o i t d i s a n t un &q u o t ;
a u t r e&q u o t ; exemple . ”/>
13 <i n p u t type=” s u b m i t ” v a l u e=” Envoyer ” c l a s s=” s a n s L a b e l ”/>
14 </form>
15 </body>
16 </html>
65
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
18 echo ”</p>\n” ;
19
20 echo ”<p>\n” ;
21 echo ” Apostrophe a v e c h t m l e n t i t i e s e t ENT_QUOTES : ” . htmlentities ( $ c h a i n e 1 ,
ENT_QUOTES, ’UTF−8 ’ , f a l s e ) . ”<br >\n” ;
22 echo ” G u i l l e m e t s a v e c a d d s l a s h e s ENT_QUOTES : ” . htmlentities ( $ c h a i n e 2 ,
ENT_QUOTES, ’UTF−8 ’ , f a l s e ) . ”<br >\n” ;
23 echo ”</p>\n” ;
24
25 echo ”<p>\n” ;
26 echo ” Apostrophe a v e c h t m l e n t i t i e s e t ENT_NOQUOTES : ” . htmlentities ( $ c h a i n e 1 ,
ENT_NOQUOTES, ’UTF−8 ’ , f a l s e ) . ”<br >\n” ;
27 echo ” G u i l l e m e t s a v e c a d d s l a s h e s ENT_NOQUOTES : ” . htmlentities ( $ c h a i n e 2 ,
ENT_NOQUOTES, ’UTF−8 ’ , f a l s e ) . ”<br >\n” ;
28 echo ”</p>” ;
29
30 ?>
31 <form method=” p o s t ” a c t i o n=” e x 0 3 _ e s c a p e T e s t R e q u e s t . php ”>
32 <i n p u t type=” t e x t ” name=” c h a i n e 1 ” v a l u e=”< ?php echo $ c h a i n e 1 ; ?>”>
33 <i n p u t type=” t e x t ” name=” c h a i n e 2 ” v a l u e=”< ?php echo $ c h a i n e 2 ; ?>”>
34 <i n p u t type=” s u b m i t ” v a l u e=” Envoyer ” c l a s s=” s a n s L a b e l ”></input >
35 </form>
36 < ?php
37 outputFinFichierHTML5 ( ) ;
38 ?>
66
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
23 G u i l l e m e t s a v e c a d d s l a s h e s ENT_NOQUOTES : Ceci e s t s o i t d i s a n t un ” a u t r e ”
exemple .<br>
24 </p> <form method=” p o s t ” action= ” ex03_escapeTestRequest . php”>
25 <i nput type= ” text ” name=” c h a i n e 1 ” value= ” C e c i e s t l ’ exemple de cha î ne avec
a p o s t r o p h e ”>
26 <i nput type= ” text ” name=” c h a i n e 2 ” value= ” C e c i e s t s o i t d i s a n t un ” a u t r e ”
exemple . ”>
27 <i nput type= ” submit ” value= ” Envoyer ” c l a s s = ” s a n s L a b e l ”></ i nput>
28 </form>
29 </body>
30 </html>
67
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
• Accéder à des données confidentielles, par exemple à toutes les données de la base ;
• Détruire ou altérer des données, par exemple supprimer la totalité d’une table.
Voici un exemple de code qui insère une donnée (colonne chaine) de type chaine (varchar)
dans une table Table1.
Code Source 4.8 : exemples/filtrage/ex06_0_postParamForDB.php
1 <!doctype html>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <l i nk rel=” s t y l e s h e e t ” href=” . /myStyle . c s s ” />
6 <t i t l e>F o r m i l a i r e HTML</ t i t l e>
7 </head>
8 <body>
9 <h1>S a i s i e d ’ une Cha î ne</h1>
10 <!−− Ce f o r m u l a i r e t r a n s m e t t r o i s v a l e u r s non s a i s i e s par l ’ u t i l i s a t e u r −−>
11 <form method=” p o s t ” action=” e x 0 7 _ e x I n j e c t M y S q l . php ”>
12 <l a b e l for=” c h a i n e 1 ”>Entrez une cha î ne</ l a b e l>
13 <i nput type=” t e x t e ” id=” c h a i n e 1 ” name=” c h a i n e 1 ” s i z e=” 45 ” /><br />
14
15 <i nput type=” s u b m i t ” value=” Envoyer ” class= ” s a n s L a b e l ”></ i nput>
16 </form>
17 </body>
18 </html>
68
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
Voici deux exemple d’injections exploitant l’absence de filtrage dans ce code. Le premier
exemple, gentillet, consiste juste à insérer deux données au lieu d’une dans la table :
Le deuxième exemple, plus méchant, consiste pour le pirate à supprimer toutes les données
contenues dans la table :
69
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Figure 4.8 : L’état des données avant l’injection SQL par le pirate
70
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
Figure 4.11 : L’état des données après l’injection SQL par le pirate
Figure 4.14 : L’état des données après l’injection SQL par le pirate
71
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
72
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
Figure 4.16 : Données dans la base après tentative d’injection SQL avec échappement
73
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
1. de valider la forme d’une chaine de caractères attendue suivant son usage (exemple :
adresse e−mail, URL, nombre réel, adresse IP, etc.).
2. de nettoyer une chaine de caractères attendue suivant son usage (élimination des carac-
tères inattendus compte tenu du type de données (exemple : élimination d’un caractère
inattendu ′ @′ dans un nombre entier).
• La fonction retourne false en cas de données invalides avec échec du filtre, ou les données
elles mêmes dans le cas de données valides, ou encore les données filtrées en cas de filtres
de nettoyage.
• $filter est le type de filtre. Bien qu’il soit en option et qu’il est une valeur par défaut
définie dans la configuration du serveur (fichier php.ini), il est fortement conseillé de
spécifier un, ou plusieurs, filtres)
• $options définit les options et/ou les flags du filtre, plus ou moins strictes (c’est à dire
que ces filtres n’éliminent pas les memes caractères suivant les options choisies).
En toute généralité, les options et les flags sont définis dans un tableau associatif (avec
deux clés facultatives 'options' et/ou 'flags') de tableaux associatifs chaqu’un de
ces tableaux associatifs définissant les valeurs d’une ou plusieurs options (pour le tableau
$options['options']) ou d’un ou plusieurs flags (pour le tableau $options['flags']).
Partez pas ! Je mets quelques exemples ci-dessous...
Nous ne ferons pas ici une présentation exhaustive des utilisations des filtres ou des options.
Pour celà voyez php.net. Nous donnons quelques exemples typiques.
74
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
if (!is_bool($value)) {
$value= filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
75
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
76
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
Par exemple, le filtre FILTER_SANITIZE_NUMBER_INT Supprime tous les caractères sauf les
chiffres, et les signes plus et moins. Cela n’empeche pas que si la donnée en entrée n’est pas un
nombre, le programme risque de ne pas fonctionner correctement. Le filtre FILTER_SANITIZE_STRING
permet de supprimer ou d’encoder diiférents jeux de caractères spéciaux (suivant la valeur du
flag).
77
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
http://php.net/manual/en/book.pcre.php
Exemples.
Par exemple, pour valider un nom ou un prénom entre 1 et 50 caractères alphabétiques
français avec des espaces ou traits d’unions, on peut utiliser quelque-chose du genre :
/^(([a-zA-ZàâéèêôùûçÀÂÉÈÔÙÛÇäöëüÄÖËÜ](\-|( )*)){1,50})$/
Notez que pour que le filtrage puisse servir à éviter les injections, il ne faut pas omettre le ̂ au
début et le $ à la fin de l’expression pour que l’expression régulière représente l’ensemble de
l’input utilisateur et non pas simplement une sous-chaîne.
Le filtrage d’une chaine de caractères accentués (au moins en français) peut se faire un plus
sytématiquement après échappement par :
'/^([a-zA-Z]'
.'|(\&[a-zA-Z]grave\;)|(\&[a-zA-Z]acute\;)|(\&[a-zA-Z]circ\;)|(\&[a-zA-Z]uml\;)'
.'|(\&[a-zA-Z]cedil\;)|(\&[a-zA-Z][a-zA-Z]lig\;)|(\ß\;)|(\&[a-zA-Z]tilde\;)'
.'|(\-)|( )|(\&\#039\;)|(\"\;)|(\.)))+$/'
Le filtrage avec preg_match se fait alors par un code du genre :
78
Chapitre 4 : Injections XSS, Filtrage, Expressions Régulières
Pour un numéro de téléphone français sous la forme de 10 chiffres commençant par 0 et par
groupes de deux séparés par des espaces :
/^(0{1}[0-9]{1}( [0-9]{2}){4})$/
En option, avec un +33 devant pour les appels internationaux et les espaces entre chiffres
optionnels :
En option, avec la possibilité de ne pas laisser d’espaces ou de mettre des tires ou des points
entre les groupes de chiffres (exemples : +33-1.02-0304.05) :
79
Chapitre 5
• Elle n’a pas d’autre comportement que de permettre la création d’instances sans aucune
vérification.
L’objectif est de pouvoir très facilement passer des instances d’une classe à l’autre, et de rendre
la manipulation des attributs très facile, sans passer par des setters/getters qui alourdissent le
code. Voici la définition du modèle POPO d’une adresse :
Code Source 5.1 : exemples/forms2/classes/Adresse.php
1 < ?php
2 namespace CoursPHP\ M e t i e r ;
3 /* * @ b r i e f C o n t i e n t l e s donn é e s de l ’ a d r e s s e d ’ une pe r s o n n e
4 ( q u i p e u t ê t r e un c l i e n t , un employ é , un f o u r n i s s e u r , e t c . . . ) */
5 class Adresse {
6 /* * i d u n i q u e de l ’ a d r e s s e */
7 public $ i d A d r e s s e ;
8 /* * i d u n i q u e de l ’ a g r é g a t Personne à q u i c o r r e s p o n d l ’ a d r e s s e */
9 public $ i d P e r s o n n e ;
10 /* * Numé ro dans l a rue , ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
11 public $numeroRue ;
12 /* * Nom de l a rue , ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
13 public $ r u e ;
14 /* * Compl é ment ( l i e u d i t , e t c . ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
15 public $complementAddr ;
16 /* * code p o s t a l */
17 public $ c o d e P o s t a l ;
18 /* * nom de l a v i l l e . ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
19 public $ v i l l e ;
20 /* * nom du pays . ne d o i t pas ê t r e n u l l mais p e u t ê t r e v i d e */
21 public $pays ;
22
23 /* * @ b r i e f Gé nère un Id de 10 c h i f f r e s hexa a l é a t o i r e s ( s o i t 5 o c t e t s ) .
80
Chapitre 5 : Conception Objet, Gestion des Erreurs
81
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
1. Le filtrage pour la sécurité, qui sera géré par des fonctions de validation ou de net-
toyage systématique (comme filter_var) ou, dans le cas de la couche de persistance
basée sur PDO, par la préparation systématique des requêtes.
82
Chapitre 5 : Conception Objet, Gestion des Erreurs
22
23 /* * @ b r i e f Mé t h o d e de N e t t o y a g e e t /ou d ’ é chappement
24 * @param $ c h a i n e { inOut } l a cha î ne de c a r a c t è r e s à f i l t r e r
25 * @param $ p o l i c y l a p o l i t i q u e de f i l t r a g e ( v o i r c o n s t a n t e s de c l a s s e )
26 * @return f a l s e en c a s d ’ é c h e c ( $ c h a i n e n ’ e s t pas une cha î ne ) */
27 private s t a t i c function f i l t e r M e t h o d (& $ c h a i n e , $ p o l i c y ) {
28 // S i l a c h a i n e n ’ e s t pas d é f i n i e , on met une cha î ne v i d e
29 $chaine = isset ( $chaine ) ? $chaine : ”” ;
30 switch ( $ p o l i c y ) {
31 case s e l f : :SANITIZE_POLICY_DISCARD_HTML_NOQUOTE :
32 // Supprimer l e s b a l i s e s uniquement , mais ne pas é c h a p p e r
33 $ c h a i n e = f i l t e r _ v a r ( $ c h a i n e , FILTER_SANITIZE_STRING,
34 FILTER_FLAG_NO_ENCODE_QUOTES) ;
35 break ;
36 case s e l f : :SANITIZE_POLICY_DISCARD_HTML :
37 // Supprimer l e s b a l i s e s e t é c h a p p e r l e s q u o t e s ” e t ’ .
38 $ c h a i n e = f i l t e r _ v a r ( $ c h a i n e , FILTER_SANITIZE_STRING, ENT_QUOTES) ;
39 break ;
40 case s e l f : :SANITIZE_POLICY_ESCAPE_SPECIAL_CHARS :
41 // Éc h a p p e r t o u t e s l e s c a r a c t è r e s sp é c i a u x HTML ( < , >, ” , e t c . )
42 $ c h a i n e = htmlspecialchars ( $ c h a i n e , ENT_QUOTES, ’UTF−8 ’ ) ;
43 break ;
44 case s e l f : :SANITIZE_POLICY_ESCAPE_ENTITIES :
45 // Éc h a p p e r t o u t e s l e s e n t i t é s HTML ( y compris l e s a c c e n t s , e t c . )
46 $ c h a i n e = htmlentities ( $ c h a i n e , ENT_QUOTES, ’UTF−8 ’ ) ;
47 break ;
48 default : // SANITIZE_POLICY_NONE : r i e n à f a i r e
49 }
50 return $ c h a i n e === f a l s e ? f a l s e : true ;
51 }
52
53 /* * @ b r i e f Mé t h o d e d ’ I n v e r s i o n d ’ é chappement
54 * @param $ c h a i n e l a cha î ne de c a r a c t è r e s à r e s t a u r e r s u i t e à un é chappement
55 * @param $ p o l i c y l a p o l i t i q u e de f i l t r a g e ( v o i r c o n s t a n t e s de c l a s s e ) */
56 private s t a t i c function f i l t e r M e t h o d R e v e r s e (& $ c h a i n e , $ p o l i c y ) {
57 // S i l a c h a i n e n ’ e s t pas d é f i n i e , on met une cha î ne v i d e
58 $chaine = isset ( $chaine ) ? $chaine : ”” ;
59 switch ( $ p o l i c y ) {
60 case s e l f : :SANITIZE_POLICY_DISCARD_HTML :
61 // On r e s t a u r e j u s t e s l e s s i m p l e s e t d o u b l e s q u o t e s q u i s o n t html−encod é
es
62 $tmp = preg_replace ( ’ /^\& q u o t \ ; $/ ’ , ” \” ” , i s s e t ( $ c h a i n e ) ? $ c h a i n e : ” ” )
;
63 $ c h a i n e = preg_replace ( ’ /^\&39\ ; $/ ’ , ” ’ ” , $tmp ) ;
64 break ;
65 case s e l f : :SANITIZE_POLICY_ESCAPE_SPECIAL_CHARS :
66 // On i n v e r s e l ’ encodage d e s c a r a c t è r e s sp é c i a u x HTML
67 $ c h a i n e = h t m l s p e c i a l c h a r s _ d e c o d e ( $ c h a i n e , ENT_QUOTES, ’UTF−8 ’ ) ;
68 break ;
69 case s e l f : :SANITIZE_POLICY_ESCAPE_ENTITIES :
70 // On i n v e r s e l ’ encodage d e s e n t i t é s HTML
71 $ c h a i n e = h t m l e n t i t i e s _ d e c o d e ( $ c h a i n e , ENT_QUOTES, ’UTF−8 ’ ) ;
72 break ;
73 default : // SANITIZE_POLICY_DISCARD_HTML_NOQUOTE : Rien à r e s t a u r e r
74 // SANITIZE_POLICY_NONE : r i e n à f a i r e
75 }
83
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
76 }
77
78 /* * @ b r i e f Mé t h o d e de ( N e t t o y a g e e t /ou d ’ é chappement )
79 * e t /ou d ’ i n v e r s i o n d ’ é chappement
80 * @param $ c h a i n e l a cha î ne de c a r a c t è r e s à f i l t r e r
81 * @param $ r e v e r s e d t r u e s ’ i l f a u t a p p l i q u e r une i n v e r s i o n d ’ é chappement
82 * f a l s e s ’ i l f a u t a p p l i q u e r un n e t t o y a g e e t /ou é chappement
83 * @param $ p o l i c y l a p o l i t i q u e de f i l t r a g e ( v o i r c o n s t a n t e s de c l a s s e ) * */
84 public s t a t i c function f i l t e r S t r i n g (& $ c h a i n e , $ r e v e r s e d , $ p o l i c y ) {
85 i f ( ! isset ( $policy ) ){
86 throw new \ E x c e p t i o n ( ” P o l i t i q u e de f i l t r a g e non d é f i n i e ” ) ;
87 }
88 return $ r e v e r s e d ? s e l f : : f i l t e r M e t h o d R e v e r s e ( $ c h a i n e , $ p o l i c y ) :
89 s e l f : :f i l t e r M e t h o d ( $chaine , $ p o l i c y ) ;
90 }
91 }
92 ?>
84
Chapitre 5 : Conception Objet, Gestion des Erreurs
30 * d e s a t t r i b u t s d ’ Adresse
31 * @param $ a d r e s s e { inOut } I n s t a n c e d ’ Adresse à c r é e r ou i n i t i a l i s e r
32 * @param $ p o l i c y l ’ une d e s p o l i t i q u e s d é f i n i e s par V a l i d a t i o n U t i l s * */
33 public s t a t i c function v a l i d a t i o n I n p u t ( $inputArray , &$ a d r e s s e , $ p o l i c y ) {
34 // S i $ a d r e s s e n ’ e s t pas une i n s t a n c e d ’ Adresse , on c r é e une i n s t a n c e :
35 i f ( ! is_object ( $ a d r e s s e ) | | !preg_match( ”/ Adresse$ / ” , get_ c l a s s ( $ a d r e s s e ) ) ) {
36 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e
37 : :g e t D e f a u l t I n s t a n c e ( $inputArray [ ’ idPersonne ’ ] ,
38 $ in p u t A r r a y [ ’ i d A d r e s s e ’ ] ) ;
39 }
40 // I n i t i a l i s a t i o n d e s a t t r i b u t s
41 $ a d r e s s e −>i d A d r e s s e = $in putA rra y [ ’ i d A d r e s s e ’ ] ;
42 $ a d r e s s e −>i d P e r s o n n e = $in putA rra y [ ’ i d P e r s o n n e ’ ] ;
43 $ a d r e s s e −>numeroRue =$in putA rra y [ ’ numeroRue ’ ] ;
44 $ a d r e s s e −>r u e = $i n p utA rray [ ’ rue ’ ] ;
45 $ a d r e s s e −>complementAddr = $in pu tA rra y [ ’ complementAddr ’ ] ;
46 $ a d r e s s e −>c o d e P o s t a l = $in putA rra y [ ’ c o d e P o s t a l ’ ] ;
47 $ a d r e s s e −> v i l l e = $in putA rray [ ’ v i l l e ’ ] ;
48 $ a d r e s s e −>pays = $i n putA rray [ ’ pays ’ ] ;
49 // F i l t r a g e d e s a t t r i b u t s a v e c l a p o l i t i q u e
50 s e l f : : f i l t e r A d r e s s e ( $adresse , false , $policy ) ;
51 }
52 }
53 ?>
La classe AdresseView permet de générer le code HTML d’une instance d’Adresse, en appli-
quant une politique de filtrage (par défaut htmlentities) avant de générer le code HTML. La
chaîne retournée peut alors être affichée (pour la politique par défaut) sans risque d’injection
HTML.
Code Source 5.4 : exemples/forms2/classes/AdresseView.php
1 < ?php
2 namespace CoursPHP\Vue ;
3 /* * @ b r i e f Impl é mente l a g éné r a t i o n d ’HTML pour a f f i c h e r une Adresse dans une
vue
4 * dans un n a v i g a r e u r .
5 * Impl é mente a u s s i d e s u t i l i t a i r e s de c o n v e r s i o n à p a r t i r d ’ une Adresse
6 * pour o b t e n i r f a c i l e m e n t l e code HTML pour a f f i c h e r une Adresse . */
7 c l a s s AdresseView {
8 /* * @ b r i e f Mé t h o d e de g éné r a t i o n de code HTML. Permet d ’ a f f i c h e r une a d r e s s e .
9 * Les a t t r i b u t s s o n t é chapp é s pour é v i t e r t o u t r i s q u e d ’ i n j e c t i o n HTML
10 * @param $ a d r e s s e l ’ i n s t a n c e d ’ a d r e s s e à a f f i c h e r
11 * @param $ s a n i t i z e P o l i c y P o l i t i q u e pour e n c o d e r ou é c h a p p e r l e s a t t r i b u t s
12 * ( Voir l a c l a s s e V a l i d a t i o n U t i l s )
13 * @return l e code HTML pour un a f f i c h a g e d é v e l o p p é . */
14 public s t a t i c function getHtmlDevelopped ( $ a d r e s s e ,
15 $ s a n i t i z e P o l i c y = \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s
16 : :SANITIZE_POLICY_ESCAPE_ENTITIES) {
17 i f ( \ CoursPHP\ M e t i e r \ A d r e s s e V a l i d a t i o n : : f i l t e r A d r e s s e (
18 $ a d r e s s e , f a l s e , $ s a n i t i z e P o l i c y ) === f a l s e ) {
19 return ” Adresse i n c o r r e c t e ” ;
20 }
21 $htmlCode = ”<s t r o n g >Adresse : </s t r o n g ><b r />\n” ;
22 $htmlCode .= $ a d r e s s e −>numeroRue ;
23 i f ( !empty( $ a d r e s s e −>numeroRue ) )
24 $htmlCode .= ” , ” ;
85
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
25 $htmlCode .= $ a d r e s s e −>r u e ;
26 i f ( !empty( $ a d r e s s e −>r u e ) )
27 $htmlCode .= ”<b r/>” ;
28 $htmlCode .= $ a d r e s s e −>complementAddr ;
29 i f ( !empty( $ a d r e s s e −>complementAddr ) )
30 $htmlCode .= ”<b r/>” ;
31 $htmlCode .= $ a d r e s s e −>c o d e P o s t a l . ” ” ;
32 $htmlCode .= $ a d r e s s e −> v i l l e ;
33 i f ( !empty( $ a d r e s s e −> v i l l e ) && !empty( $ a d r e s s e −>pays ) )
34 $htmlCode .= ”<b r/>” ;
35 $htmlCode .= $ a d r e s s e −>pays . ”<b r/>” ;
36
37 return $htmlCode ;
38 }
39
40 /* * @ b r i e f Mé t h o d e de g éné r a t i o n d ’HTML. Permet d ’ a f f i c h e r une a d r e s s e .
41 * Les a t t r i b u t s s o n t é chapp é s pour é v i t e r t o u t r i s q u e d ’ i n j e c t i o n HTML
42 * @param $ a d r e s s e l ’ i n s t a n c e d ’ a d r e s s e à a f f i c h e r
43 * @param $ s a n i t i z e P o l i c y p o l i t i q u e de n e t t o y a g e / é chappement d e s a t t r i b u t s
44 * @return l e code HTML pour un a f f i c h a g e compact . */
45 public s t a t i c function getHtmlCompact ( $ a d r e s s e ,
46 $ s a n i t i z e P o l i c y = \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s
47 : :SANITIZE_POLICY_ESCAPE_ENTITIES) {
48 i f ( \ CoursPHP\ M e t i e r \ A d r e s s e V a l i d a t i o n : : f i l t e r A d r e s s e (
49 $ a d r e s s e , f a l s e , $ s a n i t i z e P o l i c y ) === f a l s e ) {
50 return ” Adresse i n c o r r e c t e ” ;
51 }
52 $htmlCode = ” ” ;
53 $htmlCode .= $ a d r e s s e −>numeroRue ;
54 i f ( !empty( $ a d r e s s e −>numeroRue ) )
55 $htmlCode .= ” , ” ;
56 $htmlCode .= $ a d r e s s e −>r u e ;
57 i f ( !empty( $ a d r e s s e −>r u e ) )
58 $htmlCode .= ” , ” ;
59 $htmlCode .= $ a d r e s s e −>complementAddr ;
60 i f ( !empty( $ a d r e s s e −>complementAddr ) )
61 $htmlCode .= ” , ” ;
62 $htmlCode .= $ a d r e s s e −>c o d e P o s t a l . ” ” ;
63 $htmlCode .= $ a d r e s s e −> v i l l e ;
64 i f ( !empty( $ a d r e s s e −> v i l l e ) && !empty( $ a d r e s s e −>pays ) )
65 $htmlCode .= ” , ” ;
66 $htmlCode .= $ a d r e s s e −>pays ;
67
68 return $htmlCode ;
69 }
70 } // end o f c l a s s AdresseView
71 ?>
Voici un fichier de test, qui affiche une instance d’adresse en utilisant différentes politiques de
filtrage. Le code HTML d’affichage de l’instance, qui apparaît ci-dessous, illustre les différentes
politiques de filtrage/nettoyage.
Code Source 5.5 : exemples/forms2/testFiltrageHTML.php
1 < ?php
2 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / VueHtmlUtils . php ’ ) ;
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / Adresse . php ’ ) ;
86
Chapitre 5 : Conception Objet, Gestion des Erreurs
87
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Voici la partie de la sortie standard (code HTML) du CGI qui montre le résultat des différentes
formes de filtrage et d’échappement :
88
Chapitre 5 : Conception Objet, Gestion des Erreurs
10 }
11
12 /* * @ b r i e f : e x p r e s s i o n r é g u l i è r e pour l a l a n g u e Fran ç a i s e a v e c a c c e n t s ,
13 * e t c h i f f r e s */
14 private s t a t i c function getRegexLatin1WithNumbers ( ) {
15 return ’ /^[0 −9a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ç è é ê ö ì í î ï ðñ ò ó ô
õö÷øùúûĀāüýþÿ \”\ ’\ −\ ] * $/ ’ ;
16 }
17
18 /* * @ b r i e f : e x p r e s s i o n r é g u l i è r e pour l a l a n g u e Fran ç a i s e a v e c a c c e n t s ,
19 * c h i f f r e s e t p o n c t u a t i o n */
20 private s t a t i c function getRegexLatin1WithNumbersAndPunctuation ( ) {
21 return ’ /^[\ !\.\ :\ ;\ ?\ ,0 −9 a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ç è é ê ö
ì í î ï ðñò ó ôõö÷øùúûĀāüýþÿ \”\ ’\ −\ ] * $/ ’ ;
22 }
23
24 /* * @ b r i e f : Test e x p r e s s i o n r é g u l i è r e pour l a l a n g u e Fran ç a i s e a v e c a c c e n t s
25 * a v e c c o n d i t i o n s de l o n g u e u r ( par exemple pour un champ o b l i g a t o i r e ) */
26 public s t a t i c function i s V a l i d L a t i n 1 ( $ c h a i n e , $minLength , $maxLength ) {
27 return ( i s s e t ( $ c h a i n e ) &&
28 s t r l e n ( $ c h a i n e ) >= $minLength && s t r l e n ( $ c h a i n e ) <= $maxLength
29 && preg_match( s e l f : :g e t R e g e x L a t i n 1 ( ) , $ c h a i n e ) ) ;
30 }
31
32 /* * @ b r i e f : Test e x p r e s s i o n r é g u l i è r e pour l a l a n g u e Fran ç a i s e a v e c a c c e n t s
33 * e t c h i f f r e s , a v e c c o n d i t i o n s de l o n g u e u r
34 * ( par exemple pour un champ o b l i g a t o i r e ) */
35 public s t a t i c function isValidLatin1WithNumbers ( $ c h a i n e ,
36 $minLength , $maxLength ) {
37 return ( i s s e t ( $ c h a i n e ) &&
38 s t r l e n ( $ c h a i n e ) >= $minLength && s t r l e n ( $ c h a i n e ) <= $maxLength
39 && preg_match( s e l f : :getRegexLatin1WithNumbers ( ) , $ c h a i n e ) ) ;
40 }
41
42 /* * @ b r i e f : Test e x p r e s s i o n r é g u l i è r e pour l a l a n g u e Fran ç a i s e a v e c a c c e n t s ,
43 * c h i f f r e s e t p o n c t u a t i o n , a v e c c o n d i t i o n s de l o n g u e u r
44 * ( par exemple pour un champ o b l i g a t o i r e ) */
45 public s t a t i c function isValidLatin1WithNumbersAndPunctuation ( $ c h a i n e ,
46 $minLength , $maxLength ) {
47 return ( i s s e t ( $ c h a i n e ) &&
48 s t r l e n ( $ c h a i n e ) >= $minLength && s t r l e n ( $ c h a i n e ) <= $maxLength
49 && preg_match( s e l f : :getRegexLatin1WithNumbersAndPunctuation ( ) , $ c h a i n e ) ) ;
50 }
51
52 /* * @ b r i e f : Test e x p r e s s i o n r é g u l i è r e p a s s é e en paramètre
53 * a v e c c o n d i t i o n s de l o n g u e u r ( par exemple pour un champ o b l i g a t o i r e ) */
54 public s t a t i c function i s V a l i d S t r i n g ( $ c h a i n e , $regExp , $minLength , $maxLength )
{
55 return ( i s s e t ( $ c h a i n e ) &&
56 s t r l e n ( $ c h a i n e ) >= $minLength && s t r l e n ( $ c h a i n e ) <= $maxLength
57 && preg_match( $regExp , $ c h a i n e ) ) ;
58 }
59 }
60 ?>
89
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
90
Chapitre 5 : Conception Objet, Gestion des Erreurs
91
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
92
Chapitre 5 : Conception Objet, Gestion des Erreurs
153 }
154 ?>
Dans ce chapitre, nous proposons une conception de classes métiers et classes d’utilitaires
pour générer des vues HTML comportatnt des formulaires. La gestion des données saisies par
l’utilisateur nous conduit, au vu du chapitre 4, à gérer plus rigoureusement le filtrage. Nous
nous appuierons pour cela sur les utilitaires présentés dans la partie 5.2.
Vue
AdresseFormView
uses
Metier
«POPO» ExpressionsRegexUtils
Adresse
+ idAdresse : string {id} + isValidLatin1(chaine : string, minLength : int,
+ numeroRue : string maxLength : int) : boolean
+ rue : string + isValidLatin1WithNumbers(chaine : string, minLength : int,
+ complementAddr : string
+ codePostal : string maxLength : int) : boolean
+ ville : string + isValidLatin1WithNumbersAndPunctuation(chaine : string,
+ pays : string minLength : int,
+ Adresse(idAdresse : string, numeroRue : string, rue : string, maxLength : int) : boolean
complementAddr : string, codePostal : string, ville : string, pays : string) - getRegexLatin1() : string
+ generateRandomId() : string - getRegexLatin1WithNumbers() : string
+ clone() : Adresse - getRegexLatin1WithNumbersAndPunctuation() : string
+ getDefaultAdresse(idPersonne : string, idAdresse : string) : Adresse
uses
uses
AdresseValidation AdresseFabrique
uses
+ filterAdresse(inOut adresse : Adresse, reversed : boolean, policy : const int) : void + getValidInstance(Out dataError : string 0..*, inputArray :array&,
+ filterMethod(inputArray : array, out adresse, policy : const int) : void policy : const int =DISCARD_HTML_NOQUOTE
) : Adresse
uses
Notez que ce diagramme ne fait pas apparaître l’agrégat Personne, ni les classes fabrique et
93
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
validation associées, qui sont très similaires à celles concernant les adresses. Par ailleurs, la
classe Adresse est aussi dottée d’un attribut idPersonne pour représenter la clef étrangère
pour l’éagrégat Personne. Voir la figure 8.3 pour la modélisation des données (diagramme de
relation d’entités : ERD).
pkg Vue
Vue
«POPO» VueHtmlUtils
Adresse AdresseFormView
+ enTeteHTML5(title : string, charset : string, css_sheet : string) : string
+ finFichierHTML5() : string
uses
FormManager
94
Chapitre 5 : Conception Objet, Gestion des Erreurs
5 * messages d ’ e r r e u r s u r l a forme d e s a t t r i b u t s . */
6 c l a s s AdresseFormView {
7
8 /* * @ b r i e f Mé t h o d e de g éné r a t i o n d ’ un f o r m u l a i r e HTML v i e r g e . */
9 public s t a t i c function getDefaultFormHTML ( $ a c t i o n , $ i d P e r s o n n e , $ i d A d r e s s e ) {
10 return s e l f : :getFormHtml ( $ a c t i o n ,
11 \CoursPHP\ M e t i e r \ A d r e s s e
12 : :g e t D e f a u l t I n s t a n c e ( $idPersonne , $idAdresse ) ) ;
13 }
14
15 /* * @ b r i e f Mé t h o d e de g éné r a t i o n d ’ un f o r m u l a i r e HTML pr é−r e m p l i . */
16 public s t a t i c function getFormHtml ( $ a c t i o n , $ a d r e s s e ,
17 $ f i l t e r i n g P o l i c y = \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s
18 : :SANITIZE_POLICY_NONE) {
19 $ d a t a E r r o r s = array ( ) ; // Aucun message d ’ e r r e u r
20 return s e l f : :getFormErrorsHtml ( $ a c t i o n , $ a d r e s s e , $ d a t a E r r o r s ,
21 $filteringPolicy ) ;
22 }
23
24 /* * Gé nère un message d ’ e r r e u r a s s o c i é à un a t t r i b u t , s ’ i l en e x i s t e un .
25 * Le t e x t e du message e s t form é du message d ’ e r r e u r contenu dans d a t a E r r o r .
26 * @param $ d a t a E r r o r Tableau a s s o c i a t i f (nom d ’ a t t r i b u t => message d ’ e r r e u r )
27 * @param $ f i e l d N a m e nom de l ’ a t t r i b u t c o n s i d é r é */
28 private s t a t i c function addErrorMsg ( $ da t a Erro r , $ f i e l d N a m e ) {
29 $htmlCode = ” ” ;
30 i f ( !empty( $ d a t a E r r o r [ $ f i e l d N a m e ] ) ) {
31 $htmlCode .= ”<span c l a s s =\”errorMsg\”>”
32 . htmlentities ( $ d a t a E r r o r [ $ f i e l d N a m e ] , ENT_COMPAT, ”UTF−8” )
33 . ”</span>” ;
34 }
35 return $htmlCode ;
36 }
37
38 /* * @ b r i e f Mé t h o d e de g éné r a t i o n de f o r m u l a i r e HTML pr é−r e m p l i a v e c e r r e u r s .
39 * Gé nère d e s messages d ’ e r r e u r a s s o c i é s aux a t t r i b u t , s ’ i l en e x i s t e . */
40 public s t a t i c function getFormErrorsHtml ( $ a c t i o n , $ a d r e s s e , $ d a ta E r r o r ,
41 $ f i l t e r i n g P o l i c y = \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s
42 : :SANITIZE_POLICY_NONE) {
43 \CoursPHP\ M e t i e r \ A d r e s s e V a l i d a t i o n : : f i l t e r A d r e s s e ( $ a d r e s s e , f a l s e ,
44 $filteringPolicy ) ;
45 $htmlCode = FormManager : :beginForm ( ” p o s t ” , $ a c t i o n ) ;
46 $htmlCode .= FormManager : :addHiddenInput ( ” i d A d r e s s e ” , ” i d A d r e s s e ” ,
47 $ a d r e s s e −>i d A d r e s s e ) ;
48 $htmlCode .= FormManager : :addHiddenInput ( ” i d P e r s o n n e ” , ” i d P e r s o n n e ” ,
49 $ a d r e s s e −>i d P e r s o n n e ) ;
50 $htmlCode .= s e l f : :addErrorMsg ( $ d a ta E rro r , ”numeroRue” ) ;
51 $htmlCode .= FormManager : :addTextInput ( ”Numé ro ” , ”numeroRue” , ”numeroRue” ,
52 ”4” , $ a d r e s s e −>numeroRue ) ;
53 $htmlCode .= s e l f : :addErrorMsg ( $ d a ta E rro r , ” rue ” ) ;
54 $htmlCode .= FormManager : :addTextInput ( ”Rue/ p l a c e ” , ” rue ” , ” rue ” , ” 30 ” ,
55 $ a d r e s s e −>r u e ) ;
56 $htmlCode .= s e l f : :addErrorMsg ( $ d a ta E rro r , ” complementAddr ” ) ;
57 $htmlCode .= FormManager : :addTextInput ( ”Compl é ment d ’ a d r e s s e ” ,
58 ” complementAddr ” , ” complementAddr ” ,
59 ” 30 ” , $ a d r e s s e −>complementAddr ) ;
60 $htmlCode .= s e l f : :addErrorMsg ( $ d a ta E rro r , ” c o d e P o s t a l ” ) ;
95
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
96
Chapitre 5 : Conception Objet, Gestion des Erreurs
6 * Les o p t i o n s compl é m e n t a i r e s d e s i n p u t s p e u v e n t ê t r e s é l e c t i o n n é e s
7 * v i a une v a r i a b l e $ e x t r a O p t i o n s d e s mé t h o d e s . */
8 c l a s s FormManager {
9 /* * @ b r i e f g é nère l a b a l i s e & l t ; form&g t ; a v e c mé t h o d e ( Post , Get ) e t a c t i o n ( u r l
) */
10 public s t a t i c function beginForm ( $method , $ a c t i o n , $css_ c l a s s=” ” ,
11 $ e x t r a O p t i o n s=” ” ) {
12 $css_ c l a s s _option = ” ” ;
13 i f ( !empty( $css_ c l a s s ) ) {
14 $css_ c l a s s _option = ” c l a s s =\”” . $css_ c l a s s . ” \” ” ;
15 }
16 return ”<form method=\”” . $method . ” \” a c t i o n =\”” . $ a c t i o n . ” \” ”
17 . ” a c c e p t −c h a r s e t =\” u t f −8\” ” // On f o r c e l e c h a r s e t
18 . $css_ c l a s s _option . $ e x t r a O p t i o n s . ”>\n” ;
19 }
20
21 /* * @ b r i e f ferme l e f o r m u l a i r e */
22 public s t a t i c function endForm ( ) {
23 return ”</form>” ;
24 }
25
26 /* * mé t h o d e g éné r i q u e de g éné r a t i o n d ’ un i n p u t
27 * @param $ l a b e l T e x t t e x t e du l a b e l c o r r e s p o n d a n t à l ’ i n p u t
28 * @param $ t y p e t y p e d ’ i n p u t : t e x t e , date , c h e c k b o x , r a d i o , s u b m i t . . .
29 * @param $name name de l ’ i n p u t pour l a c o r r e s p o n d a n c e l a b e l / i n p u t
30 * @param $ i d ID de l ’ i n p u t pour l a c o r r e s p o n d a n c e l a b e l / i n p u t
31 * @param $ v a l u e v a l e u r i n i t i a l e du champs de l ’ i n p u t
32 * @param $ e x t r a O p t i o n s c h a i n e de c a r a c t è r e s c o n t e n a n t l e s o p t i o n s
33 * s u p p l é m e n t a i r e s de l ’ i n p u t s u i v a n t l a s y n t a x e HTML. */
34 public s t a t i c function addInput ( $ l a b e l T e x t , $type , $name , $id , $ v a l u e=n u l l ,
35 $ e x t r a O p t i o n s=” ” ) {
36 // On é chappe pour é v i t e r t o u t i n j e c t i o n
37 $ v a l u e = ( $ v a l u e == n u l l ) ? ” ” : f i l t e r _ v a r ( $va lue , FILTER_SANITIZE_STRING)
;
38 $ v a l u e O p t i o n = ” v a l u e =\”” . $ v a l u e . ” \” ” ;
39 i f ( $ e x t r a O p t i o n s == n u l l ) {
40 $ e x t r a O p t i o n s=” ” ;
41 }
42 $ return Text = ”<span c l a s s =\” f o r m F i e l d \”>” ;
43 i f ( $ l a b e l T e x t != n u l l && $ l a b e l T e x t !=” ” ) {
44 $ return Text .= ”< l a b e l f o r =\”” . $ i d . ”\”>” . $ l a b e l T e x t . ”</ l a b e l >\n” ;
45 }
46 $ return Text .= ”<i n p u t t y p e =\”” . $type . ” \” name=\”” . $name . ” \” i d =\””
47 . $ i d . ” \” ” . $ v a l u e O p t i o n . ” ” . $ e x t r a O p t i o n s . ” />\n” ;
48 $ return Text .= ”</span>” ;
49
50 return $ return Text ;
51 }
52 // ! @cond Doxygen_Suppress
53 /* * @ b r i e f mé t h o d e pour g éné r e r un i n p u t de t y p e t e x t */
54 public s t a t i c function addTextInput ( $ l a b e l T e x t , $name , $id , $ s i z e ,
55 $ v a l u e=n u l l , $ e x t r a O p t i o n s=” ” ) {
56 return s e l f : :addInput ( $ l a b e l T e x t , ” t e x t ” , $name , $id , $ valu e ,
57 ” s i z e =\”” . $ s i z e . ” \” ” . $ e x t r a O p t i o n s
);
58 }
97
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
59
60 /* * @ b r i e f mé t h o d e pour g éné r e r un i n p u t de t y p e password */
61 public s t a t i c function addPasswordInput ( $ l a b e l T e x t , $name , $id , $ s i z e ,
62 $ v a l u e=n u l l , $ e x t r a O p t i o n s=” ” ) {
63 return s e l f : :addInput ( $ l a b e l T e x t , ” password ” , $name , $id , $ valu e ,
64 ” s i z e =\”” . $ s i z e . ” \” ” . $ e x t r a O p t i o n s ) ;
65 }
66
67 /* * @ b r i e f mé t h o d e pour g éné r e r un i n p u t de t y p e r a d i o */
68 public s t a t i c function addRadioInput ( $ l a b e l T e x t , $name , $id , $checked ,
69 $ v a l u e=n u l l , $ e x t r a O p t i o n s=” ” ) {
70 return s e l f : :addInput ( $ l a b e l T e x t , ” r a d i o ” , $name , $id , $v alue ,
71 ( strcmp ( $checked , ’ c h e c k e d ’ )==0) ? ” c h e c k e d =\” c h e c k e d \” ”
72 :” ” . $ e x t r a O p t i o n s ) ;
73 }
74
75 /* * @ b r i e f mé t h o d e pour g éné r e r un i n p u t de t y p e c h e c k b o x */
76 public s t a t i c function addCheckboxInput ( $ l a b e l T e x t , $name , $id , $checked ,
77 $v alue , $ e x t r a O p t i o n s=” ” ) {
78 return s e l f : :addInput ( $ l a b e l T e x t , ” c h e c k b o x ” , $name , $id , $ valu e ,
79 ( strcmp ( $checked , ’ c h e c k e d ’ )==0) ? ” c h e c k e d =\” c h e c k e d \” ”
80 :” ” . $ e x t r a O p t i o n s ) ;
81 }
82
83 /* * @ b r i e f mé t h o d e pour g éné r e r une zone de s a i s i e & l t ; t e x t a r e a&g t ; */
84 public s t a t i c function addTextArea ( $ l a b e l T e x t , $name , $id , $rows , $ c o l s ,
85 $ v a l u e=n u l l , $ e x t r a O p t i o n s=” ” ) {
86 // On é chappe , au moins pour l e s q u o t e s , mais a u s s i
87 // pour é v i t e r t o u t i n j e c t i o n
88 $ v a l u e = ( $ v a l u e == n u l l ) ? ” ” : f i l t e r _ v a r ( $va lue , FILTER_SANITIZE_STRING)
;
89 $ v a l u e O p t i o n = ” v a l u e =\”” . $ v a l u e . ” \” ” ;
90 i f ( $ e x t r a O p t i o n s == n u l l ) {
91 $ e x t r a O p t i o n s=” ” ;
92 }
93 $ return Text .= ”<p>\n” ;
94 i f ( $ l a b e l T e x t != n u l l && $ l a b e l T e x t !=” ” ) {
95 $ return Text .= ”< l a b e l f o r =\”” . $ i d . ”\”>” . $ l a b e l T e x t . ”</ l a b e l >\n” ;
96 }
97 $ return Text .= ”<t e x t a r e a name=\”” . $name . ” \” i d =\”” . $ i d . ” \” rows=\”” . $rows
98 . ” \” c o l s =\”” . $ c o l s . ” \” ” . $ e x t r a O p t i o n s . ” >” . $ v a l u e O p t i o n
99 . ”</ t e x t a r e a >\n” ;
100 $ return Text .= ”</p>\n” ;
101 return $ return Text ;
102 }
103
104 /* * @ b r i e f mé t h o d e pour g éné r e r un i n p u t de t y p e f i l e ( u p l o a d ) */
105 public s t a t i c function addUploadInput ( $ l a b e l T e x t , $name , $id , $ s i z e ,
106 $ v a l u e=” ” , $ e x t r a O p t i o n s=” ” ) {
107 $ v a l u e O p t i o n = ( $ v a l u e == n u l l ) ? ” v a l u e =\”\”” : ” v a l u e =\”” . $ v a l u e . ” \” ” ;
108 i f ( $ e x t r a O p t i o n s == n u l l ) {
109 $ e x t r a O p t i o n s=” ” ;
110 }
111 return s e l f : :addInput ( $ l a b e l T e x t , ” f i l e ” , $name , $id , $ valu e ,
112 ” s i z e =\”” . $ s i z e . ” \” ” . $ v a l u e O p t i o n . ” ” . $ e x t r a O p t i o n s )
;
98
Chapitre 5 : Conception Objet, Gestion des Erreurs
113 }
114
115 /* * @ b r i e f mé t h o d e pour commencer une l i s t e d ’ o p t i o n s & l t ; s e l e c t&g t ; */
116 public s t a t i c function b e g i n S e l e c t ( $ l a b e l T e x t , $name , $id , $ m u l t i p l e=f a l s e ,
117 $ s i z e =6){
118 $ return Text = ” ” ;
119 i f ( $multiple ){
120 $ m u l t i p l e O p t i o n=” m u l t i p l e =\” m u l t i p l e \” s i z e =\”” . $ s i z e . ” \” ” ;
121 } else {
122 $ m u l t i p l e O p t i o n=” ” ;
123 }
124 i f ( $ l a b e l T e x t != n u l l && $ l a b e l T e x t !=” ” ) {
125 $ return Text .= ”< l a b e l f o r =\”” . $ i d . ”\”>” . $ l a b e l T e x t . ”</ l a b e l >\n” ;
126 }
127 $ return Text .= ”< s e l e c t name=\”” . $name . ( $ m u l t i p l e === true ? ” [ ] ” : ” ” ) . ” \”
i d =\”” . $ i d . ” \” ”
128 . $ m u l t i p l e O p t i o n . ”>\n” ;
129 return $ return Text ;
130 }
131
132 /* * @ b r i e f mé t h o d e s i m p l i f i é e pour t e r m i n e r une l i s t e d ’ o p t i o n s & l t ; s e l e c t&g t ;
*/
133 public s t a t i c function e n d S e l e c t ( ) {
134 $ return Text = ”</ s e l e c t ></p>\n” ;
135 return $ return Text ;
136 }
137
138 /* * @ b r i e f mé t h o d e s i m p l i f i é e pour a j o u t e r une & l t ; o p t i o n&g t ; de l i s t e & l t ;
s e l e c t&g t ;
139 * */
140 public s t a t i c function a d d S e l e c t O p t i o n ( $ valu e , $ d i s p l a y T e x t , $ s e l e c t e d=f a l s e ) {
141 $ return Text = ” ” ;
142 if ( $selected ){
143 $ s e l e c t e d O p t i o n=” s e l e c t e d =\” s e l e c t e d \” ” ;
144 } else {
145 $ s e l e c t e d O p t i o n=” ” ;
146 }
147 $ return Text .= ”<o p t i o n v a l u e =\”” . $ v a l u e . ” \” ” . $ s e l e c t e d O p t i o n . ”>”
148 . $ d i s p l a y T e x t . ”</o p t i o n >\n” ;
149 return $ return Text ;
150 }
151
152 /* * @ b r i e f mé t h o d e s i m p l i f i é e pour g éné r e r un i n p u t de t y p e r a d i o */
153 public s t a t i c function addHiddenInput ( $name , $id , $ valu e , $ e x t r a O p t i o n s=” ” ) {
154 return s e l f : :addInput ( ” ” , ” h i d d e n ” , $name , $id , ” ” . $v alue , $ e x t r a O p t i o n s ) ;
155 }
156
157 /* * @ b r i e f mé t h o d e s i m p l i f i é e pour g éné r e r un bouton s u b m i t */
158 public s t a t i c function addSubmitButton ( $ v a l u e=” Envoyer ” , $ e x t r a O p t i o n s=” ” ) {
159 return s e l f : :addInput ( n u l l , ” s u b m i t ” , ” ” , ” ” , $ valu e , ” ” . $ e x t r a O p t i o n s ) ;
160 }
161 // ! @endcond
162 }
163 ?>
Remarque. Notons que les valeurs affectées dans l’attribut value des formulaires sont sys-
99
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
submit
≪ static ≫ getValidInstance(out dataErrors, $ POST, policy)
≪ static ≫ validationInput($ POST, out adresse, policy)
adresse
≪ static ≫ getHtmlDevelopped(adresse)
code HTML Vue
VueNormale
Normale
≪ static ≫ finFichierHTML5()
code HTML
≪ static ≫ finFichierHTML5()
code HTML
100
Chapitre 5 : Conception Objet, Gestion des Erreurs
Le script qui reçoit les données saisies dans le formulaire, construit l’instance d’adresse et
appelle une vue (vue normale ou vue d’erreur, selon le cas).
Remarque. Dans certaines archirectures d’applications, un filtrage des données reçues est
effectué dè la réception des données issues d’un formulaire.
Code Source 5.12 : exemples/forms2/receptionAdresseRequest.php
1 < ?php
2 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / E x p r e s s i o n s R e g e x U t i l s . php ’ ) ;
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / Adresse . php ’ ) ;
4 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / A d r e s s e V a l i d a t i o n . php ’ ) ;
5 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / A d r e s s e F a b r i q u e . php ’ ) ;
6 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / V a l i d a t i o n U t i l s . php ’ ) ;
7 // On c r é e une i n s t a n c e à p a r t i r du t a b l e a u $_POST
8 // Les a t t r i b u t s ”name” d e s i n p u t s de l ’ a d r e s s e d o i v e n t c o r r e s p o n d r e
9 // aux noms d e s a t t r i b u t s de l a c l a s s e \CoursPHP\ M e t i e r \ Adresse
10 // Les a t t r i b u t s de l ’ a d d r e s s e s o n t a u s s i v a l é d é s pour l a l o g i q u e mé t i e r .
11 $ a d r e s s e = CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e : : g e t V a l i d I n s t a n c e (
12 $dataError , $_POST,
13 \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s : :SANITIZE_POLICY_NONE
);
14 // Appel de l a vue ou de l a vue d ’ e r r e u r :
15 i f (empty( $ d a t a E r r o r ) ) {
16 require ( dirname (__FILE__) . ’ / v u e A f f i c h e A d r e s s e . php ’ ) ;
17 } else {
18 require ( dirname (__FILE__) . ’ / v u e E r r e u r S a i s i e A d r e s s e . php ’ ) ;
19 }
20 ?>
101
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Compléments
√
Pour la validation, nous faisons le choix de modifier le moins possible la chaîne, suppri-
mant uniquement les caractères utilisés pour les balises HTML, mais uniquement pour la
génération de code HTML. Nous souhaitons en effet conserver les données brutes dans le
système d’information, enutilisant, comme nous le verrons plus loin, la sécurité apportée
par les requêtes préparées de PDO avec le codage UTF-8.
La raison de ce choix est que, pour une utilisation de notre code de filtrage (notamment
les expressions régulières) dans une API, les codes d’échappement liés à la technologie
HTML ne sont pas forcément pertinents. Nous validons par filter_var dans le cadre de
notre application WEB, mais nos objets métier et notre couche persistance ne sera pas
liée à HTML.
102
Chapitre 5 : Conception Objet, Gestion des Erreurs
8 ’UTF−8 ’ , ’ m y S t y l e . c s s ’ ) ;
9 echo CoursPHP\Vue\ AdresseView : :getHtmlDevelopped ( $ a d r e s s e ) ;
10 echo CoursPHP\Vue\ AdresseFormView : :getHiddenFormHtml (
11 ” . / e d i t A d r e s s e R e q u e s t . php ” , $ a d r e s s e , ” M o d i f i e r ” ) ;
12 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
13 ?>
La réception des données du formulaire caché via le tableau $_POST et l’affichage du formulaire
pré-rempli est codé comme suit :
Code Source 5.15 : exemples/forms2/editAdresseRequest.php
1 < ?php
2 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / E x p r e s s i o n s R e g e x U t i l s . php ’ ) ;
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / Adresse . php ’ ) ;
4 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / A d r e s s e V a l i d a t i o n . php ’ ) ;
5 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / A d r e s s e F a b r i q u e . php ’ ) ;
6 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / V a l i d a t i o n U t i l s . php ’ ) ;
7 // On c r é e une i n s t a n c e à p a r t i r du t a b l e a u $_POST
8 // Les a t t r i b u t s ”name” d e s i n p u t s de l ’ a d r e s s e d o i v e n t c o r r e s p o n d r e
9 // aux noms d e s a t t r i b u t s de l a c l a s s e \CoursPHP\ M e t i e r \ Adresse
10 // Les a t t r i b u t s de l ’ a d d r e s s e s o n t a u s s i v a l é d é s pour l a l o g i q u e mé t i e r .
11 $ a d r e s s e = CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e : : g e t V a l i d I n s t a n c e (
12 $dataError , $_POST,
13 \CoursPHP\ C o n t r o l e u r \ V a l i d a t i o n U t i l s : :SANITIZE_POLICY_NONE
);
14 // Appel s y s t é matique de l a vue d ’ e r r e u r , q u i r e n v o i e un f o r m u l a i r e pr é−r e m p l i
:
15 require ( dirname (__FILE__) . ’ / v u e E r r e u r S a i s i e A d r e s s e . php ’ ) ;
16 ?>
103
Troisième partie
Persistance
104
Table of Contents
6 Cookies 109
6.1 Création d’un cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.2 Récupération d’un cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
6.3 Suppression d’un cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.4 Mise à jour d’un cookie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
7 Sessions 114
7.1 Concept de Session et Problèmes de Sécurité . . . . . . . . . . . . . . . . . . . 114
7.2 Cycle de vie d’une Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
7.2.1 Création d’une session commune à tous les utilisateurs . . . . . . . . . 115
7.2.2 Identifiant de Session (SID) . . . . . . . . . . . . . . . . . . . . . . . . 116
7.2.3 Destruction d’une Session . . . . . . . . . . . . . . . . . . . . . . . . . 117
7.3 Gestion de l’Identifiant de Session (SID) . . . . . . . . . . . . . . . . . . . . . 118
7.3.1 Exemple de Session avec SID aléatoire transmis par GET . . . . . . . 118
7.3.2 Exemple de Session avec SID aléatoire transmis par COOKIE . . . . . 121
7.4 Login/Password : Exemple de Politique de Sécurité . . . . . . . . . . . . . . . 122
106
Introduction : Mécanismes de la
Persistence
Le protocole HTTP est un protocole sans état. Cela signifie que, dans le protocole HTTP, au-
cune information n’est conservée entre deux transaction. Théoriquement, suivant un tel proto-
cole, il faudrait qu’un client qui se reconnecte rerpenne tout depuis le début. Ce comportement
peut être problématique pour certaine application, dans lequelles le serveur doit se souvenir
des données personnelles du clients, comme son profil, son adresse, etc.
Pour cette raison, les développeurs Web doivent implémenter eux meme la persistence, qui
permet aux programmes de conserver des données d’un connexion à l’autre. Il y a trois types
de mécanismes permettant d’implémenter la persistence :
• L’authentification par login et mot de passe. C’est la manière la plus sûre d’iden-
tifier le client lorsqu’il se représente. Cependant, redemander le mot de passe du client à
chaque chargement de script pour lui réattribuer ses données peut vite devenir exaspé-
rant pour le client. Il y a généralement nécessité d’ajouter un mécanisme de persistence
temporaire des données tant que le client passe d’une page à l’autre au cours d’une même
visite.
• Les cookies, qui sont des données (généralement peu volumineuses accessibles dans le
tebleau associatif superglobal $_COOKIE) stockées sur la machine du client. Le client a la
possibilité de refuser le stockage du cookie, ou d’éliminer le cookie entre deux connections.
Un pirate a des fois la possibilité de suptiliser un cookie. En général, on ne peut pas se
fier de manière sûre au mécanisme des cookies, ce qui n’empeche pas d’exploiter les co-
okies. Les cookies sont surtout utilisés pour identifier les client d’une connexion à l’autre,
pour pouvoir lui associer les données venant d’une précédente connexion. Pour éviter un
piratage des données, l’utilisation de cookie doit être accompagnée d’une politique de
sécurité pour éviter l’usurpation d’identité.
La politique de sécurité, qui dépend de l’application considérée, va s’appuyer notamment
sur :
– Une date limite de validié du cookie, qui permet de limiter la fenêtre d’opportunité
pour un pirate.
– Le hashage ou le chiffrage, qui permet de ne pas révéler en clair les données stokées
dans un cookie.
– Éventuellement l’adresse IP du client. Cependant, sachant que les clients mobiles
peuvent changer régulièrement d’adresse IP, sachant aussi que des adresses IP sur
internet peuvent etre partagées par plusieurs clients utilisant la même passerelle, on
ne peut pas s’appuyer uniquement sur l’adresse IP, même si un changement d’adresse
107
TABLE OF CONTENTS
IP peut être l’un des critères pour redemander une authentification par mot de passe,
surtout en présence d’autres indices d’une éventuelle usurpation d’identité.
– Des systèmes de jetons aléatoires à usage unique dans le cookie et, d’une manière
générale, l’usage unique des données du cookie, qui permet de limiter la fenêtre
d’opportunité pour un pirate.
• Les sessions permettent de stocker des données coté serveur. Les données mémorisées
sont des couples clé/valeur (accessibles en PHP dans un tableau associatif superglobal
$_SESSION). Pour le stockage sont sous la forme de chaîne de caractère. La sérialisation
permet de coder des données complexes (instances de classes, etc.) dans une session.
Selon la configuration du serveur, les sessions peuvent etre stockées dans des fichiers sur
le disque, dans une base de données, ou encore (généralement sous forme chiffrée) via un
cookie sur le poste client. Ces différentes formes de stockage ont un impact sur la charge
du serveur, notamment en cas de grosses applications nécessitant que plusieurs serveurs
partagent les données de session, et sur la sécurité et la confidentialité des données.
Une session, caractérisée par un nom et un identifiant de session (SID), doit etre réattri-
buée à un client d’une page à l’autre, et éventuellement d’une visite à l’autre. Elles sont
donc combinées à la transmission de données d’un script à l’autre, soit par la méthode
GET dans l’URL, soit par la méthode POST dans un champs caché, soit par un cookie.
• Les Bases de données, qui permettent de stocker de manière durable de grandes quan-
tités de données, structurées de manière relationnelle. Pour pouvoir associer des données
dans une base de données à un client, il faut identifier le client, généralement via une clé
primaire dans une table. Cela nécessite de conserver l’information de l’identité du client
par les autres mécanismes (login, cookie, session) ci-dessus.
108
Chapitre 6
Cookies
Il existe une autre fonction, setrawcookie, de même signature, mais qui n’applique pas
d’encodage URL (voie documentation de la fonction urlencode) aux données du cookie, contrai-
rement à setcookie.
Code Source 6.2 :
b o o l s e t r a w c o o k i e ( s t r i n g $name , s t r i n g $ value , i n t $ e x p i r e = 0 ,
s t r i n g $path , s t r i n g $domain , b o o l $ s e c u r e = f a l s e ,
bool $httponly = false )
109
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
• secure : permet de ne créer le cookie seulement si la connexion est sécurisé par SSL
(protocole https).
• httponly : lorsqu’il vaut true, ce paramètre empêche l’accès direct du cookie via des
langages de scripts comme javascripts. C’est discutable dans la mesure où, par exemple,
ça dépend de l’implémentation du navigateur client.
La fonction setcookie retourne true en cas de succès de création du cookie. Cela ne permet
pas d’être sur que le cookie a été accepté chez le client. On ne peut pas savoir si le cookie a été
accepté avant d’avoir chargé un nouveau script essayant d’accéder au cookie.
On peut éventuellement stocker un tableau de plusieurs chaînes dans un cookie, mais cela
crée de fait plusieurs cookies chez le client. Mieux vaut créer un cookie avec un séparateur
de son choix (caractère ou patron de type chaîne. Éviter les caractères spéciaux HTML...),
puis utiliser le fonction explode, qui va retourner un tableau en coupant la chaîne suivant les
occurrences du séparateur.
Voici le code de création d’un cookie, valable une heure, dans tous les scripts PHP du
répertoire courant :
110
Chapitre 6 : Cookies
111
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
18 foreach ( $ t a bC h ai n e s a s $ c h a i n e ) {
19 echo ”<l i >” . $ c h a i n e . ”</ l i l i >” ;
20 }
21 echo ”</u l >” ;
22 echo Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
23 } e l s e { // Appel de l a vue d ’ e r r e u r :
24 require ( ’ ex02_vueErreur . php ’ ) ;
25 }
26
27
28 ?>
112
Chapitre 6 : Cookies
113
Chapitre 7
Sessions
• Les cookies, stockés par le navigateur du client, et éventuellement accessible côté client
via un langage de script comme javascript ;
• La méthode POST, sous la forme d’un champs caché de formulaire en clair dans le source
HTML ;
Du fait qu’il y a toujours une possibilité pour une personne malveillante d’accéder aux don-
nées transmises, il est généralement déconseillé de transmettre en clair l’identifiant de session.
Tout au moins, des données doivent permettre de vérifier que l’utilisateur qui nous transmet un
numéro de session est bien identifié, avant de lui donner accès aux données de session. En effet,
les données de session permettent entre autre de maintenir un utilisateur connecté considéré
comme authentifié, sans qu’il ait besoin de rentrer son mot de passe à chaque chargement de
script.
En dehors du risque d’usurpation d’identité lié à la transmission de l’identité de l’utilisateur
ou du numéro de session, les données de session elles mêmes, n’étant pas transmises au client,
sont relativement sûres (dans la mesure ou le serveur lui-même est sécurisé).
114
Chapitre 7 : Sessions
115
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
21 session_write_close ( ) ;
22
23 // Code de l a vue :
24 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
25 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” U t i l i s a t i o n b a s i q u e d ’ une s e s s i o n
” , ’UTF−8 ’ , ’ m ySt yle . c s s ’ ) ;
26 echo ”<h1>U t i l i s a t i o n B a s i q u e d ’ une S e s s i o n <b r/>Commune à Tous l e s C l i e n t s </h1
>” ;
27 echo ”<p>Le s c r i p t a é t é c h a r g é ” . $ c o u n t e r V a l u e . ” f o i s d e p u i s l a c r é a t i o n de
l a s e s s i o n .</p>” ;
28 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
29 ?>
116
Chapitre 7 : Sessions
20 } else {
21 // Cha î ne q u i code l a d a t e d ’ h i e r
22 $ y e s t e r d a y L o c a l e A r r a y = l o c a l t i m e ( time ( ) −60*60*24 , true ) ;
23 $yestadayDayOfMonth = str_pad ( i n t v a l ( $ y e s t e r d a y L o c a l e A r r a y [ ’tm_mday ’ ] , 1 0 ) ,
2 , ”0” ,STR_PAD_LEFT) ;
24 $yestadayMonthOfYear = str_pad ( i n t v a l ( $ y e s t e r d a y L o c a l e A r r a y [ ’tm_mon ’ ] , 1 0 )
+1, 2 , ”0” ,STR_PAD_LEFT) ;
25 $ y e s t a d a y Y e a r S i n c e E r a = str_pad ( i n t v a l ( $ y e s t e r d a y L o c a l e A r r a y [ ’ tm_year ’ ] , 1 0 )
+1900 , 4 , ”0” ,STR_PAD_LEFT) ;
26 $ y e s t e r d a y D a t e S t r i n g = $ y e s t a d a y Y e a r S i n c e E r a . ”−” . $yestadayMonthOfYear . ”−” .
$yestadayDayOfMonth ;
27 // On e f f a c e l e compteur de l a v e i l l e pour é v i t e r que l e s compteurs s ’
accumulent . . .
28 unset ($_SESSION [ ’ c o u n t e r − ’ . $ y e s t e r d a y D a t e S t r i n g ] ) ;
29 // On i n i t i a l i s e l e compteur du j o u r
30 $_SESSION [ ’ c o u n t e r − ’ . $ d a t e S t i n g ] = ”1 ” ;
31 }
32 // Mé m o r i s a t i o n de l a donn é e de s e s s i o n a v a n t f e r m e t u r e
33 $ c o u n t e r V a l u e = $_SESSION [ ’ c o u n t e r − ’ . $ d a t e S t i n g ] ;
34 // F l u s h d e s Donné e s de S e s s i o n , ( s a u v e g a r d e immé d i a t e s u r l e d i s q u e )
35 // L i b è r e i n s t a n t a n é ment l e v e r r o u pour l ’ a c c è s à l a s e s s i o n par d ’ a u t r e s
s c r i p t s ou c l i e n t s
36 session_write_close ( ) ;
37
38 // Code de l a vue :
39 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
40 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” U t i l i s a t i o n b a s i q u e d ’ une s e s s i o n
” , ’UTF−8 ’ , ’ m ySt yle . c s s ’ ) ;
41 echo ”<h1>U t i l i s a t i o n d ’ une S e s s i o n <b r/>Commune à Tous l e s C l i e n t s </h1>” ;
42
43 echo ”<p>Le s c r i p t a é t é c h a r g é ” . $ c o u n t e r V a l u e . ” f o i s a u j o u r d ’ h u i ( l e ” .
$dayOfMonth . ”/” . $monthOfYear . ”/” . $ y e a r S i n c e E r a . ” ) .</p>” ;
44 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
45 ?>
117
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
118
Chapitre 7 : Sessions
38
39 // S i un c h o i x de l a n g a g e e s t pr é c i s é dans l ’URL, on m o d i f i e l a v a r i a b l e de
session
40 i f ( i s s e t ($_GET[ ’ p r e f _ l a n g ’ ] ) ) {
41 i f ($_GET[ ’ p r e f _ l a n g ’ ] == ” en ” | | $_GET[ ’ p r e f _ l a n g ’ ] == ” f r ” ) {
42 // Les donn é e s e n t r é e s en s e s s i o n d o i v e n t ê t r e f i l t r é es ,
43 // même s i , dans ce cas , i l n ’ y a pas de danger c a r on a t e s t é a v e c ==
44 $_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] = f i l t e r _ v a r ($_GET[ ’ p r e f _ l a n g ’ ] ,
FILTER_SANITIZE_STRING) ;
45 } else {
46 // Paramètre impr é vu , on d é t r u i t l a donn é e de s e s s i o n , au c a s où
47 unset ($_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ) ;
48 }
49 }
50 // S i une pr é f é r e n c e de l a n g a g e a é t é d é f i n i e , s o i r dans l ’URL, s o i t en
session
51 i f ( i s s e t ($_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ) ) {
52 $PREFERRED_LANG = $_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ;
53 } else {
54 $PREFERRED_LANG = ” u n d e f ” ;
55 }
56
57 // F l u s h d e s Donné e s de S e s s i o n , ( s a u v e g a r d e simmé d i a t e ur l e d i s q u e )
58 session_write_close ( ) ;
59
60 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
61 // S i aucun SID i n c o r r e c t dans l ’URL
62 i f (empty( $ d a t a E r r o r ) ) { // Code de l a vue normale :
63 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” S e s s i o n a v e c SID Al é a t o i r e ” , ’
UTF−8 ’ , ’ m ySt yle . c s s ’ ) ;
64 echo ”<h1>S e s s i o n a v e c <i >SID</i > Al é a t o i r e <b r/>Transmis par <code>GET</code
></h1>” ;
65 echo ”<p>” ;
66 // Message de b i e n v e n u e dans l a l a n g u e s é l e c t i o n n é e ou en m u l t i l i n g u e s i
undef
67 echo g e t G r e e t i n g ($PREFERRED_LANG) . ”<b r/>” ;
68 echo ”<a h r e f =\”” .$_SERVER[ ’SCRIPT_NAME ’ ] . ” ?s e s s i o n −i d=” . $mySid . ”&p r e f _ l a n g=
f r \”>Fran ç a i s </a> ou ”
69 . ”<a h r e f =\”” .$_SERVER[ ’SCRIPT_NAME ’ ] . ” ?s e s s i o n −i d=” . $mySid . ”&p r e f _ l a n g=
en\”> E n g l i s h </a>” ;
70 echo ”</p>” ;
71 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
72 } e l s e { // Appel de l a vue d ’ e r r e u r :
73 require ( ’ ex04_vueErreur . php ’ ) ;
74 }
75
76
77 ?>
119
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
120
Chapitre 7 : Sessions
121
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
39 // I n i t i a l i s a t i o n d e s p a r a m è t r e s r é g i o n a u x
40
41 // S i un c h o i x de l a n g a g e e s t pr é c i s é dans l ’URL, on m o d i f i e l a v a r i a b l e de
session
42 i f ( i s s e t ($_GET[ ’ p r e f _ l a n g ’ ] ) ) {
43 i f ($_GET[ ’ p r e f _ l a n g ’ ] == ” en ” | | $_GET[ ’ p r e f _ l a n g ’ ] == ” f r ” ) {
44 // Les donn é e s e n t r é e s en s e s s i o n d o i v e n t ê t r e f i l t r é es ,
45 // même s i , dans ce cas , i l n ’ y a pas de danger c a r on a t e s t é a v e c ==
46 $_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] = htmlentities ($_GET[ ’ p r e f _ l a n g ’ ] ,
ENT_QUOTES, ”UTF−8” ) ;
47 } else {
48 // Paramètre impr é vu , on d é t r u i t l a donn é e de s e s s i o n , au c a s où
49 unset ($_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ) ;
50 }
51 }
52 // S i une pr é f é r e n c e de l a n g a g e a é t é d é f i n i e , s o i r dans l ’URL, s o i t en
session
53 i f ( i s s e t ($_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ) ) {
54 $PREFERRED_LANG = $_SESSION [ ’ p r e f e r r e d _ l a n g u a g e ’ ] ;
55 } else {
56 $PREFERRED_LANG = ” u n d e f ” ;
57 }
58
59 // F l u s h d e s Donné e s de S e s s i o n , ( s a u v e g a r d e simmé d i a t e s u r l e d i s q u e )
60 session_write_close ( ) ;
61
62 // Code de l a vue :
63 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
64 i f (empty( $ d a t a E r r o r ) ) { // Code de l a vue normale
65 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” S e s s i o n a v e c SID Al é a t o i r e ” , ’
UTF−8 ’ , ’ m ySt yle . c s s ’ ) ;
66 echo ”<h1>S e s s i o n a v e c <i >SID</i > Al é a t o i r e <b r/>Transmis par <code>COOKIE</
code></h1>” ;
67 echo ”<p>” ;
68 // Message de b i e n v e n u e dans l a l a n g u e s é l e c t i o n n é e ou en m u l t i l i n g u e s i
undef
69 echo g e t G r e e t i n g ($PREFERRED_LANG) . ”<b r/>” ;
70 echo ”<a h r e f =\”” .$_SERVER[ ’SCRIPT_NAME ’ ] . ” ?p r e f _ l a n g=f r \”>Fran ç a i s </a> ou ”
71 . ”<a h r e f =\”” .$_SERVER[ ’SCRIPT_NAME ’ ] . ” ?p r e f _ l a n g=en\”> E n g l i s h </a>” ;
72 echo ”</p>” ;
73 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
74 } e l s e { // Appel de l a vue d ’ e r r e u r :
75 require ( ’ ex04_vueErreur . php ’ ) ;
76 }
77 ?>
Nous voyons maintenant un exemple d’utilisation d’une session et de cookie un peu mieux
sécurisé.
122
Chapitre 7 : Sessions
• On effectue un contrôle par l’adresse IP du client. Cette adresse IP est stockée en session,
et est ensuite testée pour vérifier que le client n’a pas changé d’adresse IP.
Le numéro de session est envoyé chez le client via un cookie. De plus, le cookie (et la session
associée) ont une durée de validité de 2mn, temps laissé au client pour charger le script suivant.
Lors du chargement du script suivant, le numéro de session récupéré via le cookie.
Enfin, à chaque chargement de script, on change le SID aléatoire, en copiant les données
de session dans une nouvelle, et on re-génère le cookie. Le SID, ainsi que le cookie, n’est ainsi
valable qu’une seule fois.
Notons qu’une application sensible pourrait aussi effectuer d’autres contrôles, par exemple
sur le navigateur, système d’exploitation, ou encore la cohérence du referer avec la structure
du site et de ses liens internes.
La vue d’authentification (saisie de login et du mot de passe) est la suivante :
123
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Si le mot de passe est trop simple (test dans validationPasswd.php), on appelle une vue
d’erreur qui demande un nouveau mot de passe :
124
Chapitre 7 : Sessions
1 < ?php
2 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ”Éc h e c d ’ a u t h e n t i f i c a t i o n ” , ’UTF
−8 ’ , ’ m ySt yle . c s s ’ ) ;
3 echo ”<h1>Problème d ’ A u t h e n t i f i c a t i o n </h1>” ;
4 echo ”<p>” ;
5 foreach ( $ d a t a E r r o r a s $errorMsg ) {
6 echo ”<s t r o n g >” . $errorMsg . ”</s t r o n g ><b r/>” ;
7 }
8 echo ”</p>” ;
9 echo CoursPHP\Vue\ VueHtmlUtils : :getHTML_LoginForm ( ” e x 0 7 _ r e c e i v e P a s s w o r d . php ”
);
10 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
11 ?>
125
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
38 }
39 }
40 }
41 ?>
Le test sur la forme du mot de passe, ainsi que la génération du numéro de session (SID) sont
effectués par une classe d’utilitaires AuthUtils
Code Source 7.10 : exemples/sessions/classes/AuthUtils.php
1 < ?php
2 namespace CoursPHP\Auth ;
3 /* * @ b r i e f U t i l i t a i r e s de c o n n e c t i o n ( v a l i d a t i o n REGEX du mot de p a s s e ) */
4 class AuthUtils {
5 /* * F o n c ti on q u i t e s t e s i un mot de p a s s e e s t s u f f i s e m m e n t d i f f i c i l e
6 * @param $wouldBePasswd mot de p a s s e ( non hash é ) s a i s i par l ’ u t i l i s a t e u r */
7 public s t a t i c function i s S t r o n g P a s s w o r d ( $wouldBePasswd ) {
8 $ l e n g t h C o n d i t i o n = ( s t r l e n ( $wouldBePasswd ) >= 8 &&
9 s t r l e n ( $wouldBePasswd ) <= 3 5 ) ;
10 // On p e u t s û rement f a i r e p l u s e f f i c a c e pour l ’ é v a l u a t i o n d e s
11 // e x p r e s s i o n s r é g u l i è r e s . . .
12 $ C h a r a c t e r D i v e r s i t y C o n d i t i o n = preg_match( ” / [ a−z ] / ” , $wouldBePasswd )
13 && preg_match( ” / [A−Z ] / ” , $wouldBePasswd )
14 && preg_match( ” /[0 −9]/ ” , $wouldBePasswd )
15 && preg_match( ” /[\#\ −\|\.\@\[\]\=\ !\&]/ ” , $wouldBePasswd ) ;
16 return $ l e n g t h C o n d i t i o n && $ C h a r a c t e r D i v e r s i t y C o n d i t i o n ;
17 }
18 }
19 ?>
Si tout se passe bien, on crée une session d’ID aléatoire qui contient l’adresse IP du client,
pour contrôle par adresse IP lors de la prochaine visite.
126
Chapitre 7 : Sessions
7 // Voir l e c h a p i t r e s u r l e s b a s e s de donn é e s . . .
8 function use rPasswordCheckInDatabase ( $email , $hashedPassword ) {
9 // TODO : t e s t e r s i l e c o u p l e e−m a i l e t mot de p a s s e ( a p r è s h a s h a g e SHA512)
10 // s o n t b i e n pr é s e n t s dans l a b a s e de donn é e s
11 return true ;
12 }
13
14 // Test de l a forme ( r e g e x ) du mot de p a s s e e t de l ’ e−m a i l
15 \CoursPHP\Auth\ V a l i d a t i o n R e q u e s t : : v a l i d a t i o n L o g i n ( $ d at a E r r or , $email ,
$password ) ;
16
17 i f (empty( $ d a t a E r r o r ) ) { // l e s donn é e s d ’ a u t h e n t i f i c a t i o n ont l a bonne forme .
18 // On v é r i f i e que l e mot de p a s s e ( a p r è s h a s h a g e SHA512)
19 // e s t b i e n c e l u i en b a s e de donn é e .
20 i f ( ! use rPasswordCheckInDatabase ( $email , hash ( ” sha512 ” , $password ) ) ) {
21 // Renvoi d ’ une e r r e u r de l o g i n
22 $ d a t a E r r o r [ ” l o g i n ” ] = ” Erreur : l o g i n ou mot de p a s s e i n c o r r e c t ” ;
23 } else {
24 \CoursPHP\Auth\ S e s s i o n U t i l s : : c r e a t e S e s s i o n ( $ e m a i l ) ;
25 // F l u s h d e s Donné e s de S e s s i o n , ( s a u v e g a r d e simmé d i a t e ur l e d i s q u e )
26 session_write_close ( ) ;
27 }
28 }
29
30 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
31 i f (empty( $ d a t a E r r o r ) ) { // Code de l a vue normale :
32 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ”Welcome Page ” , ’UTF−8 ’ ,
33 ’ myStyle . c ss ’ ) ;
34 echo ”<h1>P e r s i s t a n c e de connexion<b r/>Exemple de p o l i t i q u e de s é c u r i t é</
h1>” ;
35 echo ” Bienvenue ! Vous ê t e s c o n v e n a b l e m e n t a u t h e n t i f i é.< b r/>” ;
36 echo ” Pour acc é d e r e n c o r e à d e s donn é e s s e n s i b l e s , ”
37 . ”<a h r e f =\”./ ex08_sessionTestIP_RandomIdCookie . php\”> c l i q u e z i c i </a>.” ;
38 echo \CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
39 } e l s e { // Appel de l a vue d ’ e r r e u r :
40 require ( ’ ex07_vueErreur . php ’ ) ;
41 }
42 ?>
La création de la session (avec son ID), contenant l’e-mail et l’adresse IP du client est effectuée
par une classe utilitaire SessionUtils :
127
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
14 $mySid = bin2hex ( $ o c t e t s ) ;
15 return $mySid ;
16 }
17
18 /* * Cré a t i o n d ’ une s e s s i o n de SID a l é a t o i r e a v e c l ’ e−m a i l ( l o g i n u n i q u e )
19 * @param $ e m a i l e−m a i l s e r v a n t de l o g i n ( i d e n t i f i a n t u n i q u e de l ’ u t i l i s a t e u r
)
20 * @param $ r o l e r ô l e de l ’ u t i l i s t e u r ( admin , v i s i t e u r , g e s t i o n n a i r e . . . )
21 * ( v o i r l e c h a p i t r e s u r l e Front C o n t r o l l e r ) * */
22 public s t a t i c function c r e a t e S e s s i o n ( $email , $ r o l e=” v i s i t o r ” ) {
23 // Dans l e c a s i m p r o b a b l e d ’ une c o l l i s i o n s u r l e SID ,
24 // Mais s u r t o u t d ’ une u s u r p a t i o n d ’ i d e n t i t é , on d é t r u i t l a s e s s i o n
25 // a v a n t de r e d é marer une s e s s i o n v i d e
26 session_write_close ( ) ;
27 session_start ( ) ;
28 session_destroy ( ) ;
29 // Le numé ro de s e s s i o n a l é a t o i r e
30 $mySid = s e l f : : g e n e r a t e S e s s i o n I d ( ) ;
31 session_id ( $mySid ) ;
32 // D e s t r u c t i o n du c o o c k i e a v a n t de l e r e c r é e r
33 setcookie ( ” s e s s i o n −i d ” , ” ” , time ( ) −60, ’ / ’ ) ;
34 // Cré a t i o n du c o o k i e a v e c SID a l é a t o i r e . V a l i d i t é du c o o k i e : 2mn
35 // Un p i r a t e aura b e s o i n de temps pour v o l e r l e c o o k i e . . .
36 setcookie ( ” s e s s i o n −i d ” , $mySid , time ( )+s e l f : :DUREE_COOKIE, ’ / ’ ) ;
37 // Dé marrage de l a s e s s i o n
38 session_start ( ) ;
39 // On é chappe , même s i on s a i t qu ’ on a v a l i d é l ’ a d r e s s e e−m a i l . . . .
40 $_SESSION [ ’ e m a i l ’ ] = htmlentities ( $email , ENT_QUOTES, ”UTF−8” ) ;
41 // On é chappe , même s i on s a i t qu ’ on a v a l i d é l ’ a d r e s s e e−m a i l . . . .
42 $_SESSION [ ’ r o l e ’ ] = htmlentities ( $ r o l e , ENT_QUOTES, ”UTF−8” ) ;
43 $_SESSION [ ’ i p A d d r e s s ’ ] = $_SERVER[ ’REMOTE_ADDR’ ] ;
44 }
45 }
46 ?>
Lorsque l’utilisateur poursuit la navigation, il reste reconnu et peut accéder à ses données
personnelles. Dans notre implémentation, pour plus de sécurité, le numéro de session est à
usage unique. Une nouvelle session, avec son nouveau SID est créée à chaque chargement de
script.
Code Source 7.13 : exemples/sessions/ex08_sessionTestIP_RandomIdCookie.php
1 < ?php
2 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / A u t h U t i l s . php ’ ) ;
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / S e s s i o n U t i l s . php ’ ) ;
4
5 $ d a t a E r r o r = array ( ) ;
6 // Test pour v o i r s i l ’ i d e n t i f i a n t de s e s s i o n e x i s t e e t s i l a donn é e a l a
bonne forme
7 // (10 c h i f f r e s hexa e n t r e 0 e t f )
8 i f ( ! i s s e t ($_COOKIE[ ’ s e s s i o n −i d ’ ] ) | |
9 !preg_match( ” /^[0 −9a−fA−F] { 2 0 } $/ ” , $_COOKIE [ ’ s e s s i o n −i d ’ ] ) ) {
10 $ d a t a E r r o r [ ’ no−c o o k i e ’ ] = ” Votre c o o k i e a peut−ê t r e e x p i r é e , ”
11 . ” Merci de vous c o n n e c t e r à nouveau . . . ” ;
12 } else {
13 // On r é c u p è r e l ’ ID de s e s s i o n
14 $mySid = $_COOKIE[ ’ s e s s i o n −i d ’ ] ;
128
Chapitre 7 : Sessions
15
16 // On r é c u p è r e l e s donn é e s de s e s s i o n :
17 session_id ( $mySid ) ;
18 session_start ( ) ;
19
20 // Test s u r l e s donn é e s de s e s s i o n e t c o n t r ô l e par IP
21 i f (empty($_SESSION [ ’ e m a i l ’ ] ) | | empty($_SESSION [ ’ i p A d d r e s s ’ ] )
22 | | $_SESSION [ ’ i p A d d r e s s ’ ] != $_SERVER[ ’REMOTE_ADDR’ ] ) {
23 $ d a t a E r r o r [ ”no−s e s s i o n ” ] = ” Votre s e s s i o n a peut−ê t r e e x p i r é e , ”
24 . ” Merci de vous c o n n e c t e r à nouveau . . . ” ;
25 session_destroy ( ) ;
26 } else {
27 // R a f f i n e m e n t : on change l e SID a l é a t o i r e , en c o p i a n t
28 // l a s e s s i o n dans une n o u v e l l e . On r e g é nè re e n s u i t e l e c o o k i e
29 // Comme ça , l e c o o k i e n ’ e s t v a l a b l e qu ’ une f o i s , e t l ’ ID de s e s s i o n a u s s i
30 // ce q u i l i m i t e beaucoup l a p o s s i b i l i t é d ’ un é v e n t u e l h a c k e r
31 $backupSession_Email = $_SESSION [ ’ e m a i l ’ ] ;
32 // On d é t r u i t l ’ a n c i e n n e s e s s i o n
33 session_destroy ( ) ;
34 // On r e c r é e une s e s s i o n :
35 CoursPHP\Auth\ S e s s i o n U t i l s : : c r e a t e S e s s i o n ( $backupSession_Email ) ;
36 // F l u s h d e s Donné e s de S e s s i o n , ( s a u v e g a r d e simmé d i a t e ur l e d i s q u e )
37 session_write_close ( ) ;
38 }
39 }
40
41 // Code de l a vue :
42 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / c l a s s e s / VueHtmlUtils . php ’ ) ;
43 i f (empty( $ d a t a E r r o r ) ) { // Code de l a vue normale
44 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” C o n s u l t a t i o n d e s Donné e s
P e r s o n n e l l e s ” , ’UTF−8 ’ , ’ m yS ty l e . c s s ’ ) ;
45 echo ”<h1>C o n s u l t a t i o n d e s Donné e s P e r s o n n e l l e s </h1>” ;
46 echo ”<p>” ;
47 echo ”Ne l e d i t e à p ers onn e : l e <i >SID</i > e s t : <b r/>” . $mySid ;
48 echo ”</p><p>” ;
129
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
130
Chapitre 8
(a) Création d’une nouvelle Base de Données (b) Création d’une nouvelle table
131
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Figure 8.3 : Vue Relationnelle de base de données avec trois tables. La définition des clés
étrangères doit être cohérente avec les clés primaire.
(a) Ajout d’un Utilisateur MySQL (b) Accès MySQL Uniquement sur le Serveur Local
Figure 8.4 : Ajout d’un utilisateur MySQL avec uniquement sur le Serveur Local
132
Chapitre 8 : Bases de Données et PHP Data Objects
(a) Privilèges Spécifiques d’un Utilisateur sur une Base (b) L’Utilisateur aura tous les droits sur une Base
Figure 8.5 : Donner tous les Droits à l’Utilisateur sur une Base spécifique
133
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
134
Chapitre 8 : Bases de Données et PHP Data Objects
50 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
51 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ”Ma Première Connexion PDO” ,
52 ’UTF−8 ’ , ’ m y S t y l e . c s s ’ ) ;
53 echo ”<h1>I n i t i e r une Connexion <i >PDO</i ></h1>” ;
54 echo ”La r e q u ê t e a b i e n é t é ex é c u t é e . . . ” ;
55 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
56 ?>
Figure 8.8 : Cas où la clé primaire existe déjà (ici : rechargement du script)
Voici un exemple où l’exception générée par le constructeur de PDO n’est pas gérée. Les
données d’authentification pour l’accès à la base de données apparaîssent en clair chez le client.
Code Source 8.3 : exemples/pdo/ex02_withNoTryCatchLeakProblem.php
1 < ?php
2 $mySqlUser = ”remy” ;
3 $mySqlPassword = ” my_password ” ;
135
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
4 $dataBase = ” ExampleMisSpelledDataBase ” ;
5
6 $dbh = new PDO( ’ mysql :h o s t=l o c a l h o s t ; dbname= ’ . $dataBase , $mySqlUser ,
7 $mySqlPassword ) ;
8
9 $ r e q u e t e = ’INSERT INTO Adresse ( id , numeroRue , rue , complementAddr , ’
10 . ’ c o d e P o s t a l , v i l l e , pays ) ’
11 . ’VALUES (”0 f d a 5 a 8 0 a ” , ”11” , ” A l l é e d e s P i e s Jaunes ” , ’
12 . ’ ”Bâ t i m e n t 2D” , ”63000” , ” Clermont−Ferrand ” , ” France ” ) ’ ;
13 $dbh−>query ( $ r e q u e t e ) ;
14
15 // Code de l a vue :
16 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
17 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ”Ma Première Connexion PDO” ,
18 ’UTF−8 ’ , ’ m y S t y l e . c s s ’ ) ;
19 // Code de l a vue :
20 foreach ( $dbh−>query ( ’SELECT * from Adresse ’ ) a s $row ) {
21 print_r ( $row ) ;
22 }
23 $dbh = n u l l ;
24 echo CoursPHP\Vue\ VueHtmlUtils : :ichierHTML5 ( ) ;
25 ?>
Dans les exemples des deux parties suivantes, nous incluerons (par un require) le fichier
suivant qui réalisera la connexion à la base de données :
Code Source 8.4 : exemples/pdo/ex03_connectToDatabasePDO.php
1 < ?php
2 $mySqlUser = ”remy” ;
3 $mySqlPassword = ” my_password ” ;
4 $dataBase = ”ExempleBD” ;
5
6 // ON DOIT ABSOLUMENT GÉRER CETTE EXCEPTION, FAUTE DE QUOI
7 // L ’UTILISATEUR DE LA BASE DE DONNÉES ET LE MOT DE PASSE
8 // APPARAÎSSENT EN CLAIR ! ! ! !
9 try {
10 // Cré a t i o n de l ’ i n s t a n c e de PDO ( d a t a b a s e h a n d l e r ) .
11 $dbh = new PDO( ’ mysql :h o s t=l o c a l h o s t ; dbname= ’ . $dataBase , $mySqlUser ,
$mySqlPassword ) ;
12 } c a t c h ( PDOException $e ) {
136
Chapitre 8 : Bases de Données et PHP Data Objects
137
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
17
18 echo ”<p>” ;
19 echo ”<s t r o n g >U t i l i s a t i o n comme t a b l e a u a s s o c i a t i f :</s t r o n g >” ;
20 echo ”</p>” ;
21 foreach ( $ s t a t e m e n t a s $row ) {
22 echo ”<p>” ;
23 echo $row [ ’ numeroRue ’ ] . ” , ” . $row [ ’ rue ’ ] . ” , ” ;
24 i f ( !empty( $row [ ’ complementAddr ’ ] ) )
25 echo $row [ ’ complementAddr ’ ] . ” , ” ;
26 echo $row [ ’ c o d e P o s t a l ’ ] . ” ” ;
27 echo $row [ ’ v i l l e ’ ] . ” ” ;
28 echo $row [ ’ pays ’ ] ;
29 echo ”</p>” ;
30 }
31
32 // Connexion non p e r s i s t a n t e : on ferme l a co n n e x i o n
33 // i l f a u t d é t r u i r e t o u s l e s o b j e c t s l i é s à l a co n n e x i o n SANS EN OUBLIER
34 // ( en l e s m e t t a n t à n u l l , pour que l a con n e x i o n s e ferme ) .
35 $statement = n u l l ;
36 $dbh = n u l l ;
37
38 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
39 ?>
Voici un exemple qui récupère les lignes des résultats d’une requête (de type SELECT) sous
une forme soit associative, soit numérique. Les clés du tableau associatif, pour chaque ligne,
sont les noms de colonnes du résultat de la requête. Les clés du tableau numérique, pour chaque
ligne, sont les numéros de colonnes du résultat de la requête (commençant à 0).
Code Source 8.6 : exemples/pdo/ex04_fetchAll_FetchModeBoth.php
1 < ?php
2 // Connexion à l a b a s e de donn é e s :
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / ex03_connectToDatabasePDO . php ’ ) ;
4
5 // S t o c k a g e d e s donn é e s r é s u l t a t de l a r e q u ê t e dans une v a r i a b l e
6 // De t y p e PDOStatement
7 $ s t a t e m e n t = $dbh−>query ( ’SELECT * from Adresse ’ ) ;
8 i f ( $ s t a t e m e n t === f a l s e ) {
9 $ d a t a E r r o r [ ” q u e r y ” ] = ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ”
10 . ” ( par exemple , l a conn exion n ’ e s t pas o u v e r t e ou l a t a b l e n ’ e x i s t e
pas . . . ) ” ;
11 die ( ) ;
12 }
13
14 $statement −>setFetchMode (PDO : :FETCH_BOTH) ;
15
16 // Pour p o u v o i r p a r c o u r i r t r o i s f o i s l e s r é s u l t a t s , on c o p i e ceux−c i
17 // dans un grand t a b l e a u .
18 // Ça p e u t u t i l i s e r beaucoup de mé moire s ’ i l y a beaucoup de l i g n e s . . .
19 $ t a b R e s u l t a t s = $statement −>f e t c h A l l ( ) ;
20
21 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
22 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ” P a r c o u r i r l e s Ré s u l t a t s d ’ une
Requ ê t e ” , ’UTF−8 ’ , ’ myStyle . c s s ’ ) ;
23 echo ”<h1>P a r c o u r i r l e s Ré s u l t a t s d ’ une Requ ê t e ( 2 )</h1>” ;
24 echo ”<p>” ;
138
Chapitre 8 : Bases de Données et PHP Data Objects
139
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
48
49 echo ”<p>” ;
50 echo ”<s t r o n g >U t i l i s a t i o n comme t a b l e a u numé r i q u e :</s t r o n g >” ;
51 echo ”</p>” ;
52 foreach ( $ t a b R e s u l t a t s a s $row ) {
53 echo ”<p>(” ;
54 f o r ( $ i = 1 ; $ i < $statement −>columnCount ( ) ; $ i ++){
55 i f ( $ i >1){
56 echo ” , ” ;
57 }
58 echo $row [ $ i ] ;
59 }
60 echo ” )</p>” ;
61 }
62 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
63
64 // Connexion non p e r s i s t a n t e : on ferme l a co n n e x i o n
65 // i l f a u t d é t r u i r e t o u s l e s o b j e c t s l i é s à l a co n n e x i o n SANS EN OUBLIER
66 // ( en l e s m e t t a n t à n u l l , pour que l a con n e x i o n de ferme .
67 $statement = n u l l ;
68 $dbh = n u l l ;
69 ?>
D’une manière générale, les méthodes fetch (renvoie une seule ligne des résultats d’une
requête) et fetchAll (renvoie toutes les lignes des résultats d’une requête) ont des options sur
la structure des données retournées. Une liste (non exaustive !!!) de ces options est :
• PDO :: FETCH_ASSOC : lignes sous forme d’un tableau associatif indexé par le nom de la
colonne ;
• PDO :: FETCH_BOTH : lignes sous forme d’un tableau à la fois associatif indexé par le nom
de la colonne et numérique indexé par le numéro de la colonne ;
• PDO :: FETCH_OBJ : lignes sous la forme d’objets anonymes dont les propriétés sont les
noms de la colonne ;
1. On indique à PDO la requête SQL, sauf que les valeurs (attributs des tables...) ne sont
pas précisées (ce sont des ?).
2. Cela permet déjà à PDO d’analyser une fois pour toute la requête, même si on doit
exécuter la requête plusieurs fois avec des valeurs différentes. C’est ce qu’on appelle
préparer la requête. Cela améliore généralement l’efficacité, réduisant la charge du serveur
et les délais d’exécution des requêtes.
140
Chapitre 8 : Bases de Données et PHP Data Objects
requête. Ces valeurs, qui peuvent correspondre à des inputs utilisateur, sont
automatiquement filtrée, évitant tout risque d’injection SQL.
Le mécanisme des requêtes préparées repose sur un lien effectué (avec la méthode bindParam)
entre une variable PHP (donnée par sa référence), et une valeur non fixée (?) dans la requête.
Il peut y avoir plusieurs syntaxes pour les requêtes préparées.
Les valeurs saisies par l’utilisateur seront récupérées du tableau $_POST dans un fichier PHP,
qui sera inclus par un require juste avant d’exécuter la requête de type INSERT :
141
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
1. La préparation de la requête de type INSERT (avec des ”?” à la place des attributs de
l’adresse) ;
2. Définit (avec bindValue) le lien entre les ”?” et des variables PHP ;
142
Chapitre 8 : Bases de Données et PHP Data Objects
15 . ” ( par exemple , l a s y n t a x e de l a r e q u ê t e e s t i n v a l i d e ”
16 . ” pour l e d r i v e r u t i l i s é . . . ) ” ;
17 } else {
18 // L i a i s o n de v a r i a b l e s a v e c l e s ” ?” de l a r e q u ê t e pr é par é e :
19 // Le prem ie r paramètre de bindParam e s t i c i l e numé ro du ” ?”
20 // en commenç ant par 1 .
21 // Lors de l ’ ex é c u t i o n de l a r e q u ê t e , chaque ” ?” s e r a remplac é par
22 // l e contenu de l a v a r i a b l e c o r r e s p o n d a n t e .
23 $statement −>bindParam ( 1 , $ i d ) ;
24 $statement −>bindParam ( 2 , $numeroRue ) ;
25 $statement −>bindParam ( 3 , $ r u e ) ;
26 $statement −>bindParam ( 4 , $complementAddr ) ;
27 $statement −>bindParam ( 5 , $ c o d e P o s t a l ) ;
28 $statement −>bindParam ( 6 , $ v i l l e ) ;
29 $statement −>bindParam ( 7 , $pays ) ;
30
31 // Ré cup é r a t i o n d e s donn é e s du f o r m u l a i r e s e t a f f e c t a t i o n d e s v a r i a b l e s
32 // $numeroRue , $rue , $complementAddr , $ c o d e P o s t a l , $ v i l l e , $pays
33 // à p a r t i r d e s donn é e s u t i l i s a t e u r ( t a b l e a u $_POST)
34 require ( dirname (__FILE__) . ’ / e x 0 6 _ r e t r i e v e I n p u t P o s t s . php ’ ) ;
35
36 // Géné r a t i o n d ’ un $ i d d i f f i c i l e à d e v i n e r .
37 $ i d = hash ( ” sha512 ” , $numeroRue . $ r u e . $complementAddr . $ c o d e P o s t a l . $ v i l l e .
$pays ) ;
38 $ i d = substr ( $id , 0 , 1 0 ) ; // r e s p e c t de l a forme d e s ID (10 c h i f f r e s hexa )
39
40 // Exé c u t i o n de l a r e q u ê t e . ( Tous l e s ” ?” de l a r e q u ê t e ont é t é l i é s à d e s
variables )
41 i f ( $statement −>e x e c u t e ( ) === f a l s e ) {
42 $ d a t a E r r o r [ ” e x e c u t e −q u e r y ” ] = ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ”
43 . ” ( par exemple , une l i g n e a v e c c e t t e c l é p r i m a i r e $ i d e x i s t e d é j à . . . )
”;
44 }
45 }
46
47 // Appel de l a vue ( ou vue d ’ e r r e u r )
48 i f ( !empty( $ d a t a E r r o r ) ) {
49 require ( ” v u eEr r e ur . php ” ) ;
50 } e l s e { // Code de l a vue :
51 require ( ” vueNormale . php ” ) ;
52 }
53 // Fermeture de l a c o nnex ion ( co n n exio n non p e r s i s t a n t e )
54 $statement = n u l l ;
55 $dbh = n u l l ;
56 ?>
Voici un autre exemple de requête préparée, avec une requête de type SELECT.
143
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
8
9 // Test en s u p p o s a n t l e mode de g e s t i o n d e s e r r e u r s PDO : :ERRMODE_SILENT
10 // ( sinon , en mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r t r y . . . c a t c h )
11 i f ( $ s t a t e m e n t === f a l s e ) {
12 $ d a t a E r r o r [ ’ p r e p a r a t i o n −q u e r y ’ ] = ” Problème de pr é p a r a t i o n de l a r e q u ê t e . ”
13 . ” ( par exemple , l a s y n t a x e de l a r e q u ê t e e s t i n v a l i d e ”
14 . ” pour l e d r i v e r u t i l i s é . . . ) ” ;
15 } else {
16 // L i a i s o n de l a v a r i a b l e $_GET[ ’ c o d e P o s t a l ’ ] a v e c l e ” ?” de l a r e q u ê t e :
17 // Le prem ie r paramètre de bindParam e s t i c i l e numé ro du ” ?” , à s a v o i r 1
18 $statement −>bindParam ( 1 , $_GET[ ’ c o d e P o s t a l ’ ] ) ;
19 // Test d ’ e r r e u r en s u p p o s a n t l e mode de g e s t i o n d e s e r r e u r s PDO : :
ERRMODE_SILENT
20 // ( sinon , a v e c l e mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r a v e c t r y
. . . catch )
21 i f ( $statement −>e x e c u t e ( ) === f a l s e ) { // Code de l a vue :
22 $ d a t a E r r o r [ ” e x e c u t e −q u e r y ” ] = ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ;
23 }
24 }
25
26 // Appel de l a vue ( ou vue d ’ e r r e u r )
27 i f ( !empty( $ d a t a E r r o r ) ) {
28 require ( ” v u eEr r e ur . php ” ) ;
29 } e l s e { // Code de l a vue :
30
31 r e q u i r e _ o n c e ( ’ c l a s s e s / VueHtmlUtils . php ’ ) ;
32 echo CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ”Requ ê t e s Pr é par é e s ” ,
33 ’UTF−8 ’ , ’ m y S t y l e . c s s ’ ) ;
34 echo ”<h1>Requ ê t e s Pr é par é e s ( 2 ) ( Donnez un Code P o s t a l )</h1>” ;
35 // A f f i c h a g e d e s r é s u l t a t s de l a r e q u ê t e
36 foreach ( $ s t a t e m e n t a s $row ) {
37 echo ”<p>” ;
38 echo $row [ ’ numeroRue ’ ] . ” , ” . $row [ ’ rue ’ ] . ” , ” ;
39 i f ( !empty( $row [ ’ complementAddr ’ ] ) )
40 echo $row [ ’ complementAddr ’ ] . ” , ” ;
41 echo $row [ ’ c o d e P o s t a l ’ ] . ” ” ;
42 echo $row [ ’ v i l l e ’ ] . ” ” ;
43 echo $row [ ’ pays ’ ] ;
44 echo ”</p>” ;
45 }
46 echo CoursPHP\Vue\ VueHtmlUtils : :finFichierHTML5 ( ) ;
47 }
48 // Fermeture de l a c o nnex ion ( co n n exio n non p e r s i s t a n t e )
49 $statement = n u l l ;
50 $dbh = n u l l ;
51 ?>
144
Chapitre 8 : Bases de Données et PHP Data Objects
145
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
L’un des avantages de la syntaxe avec des :name est de permettre une automatisation aisée
de la préparation et de l’exécution de la requête à partir d’un tableau associatif contenant les
valeurs. Dans l’exemple suivant le tableau associatif contient les attributs d’une Adresse. On
pourrait aussi lier et exécuter automatiquement la requête à partir d’un tableau $_REQUEST
directement issu d’un formulaire.
Code Source 8.12 : exemples/pdo/ex10_requetesPrepareesV3.php
1 < ?php
2 // Connexion à l a b a s e de donn é e s
3 r e q u i r e _ o n c e ( dirname (__FILE__) . ’ / ex03_connectToDatabasePDO . php ’ ) ;
4
5 // La r e q u ê t e à pr é p a r e r a v e c d e s ” : q u e l q u e C h o s e ” à l a p l a c e d e s v a l e u r s
6 $ r e q u e t e = ’REPLACE INTO Adresse ( i d A d r e s s e , numeroRue , rue , ’
7 . ’ complementAddr , c o d e P o s t a l , v i l l e , pays ) ’
8 . ’VALUES ( : i d A d r e s s e , :numeroRue , :rue , ’
9 . ’ :complementAddr , :c o d e P o s t a l , : v i l l e , :pays ) ’ ;
10
11 // Pr é p a r a t i o n de l a r e q u ê t e ( cha î ne r e p r é s e n t a n t une r e q u ê t e SQL
12 // s a u f que l e s v a l e u r s à i n s é r e r dont d e s ?)
13 $ s t a t e m e n t = $dbh−>p r e p a r e ( $ r e q u e t e ) ;
14
15 // Test en s u p p o s a n t l e mode de g e s t i o n d ’ e r r e u r s PDO : :ERRMODE_SILENT
16 // ( sinon , en mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r t r y . . . c a t c h )
17 i f ( $ s t a t e m e n t === f a l s e ) {
18 $ d a t a E r r o r [ ’ p r e p a r a t i o n −q u e r y ’ ] = ” Problème de pr é p a r a t i o n de l a r e q u ê t e . ” ;
19 } else {
20 // Cré a t i o n d ’ un t a b l e a u a s s o c i a t i f a v e c l e s v a l e u r s :
21 $i n p ut Arra y = array (
22 ” i d A d r e s s e ” => ” 9876543211 ” ,
23 ”numeroRue” => ”2 Ter ” ,
24 ” rue ” => ”Rue de l a Sé r é n i t é ” ,
25 ” complementAddr ” => ”Compl é ment u t i l e ” ,
26 ” c o d e P o s t a l ” => ” 63001 ” ,
27 ” v i l l e ” => ” Clermont−Ferrand ” ,
28 ” pays ” => ” France ” ) ;
29 // L i a i s o n de v a r i a b l e s ” : q u e l q u e C h o s e ” de l a r e q u ê t e pr é par é e :
30 // Lors de l ’ ex é c u t i o n de l a r e q u ê t e , chaque ” : q u e l q u e C h o s e ” s e r a remplac é
par
31 // l e contenu de l a v a r i a b l e c o r r e s p o n d a n t e $ i n p u t A r r a y [ ” q u e l q u e C h o s e ” ] .
32
33 // 1) On r e c h e r c h e dans l a r e q u e t e l e s cha î nes de l a forme ” : q u e l q u e C h o s e ”
34 preg_match_all ( ” /\ :[ a−zA−Z ] [ a−zA−Z0−9]+/” , $ r e q u e t e ,
35 $ k e y C o l l e c t i o n , PREG_PATTERN_ORDER) ;
36 // On p a r c o u r s l e s arguments de l a r e q u ê t e
37 foreach ( $ k e y C o l l e c t i o n [ 0 ] a s $key ) {
38 $ a s s o c i a t i v e K e y = substr ( $key , 1 ) ; // c l é dans l e t a b l e a u $ a r g s
39 $statement −>bindParam ( $key , $ in pu tA rra y [ $ a s s o c i a t i v e K e y ] ) ;
40 }
41
42 // Exé c u t i o n de l a r e q u ê t e .
43 // ( Tous l e s ” : q u e l q u e C h o s e ” de l a r e q u ê t e ont é t é l i é s à d e s v a r i a b l e s )
146
Chapitre 8 : Bases de Données et PHP Data Objects
147
Chapitre 9
Auth
SessionUtils
AuthUtils
+ createSession(email : string, role : string=”visitor”) : void
+ isStrongPassword(wouldBePassword : string) : boolean
+ generateSessionId() : string
Persistance Metier
«POPO»
AdresseGateway
Adresse
+ getAdresseById(inOut dataError : string 0..*,
idAdresse : string) : Adresse {throws Exception}
+ getAdresseAll(inOut dataError : string 0..*) : Adresse 0..* {throws Exception}
uses
«Singleton»
DataBaseManager dbh PDO
- instance : DataBaseManager
1
148
Chapitre 9 : Couche d’Accès aux données (DAL)
149
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
.
user :Script instance :DataBaseManager dbh :PDO
request
testPreparedQuery()
prepareAndExecuteQuery(requete, args)
opt create
e :Exception
[requête mal préparée]
prepare()
create
statement statement :PDOStatement
opt
false
[statement===false]
try
loop
bindParam(index++, P)
[Critical Region]
[for P in args]
execute()
try
fetchAll()
[Critical Region]
results
requête
requête INSERT
INSERT
closeCursor()
results
150
Chapitre 9 : Couche d’Accès aux données (DAL)
16
17 /* * @ b r i e f C o n s t r u c t e u r q u i c r é e une i n s t a n c e de PDO a v e c donn é e s UTF8
18 * Le c o n s t r u c t e u r e s t p r i v é : En s emb l eCl ass ne p e u t c r é e r d e s i n s t a n c e s
19 * c a r dans l e s i n g l e t o n i l ne d o i t y a v o i r qu ’ une s e u l e i n s t a n c e .
20 * Ré c u p è r e l e s e x c e p t i o n PDO e t é t a b l i t l e mode d ’ e r r e u r ”EXCEPTION” .
21 * @throw s e x c e p t i o n p e r s o n n a l i s é e en c a s d ’ e x c e p t i o n PDO */
22 private function __construct ( ) {
23 try {
24 \CoursPHP\ C o n f i g \ C o n f i g : :getAuthData ( $db_host , $db_name , $db_use r ,
$db_password ) ;
25 // Cré a t i o n de l ’ i n s t a n c e de PDO ( d a t a b a s e h a n d l e r ) .
26 $ t h i s −>dbh = new \PDO( $db_host . $db_name , $db_use r , $db_password ) ;
27 // Rendre l e s e r r e u r s PDO d é t e c t a b l e s e t g é r a b l e s par e x c e p t i o n s :
28 $ t h i s −>dbh−>s e t A t t r i b u t e ( \PDO : :ATTR_ERRMODE, \PDO : :ERRMODE_EXCEPTION) ;
29 $ t h i s −>dbh−>s e t A t t r i b u t e ( \PDO : :MYSQL_ATTR_INIT_COMMAND, ’SET NAMES UTF8 ’ ) ;
30 } c a t c h ( \ PDOException $e ) {
31 throw new \ E x c e p t i o n ( ”Dé s o l é , une e r r e u r s ’ e s t p r o d u i t e . S i l e p r o b l è m e
p e r s i s t e , merci de l e s i g n a l e r à Rémy . ” ) ;
32 }
33 }
34
35 /* * @ b r i e f Mé t h o d e s t a t i q u e p u b l i q u e d ’ a c c è s à l ’ u n i q u e i n s t a n c e .
36 * S i l ’ i n s t a n c e n ’ e x i s t e pas , e l l e e s t c r é e . On r e t o u r n e l ’ u n i q u e i n s t a n c e */
37 public s t a t i c function g e t I n s t a n c e ( )
38 {
39 i f ( n u l l === s e l f : : $ i n s t a n c e ) {
40 s e l f : : $ i n s t a n c e = new s e l f ;
41 }
42 return s e l f : : $ i n s t a n c e ;
43 }
44
45 /* * @ b r i e f Pr é pa re e t ex é c u t e une r e q u ê t e .
46 * @param $ r e q u e t e r e q u ê t e a v e c d e s ?
47 * @param $ a r g s arguments à l i e r ( b i n d e r ) aux ? dans l a r e q u ê t e
48 * Passage par r é f é r e n c e pour é v i t e r une r e c o p i e .
49 * @return f a l s e s i l a r e q u ê t e é choue ,
50 * t r u e s i s u c c è s ET r e q u ê t e d i f f é r e n t e de SELECT,
51 * ou r é s u l t a t s du SELECT dans un a r r a y à d o u b l e e n t r é e PHP s t a n d a r d
52 * @throw s e x c e p t i o n p e r s o n n a l i s é e en c a s d ’ e x c e p t i o n PDO */
53 public function prepareAndExecuteQuery ( $ r e q u e t e , &$ a r g s = n u l l ) {
54 i f ( $ a r g s === n u l l ) {
55 $ a r g s = array ( ) ;
56 }
57 // r é cup é r a t i o n du nombre d ’ arguments :
58 $numargs = count ( $ a r g s ) ;
59 // Une r e q u ê t e pr é par é e ne d o i t pas c o n t e n i r de g u i l l e m e t s ! ! !
60 i f (empty( $ r e q u e t e ) | | ! is_string ( $ r e q u e t e ) | |
61 preg_match( ’ / ( \ ” | \ ’ ) +/ ’ , $ r e q u e t e ) !== 0 ) {
62 throw new \ E x c e p t i o n ( ” Erreur c o n c e r n a n t l a s é c u r i t é . ”
63 . ”Requ ê t e i n c o m p l è t e m e n t pr é par é e . ” ) ;
64 }
65 // On ne l a i s s e pas remonter d ’ e x c e p t i o n s PDO
66 try {
67 // Pr é p a r a t i o n de l a r e q u ê t e
68 $ s t a t e m e n t = $ t h i s −>dbh−>p r e p a r e ( $ r e q u e t e ) ;
69 i f ( $ s t a t e m e n t !== f a l s e ) {
151
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
152
Chapitre 9 : Couche d’Accès aux données (DAL)
Voici une utilisation de cette classe de gestion de la base de données, avec une requête qui
affiche les adresses dont le code postal est passé par la méthode GET.
153
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
8
9 $tableName = \CoursPHP\ C o n f i g \ C o n f i g : : g e t T a b l e s P r e f i x ( ) . ’ Adresse ’ ;
10 // Requ ê t e a v e c d e s ? (mé t h o d e prepareAndExecuteQuery )
11 $ q u e r y R e s u l t s = CoursPHP\ P e r s i s t a n c e \ DataBaseManager
12 : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
13 ’SELECT * FROM ’ . $tableName
14 . ’ WHERE c o d e P o s t a l = ? ’ ,
15 $ a r g s // v a l e u r s
16 );
17 } c a t c h ( E x c e p t i o n $e ) {
18 $ d a t a E r r o r [ ] = $e−>getMessage ( ) ;
19 require ( ” v u eEr r e ur . php ” ) ;
20 }
21
22 i f ( $ q u e r y R e s u l t s === f a l s e ) {
23 // Erreur l o r s de l ’ ex é c u t i o n de l a r e q u ê t e
24 $ d a t a E r r o r [ ] = ” Problème l o r s de l a pr é p a r a t i o n de l a r e q u ê t e . ”
25 . ” ( par exemple , l a donn é e c o d e P o s t a l p a s s é e par GET e s t i n v a l i d e . . . ) ” ;
26 require ( ” v u eEr r e ur . php ” ) ;
27 } else {
28 // Code de l a vue :
29 require ( ” vueTestSingletonPDO . php ” ) ;
30 }
31 ?>
154
Chapitre 9 : Couche d’Accès aux données (DAL)
1. Les principales opérations implémentées dans une classe Gateway sont les opérations dite
CRUD, c’est à dire :
155
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
2. Dans l’implémentation ci-dessous, pour la création d’une nouvelle instance, nous propo-
sons une recette de cuisine pour la génération de l’id unique de l’adresse. Signalons que
cette technique ne passe pas à l’échelle, notamment pour une utilisation dans le cadre de
Web Services. Dans ce cas, des techniques robustes, appelées Universal Unique Identifier
(UUID) peuvent être utilisées, et des implémentations en PHP existent, par exemple
dans la fonction uniqid du langage.
3. Dans le cas de classes métiers comportant (par exemple) une agrégation (voir partie 2.2.2),
la Gateway de l’agrégat comportera généralement des méthodes permettant d’effectuer
des résultats de jointures entre les tables correspondantes (voir la partie 9.3.2 pour une
classe Gateway avec jointure et la partie 13.5 pour une exemple d’application comportant
une agrégation/jointure).
156
user :Script ag :AdresseGateway instance :DataBaseManager af :AdresseFabrique
request
create
dataError :array
try
« static » getAdresseById(InOut dataError, id)
[Critical Region] prepareAndExecuteQuery(query, args)
queryResults
alt
« static » getValidInstance(Out dataErrorsAttrib, queryResults[0])
[count(queryResults)===1]
157
Chapitre 9 : Couche d’Accès aux données (DAL)
adresse
merge(dataErrorsAttrib)
adresse
AdresseGateway::getAdresseById()
push(e ->getMessage())
[catch (Exception e)]
39 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e
40 : : g e t V a l i d I n s t a n c e ( $ d a t a E r r o r A t t r i b u t e s , $row ) ;
41 $ d a t a E r r o r = array_merge ( $d a ta E rro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
42 } else {
43 throw new \ E x c e p t i o n ( ” Adresse d ’ ID \” ” . $ i d A d r e s s e . ” \” i n t r o u v a b l e . ” ) ;
44 }
45 } else {
46 throw new \ E x c e p t i o n ( ” I m p o s s i b l e d ’ acc é d e r aux donn é e s . ” ) ;
47 }
48 } else {
49 throw new \ E x c e p t i o n ( ” Adresse d ’ ID \” ” . $ i d A d r e s s e . ” \” i n t r o u v a b l e . ” ) ;
50 }
51 return $ a d r e s s e ;
52 }
53
54 /* * Permet de r é cup é r e r une c o l l e c t i o n d ’ a d r e s s e s pr é s e n t e s dans l a t a b l e .
55 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
56 * @return c o l l e c t i o n d ’ A d r e s s e s en c a s de s u c c è s , c o l l e c t i o n v i d e s i n o n .
57 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
58 public s t a t i c function g e t A d r e s s e A l l (& $ d a t a E r r o r ) {
59 // Exé c u t i o n de l a r e q u ê t e v i a l a c l a s s e de c o n n e x i o n ( s i n g l e t o n )
60 // Les e x c e p t i o n s é v e n t u e l l e s , p e r s o n n a l i s é es , s o n t g é r é e s p l u s h a u t
61 $ a r g s=array ( ) ;
62 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
63 ’SELECT * FROM ’ . s e l f : :getTableNameAdresse ( ) ,
64 $args ) ;
65
66 // C o n s t r u c t i o n de l a c o l l e c t i o n d e s r é s u l t a t s ( f a b r i q u e )
67 $ c o l l e c t i o n A d r e s s e = array ( ) ;
68 // S i l ’ ex é c u t i o n de l a r e q u ê t e a f o n c t i o n n é
69 i f ( $ q u e r y R e s u l t s !== f a l s e ) {
70 // Parcours d e s l i g n e s du r é s u l t a t de l a r e q u ê t e :
71 foreach ( $ q u e r y R e s u l t s a s $row ) {
72 // Ajout d ’ une a d r e s s e dans l a c o l l e c t i o n :
73 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e
74 : : g e t V a l i d I n s t a n c e ( $ d a t a E r r o r A t t r i b u t e s , $row ) ;
75 $collectionAdresse [ ] = $adresse ;
76 $ d a t a E r r o r = array_merge ( $ da ta E rro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
77 }
78 } else {
79 throw new \ E x c e p t i o n ( ” Problème d ’ a c c è s aux donn é e s . ” ) ;
80 }
81
82 return $ c o l l e c t i o n A d r e s s e ;
83 }
84
85 /* * @ b r i e f Met à j o u r une a d r e s s e ( Update )
86 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
87 * @param $ i n p u t A r r a y t a b l e a u a s s o c i a t i f dont l e s c l e f s c o r r e s p o n d e n t aux
nom_contact_sportsClubs
88 * d e s a t t r i b u t s d ’ Adresse
89 * @return l ’ i n s t a n c e d ’ Adresse ( e r r e u r s ET i n s t a n c e de l ’ a d r e s s e m o d i f i é e )
90 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
91 public s t a t i c function u p d a t e A d r e s s e (& $ d at a Er r or , &$ i n p u t A r r a y ) {
92 // T e n t a t i v e de c o n s t r u c t i o n d ’ une i n s t a n c e ( e t f i l t r a g e )
93 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e
158
Chapitre 9 : Couche d’Accès aux données (DAL)
94 : :g e t V a l i d I n s t a n c e ( $dataErrorAttributes , $inputArray ) ;
95 // S i l a forme d e s a t t r i b u t s s o n t c o r r e c t s ( e x p r e s s i o n s r é g u l i è r e s )
96 i f (empty( $ d a t a E r r o r A t t r i b u t e s ) ) {
97 // Exé c u s s i o n de l a r e q u ê t e de mis à j o u r :
98 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>
prepareAndExecuteQueryAssoc (
99 ’UPDATE ’ . s e l f : :getTableNameAdresse ( )
100 . ’ SET i d P e r s o n n e= :idPersonne , ’
101 . ’ numeroRue= :numeroRue , rue= :rue , ’
102 . ’ complementAddr= :complementAddr , c o d e P o s t a l= :
codePostal , ’
103 . ’ v i l l e = : v i l l e , pays= :pays WHERE i d A d r e s s e= :i d A d r e s s e ’
,
104 $in putA rra y
105 );
106 i f ( $ q u e r y R e s u l t s === f a l s e ) {
107 throw new \ E x c e p t i o n ( ” Problème d ’ a c c è s aux donn é e s . ” ) ;
108 }
109 } else {
110 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
111 }
112 return $ a d r e s s e ;
113 }
114
115 /* * @ b r i e f I n s è r e une n o u v e l l e a d r e s s e ( C r ea t e )
116 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
117 * @param $ i n p u t A r r a y t a b l e a u a s s o c i a t i f dont l e s c l e f s c o r r e s p o n d e n t aux
nom_contact_sportsClubs
118 * d e s a t t r i b u t s d ’ Adresse
119 * @return l ’ i n s t a n c e d ’ Adresse ( e r r e u r s ET i n s t a n c e de l ’ a d r e s s e c r é é e )
120 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
121 public s t a t i c function c r e a t e A d r e s s e (& $ da ta E r ro r , &$ i n p u t A r r a y ) {
122 // T e n t a t i v e de c o n s t r u c t i o n d ’ une i n s t a n c e ( e t f i l t r a g e )
123 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e
124 : :g e t V a l i d I n s t a n c e ( $dataErrorAttributes , $inputArray ) ;
125 // S i l a forme d e s a t t r i b u t s s o n t c o r r e c t s ( e x p r e s s i o n s r é g u l i è r e s )
126 i f (empty( $ d a t a E r r o r A t t r i b u t e s ) ) {
127 // Exé c u s s i o n de l a r e q u ê t e d ’ i n s e r t i o n :
128 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>
prepareAndExecuteQueryAssoc (
129 ’REPLACE INTO ’ . s e l f : :getTableNameAdresse ( )
130 . ’ ( i d A d r e s s e , idPersonne , numeroRue , rue , ’
131 . ’ complementAddr , c o d e P o s t a l , v i l l e , pays ) ’
132 . ’VALUES ( : i d A d r e s s e , :idPersonne , :numeroRue , :rue ,
’
133 . ’ :complementAddr , :c o d e P o s t a l , : v i l l e , :pays ) ’ ,
134 $inp utA r ra y
135 );
136 i f ( $ q u e r y R e s u l t s === f a l s e ) {
137 throw new \ E x c e p t i o n ( ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ) ;
138 }
139 } else {
140 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
141 }
142 $ a d r e s s e −>i d A d r e s s e = $in putA rra y [ ’ i d A d r e s s e ’ ] ; // pour v a l e u r r e t o u r n é e
143 return $ a d r e s s e ;
159
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
144 }
145
146 /* * @ b r i e f Supprime une a d r e s s e à p a r t i r de son ID .
147 * Retourne l e modèle de donn é e s ( e r r e u r s ET i n s t a n c e de l ’ Adresse supprim é e )
148 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
149 * @param $ i d A d r e s s e : c l é p r i m a i r e de l ’ a d r e s s e à r é cup é r e r
150 * @return i n s t a n c e d ’ Adresse en c a s de s u c c è s , u n d e f i n e d s i n o n .
151 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
152 public s t a t i c function d e l e t e A d r e s s e (& $ da ta E r ro r , $ i d A d r e s s e ) {
153 // Test s i l ’ a d r e s s e e x i s t e e t r é cup é r a t i o n s donn é e s à s u p p r i m e r
154 $ d a t a E r r o r I d S e a r c h = array ( ) ;
155 $ a d r e s s e = s e l f : :g e t A d r e s s e B y I d ( $ d a t a E r r o r I d S e a r c h , $ i d A d r e s s e ) ;
156
157 i f (empty( $ d a t a E r r o r I d S e a r c h ) ) {
158 // Exé c u t i o n de l a r e q u ê t e v i a l a c l a s s e de co n n e x i o n ( s i n g l e t o n )
159 // Les e x c e p t i o n s é v e n t u e l l e s s o n t g é r é e s par l e C o n t r o l e u r
160 $ a r g s=array ( $ i d A d r e s s e ) ;
161 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
162 ’DELETE FROM ’ . s e l f : :getTableNameAdresse ( )
163 . ’ WHERE i d A d r e s s e=? ’ , $ a r g s
164 );
165 i f ( $ q u e r y R e s u l t s === f a l s e ) {
166 throw new \ E x c e p t i o n ( ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ) ;
167 }
168 } else {
169 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r I d S e a r c h ) ; // f u s i o n
170 }
171 return $ a d r e s s e ;
172 }
173 }
174 ?>
Voici un script de test des fonctionnalités (et gestion des erreurs) de la classe Gateway :
160
Chapitre 9 : Couche d’Accès aux données (DAL)
22 // ID de l a Personne ” personneCreee1 ” ( d o i t ê t r e pr é a l a b l e m e n t c r é é e )
23 $ i d P e r s o n n e 1 = ” 165 d f e 8 7 9 0 ” ;
24 try {
25 // Cré a t i o n de l a Personne
26 $ a r g s P e r s o n n e = array ( ” i d P e r s o n n e ” => $ id Pe r s o n n e 1 ,
27 ”nom” => ” personneCreee1 − T i t i l e t o u t p ’ t i t ” ) ;
28 $ p e r s o n n e C r e e e 1 = CoursPHP\ P e r s i s t a n c e \ PersonneGateway : : c r e a t e P e r s o n n e (
29 $ d at a E r r or , $ a r g s P e r s o n n e ) ;
30 // Test 1 de c r é a t i o n d ’ une a d r e s s e pour c e t t e Personne
31 $ a r g s A d r e s s e = array ( ” i d A d r e s s e ” => $ i d A d r e s s e 1 ,
32 ” i d P e r s o n n e ” => $idP e r s o n n e 1 ,
33 ”numeroRue” => ”1 ” ,
34 ” rue ” => ” B o u l e v a r d d e s E n t i e r s Longs ” ,
35 ” complementAddr ” =>” a d r e s s e C r e e e 1 ” ,
36 ” c o d e P o s t a l ” => ” 63000 ” ,
37 ” v i l l e ” => ” Clermont−Ferrand ” ,
38 ” pays ” => ” France ” ) ;
39 $ a d r e s s e C r e e e 1 = CoursPHP\ P e r s i s t a n c e \ AdresseGateway : : c r e a t e A d r e s s e (
161
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
40 $ d at a E r r or , $ a r g s A d r e s s e ) ;
41 } c a t c h ( E x c e p t i o n $e ) {
42 $ d a t a E r r o r [ ] = ” a d r e s s e C r e e e 1 : ” . $e−>getMessage ( ) ;
43 }
44 // Cré a t i o n d ’ une Adresse 2
45 $ i d A d r e s s e 2 = ” 165 d f e 1 2 5 4 ” ;
46 try {
47 // Test 2 de c r é a t i o n d ’ une a d r e s s e
48 $ a r g s A d r e s s e = array ( ” i d A d r e s s e ” => $ i d A d r e s s e 2 ,
49 ” i d P e r s o n n e ” => $idP e r s o n n e 1 ,
50 ”numeroRue” => ”2 ” ,
51 ” rue ” => ” B o u l e v a r d d e s F l o t t a n t s F l o u s ” ,
52 ” complementAddr ” =>” a d r e s s e C r e e e 2 ” ,
53 ” c o d e P o s t a l ” => ” 63000 ” ,
54 ” v i l l e ” => ” C l a i r mon Fernand ” ,
55 ” pays ” => ” France ” ) ;
56 $ a d r e s s e C r e e e 2 = CoursPHP\ P e r s i s t a n c e \ AdresseGateway : : c r e a t e A d r e s s e (
57 $ d at a E r r or , $ a r g s A d r e s s e ) ;
58 } c a t c h ( E x c e p t i o n $e ) {
59 $ d a t a E r r o r [ ] = ” a d r e s s e C r e e e 2 : ” . $e−>getMessage ( ) ;
60 }
61 // Cré a t i o n d ’ une a d r e s s e a v e c un e r r e u r s u r l ’ a t t r i b u t ”nom”
62 try {
63 $ a r g s A d r e s s e = array ( ” i d A d r e s s e ” => ” 165 d f e 1 3 4 2 ” ,
64 ” i d P e r s o n n e ” => $idP e r s o n n e 1 ,
65 ”numeroRue” => ”2@” ,
66 ” rue ” => ” B o u l e v a r d d e s F l o t t a n t s Fou@reux ” ,
67 ” complementAddr ” =>” @dresseCreee ” ,
68 ” c o d e P o s t a l ” => ” 6300000 ” ,
69 ” v i l l e ” => ” P@ris ” ,
70 ” pays ” => ” Un@ited Condom” ) ;
71 $ a d r e s s e C r e e e B u g g y = CoursPHP\ P e r s i s t a n c e \ AdresseGateway
72 : : c r e a t e A d r e s s e ( $ d at a E r r or , $ a r g s A d r e s s e ) ;
73 } c a t c h ( E x c e p t i o n $e ) {
74 $dataError [ ] = ” a d r e s s e C r e e e B u g g y : ” . $e−>getMessage ( ) ;
75 }
76 // Mise à j o u r d ’ une a d r e s s e
77 try {
78 $ a r g s A d r e s s e = array ( ” i d A d r e s s e ” => $ i d A d r e s s e 2 ,
79 ” i d P e r s o n n e ” => $idP e r s o n n e 1 ,
80 ”numeroRue” => ”2 ” ,
81 ” rue ” => ” B o u l e v a r d d e s P a r q u e t s F l o t t a n t s ” ,
82 ” complementAddr ” =>” a d r e s s e C r e e e 2 m o d i f i é e ” ,
83 ” c o d e P o s t a l ” => ” 63210 ” ,
84 ” v i l l e ” => ” C l a i r mon Fernand ” ,
85 ” pays ” => ” France ” ) ;
86 $ a d r e s s e M o d i f i e e 2 = CoursPHP\ P e r s i s t a n c e \ AdresseGateway
87 : :u p d a t e A d r e s s e ( $ d at a E r r or , $ a r g s A d r e s s e ) ;
88 } c a t c h ( E x c e p t i o n $e ) {
89 $ d a t a E r r o r [ ] = ” a d r e s s e M o d i f i e e 2 : ” . $e−>getMessage ( ) ;
90 }
91 // Mise à j o u r d ’ une a d r e s s e a v e c un e r r e u r s u r l e s a t t r i b u t s
92 try {
93 $ a r g s A d r e s s e = array ( ” i d A d r e s s e ” => $ i d A d r e s s e 2 ,
94 ” i d P e r s o n n e ” => $ i dP e r s o n n e 1 ,
95 ”numeroRue” => ”2@” ,
162
Chapitre 9 : Couche d’Accès aux données (DAL)
163
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
164
Chapitre 9 : Couche d’Accès aux données (DAL)
20
21 /* * Permet de r é cup é r e r une pe rs o n n e à p a r t i r de son ID .
22 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
23 * @param $ i d P e r s o n n e : c l é p r i m a i r e de l a p e r s o n n e à r é cup é r e r
24 * @return i n s t a n c e de Personne ( a v e c s e s a d r e s s e s ) en c a s de s u c c è s .
25 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
26 public s t a t i c function getPersonneById (& $ dat a E r r or , $ i d P e r s o n n e ) {
27 i f ( isset ( $idPersonne ) ) {
28 $currentPersonne = null ;
29 $ a r g s=array ( $ i d P e r s o n n e ) ;
30 // J o i n t u r e pour r é cup é r e r l e s Adresse
31 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
32 ’SELECT * FROM ’ . s e l f : :getTableNamePersonne ( )
33 . ’ NATURAL LEFT JOIN ’ . AdresseGateway : :getTableNameAdresse ( )
34 . ’ WHERE ’ . s e l f : :getTableNamePersonne ( ) . ’ . i d P e r s o n n e=? ’ ,
35 $args ) ;
36 // S i l ’ ex é c u t i o n de l a r e q u ê t e a f o n c t i o n n é e t i l y a un r é s u l t a t
37 i f ( i s s e t ( $ q u e r y R e s u l t s ) && is_array ( $ q u e r y R e s u l t s )
38 && count ( $ q u e r y R e s u l t s ) >= 1
39 ) {
40 $ c o l l e c t i o n P e r s o n n e = array ( ) ;
41 // Pour chaque l i g n e
42 foreach ( $ q u e r y R e s u l t s a s $row ) {
43 // S i on e s t p a s s é à l a pe rs o n n e s u i v a n t e
44 i f ( $ c u r r e n t P e r s o n n e === n u l l | |
45 $ c u r r e n t P e r s o n n e −>i d P e r s o n n e !== $row [ ’ i d P e r s o n n e ’ ]
46 ){
47 i f ( !empty( $ c o l l e c t i o n P e r s o n n e ) ) {
48 throw new \ E x c e p t i o n ( ” Personne : l ’ i d e n t i f i a n t d o i t ê t r e u n i q u e ” ) ;
49 }
50 $ c u r r e n t P e r s o n n e = \CoursPHP\ M e t i e r \ P e r s o n n e F a b r i q u e
51 : : g e t V a l i d I n s t a n c e ( $ d a t a E r r o r A t t r i b u t e s , $row ) ;
52 $collectionPersonne [ ] = $currentPersonne ;
53 }
54 // S i l a Personne p o s s è d e au moins un Adresse
55 i f ( $row [ ’ i d A d r e s s e ’ ] !== n u l l ) {
56 // Ajout d ’ une Adresse dans l a c o l l e c t i o n :
57 $ a d r e s s e = \CoursPHP\ M e t i e r \ A d r e s s e F a b r i q u e
58 : : g e t V a l i d I n s t a n c e ( $ d a t a E r r o r A t t r i b u t e s , $row ) ;
59 $ c u r r e n t P e r s o n n e −>addAdresse ( $ a d r e s s e ) ;
60 }
61 }
62 // On f u s i o n n e l e s t a b l e a u x d ’ e r r e u r s
63 $ d a t a E r r o r = array_merge ( $ da ta E rro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
64 } else {
65 throw new \ E x c e p t i o n ( ” Personne : donn é e s i n c o r r e c t e s . ” ) ;
66 }
67 } else {
68 throw new \ E x c e p t i o n ( ” Personne : donn é e s i n t r o u v a b l e s . ” ) ;
69 }
70 return $ c u r r e n t P e r s o n n e ;
71 }
72
73 /* * Permet de r é cup é r e r une c o l l e c t i o n d ’ p e r s o n n e s pr é s e n t e s dans l a t a b l e .
74 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
75 * @return c o l l e c t i o n de Personnes en c a s de s u c c è s , c o l l e c t i o n v i d e s i n o n .
165
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
166
Chapitre 9 : Couche d’Accès aux données (DAL)
131 ’ WHERE i d P e r s o n n e= :i d P e r s o n n e ’ ,
132 $in putA rra y
133 );
134 i f ( $ q u e r y R e s u l t s === f a l s e ) {
135 throw new \ E x c e p t i o n ( ” Problème d ’ a c c è s aux donn é e s . ” ) ;
136 }
137 } else {
138 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
139 }
140 return $ p e r s o n n e ;
141 }
142
143 /* * @ b r i e f I n s è r e une n o u v e l l e per s on n e ( Cr e a t e )
144 * @param $ d a t a E r r o r donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
145 * @param $ i n p u t A r r a y t a b l e a u a s s o c i a t i f dont l e s c l e f s c o r r e s p o n d e n t aux noms
146 * d e s a t t r i b u t s de Personne
147 * @return l ’ i n s t a n c e de Personne ( e r r e u r s ET i n s t a n c e de l a p e r s o n n e c r é é e )
148 * @throw s en c a s e de probl ème d ’ a c c è s à l a b a s e de donn é e s */
149 public s t a t i c function c r e a t e P e r s o n n e (& $ da ta E r r or , &$ i n p u t A r r a y ) {
150 // T e n t a t i v e de c o n s t r u c t i o n d ’ une i n s t a n c e ( e t f i l t r a g e )
151 $ p e r s o n n e = \CoursPHP\ M e t i e r \ P e r s o n n e F a b r i q u e
152 : :g e t V a l i d I n s t a n c e ( $dataErrorAttributes , $inputArray ) ;
153
154 // S i l a forme d e s a t t r i b u t s s o n t c o r r e c t s ( e x p r e s s i o n s r é g u l i è r e s )
155 i f (empty( $ d a t a E r r o r A t t r i b u t e s ) ) {
156 // Exé c u s s i o n de l a r e q u ê t e d ’ i n s e r t i o n :
157 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>
prepareAndExecuteQueryAssoc (
158 ’REPLACE INTO ’ .
159 s e l f : :getTableNamePersonne ( ) . ’ ( idPersonne , nom) ’
160 . ’VALUES ( : idPersonne , :nom) ’ ,
161 $inp utA r ra y
162 );
163 i f ( $ q u e r y R e s u l t s === f a l s e ) {
164 throw new \ E x c e p t i o n ( ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ) ;
165 }
166 } else {
167 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r A t t r i b u t e s ) ; // f u s i o n
168 }
169
170 $personne −>i d P e r s o n n e = $inp ut A r ra y [ ’ i d P e r s o n n e ’ ] ; // pour v a l e u r r e t o u r n é e
171 return $ p e r s o n n e ;
172 }
173
174 /* * @ b r i e f Supprime une pers onn e à p a r t i r de son ID , a i n s i que s e s A d r e s s e s .
175 * @param $ d a t a E r r o r : donn é e s d ’ e r r e u r s ( c o u p l e nomChamp => message )
176 * @param $ i d P e r s o n n e : c l é p r i m a i r e de l a pe r s o n n e à r é cup é r e r
177 * @return l e modèle de donn é e s ( e r r e u r s ET i n s t a n c e de Personne supprim é e )
178 * @throw s en c a s e de prob lème d ’ a c c è s à l a b a s e de donn é e s */
179 public s t a t i c function d e l e t e P e r s o n n e (& $ da t a E r ro r , $ i d P e r s o n n e ) {
180 // Test s i l a pe rso nne e x i s t e e t r é cup é r a t i o n s donn é e s à s u p p r i m e r
181 $ d a t a E r r o r I d S e a r c h = array ( ) ;
182 $ p e r s o n n e = s e l f : :getPersonneById ( $ d a t a E r r o r I d S e a r c h , $ i d P e r s o n n e ) ;
183 // S i l a Personne e x i s t e
184 i f (empty( $ d a t a E r r o r I d S e a r c h ) ) {
185 // S u p p r e s s i o n en c a s c a d e d e s A d r e s s e s a s s o c i é e s à l a Personne
167
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
186 $ a r g s=array ( $ i d P e r s o n n e ) ;
187 i f ( DataBaseManager : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
188 ’DELETE FROM ’ .
189 AdresseGateway : :getTableNameAdresse ( ) . ’ WHERE i d P e r s o n n e
=? ’ ,
190 $args
191 ) === f a l s e ) {
192 throw new \ E x c e p t i o n ( ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ) ;
193 }
194 // S u p p r e s s i o n de l a per son n e e l l e même
195 $ a r g s=array ( $ i d P e r s o n n e ) ;
196 $ q u e r y R e s u l t s = DataBaseManager : : g e t I n s t a n c e ( )−>prepareAndExecuteQuery (
197 ’DELETE FROM ’ .
198 s e l f : :getTableNamePersonne ( ) . ’ WHERE i d P e r s o n n e=? ’ ,
199 $args
200 );
201 i f ( $ q u e r y R e s u l t s === f a l s e ) {
202 throw new \ E x c e p t i o n ( ” Problème d ’ ex é c u t i o n de l a r e q u ê t e . ” ) ;
203 }
204 } else {
205 $ d a t a E r r o r = array_merge ( $da t a Erro r , $ d a t a E r r o r I d S e a r c h ) ; // f u s i o n
206 }
207 return $ p e r s o n n e ;
208 }
209 }
210 ?>
168
Chapitre 9 : Couche d’Accès aux données (DAL)
28 $ d at a E r r or , $ a r g s P e r s o n n e ) ;
29 } c a t c h ( E x c e p t i o n $e ) {
30 $ d a t a E r r o r [ ] = ” personneCreee1 : ” . $e−>getMessage ( ) ;
31 }
32 // Cré a t i o n d ’ une Personne 2
33 $ i d P e r s o n n e 2 = ” 165 d f e 8 7 8 4 ” ;
34 try {
35 // Test 2 de c r é a t i o n d ’ une per s on n e
36 $ a r g s P e r s o n n e = array ( ” i d P e r s o n n e ” => $ id Pe r s o n n e 2 ,
37 ”nom” => ” personneCreee2 − Toutou i l e s t doux ” ) ;
38 $ p e r s o n n e C r e e e 2 = CoursPHP\ P e r s i s t a n c e \ PersonneGateway : : c r e a t e P e r s o n n e (
39 $ d at a E r r or , $ a r g s P e r s o n n e ) ;
40 } c a t c h ( E x c e p t i o n $e ) {
41 $ d a t a E r r o r [ ] = ” personneCreee2 : ” . $e−>getMessage ( ) ;
42 }
43 // Cré a t i o n d ’ une p er s onn e a v e c un e r r e u r s u r l ’ a t t r i b u t ”nom”
44 try {
45 $ a r g s P e r s o n n e = array ( ” i d P e r s o n n e ” => ” 165 d f e 8 7 8 2 ” ,
46 ”nom” => ” T@rte @ l@ c r ême” ) ;
47 $personneCreeeBuggy = CoursPHP\ P e r s i s t a n c e \ PersonneGateway
169
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
48 : : c r e a t e P e r s o n n e ( $ d at a E r r or , $ a r g s P e r s o n n e ) ;
49 } c a t c h ( E x c e p t i o n $e ) {
50 $dataError [ ] = ” personneCreeeBuggy : ” . $e−>getMessage ( ) ;
51 }
52 // Mise à j o u r d ’ une per son ne
53 try {
54 $ a r g s P e r s o n n e = array ( ” i d P e r s o n n e ” => $ id Pe r s o n n e 2 ,
55 ”nom” => ” personneCreee2 − m o d i f i e e − Toto a eu z é ro ” )
;
56 $ p e r s o n n e M o d i f i e e 2 = CoursPHP\ P e r s i s t a n c e \ PersonneGateway
57 : :updatePersonne ( $ d at a E r r or , $ a r g s P e r s o n n e ) ;
58 } c a t c h ( E x c e p t i o n $e ) {
59 $ d a t a E r r o r [ ] = ” p e r s o n n e M o d i f i e e 2 : ” . $e−>getMessage ( ) ;
60 }
61 // Mise à j o u r d ’ une per son ne a v e c un e r r e u r s u r l ’ a t t r i b u t ”nom”
62 try {
63 $ a r g s P e r s o n n e = array ( ” i d P e r s o n n e ” => $ id Pe r s o n n e 2 ,
64 ”nom” => ” Toto @ un v é l o ” ) ;
65 $ p e r s o n n e M o d i f i e e B u g g y = CoursPHP\ P e r s i s t a n c e \ PersonneGateway
66 : : c r e a t e P e r s o n n e ( $ d at a E r r or , $ a r g s P e r s o n n e ) ;
67 } c a t c h ( E x c e p t i o n $e ) {
68 $ d a t a E r r o r [ ] = ” p e r s o n n e M o d i f i e e B u g g y : ” . $e−>getMessage ( ) ;
69 }
70 // Recherche de Personne par ID :
71 try {
72 $personneById = CoursPHP\ P e r s i s t a n c e \ PersonneGateway : :getPersonneById (
73 $dataError , $ i d P e r s o n n e 1 ) ;
74 } c a t c h ( E x c e p t i o n $e ) {
75 $ d a t a E r r o r [ ] = ” personneById : ” . $e−>getMessage ( ) ;
76 }
77 // Recherche d ’ a d r e s s e a v e c ID i n e x i s t a n t :
78 try {
79 $personneByIdBuggy = CoursPHP\ P e r s i s t a n c e \ PersonneGateway
80 : :getPersonneById ( $ d at a E r r or , ”dummyId” ) ;
81 } c a t c h ( E x c e p t i o n $e ) {
82 $ d a t a E r r o r [ ] = ’ personneByIdBuggy : ’ . $e−>getMessage ( ) ;
83 }
84 // S u p p r e s s i o n d ’ une Personne ( personneCree1 )
85 try {
86 $ p e r s o n n e D e l e t e d = CoursPHP\ P e r s i s t a n c e \ PersonneGateway
87 : : d e l e t e P e r s o n n e ( $ d a t a Er r o r ,
88 $idPersonne1 ) ;
89 } c a t c h ( E x c e p t i o n $e ) {
90 $ d a t a E r r o r [ ] = $e−>getMessage ( ) ;
91 }
92 // Ré cup é r a t i o n de t o u t e s l e s a d r e s s e s
93 try {
94 $ p e r s o n n e A l l= CoursPHP\ P e r s i s t a n c e \ PersonneGateway
95 : :getPersonneAll ( $dataError ) ;
96 } c a t c h ( E x c e p t i o n $e ) {
97 $ d a t a E r r o r [ ] = ” ” . $e−>getMessage ( ) ;
98 }
99
100 // Code de l a vue :
101 require ( ’ ex16_vuePersonneGateway . php ’ ) ;
102 ?>
170
Chapitre 9 : Couche d’Accès aux données (DAL)
171
Quatrième partie
172
Table of Contents
174
Chapitre 10
Analyse Fonctionnelle
10.1 Storyboards
Les Storyboards sont des croquis, élaborés avec un expert métier, qui représentent les différentes
vues d’une application.
(a) Page d’accueil (b) Après création d’une instance (c) Suppression d’instance
175
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Figure 10.2 : Storyboards : Vue normale et vue d’erreur de saisie d’une instance d’Adresse
Figure 10.3 : Use Case Diagram : Les actions possibles pour l’utilisateur
176
Chapitre 11
177
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
11.2 Autoload
La classe Autoload déclare et implémente une méthode callback qui sera appelée lors de l’uti-
lisation dans le programme d’une classe (ou d’un trait) inconnu(e). La méthode callback en
question cherche alors dans les répertoires un fichier source PHP dont le nom correspond à
celui de la classe en question, et charge ce fichier source pour définir la classe « à la volée ».
Nous présentons une classe Autoload conforme à la norme PSR-4 (pour PHP Standard
Recommendations, voir la partie 2.1.2). Suivant cette norme, les namespaces du modules com-
portent tous un préfixe, appelé Vendor Name du module. Dans nos exemples, ce préfixe est
le namespace : \CoursPHP. Le but de ce préfixe est de garantir que des frameworks différents
ne produiront pas de collisions dans les noms de namespaces, de classe, etc. qui poseraient des
problèmes d’interopérabilité.
En outre, le chemin relatif complet (définissant aussi le sous-répertoire du répertoire racine
de notre module) vers le fichier source de la classe doit être nommé suivant le nom complet
de la classe, en tenant compte de ses sous-namespaces (voir la partie 11.1). Ces conventions
sur les namespaces et les chemins vers classes permettent de déterminer automatiquement
l’emplacement du fichier source de la classe à partir de son nom complet.
La transformation du nom complet de la classe en chemin vers le fichier source est illustrée
ci-dessous :
178
Chapitre 11 : Organisation des Répertoires et Configuration
25 * d ’ une c l a s s e inconnue . La mé t h o d e c h a r g e a l o r s l a c l a s s e en q u e s t i o n .
26 *
27 * @param $ c l a s s : nom c o m p l e t de l a c l a s s e à c h a r g e r .
28 *
29 * @note L ’ a r b o r e s c e n c e d e s r é p e r t o i r e s e t l e s noms de f i c h i e r s PHP
30 * c o n t e n a n t l e s c l a s s e s d o i v e n t c o i n c i d e r a v e c l e s sous−namespace
31 * de l a c l a s s e pour t r o u v e r d i r e c t e m e n t l e r é p e r t o i r e c o n t e n a n t
32 * l e f i c h i e r s o u r c e de l a c l a s s e . */
33 public s t a t i c function autoloadCallback_PSR_4 ( $ c l a s s ) {
34 // La c l a s s e a−t− e l l e l e bon pr é f i x e de namespace ?
35 $longueurVendorNamespace = s t r l e n ( s e l f : :$vendorNamespace ) ;
36 i f ( strncmp ( s e l f : :$vendorNamespace , $ c l a s s , $longueurVendorNamespace ) !== 0 )
{
37 // Echec de l ’ a u t o l o a d e r . Esp é ron s qu ’ i l y en a un deuxième . . .
38 return ;
39 }
40 // On e n l è v e l e pr é f i x e ‘ ‘ Vendor Namespace ” .
41 $ r e l a t i v e C l a s s = substr ( $ c l a s s , $longueurVendorNamespace ) ;
42 // Chemin v e r s l e f i c h i e r s o u r c e de l a c l a s s e :
43 g l o b a l $ r o o t D i r e c t o r y ; // Voir d é b u t de i n d e x . php
44 $ f i l e P a t h = $ r o o t D i r e c t o r y . s t r _ r e p l a c e ( ’ \\ ’ , ’ / ’ , $ r e l a t i v e C l a s s ) . ’ . php ’ ;
45 // s i l e f i c h i e r e x i s t e
46 i f ( file_exists ( $filePath ) ) {
47 // Chargement de l a c l a s s e :
48 require ( $ f i l e P a t h ) ;
49 }
50 }
51 } // f i n de l a c l a s s e Autoload
52 ?>
179
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
180
Chapitre 11 : Organisation des Répertoires et Configuration
Enfin, la classe Config contiendra aussi les données d’identification du serveur de bases de
données, qui seront utilisées en remplaçant de la méthode DataBaseManager::getAuthData,
utilisée dans le constructeur de la classe DataBaseManager (voir le chapitre 9.2) par une mé-
thode similaire Config::getAuthData de la classe Config.
181
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
182
Chapitre 11 : Organisation des Répertoires et Configuration
60 return $rootURI ;
61 }
62
63 /* * @ b r i e f r e t o u r n e l e t a b l e a u d e s (URLS v e r s l e s ) f e u i l l e s de s t y l e CSS */
64 public s t a t i c function getStyleSheetsURL ( ) {
65 // Ré p e r t o i r e c o n t e n a n t l e s s t y l e s c s s
66 // Le n e t t o y a g e par f i l t e r _ v a r é v i t e t o u t r i s q u e d ’ i n j e c t i o n XSS
67 $cssDirectoryURL = f i l t e r _ v a r (
68 ” h t t p ://” .$_SERVER[ ’SERVER_NAME’ ] . s e l f : :getRootURI ( ) . ”/ c s s / ” ,
69 FILTER_SANITIZE_URL) ;
70 return array ( ” d e f a u l t ” => $cssDirectoryURL . ” d e f a u l t S t y l e . c s s ” ) ;
71 }
72
73 /* * @ b r i e f Gé nère 10 c h i f f r e s hexa a l é a t o i r e s ( s o i t 5 o c t e t s ) : */
74 public s t a t i c function generateRandomId ( )
75 {
76 // Géné r a t i o n de 5 o c t e t s ( pseudo −) a l é a t o i r e s cod é s en hexa
77 $ c r y p t o S t r o n g = f a l s e ; // V a r i a b l e pour p a s s a g e par r é f é r e n c e
78 $ o c t e t s = openssl_random_pseudo_bytes ( 5 , $ c r y p t o S t r o n g ) ;
79 return bin2hex ( $ o c t e t s ) ;
80 }
81 }
82 ?>
183
Chapitre 12
Architecture Modèle-Vue-Contrôleur
12.2 Le Contrôleur
Le contrôleur est chargé de :
1. Reconnaître l’action (événement) à réaliser pour l’exécuter.
3. Tester les erreurs et récupérer les éventuelles exceptions pour éviter un caca.
184
Chapitre 12 : Architecture Modèle-Vue-Contrôleur
Modèle-Vue-Controleur
Controleur
Vue
Controleur uses
+ Controleur(action)
- actionGet() : void
- actionGetAll() : void
- actionKeyIn() : void
- actionEdit() : void
- actionUpdate() : void
- actionCreate() : void
- actionDelete() : void
uses
uses
uses
Modele
Model
# dataError : array
+ getError() : array|false
+ ModelAdresse(dataError : array = array())
ModelAdresse
- adresse : Adresse
- title : string ModelCollectionAdresse
+ getData() : Adresse - collectionAdresse : Adresse 0..*
+ getTitle() : string + getData() : Adresse 0..*
+ getModelDefaultAdresse() : ModelAdresse + ModelCollectionAdresse()
+ getModelAdresse(idAdresse : string) : ModelAdresse + getModelDefaultAdresse() : ModelCollectionAdresse
+ getModelAdresseUpdate(inputArray : array) : ModelAdresse + getModelAdresseAll() : ModelCollectionAdresse
+ getModelAdresseCreate(inputArray : array) : ModelAdresse
+ deleteAdresse(idAdresse : string) : ModelAdresse
uses
uses
Persistance
uses AdresseGateway
uses
+ generateRandomId() : string
+ getAdresseById(inOut dataError : string[ ], idAdresse : string) : Adresse {throws Except.}
+ getAdresseAll(inOut dataError : string[ ]) : Adresse 0..* {throws Exception}
«Singleton» + createAdresse(inOut dataError : string[ ], inputArray : array&) : Adresse {throws Except.}
DataBaseManager + updateAdresse(inOut dataError : string[ ], inputArray : array&) : Adresse {throws Excep.} AdresseFabrique
+ deleteAdresse(inOut dataError : string[ ], idAdresse : string) : Adresse {throws Exception}
185
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
186
Chapitre 12 : Architecture Modèle-Vue-Contrôleur
187
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
98 // C o n s t r u c t i o n du modèle e t i m p l é men ta t i o n de l a p e r s i s t a n c e :
99 $modele = \CoursPHP\ Modele \ ModelAdresse : :g e t M o de l A d r e s se ( $ i d A d r e s s e ) ;
100 // t e s t d ’ e r r e u r :
101 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) { // Appel de l a vue
102 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” s a i s i e A d r e s s e U p d a t e ” ] ) ;
103 } e l s e { // Appel de l a vue d ’ e r r e u r
104 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
105 }
106 }
107
108 /* * @ b r i e f Implemente l ’ a c t i o n ” u p d a t e ” : met à j o u r une i n s t a n c e dans l a BD
109 */
110 private function a c t i o n U p d a t e ( ) {
111 // C o n s t r u c t i o n du modèle de donn é e s v a l i d é e s e t i m p l é m e n t a t i o n p e r s i s t a n c e
112 $modele = \CoursPHP\ Modele \ ModelAdresse : :getModelAdresseUpdate ($_REQUEST) ;
113 // t e s t d ’ e r r e u r :
114 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) { // Appel de l a vue
115 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e A d r e s s e ” ] ) ;
116 } e l s e { // Appel de l a vue d ’ e r r e u r
117 i f ( !empty( $modele−>g e t E r r o r ( ) [ ’ p e r s i s t a n c e ’ ] ) ) {
118 // Erreur d ’ a c c è s à l a b a s e de donn é e
119 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
120 } e l s e { // Appel de l a vue d ’ e r r e u r
121 // Erreur de s a i s i e ( a t t r i b u t i n c o r r e c t )
122 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” s a i s i e A d r e s s e U p d a t e ”
]) ;
123 }
124 }
125 }
126
127 /* * @ b r i e f Implemente l ’ a c t i o n ” c r e a t e ” : c r é e une i n s t a n c e dans l a BD
128 */
129 private function a c t i o n C r e a t e ( ) {
130 // C o n s t r u c t i o n du modèle de donn é e s v a l i d é e s e t i m p l é m e n t a t i o n p e r s i s t a n c e
131 $modele = \CoursPHP\ Modele \ ModelAdresse : :g e t M o d e l A d r e s s e C r e a t e ($_REQUEST) ;
132 // t e s t d ’ e r r e u r :
133 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) { // Appel de l a vue
134 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e A d r e s s e ” ] ) ;
135 } e l s e { // Appel de l a vue d ’ e r r e u r
136 i f ( !empty( $modele−>g e t E r r o r ( ) [ ’ p e r s i s t a n c e ’ ] ) ) {
137 // Erreur d ’ a c c è s à l a b a s e de donn é e
138 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
139 } else {
140 // Erreur de s a i s i e ( a t t r i b u t i n c o r r e c t )
141 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” s a i s i e A d r e s s e C r e a t e ”
]) ;
142 }
143 }
144 }
145
146 /* * @ b r i e f Implemente l ’ a c t i o n ” d e l e t e ” : supprime une i n s t a n c e v i a son ID
147 */
148 private function a c t i o n D e l e t e ( ) {
149 // ID de l ’ i n s t a n c e à su ppr imer
150 $ i d A d r e s s e = f i l t e r _ v a r ($_REQUEST[ ’ i d A d r e s s e ’ ] , FILTER_SANITIZE_STRING) ;
151 // C o n s t r u c t i o n du modèle e t i m p l é men ta t i o n de l a p e r s i s t a n c e :
188
Chapitre 12 : Architecture Modèle-Vue-Contrôleur
12.3 Le Modèle
Le but du modèle est de stocker les données nécessaires à la vue pour afficher le résultat d’une
action. Par exemple, pour l’action get-all affichant toutes les adresses de la base de données,
le modèle doit contenir une collection d’instances d’Adresse, qui contient toutes les adresses.
Pour l’action create de création d’une nouvelle adresse, la vue doit afficher l’adresse saisie
pour confirmation, et le modèle contiendra donc une seule instance d’Adresse.
Dans notre implémentation, le modèle contient aussi les données d’erreurs. Une classe de
base appelée Model, générique, contient le tableau des erreurs et son accesseur (qui renvoit le
booléen false en cas de tableau vide). Le tableau des erreurs est un tableau associatif dont les
clés sont les types d’erreurs (champs de formulaire incorrect, login, accès à la base de données,
etc.) et la valeur un message d’erreur pour informer l’utilisateur ou stocker dans un fichier log.
189
.
.
user :Index ma :ModelAdresse av :AdresseView ag :AdresseGateway os :OutputStream
request
create
ctrl :Controleur
try
alt
actionGet(id)
[Critical Region] [action==get]
« static » getModelAdresse(id)
getAdresseById(inOut dataError, id)
adresse
create
switch général
switch général modele :ModelAdresse
modele
alt
requireView(modele)
[!modele->getError()]
getData()
adresse
Vue normale
Vuenormale
getHtmlDevelopped(adresse)
htmlCode
Rémy Malgouyres, http://malgouyres.org/
printf(htmlCode)
190
[else] requireErrorView(modele)
à partir de son ID
getError()
errMsg Vue d’erreur
Vued’erreur
printf(errMsg)
requireErrorView(mdl)
getError()
Vue d’erreur
Vued’erreur
errMsg
printf(errMsg)
Diag 9. Diagramme de séquence de l’action get qui permet d’afficher une adresse
Programmation Web Côté Serveur en PHP
Chapitre 12 : Architecture Modèle-Vue-Contrôleur
17 }
18
19 /* * @ b r i e f C o n s t r u c t e u r
20 * @param $ d a t a E r r o r un t a b l e a u a s s o c i a t i f dont l e s v a l e u r s s o n t d e s messages
d ’ erreur .
21 * ( par exemple un t a b l e a u v i d e , au d é b u t d ’ un t r a i t ement ) */
22 public function __construct ( $ d a t a E r r o r = array ( ) ) {
23 $ t h i s −>d a t a E r r o r = $ d a t a E r r o r ;
24 }
25 }
26 ?>
La classe ModelAdresse, qui hérite de Model contient les données d’une instance d’Adresse,
avec son accesseur getData(). Dans notre implémentation, le modèle contient aussi du texte
(ici le titre) à afficher dans la vue.
Les méthodes de la classe ModelAdresse correspondent aux différentes actions qui ne
portent que sur une seule adresse (suppression d’une adresse, saisie ou modification d’une
adresse, affichage des détails d’une adresse, etc.) Ces méthodes appellent des méthodes d’accès
aux données de la classe AdresseGateway pour implémenter la persistence.
191
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
35 }
36
37 /* * @ b r i e f Retourne un modèle a v e c une i n s t a n c e d ’ Adresse à p a r t i r
38 * de son ID par a c c è s à l a couche P e r s i s t a n c e .
39 * @param $ i d A d r e s s e I d e n t i f i a n t u n i q u e de l ’ a d r e s s e à c o n s u l t e r */
40 public s t a t i c function getModel Ad re sse ( $ i d A d r e s s e ) {
41 $model = new s e l f ( array ( ) ) ;
42 // Appel de l a couche d ’ a c c è s aux donn é e s :
43 $model−>a d r e s s e = \CoursPHP\ P e r s i s t a n c e \ AdresseGateway : :g e t A d r e s s e B y I d (
44 $model−>d a taErro r , $ i d A d r e s s e ) ;
45 $model−> t i t l e = ” A f f i c h a g e d ’ une a d r e s s e ” ;
46 return $model ;
47 }
48
49 /* * @ b r i e f M o d i f i e une a d r e s s e dans l a couche P e r s i s t a n c e .
50 * @param $ i n p u t A r r a y t a b l e a u a s s o c i a t i f dont l e s c l e f s c o r r e s p o n d e n t
51 * aux noms d e s a t t r i b u t s d ’ Adresse */
52 public s t a t i c function getModelAdresseUpdate ( $ i n p u t A r r a y ) {
53 $model = new s e l f ( array ( ) ) ;
54 // Appel de l a couche d ’ a c c è s aux donn é e s :
55 $model−>a d r e s s e = \CoursPHP\ P e r s i s t a n c e \ AdresseGateway : :u p d a t e A d r e s s e (
56 $model−>d a t a Er r o r , $ i n p u t A r r a y ) ;
57 $model−> t i t l e = ”L ’ a d r e s s e a é t é mise à j o u r ” ;
58 return $model ;
59 }
60
61 /* * @ b r i e f I n s è r e une a d r e s s e en c r é ant un n o u v e l ID dans l a BD
62 * @param $ i n p u t A r r a y t a b l e a u a s s o c i a t i f dont l e s c l e f s c o r r e s p o n d e n t aux noms
63 * d e s a t t r i b u t s d ’ Adresse ( à l ’ e x v e p t i o n de l ’ ID ) */
64 public s t a t i c function g e t M o d e l A d r e s s e C r e a t e ( $ i n p u t A r r a y ) {
65 $model = new s e l f ( array ( ) ) ;
66 // Appel de l a couche d ’ a c c è s aux donn é e s :
67 $model−>a d r e s s e = \CoursPHP\ P e r s i s t a n c e \ AdresseGateway : : c r e a t e A d r e s s e (
68 $model−>d a t a Er r o r , $ i n p u t A r r a y ) ;
69 $model−> t i t l e = ”L ’ a d r e s s e a é t é i n s é r é e ” ;
70 return $model ;
71 }
72
73 /* * @ b r i e f Supprime une a d r e s s e dans l a BD e t r e t o u r n e l ’ a d r e s s e .
74 * @param $ i d A d r e s s e I d e n t i f i a n t u n i q u e de l ’ a d r e s s e à s u p p r i m e r */
75 public s t a t i c function d e l e t e A d r e s s e ( $ i d A d r e s s e ) {
76 $model = new s e l f ( array ( ) ) ;
77 // Appel de l a couche d ’ a c c è s aux donn é e s :
78 $model−>a d r e s s e = \CoursPHP\ P e r s i s t a n c e \ AdresseGateway : : d e l e t e A d r e s s e (
79 $model−>d at a E r r or , $ i d A d r e s s e ) ;
80 $model−> t i t l e = ” Adresse supprim é e ” ;
81 return $model ;
82 }
83 }
84 ?>
La classe ModelCollectionAdresse, qui hérite aussi de Model contient les données d’une
collection d’instances d’Adresse, avec son accesseur getData(), qui cette fois renvoie la col-
lection en question. Les méthodes de la classe ModelCollectionAdresse correspondent aux
différentes actions qui ne portent que sur une collection d’adresse (ici, uniquement “afficher
toute la table”, mais on pourrait, par exemple, faire des requêtes avec LIMIT et OFFSET pour
192
Chapitre 12 : Architecture Modèle-Vue-Contrôleur
paginer). Ces méthodes appelle des méthodes d’accès aux données de la classe AdresseGateway
pour implémenter la persistence.
Code Source 12.5 : exemples/mvc/Modele/ModelCollectionAdresse.php
1 < ?php
2 namespace CoursPHP\ Modele ;
3 /* *
4 * @ b r i e f C l a s s e Modèle pour s t o c k e r une c o l l e c t i o n de Adresse
5 */
6 c l a s s M o d e l C o l l e c t i o n A d r e s s e e x t e n d s Model
7 {
8 /* * C o l l e c t i o n d ’ a d r e s s e s , donn é e s mé t i e r du modèle */
9 private $ c o l l e c t i o n A d r e s s e ;
10
11 /* * Donne a c c è s à l a c o l l e c t i o n d ’ a d r e s s e s */
12 public function getData ( ) {
13 return $ t h i s −>c o l l e c t i o n A d r e s s e ;
14 }
15
16 /* * @ b r i e f C o n s t r u c t e u r par d é f a u t ( p r i v é , c r é e d e s c o l l e c t i o n s v i d e s ) */
17 private function __contruct ( ) {
18 $ t h i s −>c o l l e c t i o n A d r e s s e = array ( ) ;
19 $ t h i s −>d a t a E r r o r = array ( ) ;
20 }
21
22 /* * @ b r i e f Retourne un modèle a v e c l a c o l l e c t i o n de t o u t e s l e s a d r e s s e s
23 * par a c c è s à l a b a s e de donn é e s . */
24 public s t a t i c function g e t M o d e l A d r e s s e A l l ( ) {
25 $model = new s e l f ( array ( ) ) ;
26 // Appel de l a couche d ’ a c c è s aux donn é e s :
27 $model−>c o l l e c t i o n A d r e s s e = \CoursPHP\ P e r s i s t a n c e \ AdresseGateway
28 : : g e t A d r e s s e A l l ( $model−>d a t a E r r o r ) ;
29 return $model ;
30 }
31 }
32 ?>
193
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Voyons maintenant la vue qui affiche toutes les adresses (figure 10.1d) :
Code Source 12.7 : exemples/mvc/Vue/vues/vueCollectionAdresse.php
1 <?=\CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ’ Bienvenue s u r n o t r e s i t e ’ , ’
2 UTF−8’ , \CoursPHP\ C o n f i g \ C o n f i g : :getStyleSheetsURL ( ) [ ’ default ’ ] ) ?>
3 <h1>Toutes l e s a d r e s s e s</h1>
4 <p>
5 <a href=”<?=\CoursPHP\ C o n f i g \ C o n f i g : :getRootURI ( ) ?>”>R e v e n i r à l ’ ac cue i l</a>
6 </p>
7 <?php
8 echo ”<table><tbody>” ;
9 f o r e a c h ( $modele−>getData ( ) a s $ a d r e s s e ) {
10 echo ”<tr>” ;
11 echo ”<td><a href= \” ? a c t i o n = d e l e t e&idAdresse= ” . $a d r e s se −>i d A d r e s s e
12 . ” \”>s u p p r i m e r</a></td>” ;
13 echo ”<td><a href= \” ? a c t i o n = e d i t&idAdresse= ” . $ a d re s s e −>i d A d r e s s e
14 . ” \”>m o d i f i e r</a></td>” ;
15 echo ”<td>” . \ CoursPHP\Vue\ AdresseView : :getHtmlCompact ( $ a d r e s s e ) . ”</td>” ;
16 echo ”<tr>” ;
17 }
18 echo ”</tbody></table>” ;
19 ?>
20 <?=\CoursPHP\Vue\ VueHtmlUtils : : f i n F i c h i e r H t m l 5 ( ) ; ?>
Voyons enfin, par exemple, la vue d’erreur concernant la saisie incorrecte d’une adresse (fi-
gure 10.2b).
Code Source 12.8 : exemples/mvc/Vue/vues/vueErreurSaisieCreate.php
1 <?=\CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ’ Bienvenue s u r n o t r e s i t e ’ ,
2 ’UTF−8’ , \CoursPHP\ C o n f i g \ C o n f i g : :getStyleSheetsURL ( ) [ ’ default ’ ] ) ?>
3
4 <h1>E r r e u r de s a i s i e d ’ une a d r e s s e</h1>
5 <?=\CoursPHP\Vue\ AdresseFormView : :getFormErrorsHtml ( ” ?a c t i o n = c r e a t e ” ,
6 $modele−>getData ( ) , $modele−>g e t E r r o r ( ) ) ?>
7 <p>
8 <a href=”<?=\CoursPHP\ C o n f i g \ C o n f i g : :getRootURI ( ) ?>”>R e v e n i r à l ’ ac cue i l</a>
9 </p>
10 <?=\CoursPHP\Vue\ VueHtmlUtils : : f i n F i c h i e r H t m l 5 ( ) ; ?>
194
Chapitre 13
13.1 Storyboards
195
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
Dans le diagramme de cas d’utilisation de la figure 13.3, nous proposons unn type d’utili-
sateurs générique User, avec deux spécialisations : Visitor et Admin.
Figure 13.3 : Use Case Diagram : Les actions possibles pour les deux types d’utilisateurs
13.3 Le Front-Controller
Lorsque nous souhaitons gérer plusieurs rôles d’utilisateurs, il est commode d’avoir un contrô-
leur par rôle, qui gère les actions disponibles pour les utilisateurs de ce rôle. Cependant, sans le
Front-Controller, cela nécessiterait de gérer plusieurs URL d’index, correspondant à des droits
d’accès différents. Le rôle du Front-Controller est :
2. De tester si l’utilisateur a des droits suffisants (si les droits sont insuffisants, on affiche
selon le cas une page d’erreur ou une page d’authentification.) ;
3. De créer une instance du contrôleur adapté pour l’action avec le rôle de l’utilisateur.
196
Chapitre 13 : Utilisateurs et Front Controller
197
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
32
33 // 2) A c t i o n s a c c e s s i b l e s uniquement aux a d m i n i s t r a t e u r s :
34 case ” s a i s i e ” : // S a i s i e d ’ une n o u v e l l e Adresse
35 case ” e d i t ” : // S a i s i e d e s m o d i f i c a t i o n s d ’ une Adresse
36 case ” u p d a t e ” : // Met à j o u r une Adresse dans l a BD
37 case ” c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
38 case ” d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
39 // L ’ u t i l i s a t e u r a−t− i l d e s d r o i t s s u f f i s a n t s ?
40 i f ( $ r o l e === ” admin ” ) {
41 $adminCtrl = new ControleurAdmin ( $ a c t i o n ) ;
42 } else {
43 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
44 }
45 break ;
46
47 // 3) A c t i o n s a c c e s s i b l e s aux v i s i t e u r s e t aux a d m i n i s t r a t e u r s :
48 case ” g e t ” : // A f f i c h a g e d ’ une Adresse à p a r t i r de son ID
49 case ” g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Adresse ’ s
50 default : // L ’ a c t i o n par d é f a u t
51 // L ’ i m p l é me nt at io n ( donc l e c o n t r ô l e u r ) d é pend du r ô l e
52 i f ( $ r o l e === ” admin ” ) {
53 $adminCtrl = new ControleurAdmin ( $ a c t i o n ) ;
54 } else {
55 $ public C t r l = new C o n t r o l e u r V i s i t o r ( $ a c t i o n ) ;
56 }
57 }
58 } c a t c h ( E x c e p t i o n $e ) { // Page d ’ e r r e u r par d é f a u t
59 $modele = new \CoursPHP\ Modele \ Model (
60 array ( ’ e x c e p t i o n ’ => $e−>getMessage ( ) ) ) ;
61 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
62 }
63 }
64 }
65 ?>
Voici le contrôleur spécialisé pour les actions accessibles à un visiteur non authentifié.
198
Chapitre 13 : Utilisateurs et Front Controller
19 case ” v a l i d a t e A u t h ” :
20 $ t h i s −>a c t i o n V a l i d a t e A u t h ( ) ;
21 break ;
22 case ” g e t ” : // A f f i c h a g e d ’ une Adresse à p a r t i r de son ID
23 $ t h i s −>a c t i o n G e t ( ) ;
24 break ;
25 case ” g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Adresse ’ s
26 $ t h i s −>a c t i o n G e t A l l ( ) ;
27 break ;
28 default : // L ’ a c t i o n i n d é f i n i e ( page par d é f a u t , i c i a c c u e i l )
29 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” d e f a u l t ” ] ) ;
30 break ;
31 }
32 }
33
34 /* *
35 * @ b r i e f Implemente l ’ a c t i o n ” a u t h ” : S a i s i e du l o g i n /mot de p a s s e
36 */
37 private function actionAuth ( ) {
38 $modele = new \CoursPHP\ Modele \ Model ( array ( ) ) ;
39 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
40 }
41
42 /* *
43 * @ b r i e f Implemente l ’ a c t i o n ” v a l i d a t e A u t h ”
44 * V a l i d a t i o n du l o g i n / password e t c r é a t i o n de s e s s i o n .
45 */
46 private function a c t i o n V a l i d a t e A u t h ( ) {
47 \CoursPHP\Auth\ V a l i d a t i o n R e q u e s t : : v a l i d a t i o n L o g i n ( $ d a t aE r r o r , $email ,
$password ) ;
48 $modele = \CoursPHP\Auth\ A u t h e n t i c a t i o n : : c h e c k A n d I n i t i a t e S e s s i o n (
49 $email , $password , $ d a t a E r r o r ) ;
50 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
51 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” d e f a u l t A d m i n ” ] ) ;
52 } else {
53 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
54 }
55 }
56
57 /* *
58 * @ b r i e f Implemente l ’ a c t i o n ” g e t ” : r é c u p è r e une i n s t a n c e à p a r t i r de ID
59 */
60 private function a c t i o n G e t ( ) {
61 // ID de l ’ i n s t a n c e à r é cup é r e r
62 $rawId = i s s e t ($_REQUEST[ ’ i d A d r e s s e ’ ] ) ? $_REQUEST[ ’ i d A d r e s s e ’ ] : ” ” ;
63 $ i d A d r e s s e = f i l t e r _ v a r ( $rawId , FILTER_SANITIZE_STRING) ;
64 $modele = \CoursPHP\ Modele \ ModelAdresse : :g e t M o de l A d r e s se ( $ i d A d r e s s e ) ;
65 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
66 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e A d r e s s e ” ] ) ;
67 } else {
68 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
69 }
70 }
71
72 /* *
73 * @ b r i e f Implemente l ’ a c t i o n ” g e t − a l l ” : Ré c u p è r e t o u t e s l e s i n s t a n c e s
199
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
74 */
75 private function a c t i o n G e t A l l ( ) {
76 $modele = \CoursPHP\ Modele \ M o d e l C o l l e c t i o n A d r e s s e : : g e t M o d e l A d r e s s e A l l ( ) ;
77 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
78 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e C o l l e c t i o n A d r e s s e ” ] ) ;
79 } else {
80 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
81 }
82 }
83 }
84 ?>
Voici le contrôleur spécialisé pour les actions accessibles à un utilisateur authentifié avec le rôle
admin.
200
Chapitre 13 : Utilisateurs et Front Controller
41 }
42 }
43
44 /* * @ b r i e f Implemente l ’ a c t i o n ” g e t ” : Ré c u p è r e une i n s t a n c e à p a r t i r de ID
45 */
46 private function a c t i o n G e t ( ) {
47 // ID de l ’ i n s t a n c e à r é cup é r e r
48 $rawId = i s s e t ($_REQUEST[ ’ i d A d r e s s e ’ ] ) ? $_REQUEST[ ’ i d A d r e s s e ’ ] : ” ” ;
49 $ i d A d r e s s e = f i l t e r _ v a r ( $rawId , FILTER_SANITIZE_STRING) ;
50 $modele = \CoursPHP\ Modele \ ModelAdresse : :g e t M o de l A d r e s se ( $ i d A d r e s s e ) ;
51 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
52 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e A d r e s s e A d m i n ” ] ) ;
53 } else {
54 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
55 }
56 }
57
58 /* * @ b r i e f Implemente l ’ a c t i o n ” g e t − a l l ” : Ré c u p è r e t o u t e s l e s i n s t a n c e s
59 */
60 private function a c t i o n G e t A l l ( ) {
61 $modele = \CoursPHP\ Modele \ M o d e l C o l l e c t i o n A d r e s s e : : g e t M o d e l A d r e s s e A l l ( ) ;
62 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
63 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e C o l l e c t i o n A d r e s s e A d m i n
” ]) ;
64 } else {
65 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
66 }
67 }
68
69 /* * @ b r i e f Implemente l ’ a c t i o n ” s a i s i e ” : A f f i c h e un f o r m u l a i r e v i e r g e
70 */
71 private function a c t i o n K e y I n ( ) {
72 $modele = \CoursPHP\ Modele \ ModelAdresse : : g e t M o d e l D e f a u l t A d r e s s e ( ) ;
73 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” s a i s i e A d r e s s e C r e a t e ” ] ) ;
74 }
75
76 /* * @ b r i e f Implemente l ’ a c t i o n ” e d i t ” : A f f i c h e un f o r m u l a i r e de m o d i f i c a t i o n
77 */
78 private function a c t i o n E d i t ( ) {
79 // ID de l ’ i n s t a n c e à m o d i f i e r
80 $rawId = i s s e t ($_REQUEST[ ’ i d A d r e s s e ’ ] ) ? $_REQUEST[ ’ i d A d r e s s e ’ ] : ” ” ;
81 $ i d A d r e s s e = f i l t e r _ v a r ($_REQUEST[ ’ i d A d r e s s e ’ ] , FILTER_SANITIZE_STRING) ;
82 $modele = \CoursPHP\ Modele \ ModelAdresse : :g e t M o de l A d r e s se ( $ i d A d r e s s e ) ;
83 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
84 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” s a i s i e A d r e s s e U p d a t e ” ] ) ;
85 } else {
86 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
87 }
88 }
89
90 /* * @ b r i e f Implemente l ’ a c t i o n ” u p d a t e ” : Met à j o u r une i n s t a n c e dans l a BD
91 */
92 private function a c t i o n U p d a t e ( ) {
93 // C o n s t r u c t i o n du modèle a v e c l ’ a d r e s s e v a l i d é e
94 $modele = \CoursPHP\ Modele \ ModelAdresse : :getModelAdresseUpdate ($_POST) ;
95 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
201
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
202
Chapitre 13 : Utilisateurs et Front Controller
203
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
46 * @param $ e m a i l e−m a i l de l ’ u t i l i s a t e u r s e r v a n t d ’ ID u n i q u e
47 * @param $ r o l e Rô l e de l ’ u t i l i s a t e u r */
48 public s t a t i c function getModelUserFromSession ( $email , $ r o l e ) {
49 $model = new s e l f ( array ( ) ) ;
50 $model−>r o l e = $ r o l e ;
51 $model−>e m a i l = $ e m a i l ;
52 return $model ;
53 }
54 }
55 ?>
204
Chapitre 13 : Utilisateurs et Front Controller
205
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
206
Chapitre 13 : Utilisateurs et Front Controller
207
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
11 /* *
12 * @ b r i e f C ’ e s t dans l e c o n t r u c t e u r que l e c o n t r ô l e u r f a i t son t r a v a i l .
13 */
14 function __construct ( ) {
15 try {
16 // Ré cup é r a t i o n de l ’ a c t i o n
17 $ a c t i o n = i s s e t ($_REQUEST[ ’ a c t i o n ’ ] ) ? $_REQUEST[ ’ a c t i o n ’ ] : ” ” ;
18
19 // L ’ u t i l i s a t e u r e s t − i l i d e n t i f i é ? S i oui , q u e l e s t son r ô l e ?
20 $modele = \CoursPHP\Auth\ A u t h e n t i c a t i o n : : r e s t o r e S e s s i o n ( ) ;
21 $ r o l e = ( $modele−>g e t E r r o r ( ) === f a l s e ) ? $modele−>g e t R o l e ( ) : ” ” ;
22
23 // On d i s t i n g u e d e s c a s d ’ u t i l i s a t i o n , s u i v a n t l ’ a c t i o n
24 switch ( $ a c t i o n ) {
25 // 1) A c t i o n s c o n c e r n a n t l ’ a u t h e n t i f i c a t i o n :
26 case ” a u t h ” : // Vue de s a i s i e du l o g i n / password
27 case ” v a l i d a t e A u t h ” : // V a l i d a t i o n du l o g i n / password
28 $ a u t h C t r l = new ControleurAuth ( $ a c t i o n ) ;
29 break ;
30
31 // 2) A c t i o n s a c c e s s i b l e s uniquement aux a d m i n i s t r a t e u r s :
32 // 2 . a ) Concernant l e s a d r e s s e s
33 case ” a d r e s s e −s a i s i e ” : // S a i s i e d ’ une n o u v e l l e Adresse
34 case ” a d r e s s e −e d i t ” : // S a i s i e d e s m o d i f i c a t i o n s d ’ une Adresse
35 case ” a d r e s s e −u p d a t e ” : // Met à j o u r une Adresse dans l a BD
36 case ” a d r e s s e −c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
37 case ” a d r e s s e −d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
38 i f ( $ r o l e == ” admin ” ) {
39 $adminCtrl = new ControleurAdminAdresse ( $ a c t i o n ) ;
40 } else {
41 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
42 }
43 break ;
44 // 2 . b ) Concernant l e s p e r s o n n e s
45 case ” personne−s a i s i e ” : // S a i s i e d ’ une n o u v e l l e Personne
46 case ” personne−e d i t ” : // S a i s i e d e s m o d i f i c a t i o n s d ’ une Personne
47 case ” personne−u p d a t e ” : // Met à j o u r une Personne dans l a BD
48 case ” personne−c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Personne dans l a BD
49 case ” personne−d e l e t e ” : // S u p r e s s i o n d ’ une Personne à p a r t i r de son
ID
50 i f ( $ r o l e == ” admin ” ) {
51 $adminCtrl = new ControleurAdminPersonne ( $ a c t i o n ) ;
52 } else {
53 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
54 }
55 break ;
56
57 // 3) A c t i o n s a c c e s s i b l e s aux v i s i t e u r s e t aux a d m i n i s t r a t e u r s :
58 // 3 . a ) Concernant l e s a d r e s s e s
59 case ” a d r e s s e −g e t ” : // A f f i c h a g e d ’ une Adresse à p a r t i r de son ID
60 case ” a d r e s s e −g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Adresse ’ s
61 // L ’ i m p l é men t a ti on ( donc l e c o n t r ô l e u r ) d é pend du r ô l e
62 i f ( $ r o l e == ” admin ” ) {
63 $adminCtrl = new ControleurAdminAdresse ( $ a c t i o n ) ;
64 } else {
65 $ public C t r l = new C o n t r o l e u r V i s i t o r A d r e s s e ( $ a c t i o n ) ;
208
Chapitre 13 : Utilisateurs et Front Controller
66 }
67 break ;
68 // 3 . b ) Concernant l e s p e r s o n n e s
69 case ” personne−g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Personne ’ s
70 i f ( $ r o l e == ” admin ” ) {
71 $adminCtrl = new ControleurAdminPersonne ( $ a c t i o n ) ;
72 } else {
73 $ public C t r l = new C o n t r o l e u r V i s i t o r P e r s o n n e ( $ a c t i o n ) ;
74 }
75 break ;
76 default :
77 i f ( $ r o l e == ” admin ” ) {
78 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” d e f a u l t A d m i n ” ] ) ;
79 } else {
80 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” d e f a u l t ” ] ) ;
81 }
82 }
83 } c a t c h ( \ E x c e p t i o n $e ) { // Page d ’ e r r e u r par d é f a u t
84 $modele = new \CoursPHP\ Modele \ Model (
85 array ( ’ e x c e p t i o n ’ => $e−>getMessage ( ) ) ) ;
86 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
87 }
88 }
89 }
90 ?>
Voici à titre d’exemple, le code du ControllerAuth gérant les actions associées à l’authentifica-
tion :
209
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
27
28 /* * @ b r i e f Implemente l ’ a c t i o n ” a u t h ” : s a i s i e du l o g i n / password
29 */
30 private function actionAuth ( ) {
31 $modele = new \CoursPHP\ Modele \ Model ( array ( ) ) ;
32 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
33 }
34
35 /* *
36 * @ b r i e f Implemente l ’ a c t i o n ” v a l i d a t e A u t h ”
37 * V a l i d a t i o n du l o g i n / password e t c r é a t i o n de s e s s i o n .
38 */
39 private function a c t i o n V a l i d a t e A u t h ( ) {
40 \CoursPHP\Auth\ V a l i d a t i o n R e q u e s t : : v a l i d a t i o n L o g i n ( $ d a t aE r r o r , $email ,
$password ) ;
41 $modele = \CoursPHP\Auth\ A u t h e n t i c a t i o n : : c h e c k A n d I n i t i a t e S e s s i o n (
42 $email , $password , $ d a t a E r r o r ) ;
43 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
44 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” d e f a u l t A d m i n ” ] ) ;
45 } else {
46 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a u t h e n t i f i c a t i o n ” ] ) ;
47 }
48 }
49
50 }
51 ?>
Voici, toujours à titre d’exemple, le code du ControllerAdminPersonne gérant les actions asso-
ciées aux personnes :
210
Chapitre 13 : Utilisateurs et Front Controller
211
Rémy Malgouyres, http://malgouyres.org/ Programmation Web Côté Serveur en PHP
79 /* * @ b r i e f Implemente l ’ a c t i o n ” e d i t ” : a f f i c h e un f o r m u l a i r e de m o d i f i c a t i o n
80 */
81 private function a c t i o n E d i t ( ) {
82 // ID de l ’ i n s t a n c e à m o d i f i e r
83 $rawId = i s s e t ($_REQUEST[ ’ i d P e r s o n n e ’ ] ) ? $_REQUEST[ ’ i d P e r s o n n e ’ ] : ” ” ;
84 $ i d P e r s o n n e = f i l t e r _ v a r ($_REQUEST[ ’ i d P e r s o n n e ’ ] , FILTER_SANITIZE_STRING) ;
85 $modele = \CoursPHP\ Modele \ ModelPersonne : :getModelPersonne ( $ i d P e r s o n n e ) ;
86 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
87 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” s a i s i e P e r s o n n e U p d a t e ” ] ) ;
88 } else {
89 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
90 }
91 }
92
93 /* * @ b r i e f Implemente l ’ a c t i o n ” u p d a t e ” : met à j o u r une i n s t a n c e dans l a BD
94 */
95 private function a c t i o n U p d a t e ( ) {
96 // C o n s t r u i r e l e modèle de Personne mise à j o u r
97 $modele = \CoursPHP\ Modele \ ModelPersonne : :getModelPersonneUpdate ($_POST) ;
98 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
99 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e P e r s o n n e ” ] ) ;
100 } else {
101 i f ( !empty( $modele−>g e t E r r o r ( ) [ ’ p e r s i s t a n c e ’ ] ) ) {
102 // Erreur d ’ a c c è s à l a b a s e de donn é e
103 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
104 } else {
105 // Erreur de s a i s i e
106 require ( \ CoursPHP\ C o n f i g \ C o n f i g
107 : :g e t V u e s E r r e u r ( ) [ ” s a i s i e U p d a t e P e r s o n n e ” ] ) ;
108 }
109 }
110 }
111
112 /* * @ b r i e f Implemente l ’ a c t i o n ” c r e a t e ” : c r é e une i n s t a n c e dans l a BD
113 */
114 private function a c t i o n C r e a t e ( ) {
115 // C o n s t r u i r e l e modèle de Personne mise à j o u r
116 $modele = \CoursPHP\ Modele \ ModelPersonne : :g e t M o d e l P e r s o n n e C r e a t e ($_POST) ;
117 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
118 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :getVues ( ) [ ” a f f i c h e P e r s o n n e ” ] ) ;
119 } else {
120 i f ( !empty( $modele−>g e t E r r o r ( ) [ ’ p e r s i s t a n c e ’ ] ) ) {
121 // Erreur d ’ a c c è s à l a b a s e de donn é e
122 require ( \ CoursPHP\ C o n f i g \ C o n f i g : :g e t V u e s E r r e u r ( ) [ ” d e f a u l t ” ] ) ;
123 } else {
124 // Erreur de s a i s i e
125 require ( \ CoursPHP\ C o n f i g \ C o n f i g
126 : :g e t V u e s E r r e u r ( ) [ ” s a i s i e C r e a t e P e r s o n n e ” ] ) ;
127 }
128 }
129 }
130
131 /* * @ b r i e f Implemente l ’ a c t i o n ” d e l e t e ” : supprime une i n s t a n c e v i a son ID
132 */
133 private function a c t i o n D e l e t e ( ) {
134 // ID de l ’ i n s t a n c e à su ppr imer
212
Chapitre 13 : Utilisateurs et Front Controller
Voici enfin la vue affichant une collection de personnes avec les adresses agrégées (voir fi-
gure 13.4) :
Code Source 13.11 : exemples/metierFrontArchi/Vue/vues/vueCollectionPersonneAdmin.php
1 < ?=\CoursPHP\Vue\ VueHtmlUtils : :enTeteHTML5 ( ’ Bienvenue s u r n o t r e s i t e ’ , ’UTF−8 ’ ,
2 \CoursPHP\ C o n f i g \ C o n f i g : :getStyleSheetsURL ( ) [ ’ d e f a u l t ’ ] ) ?>
3 <h1>Toutes l e s p e r s o n n e s </h1>
4
5 <a h r e f=”< ?=\CoursPHP\ C o n f i g \ C o n f i g : :getRootURI ( ) ?>”>R e v e n i r à l ’ a c c u e i l </a>
6 <a h r e f =” ?a c t i o n=personne−s a i s i e&i d P e r s o n n e=<?=
7 \CoursPHP\ M e t i e r \ Personne : :generateRandomId ( )
8 ?>”>A j o u t e r une personne </a>
9
10 < ?php
11 f o r e a c h ( $modele−>g e t D a t a ( ) as $ p ers o n n e ) {
12 echo ”< d i v c l a s s =\” d i s p l a y P e r s o n n e \”>” ;
13 echo \CoursPHP\Vue\ PersonneView : :g e t H t m l D e v e l o p p e d ( $personne , t r u e ) ;
14 echo ”</ d i v >” ;
15 }
16 ?>
17 < ?=\CoursPHP\Vue\ VueHtmlUtils : :f i n F i c h i e r H t m l 5 ( ) ; ?>
213