Programmation Web. Coté serveur : HTML, CSS, PHP, PDO



Documents pareils
HMTL. Exemple de fichier HTML. Structure d un document HTML. Exemple de fichier HTML. Balises HTML. IFT1147 Programmation Serveur Web avec PHP

Les outils de création de sites web

Présentation du Framework BootstrapTwitter

HTML, CSS, JS et CGI. Elanore Elessar Dimar

HTML. Notions générales

.. CSS. Damien Nouvel. Damien Nouvel (Inalco) CSS 1 / 15

Formation HTML / CSS. ar dionoea

Bernard Lecomte. Débuter avec HTML

CRÉER, ROUTER ET GÉRER UNE NEWSLETTER, UN ING

ING & NEWSLETTER NEWSLETTER RESPONSIVE

Programmation Internet Cours 4

LES GRANDES ETAPES DE CREATION D UN WEB DESIGN

INTERNET est un RESEAU D ORDINATEURS RELIES ENTRE EUX A L ECHELLE PLANETAIRE. Internet : interconnexion de réseaux (anglais : net = réseau)

STID 2ème année : TP Web/PHP

Travaux dirigés n 10

Tutoriel : Feuille de style externe

Installation d un serveur HTTP (Hypertext Transfer Protocol) sous Débian 6

TIC. Réseau informatique. Historique - 1. Historique - 2. TC - IUT Montpellier Internet et le Web

Dans nos locaux au 98 Route de Sauve NÎMES. Un ordinateur PC par stagiaire, scanner, imprimante/copieur laser couleur

TP 5 Les CMS, la forme et le fond Internet et Outils (IO2)

Notes pour l utilisation d Expression Web

Optimiser pour les appareils mobiles

Pack Fifty+ Normes Techniques 2013

RAPPORT AUDIT SEO. Élaboré à l'attention de : Monsieur Greber Élaboré par : Cédric Peinado

Normes techniques 2011

Utilisation de l éditeur.

Devenez un véritable développeur web en 3 mois!

Les sites Internet dynamiques. contact : Patrick VINCENT pvincent@erasme.org

Sana Sellami. Licence Professionnelle SIL

FORMATION / CREATION DE SITE WEB / 4 JOURNEES Sessions Octobre 2006

Initiation à html et à la création d'un site web

creer votre site internet en html/css

Introduction à Expression Web 2

mon site web via WordPress

Magento. Magento. Réussir son site e-commerce. Réussir son site e-commerce BLANCHARD. Préface de Sébastien L e p e r s

< Atelier 1 /> Démarrer une application web

CREATION d UN SITE WEB (INTRODUCTION)

Formation Webmaster : Création de site Web Initiation + Approfondissement

RESPONSIVE WEB DESIGN

Le logiciel de création de site internet IZISPOT est un outil très puissant et qui est assez simple après quelques temps d utilisation.

LANGAGUE JAVA. Public Développeurs souhaitant étendre leur panel de langages de programmation

SUPPORT DE COURS / HTML

INTRODUCTION AU CMS MODX

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Autour du web. Une introduction technique Première partie : HTML. Georges-André SILBER Centre de recherche en informatique MINES ParisTech

<Créer un site Web. avec/> Suzanne Harvey

3. RÉALISATION ET QUALIFICATION D UN PROTOTYPE 3.1 Réalisation d un prototype CRÉATION D UNE PAGE WEB STATIQUE AU FORMAT HTML

Publier dans la Base Documentaire

Groupe Eyrolles, 2003, ISBN : X

COMMENT PUBLIER SUR ARIANE?

Spétechs Mobile. Octobre 2013

INFORMATIQUE & WEB. PARCOURS CERTIFICAT PROFESSIONNEL Programmation de sites Web. 1 an 7 MODULES. Code du diplôme : CP09

Intégrateur Web HTML5 CSS3

145A, avenue de Port Royal, Bonaventure (Québec) G0C 1E0 Sans frais :

Langage HTML (2 partie) <HyperText Markup Language> <tv>lt La Salle Avignon BTS IRIS</tv>

Echosgraphik. Ce document sert uniquement à vous donner une vision sur ma manière de travailler et d appréhender un projet

Publier un Carnet Blanc

Formation : WEbMaster

Technologies du Web. Créer et héberger un site Web. Pierre Senellart. Page 1 / 26 Licence de droits d usage

FileMaker Server 11. Publication Web personnalisée avec XML et XSLT

Spétechs Mobile. D e r n i è r e m i s e à j o u r : a o û t 2014

Bureautique Initiation Excel-Powerpoint

KompoZer. Composition du site : _ une page d'accueil : index.html. _ une page pour la théorie : theorie.html. _ une page pour les photos : photos.

Créer un site Web : mode d emploi Sous SPIP, avec le squelette «établissement» de l académie de Versailles

1. La notion de cascade

Module BD et sites WEB

Auteur LARDOUX Guillaume Contact Année 2014 DEVELOPPEMENT MOBILE AVEC CORDOVA

Introduction à HTML5, CSS3 et au responsive web design

les techniques d'extraction, les formulaires et intégration dans un site WEB

WEB & DÉVELOPPEMENT LES BASES DU WEB LE LANGAGE HTML FEUILLES DE STYLES CSS HISTORIQUE D INTERNET ET DU WEB LES DIFFÉRENTS LANGAGES

Media queries : gérer différentes zones de visualisation

NFA016 : Introduction. Pour naviguer sur le Web, il faut : Naviguer: dialoguer avec un serveur web

1. La plate-forme LAMP

SII Stage d informatique pour l ingénieur

Optimiser les s marketing Les points essentiels

25 mars. Tutoriel sur Laravel. Préparé par : Lydiane Beaulne-Bélisle. Ceci est un tutorial qui montre comment débuter avec le Framework PHP Laravel.

Stage «Créer et animer un site Web en équipe»

Diffuser un contenu sur Internet : notions de base... 13

FileMaker Server 12. publication Web personnalisée avec XML

BES WEBDEVELOPER ACTIVITÉ RÔLE

HTML5 et CSS3 pour des sites Responsive Web Design

02/02/2011. test 1. Communication visuelle & web. Pao. Principes fondamentaux. Les six principes de base. La mise en page. Module sur trois journées

Programmation Web. Madalina Croitoru IUT Montpellier

RESUME DE CARRIERE. Alice JULIENNE. 23 ans Nationalité Française Développeur Web Front-End. Compétences

Internet. DNS World Wide Web. Divers. Mécanismes de base Exécution d'applications sur le web. Proxy, fire-wall

RESPONSIVE DESIGN : Comment offrir à vos sites une adaptabilité parfaite?

Théorie : internet, comment ça marche?

Spétechs Mobile. D e r n i è r e m i s e à j o u r : s e p t e m b r e

TP JAVASCRIPT OMI4 TP5 SRC

Services bancaires par Internet aux entreprises. Guide pratique pour : Rapports de solde Version

La mémorisation des mots de passe dans les navigateurs web modernes

{less} Guide de démarrage

MAILING KOMPOZER... 2 CREEZ UNE PAGE... 2 FORMAT DE LA PAGE... 2 AJOUTER DU TEXTE SUR UNE PAGE... 4

Utiliser un CMS: Wordpress

Sommaire : Pourquoi créer un site web? Qu est-ce qu un site Web? Les différents types de sites. Quelles solutions peuvent être employées?

Programmation Web. Introduction

Tapez le titre de la page «BASTIA ville méditerranéenne», puis allez deux fois à la ligne à l aide de la touche Entrée.

UN SITE WEB RESPONSIVE EN UNE HEURE?

Transcription:

Programmation Web Coté serveur : HTML, CSS, PHP, PDO Rémy Malgouyres LIMOS UMR 6158, IUT, département info Université Clermont 1 B.P. 86 63172 AUBIERE cedex http ://www.malgouyres.org/

Table des matières Table des matières 1 I Documents Hypertexte HTML/CSS 4 1 Pages web statiques HTML5 7 1.1 HTML, la norme et son évolution......................... 7 1.2 Validation W3C et tests de portabilité...................... 7 1.3 Structure d un document HTML ou XHTML................... 9 1.4 Premier document HTML5............................ 10 1.5 Structure du texte en HTML........................... 11 1.6 Mise en forme du texte HTML : styles CSS................... 12 1.7 Formes d inclusion de styles CSS......................... 17 1.8 Liens......................................... 19 1.9 Tableaux....................................... 22 1.10 Insertion d images................................. 27 1.11 Figures et sous-figures avec légende........................ 29 1.12 Caractères spéciaux................................. 31 2 Styles CSS et mise en page 32 2.1 Éléments HTML de type block et inline...................... 32 2.2 Distinguer des parties dans un document : balise div.............. 36 2.3 Imbrication des balises et CSS........................... 37 2.4 Arborescence de balises et CSS.......................... 39 2.5 Classes CSS..................................... 41 2.6 Sélecteurs de style CSS par ID........................... 47 2.7 Marges et bordures................................. 51 2.8 Positionnement absolu............................... 52 2.9 Positionnement relatif............................... 54 2.10 Structuration d une page en HTML5....................... 56 2.11 Exemples de mise en page............................. 58 2.12 CSS adaptatifs : Media Queries.......................... 64 II Bases du langage PHP 67 3 PHP procédural 71 1

TABLE DES MATIÈRES 3.1 Notion de CGI................................... 71 3.2 Générer du code HTML avec un CGI en PHP.................. 72 3.3 Exemple de fonction en PHP........................... 73 3.4 Inclure un fichier PHP dans un autre....................... 74 3.5 Arithmétique : types int et float........................ 75 3.6 Tableaux indexés : avec une clé de type int................... 76 3.7 Tableaux associatifs : avec une clé de type String................ 77 3.8 Passage de paramètre à un script PHP...................... 79 3.9 Variables Locales ou Globales, Références.................... 82 4 Les classes en PHP 85 4.1 Exemples de classes PHP............................. 86 4.2 Validation en entrée et gestion d une exception................. 94 4.3 Classe Employe héritant de la classe Personne.................. 103 III Formulaires et Filtrage des Données Utilisateur 108 5 Formulaires HTML/PHP 111 5.1 Formulaires HTML................................. 111 5.2 Exemple de style CSS pour formulaire...................... 112 5.3 Validation pour la sécurité : Appel de filter_var................ 118 5.4 Appel des vues................................... 119 5.5 Tableaux $_POST $_GET $_REQUEST........................ 121 5.6 Formulaires dynamiques an javascript....................... 123 6 Injection, Filtrage, Expressions Régulières 126 6.1 Injections HTML et échappement......................... 126 6.2 Injections SQL................................... 133 6.3 La fonction filter_var.............................. 139 6.4 Expressions régulières............................... 143 7 Formulaires PHP/HTML, filtrage, exceptions 145 7.1 La Classe Adresse................................. 145 7.2 Filtrage des attributs................................ 147 7.3 Fabrique d Adresse................................. 151 7.4 Génération de formulaires et classe AdresseFormView.............. 152 7.5 Enchaînement de la saisie à la vue........................ 158 7.6 Les Vues....................................... 160 7.7 Modification d une Adresse............................ 162 IV Persistance 163 8 Cookies 169 8.1 Création d un cookie................................ 169 8.2 Récupération d un cookie.............................. 171 8.3 Suppression d un cookie.............................. 172 2

TABLE DES MATIÈRES 8.4 Mise à jour d un cookie............................... 173 9 Sessions 174 9.1 Concept de Session et Problèmes de Sécurité................... 174 9.2 Créer une session.................................. 175 9.3 Création d une session commune à tous les utilisateurs............. 175 9.4 Durée et SID d une session............................. 176 9.5 Destruction d une Session............................. 177 9.6 Exemple de Session avec SID aléatoire transmis par GET........... 178 9.7 Exemple de Session avec SID aléatoire transmis par COOKIE......... 180 9.8 Exemple Politique de Sécurité en Matière de Session.............. 182 10 Bases de Données et PHP Data Objects 191 10.1 Créer un Base de Données dans phpmyadmin.................. 191 10.2 Initiation à PDO : connexion, query, destruction................ 195 10.3 Requêtes Préparées................................. 202 10.4 Classe Singleton de Connexion à une Base de Données............. 206 V Conception d Architectures Avancées 210 11 Analyse Fonctionnelle 213 11.1 Storyboards..................................... 213 11.2 Diagrammes de Cas d Utilisations......................... 214 12 Organisation des Répertoires et Configuration 215 12.1 Organisation des Répertoires............................ 215 12.2 Autoload....................................... 216 12.3 La classe Config : éviter les URL en dûr..................... 217 13 Architectures MVC et DAL 220 13.1 Le Contrôleur.................................... 220 13.2 Le Modèle...................................... 223 13.3 Les Vues....................................... 226 13.4 La Gateway pour les instances d Adresse.................... 227 14 Utilisateurs et Front Controller 231 14.1 Storyboards..................................... 231 14.2 Diagramme de Cas d Utilisation.......................... 232 14.3 Le Front-Controller................................. 232 14.4 Gestion de l Authentification............................ 237 3

Première partie Documents Hypertexte HTML/CSS 4

Table of Contents 1 Pages web statiques HTML5 7 1.1 HTML, la norme et son évolution......................... 7 1.2 Validation W3C et tests de portabilité...................... 7 1.2.1 Validateur W3C.............................. 7 1.2.2 Tests de portabilité............................. 8 1.3 Structure d un document HTML ou XHTML................... 9 1.4 Premier document HTML5............................ 10 1.5 Structure du texte en HTML........................... 11 1.6 Mise en forme du texte HTML : styles CSS................... 12 1.7 Formes d inclusion de styles CSS......................... 17 1.8 Liens......................................... 19 1.9 Tableaux....................................... 22 1.10 Insertion d images................................. 27 1.11 Figures et sous-figures avec légende........................ 29 1.12 Caractères spéciaux................................. 31 2 Styles CSS et mise en page 32 2.1 Éléments HTML de type block et inline...................... 32 2.1.1 Éléments blocks............................... 32 2.1.2 Éléments inline............................... 33 2.1.3 Le flux et la propriété CSS display................... 35 2.2 Distinguer des parties dans un document : balise div.............. 36 2.3 Imbrication des balises et CSS........................... 37 2.4 Arborescence de balises et CSS.......................... 39 2.5 Classes CSS..................................... 41 2.6 Sélecteurs de style CSS par ID........................... 47 2.7 Marges et bordures................................. 51

TABLE OF CONTENTS 2.8 Positionnement absolu............................... 52 2.9 Positionnement relatif............................... 54 2.10 Structuration d une page en HTML5....................... 56 2.11 Exemples de mise en page............................. 58 2.12 CSS adaptatifs : Media Queries.......................... 64 6

Chapitre 1 Pages web statiques HTML5 1.1 HTML, la norme et son évolution Le langage HTML, ou Hyper Text Markup Language, permet de décrire et de mettre en forme des documents variés, depuis du simple texte jusqu à des documents multimédia riches avec la définition d HTML 5. Une page HTML est en général destinée à être publiée sur le World Wide Web, où toutes sortes de gens utilisent toutes sortes de navigateurs qui fonctionnent sous sdifférentes platteformes (Mac OS, ipad, Linux, Androïd, MS Windows, etc. pour citer les plus courants). Pour que celà fonctionne, il a été nécessaire de définir un standard pour le langage HTML. C est le standard du World Wide Web Consortium, ou W3C. A noter le rôle déterminant qu a joué la libération du code source du navigateur Netscape par la société Netscape Communications Corporation pour que la pluralité des acteurs n évitent que les standards du web soient de fait propriétaire. 1.2 Validation W3C et tests de portabilité 1.2.1 Validateur W3C Lorsqu on écrit une page web en HTML, pour être sûr que celle-ci soit correctement interprétée et affichée par tous les navigateurs qui supportent correctement la norme, il faut valider cette page pour s assurer qu elle est conforme à la norme. Le processus est similaire à l analyse de la syntaxe d un programme par un compilateur et peut se faire en ligne en uploadant le fichier ou en donnant son URL publique. Certains éditeurs proposent une validation interne ou même à la volée. Les scripts en PHP et autre ne peuvent pas être directement validés car ce sont en fait des programmes. Par contre, leur sortie (ce qu ils affichent) doit être du HTML conforme à la norme. 7

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web (a) L upload d un fichier HTML (b) Résultat correct sur le validateur W3C Figure 1.1 : Le processus de validation d un fichier HTML sur le validateur W3C 1.2.2 Tests de portabilité Même pour un document validé, les navigateurs n ont pas tous la même implémentation du moteur d analyse et de rendu du document, notamment en ce qui concerne les styles par défaut. Pour cette raison, il est indispensable avant de publier un site web, de le tester sur le plus possible de plate-formes et de navigateurs. Ceci peut être simplifié par des outils comme VirtualBox (mais il en existe d autres...), qui permettent en virtualisant de faire tourner simultanément plusieurs systèmes d exploitation sur un même ordinateur. Par exemple, sur la figure 1.2, on voit un exemples où l affichage de la page est testé simultanément avec Internet Explorer et Safari sous Windows, Firefox, Chrome et Opera sous linux et Chrome sous tablette et smartphone Android. Le système Windows tourne en virtuel dans VirtualBox (disponible dans la logitèque d Ubuntu). et le serveur Web (Apache) est instalé en local sous Ubuntu. Les systèmes Windows et Ubuntu sont connectés par un réseau local virtuel interne au système hôte, en l hoccurence Ubuntu. Notons que les navigateurs sur smartphones sont particulièrement capricieux car ils n ont pas les ressources pour implémenter toutes les variantes, surtout sur du code non validé. 8

Chapitre 1 : Pages web statiques HTML5 Figure 1.2 : Le processus de test de portabilité avec VirtualBox. 1.3 Structure d un document HTML ou XHTML Un document HTML ou XHTML doit comporter : 1. Sur la première ligne qui ne soit pas constituée d un commentaire : le doctype qui spécifie le type de document (HTML, XHTML et version). Ceci permet que le navigateur puisse supporter et interpréter plusieurs formats de documents. 2. Une balise de début de description de document <html [+attributs]>. 3. Un en-tête compris dans une balise <head>...</head>. 4. Dans le header, une spécification de l encoding ou charset : ISO-8859-1, latin1, et maintenant systématiquement utf-8. Ce dernier est d ailleurs le défaut utilisé lorsque l encoding n est pas spécifié. 5. Dans le header, de manière optionnelle, une description du style de document (couleurs, polices, tailles, etc.) au format CSS. 6. Un corps du document dans une balise <body>...</body>. 9

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web Par exemple, le document Hello World! en XHTML 1.0 strict se compose comme suit : exemples/chapitrehtml/ex01_helloworldxhtml.html 1 <!DOCTYPE html PUBLIC //W3C//DTD XHTML 1. 0 S t r i c t //EN 2 http ://www. w3. org /TR/xhtml1/DTD/xhtml1 s t r i c t. dtd > 3 <! D é c l a r a t i o n du debut d un document HTML avec l a langue : > 4 <html xml :lang= en lang= en xmlns= http ://www. w3. org /1999/ xhtml > 5 <head> <! début de l en t ê t e HTML > 6 <! D é c l a r a t i o n du type d encodage > 7 <meta http equiv= Content Type content= t e x t /html ; c h a r s e t=utf 8 /> 8 <! T i t r e de l a page dans l a f e n ê t r e ou l o n g l e t du n a v i g a t e u r > 9 <t i t l e>my f i r s t XHTML 1. 0 S t r i c t document</ t i t l e> 10 </head> 11 <body> 12 <p>hello world!</p> 13 </body> 14 </html> Le document Hello World! en HTML5 se compose comme suit : exemples/chapitrehtml/ex02_helloworldhtml5.html 1 <! doctype html> 2 <! D e c l a r a t i o n du debut d un document HTML avec l a langue : > 3 <html lang= f r > 4 <head> 5 <meta charset= UTF 8 /> 6 <! D é c l a r a t i o n du type d encodage > 7 <! T i t r e de l a page dans l a f e n ê t r e ou l o n g l e t du n a v i g a t e u r > 8 <t i t l e>my f i r s t HTML 5 document</ t i t l e> 9 </head> 10 <body> 11 <p> 12 Hello world! 13 </p> 14 </body> 15 </html> Le XHTML 1.0 strict possède une syntaxe plus stricte que ses prédécesseurs, simplifiant le travail des navigateurs et des moteurs de recherche. En particulier, toutes les balises sont en minuscules et il y a obligation de fermer les balises, quitte à mettre une balise auto-fermante comme <br/>. La norme HTML5 réintroduit un certain laxisme au niveau de la syntaxe mais il est préférable pour la lisibilité du code de respecter la syntaxe XHTML 1.0 strict dans une page HTML5. 1.4 Premier document HTML5 exemples/chapitrehtml/ex03_corps_balises.html 1 <! doctype html> 2 <! D e c l a r a t i o n du debut d un document HTML > 3 <html lang= f r > 4 <! Voici l en t e t e qui d e c l a r e l e s p r o p r i e t e s g e n e r a l e s de l a page > 5 <head> <! debut de l en t e t e HTML > 10

Chapitre 1 : Pages web statiques HTML5 6 <! d e c l a r a t i o n de l encodage pour l e s a c c e n t s... > 7 <meta charset= UTF 8 /> 8 <! T i t r e de l a page ( a u s s i t i t r e de l a f e n ê t r e du n a v i g a t e u r ) > 9 <t i t l e>premières b a l i s e s HTML</ t i t l e> 10 </head> 11 <body> <! début du corps HTML > 12 <h1>mon premier f i c h i e r HTML</h1> 13 <p> <! Nouveau paragraphe ( saut de l i g n e ) > 14 Ceci e s t mon premier f i c h i e r HTML. <br/> <! à l a l i g n e > 15 Le body r e p r é s e n t e l e corps du document, 16 dans l e q u e l on met l e t e x t e à a f f i c h e r. 17 </p> <! Fin de paragraphe > 18 <p> 19 Le header ( b a l i s e head ) d é f i n i t l e s p r o p r i é t é s g l o b a l e s du document, 20 t e l l e s que l encodage, l e t i t r e de l a page et des éléments de s t y l e. 21 </p> 22 </body> <! f i n du corps HTML > 23 </html> <! f i n du code HTML > 1.5 Structure du texte en HTML exemples/chapitrehtml/ex04_structure_document.html 1 <! doctype html> 2 <! D e c l a r a t i o n du debut d un document HTML > 3 <html lang= f r > 4 <! Voici l en t e t e qui d e c l a r e l e s p r o p r i e t e s g e n e r a l e s de l a page > 5 <head> <! debut de l en t e t e HTML > 6 <! d e c l a r a t i o n de l encodage pour l e s a c c e n t s... > 7 <meta charset= UTF 8 /> 8 <! T i t r e de l a page ( a u s s i t i t r e de l a f e n ê t r e du n a v i g a t e u r ) > 9 <t i t l e>s t r u c t u r e d un document HTML</ t i t l e> 10 </head> 11 <body> <! début du corps HTML > 11

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 12 <h1>s t r u c t u r e d un document HTML</h1> 13 <p> 14 HTML e s t un langage de d e s c r i p t i o n de documents non WISIWIG, 15 c e s t à d i r e que l e f i c h i e r source ne ressemble pas vraiment 16 au document t e l que l u t i l i s a t e u r f i n a l l e verra.<br/> 17 WISIWIG : <em>what You See I s What You Get</em>. 18 </p> 19 <p> 20 En HTML, l e s <em>b a l i s e s</em>, qui sont encadrées par des &l t ; et &gt ;, 21 <strong>d é f i n i s s e n t l a s t r u c t u r e du document</strong> en c a r a c t é r i s a n t d i f f é r e n t e s 22 p a r t i e s du document ( t i t r e s, paragraphes, tableaux, élément important, 23 l i s t e à puces, images, o b j e t s de type vidéo f l a s h, multimédia pour <em> HTML5</em>, e t c. 24 </p> 25 <p> 26 Par exemple, l a b a l i s e &l t ; p&gt ; &l t ; / p&gt ; d é l i m i t e un 27 paragraphe. Un couple de b a l i s e s avec du t e x t e antre l e s b a l i s e s s a p p e l l e un 28 <em>élément</em>. 29 </p> 30 </body> <! f i n du corps HTML > 31 </html> <! f i n du code HTML > 1.6 Mise en forme du texte HTML : styles CSS exemples/chapitrehtml/ex05_mise_en_forme_locale.html 1 <! doctype html> 2 <! D e c l a r a t i o n du debut d un document HTML > 3 <html lang= f r > 4 <! Voici l en t e t e qui d e c l a r e l e s p r o p r i e t e s g e n e r a l e s de l a page > 5 <head> <! debut de l en t e t e HTML > 6 <meta charset= UTF 8 /> <! D e c l a r a t i o n du type d encodage > 7 <! T i t r e de l a page ( a u s s i t i t r e de l a f e n ê t r e du n a v i g a t e u r ) > 8 <t i t l e>s t y l e CSS HTML locaux</ t i t l e> 12

Chapitre 1 : Pages web statiques HTML5 9 </head> 10 <body style= font family : A r i a l Verdana ; font s i z e : 125% ; width : 800px ; > <! début du corps HTML > 11 <h1>mise en forme CSS l o c a l e</h1> 12 <p style= text a l i g n : j u s t i f y ; > 13 Le s t y l e <em>css</em> des éléments permet l a mise en forme ( p o s i t i o n, t a i l l e, couleur, p o l i c e, bordure,... ) 14 d un élément et de son contenu. 15 </p> 16 <p style= text a l i g n : j u s t i f y ; > 17 Un t e x t e j u s t i f i é e s t un t e x t e dont l e bord d r o i t e s t a l i g n é avec l e bord d r o i t de l a 18 b o î t e englobant l e t e x t e. La p r o p r i é t é <em>css</em> <code>text a l i g n</code > permet de 19 g é r e r l alignement ( j u s t i f i é, d r o i t, gauche, c e n t r é ) du t e x t e dans un élément. 20 </p> 21 <p style= text a l i g n :center > 22 La p r o p r i é t é <code>font weight</code> permet de mettre des <span style= font weight :bold ; >éléments en gras</span> 23 ou <span style= font weight :bolder ; >en t r è s gras</span>. 24 <br/> 25 La p r o p r i é t é <code>font v a r i a n t</code> permet de mettre des <span style= font v a r i a n t :small caps ; >éléments en p e t i t e s c a p i t a l e s</span>. 26 <br/> 27 La p r o p r i é t é <code>font s t y l e</code> permet de mettre des <span style= font s t y l e : i t a l i c ; >éléments en i t a l i q u e s</span> 28 <br/> 29 <strong>ces p r o p r i é t é s ne doivent pas ê t r e confondues avec l e s b a l i s e s &l t ; strong&gt ;, &l t ; em&gt ;, e t c. qui d é f i n i s s e n t 30 l a s t r u c t u r e du document ( éléments importants, à s o u l i g n e r, e t c... )</strong> 31 </p> 13

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 32 </body> <! f i n du corps HTML > 33 </html> <! f i n du code HTML > exemples/chapitrehtml/ex06_mise_en_forme_globale.html 1 <! doctype html> 2 <! D e c l a r a t i o n du debut d un document HTML > 3 <html lang= f r > 4 <! Voici l en t e t e qui d e c l a r e l e s p r o p r i e t e s g e n e r a l e s de l a page > 5 <head> 6 <meta charset= utf 8 /> <! D e c l a r a t i o n du type d encodage > 7 <style> 8 /* D é f i n i t i o n du s t y l e */ 9 body { 10 font family : A r i a l Verdana ; 11 font s i z e : 125% ; 12 width : 800px ; 13 } 14 p { 15 text a l i g n : j u s t i f y ; 16 }/* mise en forme des paragraphes */ 17 /* mise en forme du t i t r e */ 18 h1 { 19 text a l i g n : c e n t e r ; 20 font s i z e : 150% ; 21 } 14

Chapitre 1 : Pages web statiques HTML5 22 /* mise en forme élémentt important l e s 120% sont r e l a t i f au contexte */ 23 strong { 24 font v a r i a n t : small caps ; 25 font s i z e : 120% ; 26 } 27 </ style> 28 <t i t l e>s t y l e s CSS globaux</ t i t l e> 29 </head> 30 <body> <! début du corps HTML > 31 <h1>mise en forme CSS g l o b a l e</h1> 32 <p> 33 I l peut ê t r e f a s t i d i e u x de g é r e r à chaque b a l i s e l a s pect du t e x t e ou l e graphisme. 34 De plus, une d é f i n i t i o n g l o b a l e du s t y l e de l a page e s t plus modulaire ( un s e u l e n d r o i t 35 à m o d i f i e r pour changer tous l e s s t y l e s des b a l i s e s d un même type. 36 Pour c e t t e raison, <strong>on peut d é f i n i r l e s t y l e <em>css</em> globalement</strong> via une b a l i s e &l t ; s t y l e&gt ; 37 au niveau de l en t ê t e (& l t ; head&gt ; ). 38 </p> 39 <p> 40 Si l on s o u h a i t e changer l a s pect des éléments s t r u c t u r e l s, par exemple 41 dont l importance e s t s o u l i g n é e avec 42 &l t ; strong&gt ; &l t ; / strong&gt ;, 43 on l e d é f i n i t au niveau du s t y l e g l o b a l. 44 </p> 45 <p> 46 On peut a i n s i d é f i n i r l e s s t y l e s typographiques ( fonte,... ) et l a mise 47 en page ( alignement à gauche, à d r o i t e, j u s t i f i é, e t c. ) du t e x t e 48 dans l e s d i f f é r e n t s éléments d une page HTML au niveau de l en t ê t e. 49 </p> 50 <p> 51 Enfin, s i l on s o u h a i t e changer l e s t y l e localement pour d é c o r e r 52 sans qu i l s a g i s s e d un élément s t r u c t u r e l, on peut <strong style= font v a r i a n t :normal ; >s u r c h a r g e r l e s t y l e g l o b a l</strong> 53 localement. 54 On peut a u s s i u t i l i s e r<span style= font family :Comic Sans MS; font s i z e :150% > l a b a l i s e g é nérique &l t ; span&gt ;& l t ; / span&gt ;. </span> 55 pour m o d i f i e r localement l a s p ect du t e x t e sans m o d i f i e r l a s t r u c t u r e. 56 </p> 57 </body> <! f i n du corps HTML > 58 </html> <! f i n du code HTML > exemples/chapitrehtml/ex07_couleurs.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <style> 6 /* D é f i n i t i o n du s t y l e */ 7 body { 8 font s i z e : 125% ; 9 background c o l o r : #c0c0c0 ; /* f o n t e par défaut */ 10 c o l o r : #333333 ; 11 font weight : bold 15

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 12 } 13 p { 14 text a l i g n : j u s t i f y ; 15 }/* mise en forme des paragraphes */ 16 /* mise en forme du t i t r e */ 17 h1 { 18 text a l i g n : c e n t e r ; 19 font s i z e : 150% ; 20 background c o l o r : #ddd ; 21 border s t y l e : s o l i d ; 22 border c o l o r : black ; 23 border width : 2px ; 24 } 25 /* mise en forme élémentt important l e s 120% sont r e l a t i f au contexte */ 26 strong { 27 background c o l o r : white ; 28 c o l o r : black ; 29 font weight : bolder ; 30 } 31 </ style> 32 <t i t l e>d é f i n i t i o n des c o u l e u r s</ t i t l e> 33 </head> 34 <body> 35 <h1> D é f i n i t i o n des c o u l e u r s dans dans un s t y l e CSS </h1> 36 <p> 37 Dans l e s t y l e CSS, on peut a u s s i d é f i n i r l e s c o u l e u r s des d i f f é r e n t s 38 éléments. 39 </p> 40 <p> 41 Les s i t e s web ont en g é n é r a l une <strong>c h a r t e graphique</strong> qui 42 comprend un p e t i t nombre de c o u l e u r s bien harmonisées qui symbolisent bien 43 l e n t i t é que r e p r é s e n t e l e s i t e. 44 </p> 45 <p> 46 Dans l e s e n t r e p r i s e s, ce sont souvent des personnes d i f f é r e n t e s qui 47 s occupent du s t y l e CSS ou qui s occupent du contenu et des f o n c t i o n a l i t é s 48 du s i t e. 49 </p> 16

Chapitre 1 : Pages web statiques HTML5 50 </body> 51 </html> 1.7 Formes d inclusion de styles CSS Il y a essentiellement 3 manières de modifier le style graphique des différents éléments d une page HTML en utilisant CSS : 1. Au niveau des balises HTML avec l option style="..." (style CSS local) ; 2. Au niveau du header de la page HTML avec la balise <style type="text/css"> (style CSS global) ; 3. En incluant une feuille de style qui se trouve dans un fichier.css séparée avec la balise <link/> au niveau du header HTML (style CSS global pouvant être inclus dans plusieurs pages d un même site) : <link rel="stylesheet" href="./my_style.css" /> Cela permet de définir son style CSS globalement pour tout un site, de manière que toutes les pages aient le même style graphique. Du fait que le style CSS est défini à un seul endroit, la maintenance est plus facile : il n y a qu un seul endroit à changer pour modifier l aspect de tout le site. 4. En ajoutant une feuille de style complémentaire au niveau du header HTML avec la directive CSS import url (style CSS global additionnel pouvant être inclus dans plusieurs pages d un même site) : <style> @import url(./my_extra_style.css); </style> Cela permet d ajouter plusieurs feuilles de style à une même page, ce qui augmente la souplesse de l organisation des styles CSS. Pour le dernier exemple (sur les couleurs) de la partie 1.6, on peut par exemple obtenir la même chose en incluant le style CSS dans une feuille de style séparée : exemples/chapitrehtml/ex08_css_stylesheet_couleur.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>f e u i l l e s de S t y l e <i>css</ i></ t i t l e> 7 </head> 8 <body> 9 <h1> Créer une f e u i l l e de s t y l e CSS </h1> 10 <p> 17

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 11 Le s t y l e <i>css</ i> peut ê t r e d é f i n i dans un f i c h i e r <code>. c s s</code> séparé 12 du f i c h i e r <i>html</ i>. 13 </p> 14 <p> 15 Celà permet d augmenter l a modularité du code d un s i t e web car 16 l e s t y l e <i>css</ i> de t o u t e s l e s pages d un même s i t e peut ê t r e 17 d é f i n i à un s e u l e n d r o i t. 18 </p> 19 <p> 20 S i l f a u t changer l e s t y l e d un c e r t a i n type de b a l i s e s dans tout l e s i t e, 21 i l n y a qu un s e u l e n d r o i t à changer. ; ) 22 </p> 23 </body> 24 </html> exemples/chapitrehtml/mystyle.css 1 /* D é f i n i t i o n du s t y l e */ 2 body { 3 font family : A r i a l Verdana ; 4 font s i z e : 125% ; /* f a c t e u r d é v h e l l e sur l a t a i l l e g l o b a l e de l a p o l i c e */ 5 background c o l o r : #c0c0c0 ; /* f o n t e par défaut */ 6 c o l o r : #333333 ; /* c o u l e u r du t e x t e g l o b a l e */ 7 } 8 /* mise en forme des paragraphes */ 9 p { 10 text a l i g n : j u s t i f y ; /* t e x t e j u s t i f i é dans l e s paragraphes */ 11 } 12 /* mise en forme du t i t r e */ 13 h1 { 14 text a l i g n : c e n t e r ; /* t e x t e c e n t r é */ 15 font s i z e : 150% ; /* f a c t e u r d é c h e l l e de l a p o l i c e */ 16 background c o l o r : #ddd ; /* c o u l e u r du fond */ 17 border s t y l e : s o l i d ; /* bordure en t r a i t p l e i n */ 18 border c o l o r : black ; /* c o u l e u r du bord */ 19 border width : 2px ; /* é p a i s s e u r du bord */ 20 border r a d i u s : 10px ; /* bordure a r r o n d i e */ 21 } 22 /* mise en forme élémentt important l e s 120% sont r e l a t i f au contexte */ 18

Chapitre 1 : Pages web statiques HTML5 23 strong { 24 c o l o r : black ; /* t e x t e n o i r */ 25 font weight : bolder ; /* extra gras */ 26 font v a r i a n t : small caps ; /* p e t i t e s c a p i t a l e s */ 27 } Dans la suite ce ce chapitre, nous inclurons dans toutes les pages HTML la feuille de style de ce dernier exemple. 1.8 Liens exemples/chapitrehtml/ex09_liens.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>liens hypertexte</ t i t l e> 7 </head> 8 <body> 9 <! début du corps HTML > 10 <h1>liens hypertexte</h1> 11 <div> 12 <strong>on peut c r é e r d i f f é r e n t s types de l i e n s :</strong> 13 <ul> 14 <! l i s t e à puces > 15 < l i> 16 l i e n s hypertexte en r e l a t i f : <a href=. / ex_images. html >c l i q u e z i c i< /a>. 17 </ l i> 19

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 18 < l i> 19 l i e n s hypertexte en absolu : <a href= http ://www. remysprogwebtuto. org / exemples /html/ex_images. html > c l i q u e z i c i</a>. 20 </ l i> 21 < l i> 22 l i e n s v e r s une ancre v e r s un autre emplacement dans l a page : <a href= #monparagraphe >Voir l e deuxième par ag rap he</a> 23 </ l i> 24 </ ul> 25 </ div> 26 <p id= monparagraphe style= font s i z e : 150% ; font weight : b older ; > 27 Pour f a i r e des l i e n s v e r s l e s i t e même, i l vaut t o u j o u r s mieux 28 u t i l i s e r des l i e n s en r e l a t i f s car s i on déménage l e s i t e ( ou 29 s i on r écupère c e r t a i n e s c l a s s e s ), l e s l i e n s ne c a s s e n t pas. 30 ( à c o n d i t i o n de garder l a r b o r e s c e n c e des r é p e r t o i r e s t e l l e q u e l l e ) 31 <br/> 32 &Eacute ; v i t e z l e s chemins du genre : 33 <br/> 34 <code> 35 C :/ j e / tourne / pas / sur /un/ s e r v e u r / l i n u x. html </code> 36 </p> 37 </body> 38 <! f i n du corps HTML > 39 </html> 40 <! f i n du code HTML > 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> exemples/chapitrehtml/ex10_liens_mise_en_forme.html 20

Chapitre 1 : Pages web statiques HTML5 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 /* s t y l e par défaut des l i e n s */ 8 a : l i n k { 9 text d e c o r a t i o n : none ; 10 c o l o r : #00e ; /* bleu c l a i r */ 11 } 12 /* s t y l e des l i e n s v i s i t é s */ 13 a : v i s i t e d { 14 text d e c o r a t i o n : none ; 15 c o l o r : #c0c ;/* mauve */ 16 } 17 /* s t y l e des l i e n s v i s i t é s */ 18 a :hover { 19 text 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 é */ 20 c o l o r : #e40 ;/* rouge v i f */ 21 } 22 </ style> 23 <t i t l e>liens hypertexte ( 2 )</ t i t l e> 24 </head> 25 <body> 26 <! début du corps HTML > 27 <h1>mise en forme des l i e n s hypertexte</h1> 28 <div> 29 <strong>on peut c r é e r d i f f é r e n t s types de l i e n s :</strong> 30 <ul> 31 <! l i s t e à puces > 32 < l i> 33 l i e n s hypertexte en r e l a t i f : <a href=. / ex_images. html >c l i q u e z i c i< /a>. 34 </ l i> 35 < l i> 36 l i e n s hypertexte en absolu : <a href= http ://www. remysprogwebtuto. org / exemples /html/ex_images. html > c l i q u e z i c i</a>. 37 </ l i> 38 < l i> 39 l i e n s v e r s une ancre v e r s un autre emplacement dans l a page : <a href= #monparagraphe >Voir l e deuxième par ag rap he</a> 40 </ l i> 41 </ ul> 42 </ div> 43 <p id= monparagraphe style= font s i z e : 150% ; font weight : b older ; > 44 Pour f a i r e des l i e n s v e r s l e s i t e même, i l vaut t o u j o u r s mieux 45 u t i l i s e r des l i e n s en r e l a t i f s car s i on déménage l e s i t e ( ou 46 s i on r écupère c e r t a i n e s c l a s s e s ), l e s l i e n s ne c a s s e n t pas. 47 ( à c o n d i t i o n de garder l a r b o r e s c e n c e des r é p e r t o i r e s t e l l e q u e l l e ) 48 <br/> 49 &Eacute ; v i t e z l e s chemins du genre : 50 <br/> 51 <code> 52 C :/ j e / tourne / pas / sur /un/ s e r v e u r / l i n u x. html </code> 53 </p> 54 </body> 55 <! f i n du corps HTML > 56 </html> 57 <! f i n du code HTML > 21

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 1.9 Tableaux exemples/chapitrehtml/ex11_tableaux.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>tableaux en HTML</ t i t l e> 7 </head> 8 <body> 9 <! début du corps HTML > 10 <h1>tableaux en HTML 5</h1> 11 12 <p> 13 Voici une t a b l e avec l e s t y l e par défaut. Le rendu e s t un peu sommaire. 14 </p> 15 <table> 16 <caption> <! Légende ( t i t r e ) de l a table > 17 Exemple de t a b l e sans mise en forme 18 </ caption> 19 <tbody><! corps de l a table > 20 <tr><! n o u v e l l e l i g n e > 21 <td><! n o u v e l l e case > 22 Ceci e s t l a case<br/>d en haut à gauche 23 </ td> 24 <td><! n o u v e l l e case > 25 Ceci e s t l a case<br/>d en haut au m i l i e u 26 </ td> 27 <td><! n o u v e l l e case > 28 Ceci e s t l a case<br/>d en haut à d r o i t e 29 </ td> 30 </ tr> 31 <tr> <! n o u v e l l e l i g n e > 32 <td><! n o u v e l l e case > 33 Ceci e s t l a case<br/>d en bas à gauche 34 </ td> 35 <td><! n o u v e l l e case > 36 Ceci e s t l a case<br/>d en bas au m i l i e u 22

Chapitre 1 : Pages web statiques HTML5 37 </ td> 38 <td><! n o u v e l l e case > 39 Ceci e s t l a case<br/>d en bas à d r o i t e 40 </ td> 41 </ tr> 42 </tbody> 43 </ table> 44 </body><! f i n du corps HTML > 45 </html> 46 <! f i n du code HTML > exemples/chapitrehtml/ex12_tableaux_th.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>tableaux en HTML ( 2 )</ t i t l e> 7 </head> 8 <body> 9 <! début du corps HTML > 10 <h1>tableaux : en t ê t e de l i g n e s et de c o l o n n e s</h1> 11 12 <p> 13 Voici une t a b l e avec l e s t y l e par défaut et avec des en t ê l e ( t i t r e s ) de l i g n e et colonne. 14 </p> 15 <table> 16 <caption> 17 Exemple de t a b l e sans mise en forme 18 </ caption> 19 <thead><! En t ê t e de l a table > 20 <tr><! n o u v e l l e l i g n e ( l i g n e de t i t r e s de colonnes ) > 21 <th ></th><! case v i d e en haut à gauche > 22 <th ><strong>colonne 1</ strong></ th> 23 <th><strong>colonne 2</ strong></ th> 23

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 24 <th><strong>colonne 3</ strong></ th> 25 </ tr> 26 </thead> 27 <tbody><! corps de l a table > 28 <tr> <! n o u v e l l e l i g n e > 29 <th ><! t i t r e de l i g n e > 30 <strong>l i g n e&nbsp ; 1</strong> 31 </ th> 32 <td><! n o u v e l l e case > 33 Ceci e s t l a case<br/> 34 d en haut à gauche 35 </ td> 36 <td><! n o u v e l l e case > 37 Ceci e s t l a case<br/> 38 d en haut au m i l i e u 39 </ td> 40 <td><! n o u v e l l e case > 41 Ceci e s t l a case<br/> 42 d en haut à d r o i t e 43 </ td> 44 </ tr> 45 <tr><! n o u v e l l e l i g n e > 46 <th><! t i t r e de l i g n e > 47 <strong>l i g n e&nbsp ; 2</strong> 48 </ th> 49 <td><! n o u v e l l e case > 50 Ceci e s t l a case<br/> 51 d en bas à gauche 52 </ td> 53 <td><! n o u v e l l e case > 54 Ceci e s t l a case<br/> 55 d en bas au m i l i e u 56 </ td> 57 <td><! n o u v e l l e case > 58 Ceci e s t l a case<br/> 59 d en bas à d r o i t e 60 </ td> 61 </ tr> 62 </tbody> 63 </ table> 64 </body><! f i n du corps HTML > 65 </html> 66 <! f i n du code HTML > exemples/chapitrehtml/ex13_tableaux_mise_en_forme.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 @import u r l (. / ex13_stylesheet_tableaux. c s s ) ; 8 </ style> 9 <t i t l e>tableaux en HTML ( 3 )</ t i t l e> 10 </head> 24

Chapitre 1 : Pages web statiques HTML5 11 <body> 12 <! début du corps HTML > 13 <h1>tableaux : mise en forme</h1> 14 <table> 15 <caption> 16 Exemple de t a b l e avec mise en forme 17 </ caption> 18 <thead><! En t ê t e de l a table > 19 <tr><! n o u v e l l e l i g n e ( l i g n e de t i t r e s de colonnes ) > 20 <th style= border r a d i u s : 10px 0 0 0 ></th><! case v i d e en haut à gauche > 21 <th >Colonne 1</ th> 22 <th>colonne 2</ th> 23 <th style= border r a d i u s : 0 10px 0 0 >Colonne 3</th> 24 </ tr> 25 </thead> 26 <tbody><! corps de l a table > 27 <tr> <! n o u v e l l e l i g n e > 28 <th ><! t i t r e de l i g n e > 29 l i g n e&nbsp ; 1 30 </ th> 31 <td><! n o u v e l l e case > 32 Ceci e s t l a case<br/> 33 d en haut à gauche 34 </ td> 35 <td><! n o u v e l l e case > 36 Ceci e s t l a case<br/> 37 d en haut au m i l i e u 38 </ td> 39 <td><! n o u v e l l e case > 40 Ceci e s t l a case<br/> 41 d en haut à d r o i t e 42 </ td> 25

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 43 </ tr> 44 <tr><! n o u v e l l e l i g n e > 45 <th style= border r a d i u s : 0 0 0 10px ><! t i t r e de l i g n e > 46 l i g n e&nbsp ; 2 47 </ th> 48 <td><! n o u v e l l e case > 49 Ceci e s t l a case<br/> 50 d en bas à gauche 51 </ td> 52 <td><! n o u v e l l e case > 53 Ceci e s t l a case<br/> 54 d en bas au m i l i e u 55 </ td> 56 <td style= border r a d i u s : 0 0 10px 0 ><! n o u v e l l e case > 57 Ceci e s t l a case<br/> 58 d en bas à d r o i t e 59 </ td> 60 </ tr> 61 </tbody> 62 </ table> 63 <p> 64 <strong>remarque.</strong> La p r o p r i é t é <i>css</ i> <code>border r a d i u s</ code> permet de c r é e r 65 des a n g l e s a r r o n d i s pour l e s bordures. E l l e peut se d é f i n i r globalement pour l e s 4 a n g l e s 66 ( v o i r i c i l e s t y l e de l a b a l i s e &l t ; t a b l e&gt ; dans l a f e u i l l e de s t y l e des tableaux ) 67 du bord ou bien i n d i v i d u e l l e m e n t pour chaque angle ( v o i r i c i l e s s t y l e s locaux sur &l t ; th&gt ; et &l t ; td&gt ; ). 68 </p> 69 </body><! f i n du corps HTML > 70 </html> 71 <! f i n du code HTML > exemples/chapitrehtml/ex13_stylesheet_tableaux.css 1 /** FEUILLE DE STYLE COMPLÉMENTAIRE POUR MISE EN FORME DES TABLEAUX **/ 2 t a b l e { /* mise en forme des t a b l e s */ s 3 background c o l o r : #ddd ; /* fond g r i s */ 4 /* Paramètres ombrage : bas, d r o i t e, dégradé, c o u l e u r */ 5 box shadow : 8px 8px 22 px #000 ; /* Ombrage aux b ord s de l a t a b l e */ 6 border width : 3px ; /* é p a i s s e u r du t r a i t pour l e bord */ 7 border s t y l e : s o l i d ; /* bord en t r a i t continu */ 8 border c o l o r : black ; /* c o u l e u r du bord */ 9 border r a d i u s : 10px ; 10 } 11 caption { 12 c o l o r :red ; 13 font s i z e :130% ; 14 } 15 t r td { /* mise en forme des c e l l u l e s */ 16 border s t y l e : dashed ; /* bord en p o i n t i l l é s */ 17 border width : 2px ; /* é p a i s s e u r du t r a i t pour l e bord */ 18 border c o l o r : black ; /* c o u l e u r du bord */ 19 background c o l o r : white ;/* fond blanc */ 20 c o l o r : black ; /* c o u l e u r du t e x t e */ 26

Chapitre 1 : Pages web statiques HTML5 21 text a l i g n :center ; /* t e x t e c e n t r é */ 22 padding : 20px ; /* espace e n t r e l e t e x t e et l e bord de l a c e l l u l e */ 23 } 24 th {/* mise en forme des en t ê t e de l i g n e et colonne */ 25 border s t y l e : s o l i d ; /* bord en t r a i t continu */ 26 border width : 2px ; /* é p a i s s e u r du t r a i t pour l e bord */ 27 border c o l o r : black ; /* c o u l e u r du bord */ 28 text a l i g n :center ; /* t e x t e c e n t r é */ 29 font weight : bolder ; /* c a r a c t è r e s gras appuyé */ 30 c o l o r : black ; /* c o u l e u r du t e x t e */ 31 padding : 20px ; /* espace e n t r e l e t e x t e et l e bord de l a c e l l u l e */ 32 } 1.10 Insertion d images Avant d insérer des images dans un site web, des retouches de l image sont souvent nécessaires : 1. L usage veut que l on essaie de réduire le poids en octets de l image, soit en réduisant le nombre de pixels par redimensionnement de l image, soit en compressant plus fortement l images (paramètre d enregistrement JPEG ou PNG) lorsque c est possible sans dégrader la qualité. 2. Il faut souvent mettre un fond transparent pour l image si l on veut l incruster sur un fond en couleur. 3. Il faut parfois éclaircir ou foncer l image pour faire ressortir le contraste avec le texte incrusté dessus. 4. Il faut parfois retoucher les couleurs pour les adapter à la charte graphique. Le logiciel open-source GIMP permet de réaliser toutes ces opérations (facilement avec un peu d habitude). 27

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web exemples/chapitrehtml/ex14_images.html 1 <! doctype html> 2 <html lang= f r > 3 <head > 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>i n s e r t i o n d images en HTML</ t i t l e> 7 </head> 8 <body> <! début du corps HTML > 9 <h1>i n s e r t i o n d images en HTML</h1> 10 <p> 11 On i n s è r e l e s images avec l a b a l i s e &l t ; img&gt ;&nbsp ; :<br/> 12 </p> 13 <p style= text a l i g n : c e n t e r ; > 14 15 16 <img src=. / p i c /gimp. png alt= The GIMP Logo width= 150 17 style= v e r t i c a l a l i g n : middle ; 18 /> 19 <img src=. / p i c /3d gnu head_petit. png width= 150 20 alt= The GNU Logo 21 style= v e r t i c a l a l i g n : middle ; 22 /> 23 </p> 24 <p> 25 On peut r e t o u c h e r l e s images avec l e l o g i c i e l GNU GIMP<br/> 26 voyez l a 27 <a href=. / p i c / capture_gimp. png >capture d écran</a> montrant 28 comment diminuer l e nombre de p i x e l s d une image pour en diminuer l e 29 poids ( en megaoctets ). 30 </p> 31 32 </body> <! f i n du corps HTML > 33 </html> <! f i n du code HTML > 1 <! doctype html> 2 <html lang= f r > exemples/chapitrehtml/ex15_images_avec_click.html 28

Chapitre 1 : Pages web statiques HTML5 3 <head > 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>click sur une image en HTML</ t i t l e> 7 </head> 8 <body> <! début du corps HTML > 9 <h1>c l i c k s u r une image en HTML</h1> 10 <p> 11 On i n s è r e l e s images avec l a b a l i s e &l t ; img&gt ;&nbsp ; :<br/> 12 </p> 13 <p style= text a l i g n : c e n t e r ; > 14 Cliquez sur l e GNU pour l e v o i r en grand :<br/> 15 <img src=. / p i c /gimp. png alt= The GIMP Logo width= 150 16 style= v e r t i c a l a l i g n : middle ; 17 /> 18 <a href=. / p i c /3d gnu head_fond_transp. png > 19 <img src=. / p i c /3d gnu head_petit. png width= 150 20 alt= The GNU Logo 21 style= v e r t i c a l a l i g n : middle ; 22 /> 23 </a> 24 </p> 25 26 </body> <! f i n du corps HTML > 27 </html> <! f i n du code HTML > 1.11 Figures et sous-figures avec légende 1 <! doctype html> exemples/chapitrehtml/ex16_figure.html 29

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 2 <html lang= f r > 3 <head > 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>figures avec l é g e n d e s en HTML</ t i t l e> 7 </head> 8 <body> <! début du corps HTML > 9 <h1>figures avec légende en HTML</h1> 10 <p> 11 On c r é e une f i g u r e contenant une image avec l a b a l i s e &l t ; f i g u r e&gt ;&nbsp ; :<br/> 12 </p> 13 <f i g u r e style= text a l i g n :center ; > 14 <img src=. / p i c /gimp. png alt= The GIMP Logo width= 150 15 style= v e r t i c a l a l i g n : middle ; 16 /> 17 <f i g c a p t i o n>le Logo de <i>gimp</ i></ f i g c a p t i o n> 18 </ f i g u r e> 19 <f i g u r e style= text a l i g n :center ; > 20 <img src=. / p i c /3d gnu head_petit. png width= 150 21 alt= The GNU Logo 22 style= v e r t i c a l a l i g n : middle ; 23 /> 24 <f i g c a p t i o n>le Logo de <i>gnu</ i></ f i g c a p t i o n> 25 </ f i g u r e> 26 </body> <! f i n du corps HTML > 27 </html> <! f i n du code HTML > exemples/chapitrehtml/ex17_subfigure.html 1 <! doctype html> 2 <html lang= f r > 3 <head > 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 30

Chapitre 1 : Pages web statiques HTML5 6 <t i t l e>sous f i g u r e s avec l é g e n d e s en HTML</ t i t l e> 7 </head> 8 <body> <! début du corps HTML > 9 <h1>sous f i g u r e s avec l é g e n d e s en HTML</h1> 10 <p> 11 On c r é e des sous f i g u r e s en imbriquant b a l i s e s &l t ; f i g u r e&gt ;&nbsp ; :<br/> 12 On peut f a i r e en s o r t e que l e s f i g u r e s se mettent l une à c ôté de l autre avec 13 l a p r o p r i é t é <i>css</ i> <code> d i s p l a y : i n l i n e block ; </code>. 14 </p> 15 <f i g u r e style= text a l i g n :center ; > 16 <f i g u r e style= d i s p l a y : i n l i n e block ; > 17 <img src=. / p i c /gimp. png alt= The GIMP Logo width= 150 18 style= v e r t i c a l a l i g n : middle ; 19 /> 20 <f i g c a p t i o n><b>( a )</b> Le Logo de <i>gimp</ i></ f i g c a p t i o n> 21 </ f i g u r e> 22 <f i g u r e style= d i s p l a y : i n l i n e block ; > 23 <img src=. / p i c /3d gnu head_petit. png width= 150 24 alt= The GNU Logo 25 style= v e r t i c a l a l i g n : middle ; 26 /> 27 <f i g c a p t i o n><b>( b )</b> Le Logo de <i>gnu</ i></ f i g c a p t i o n> 28 </ f i g u r e> 29 <f i g c a p t i o n><b>figure 1.</b> Exemples de l o g o s de l o g i c i e l s ou l i c e n c e s Open Source</ f i g c a p t i o n> 30 </ f i g u r e> 31 </body> <! f i n du corps HTML > 32 </html> <! f i n du code HTML > 1.12 Caractères spéciaux De nos jours les accents dans certains langues comme le français sont pris en compte sans problème par le standard unicode UTF (par exemple UTF-8). On peut donc sans crainte taper des accents au clavier dans un éditeur HTML. Certains caractères spéciaux, tels que les caractères qui ont une signification particulière dans le langage HTML (comme < et >), doivent cependant être représentée par une séquence d échappement (commençant par & et terminant par ;). De nombreuses pages recenssent ces séquences d échappement sur le web : https://www.google.fr/#q=special+characters+html 31

Chapitre 2 Styles CSS et mise en page 2.1 Éléments HTML de type block et inline Avant d étudier plus avant les styles CSS, nous devons en dire un peu plus sur la structuration des pages HTML. On distingue en HTML dans catégories d éléments : les éléments de type block et les éléments de type inline. Ces deux sortes d éléments ne se comportent pas de la même manière quand à leur positionnement dans la page : 2.1.1 Éléments blocks exemples/chapitrecss/ex01_blocks.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>éléments de type block </ t i t l e> 32

Chapitre 2 : Styles CSS et mise en page 7 </head> 8 <body> 9 <h1>éléments de type block </h1> 10 <p> 11 I l e x i s t e en XHTML deux principaux types de b a l i s e s&nbsp ; : i n l i n e ou block. 12 </p> 13 <o l> 14 < l i> 15 <strong>exemples de b a l i s e s de type block&nbsp ; :</strong> 16 <br/> 17 <ol type= a > 18 < l i> 19 &l t ; p&gt ;&nbsp ; : nouveau paragraphe&#59 ; 20 </ l i> 21 < l i> 22 &l t ; t a b l e&gt ;&nbsp ; : tableau contenant des donnée&#59 ; 23 </ l i> 24 < l i> 25 &l t ; h1&gt ;&nbsp ;,..., &l t ; h6&gt ;&nbsp ; : d i f f é r e n t s 26 niveaux de t i t r e &#59 ; 27 </ l i> 28 < l i> 29 &l t ; dl&gt ;&nbsp ; : l i s t e de d é f i n i t i o n &#59 ; 30 </ l i> 31 < l i> 32 &l t ; ul&gt ;&nbsp ; : l i s t e non ordonnée&#59 ; 33 </ l i> 34 < l i> 35 &l t ; o l&gt ;&nbsp ; : l i s t e ordonnée&#59 ; 36 </ l i> 37 < l i> 38 &l t ; pre&gt ;&nbsp ; : i n s e r t i o n de code ( preformated t e x t ) verbatim 39 en p o l i c e t y p e w r i t e r avec r e s p e c t de l i n d e n t a t i o n. 40 </ l i> 41 </ ol> 42 Ces b a l i s e s changent l apparence de l e u r contenu et l e u r nature 43 au niveau s t r u c t u r e l et éventuellement l e u r f o n c t i o n dans l e cas du l i e n 44 ou de l image. 45 <br/> 46 En <i>html5</ i>, on trouve a u s s i l e s b a l i s e s sémantiques &l t ; header&gt ;, &l t ; f o o t e r&gt ;, &l t ; nav&gt ;, e t c. que nous verrons plus l o i n. 47 </ l i> 48 </ ol> 49 </body> 50 </html> Lors de l insertion d un élément de type block dans un document HTML, l élément va (par défaut) à la ligne : l élément est inséré aligné à gauche sous l élément précédent. 2.1.2 Éléments inline 1 <! doctype html> exemples/chapitrecss/ex02_inline.html 33

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>éléments de type i n l i n e </ t i t l e> 7 </head> 8 <body> 9 <h1>éléments de type i n l i n e </h1> 10 <ol s t a r t= 2 > 11 < l i><strong>exemples de b a l i s e s en l i g n e ou i n l i n e &nbsp ; :</strong></ l i> 12 <ol type= a > 13 < l i>&l t ; span&gt ;&nbsp ; : changement l o c a l de s t y l e&nbsp ;&#59 ;</ l i> 14 < l i>&l t ; a&gt ;&nbsp ; : l i e n hypertexte&#59 ;</ l i> 15 < l i>&l t ; strong&gt ;&nbsp ; : élément important&#59 ;</ l i> 16 < l i>&l t ; em&gt ;&nbsp ; : élément à s o u l i g n e r &#59 ;</ l i> 17 < l i>&l t ; q&gt ;&nbsp ; : c i t a t i o n c o u r t e&#59 ;</ l i> 18 < l i>&l t ; code&gt ;&nbsp ; : t e x t e en p o l i c e <code>t y p e w r i t e r</code></ l i> 19 </ ol> 20 Ces b a l i s e s changent l apparence de l e u r contenu mais pas l e u r nature 21 au niveau s t r u c t u r e l ni l e u r p o s i t i o n dans l e document. 22 </ l i> 23 </ ol> 24 <p> 25 Tout élément i n l i n e d o i t ê t r e contenu dans au moins un block. Le b l o c k s peuvent 26 ê t r e imbriqués mais l e s b l o c k s &l t ; p&gt ;&nbsp ; et l e s b l o c k s t i t r e 27 &l t ; h1&gt ;&nbsp ;,..., &l t ; h6&gt ;&nbsp ; ne peuvent c o n t e n i r d a u t r e s b l o c k s.< br/> 28 Un élément i n l i n e ne peut c o n t e n i r aucun élément de type block ; 29 </p> 30 </body> 31 </html> Lors de l insertion d un élément de type inline dans un document HTML, l élément s insère (par défaut) à la suite sur la même ligne : l élément est inséré aligné à la suite de l élément précédent sur la même ligne, ou à la ligne suivante s il n y a plus de place sur la ligne. 34

Chapitre 2 : Styles CSS et mise en page 2.1.3 Le flux et la propriété CSS display Le positionnement par défaut des éléments de type block ( à la ligne ) et inline ( à la suite sur la même ligne ) s appelle la position dans le flux. La propriété CSS display permet de modifier la place dans le flux des éléments : display: none : L élément est purement et simplement supprimé du flux, comme s il n existait pas. Cela permet de faire apparaître ou disparaître des éléments suivants des événements, par exemple des événements Javascript. On peut ainsi créer des popups, etc... display: inline : l élément est inséré comme s il s agissait d un élément de type inline ; display: block : l élément est inséré comme s il s agissait d un élément de type block ; display: inline-block : Ces éléments peuvent contenir d autres éléments de type block ou inline. Ils s insèrent dans le flux comme des éléments inline : à la suite sur la même ligne. exemples/chapitrecss/ex03_propriete_display.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>p r o p r i é t é d i s p l a y</ t i t l e> 7 </head> 8 <body> 9 <h1>p r o p r i é t é d i s p l a y</h1> 10 <p style= border s t y l e : groove ; d i s p l a y : i n l i n e block ; v e r t i c a l a l i g n : middle ; > 11 Ce premier paragraphe,<br/>avec un bord en t r a i t 3D, 12 <br/>e s t un paragraphe en i n l i n e block. 13 </p> 35

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 14 <p style= border s t y l e : dashed ; d i s p l a y : i n l i n e block ; v e r t i c a l a l i g n : middle ; > 15 Ce second paragraphe, <br/>avec un bord en t i r e t s, 16 <br/>e s t un paragraphe en i n l i n e bloc. 17 </p> 18 <p style= border s t y l e : s o l i d ; d i s p l a y : block ; v e r t i c a l a l i g n : middle ; > 19 Ce t r o i s i è m e paragraphe, <br/>avec un bord en t r a i t p l e i n, 20 <br/>e s t un paragraphe normal de type block. 21 </p> 22 <p style= border s t y l e : s o l i d ; d i s p l a y : none ; v e r t i c a l a l i g n : middle ; > 23 Ce quatrième paragraphe, <br/>avec un bord en t r a i t p l e i n, 24 <br/>e s t un paragraphe en d i s p l a y : none ( non a f f i c h é! ). 25 </p> 26 <p style= border s t y l e : dotted ; d i s p l a y : i n l i n e ; v e r t i c a l a l i g n : middle ; > 27 Ce cinquième paragraphe, <br/>avec un bord en p o i n t i l l é s, 28 <br/>e s t un paragraphe en i n l i n e. 29 </p> 30 </body> 31 </html> 2.2 Distinguer des parties dans un document : balise div exemples/chapitrecss/ex04_div.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>la B a l i s e &l t ; div&gt ;</ t i t l e> 7 </head> 8 <body> 36

Chapitre 2 : Styles CSS et mise en page 9 <h1>d i s t i n g u e r des p a r t i e s dans l a page&nbsp ; :<br/>la b a l i s e &l t ; div&gt ;</h1 > 10 <div style= background c o l o r : #f85 > 11 <p> 12 <b>1)</b> Un élément &l t ; div&gt ; e s t une p a r t i e d un document <i>html</ i >. 13 La b a l i s e &l t ; div&gt ; e s t ( par défaut ) de type block. 14 </p> 15 <p> 16 Contrairement aux paragraphes, un &l t ; div&gt ; peut c o n t e n i r d a u t r e s b a l i s e s 17 de type block comme d a u t r e s &l t ; div&gt ;, des paragraphes, des tableaux, e t c. 18 </p> 19 </ div> 20 <div style= background c o l o r :white ; > 21 <p> 22 <b>2)</b> Le &l t ; div&gt ; d i f f è r e d un &l t ; span&gt ; en c e c i que l e span e s t 23 ( par défaut ) de type i n l i n e et 24 <span style= background c o l o r : black ; c o l o r : white ; border r a d i u s : 5px ; > 25 l e &l t ; span&gt ; ne modifie pas vraiment l a s t r u c t u r e du document 26 </span>. 27 I l donne j u s t e un s t a t u t ou un s t y l e p a r t i c u l i e r à une c e r t a i n e étendue du document. 28 </p> 29 <p> 30 Le &l t ; div&gt ;, au c o n t r a i r e, permet de <strong>d i v i s e r</strong> l e document en 31 p a r t i e s qui peuvent ê t r e d i s p o s é e s au gré de l a f a n t a i s i e du d e s i g n e r. 32 Le &l t ; div&gt ; e s t l a base de l a d i v i s i o n des pages en d i f f é r e n t e s p a r t i e s. 33 </p> 34 </ div> 35 </body> 36 </html> 2.3 Imbrication des balises et CSS exemples/chapitrecss/ex05_imbrication_balises_et_css.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 body p{ 8 background c o l o r : #777 ; 9 c o l o r : white ; 10 } 11 body div p{ 12 background c o l o r : #eee ; 37

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 13 c o l o r : #111 ; 14 } 15 body div div p{ 16 background c o l o r : #111 ; 17 c o l o r : #eee ; 18 } 19 </ style> 20 <t i t l e>i m b r i c a t i o n des b a l i s e s et <i>css</ i></ t i t l e> 21 </head> 22 <body> 23 <h1>i m b r i c a t i o n des b a l i s e s et <i>css</ i></h1> 24 <p> 25 Les b a l i s e s peuvent ( moyennant c e r t a i n s c o n t r a i n t e s sur l i m b r i c a t i o n des b l o c k s ) 26 s imbriquer l e s unes dans l e s a u t r e s. I c i un paragraphe imbriqué directement 27 dans l e &l t ; body&gt ;.<br/> 28 C e s t l e s t y l e <code>body p</code> qui s applique i c i. 29 </p> 30 <div> 31 <p> 32 Le s t y l e <i>css</ i> des éléments peut ê t r e r é g l é différemment s uivant l e u r 33 i m b r i c a t i o n dans d a u t r e s b a l i s e s. I c i un paragraphe imbriqué dans un & l t ; div&gt ; 34 l u i même imbriqué directement dans l e &l t ; body&gt ;.<br/> 35 C e s t l e s t y l e <code>body div p</code> qui s applique i c i. 36 </p> 37 <p> 38 I c i un autre paragraphe imbriqué dans un &l t ; div&gt ; 39 l u i même imbriqué directement dans l e &l t ; body&gt ;.<br/> 40 C e s t l e s t y l e <code>body div p</code> qui s applique i c i. 41 </p> 42 </ div> 38

Chapitre 2 : Styles CSS et mise en page 43 <div> 44 <p> 45 I c i encore un autre paragraphe imbriqué dans un &l t ; div&gt ; 46 l u i même imbriqué directement dans l e &l t ; body&gt ;.<br/> 47 C e s t l e s t y l e <code>body div p</code> qui s applique i c i. 48 </p> 49 <div> 50 <p> 51 I c i on a un paragraphe imbriqué dans un &l t ; div&gt ; 52 l u i même dans un &l t ; div&gt ; imbriqué directement dans l e &l t ; body&gt ;.<br/> 53 C e s t l e s t y l e <code>body div div p</code> qui s applique i c i. 54 </p> 55 </ div> 56 </ div> 57 </body> 58 </html> 2.4 Arborescence de balises et CSS L imbrication des balises HTML d un document crée une arborescence, où une balise B 1 est fille d une autre balise B 2 si la balise B 1 est immédiatement imbriquée dans B 2 dans le document (voir la figure 2.1). body div h1 p div ul a p li span Figure 2.1 : L arbre d imbrication des balises de l exemple ex11_arborescencecss_html Dans le fichier CSS, on peut définir un style (et éventuellement plusieurs classes CSS) pour chaque sous-arbre de l arborescence. Pour cela, on indique le sous-arbre par la succession des noeuds de la racine de l arbre vers la racine du sous-arbre (voir exemple ci-dessous). 39

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web exemples/chapitrecss/ex06_arborescencecss.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / ex06_arborescencecss. c s s /> 6 <t i t l e>arborescence de b a l i s e s</ t i t l e><t i t l e>arborescence de b a l i s e s et CSS< / t i t l e> 7 </head> 8 <body> 9 <h1>t i t r e p r i n c i p a l</h1> 10 <p> 11 f e u i l l e 1 12 <a href=. / my_url. html > f e u i l l e 2</a> 13 </p> 14 <div> 15 <div> 16 <p> 17 noeud 3 <span> f e u i l l e 4</span> 18 <p> 19 </ div> 20 </ div> 21 <div> 22 <ul> 23 < l i> 24 f e u i l l e 5 25 </ l i> 26 < l i> 27 f e u i l l e 6 28 </ l i> 29 </ ul> 30 </ div> 31 </body> 32 </html> 1 /* s t y l e par défaut du t e x t e */ 2 body { 3 font family : times, s e r i f ; 4 font s i z e :14 pt ; 5 background c o l o r : #ccc ; 6 c o l o r : #222 ; 7 } exemples/chapitrecss/ex06_arborescencecss.css 40

Chapitre 2 : Styles CSS et mise en page 8 9 h1 { 10 text a l i g n : c e n t e r ; 11 } 12 13 div { 14 background c o l o r : #f f 0 ; 15 } 16 17 p { 18 19 background c o l o r : white ; 20 21 } 22 23 p a { 24 25 text d e c o r a t i o n : o v e r l i n e ; 26 27 } 28 29 div div p { 30 c o l o r : red ; 31 text a l i g n : c e n t e r ; 32 background c o l o r : #ddd ; 33 34 } 35 36 37 div div p span { 38 font family : Comic Sans MS; 39 font s i z e :18 pt ; 40 } 41 42 43 div ul { 44 background c o l o r : #0 f f ; 45 c o l o r : red ; 46 } 2.5 Classes CSS Les classes CSS permettent d appliquer un style CSS différent à différentes catégories (ou classes, que l on distingue pour un même type de balises HTML. exemples/chapitrecss/ex07_classes_css.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / ex07_classes_css. c s s /> 6 <t i t l e>c l a s s e s CSS</ t i t l e> 7 </head> 8 <body> 41

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 9 <h1>c l a s s e s CSS</h1> 10 <p class= l a b e l > 11 Menu : 12 </p> 13 <ol class= menu > 14 < l i> 15 <a class= boutton ombre href= #part1 >Qu est ce que c l a s s e s <i>css</ i> &nbsp ;?</a> 16 </ l i> 17 < l i> 18 <a class= boutton ombre href= #part2 >À quoi ça s e r t&nbsp ;?</a> 19 </ l i> 20 < l i> 21 <a class= boutton ombre href= #part2 >Exemple d usage</a> 22 </ l i> 23 </ ol> 24 <h2 id= part1 ><b>1)</b> Qu est ce que c l a s s e s <i>css</ i>&nbsp ;?</h2> 25 <p > 26 Les c l a s s e s permettent de d é f i n i r p l u s i e u r s c l a s s e s de c o n t e x t e s 27 dans l e s q u e l s l e s mises en formes sont d i f f é r e n t e s ( v o i r <a class= normallink href= #part2 >p a r t i e&nbsp ; 2</a>) 28 </p> 29 <h2 id= part2 ><b>2)</b> À quoi ça s e r t&nbsp ;?</h2> 30 <p> 31 Ainsi, des éléments qui ont l e même niveau d i m b r i c a t i o n dans l e s b a l i s e s 32 pourront a v o i r un s t y l e d i f f é r e n t s e l o n l e u r usage. 33 </p> 34 <h2 id= part3 ><b>3)</b> Exemple d usage</h2> 35 <p> 36 Par exemple, pour l e s l i e n s&nbsp ; 37 </p> 38 <o l> 42

Chapitre 2 : Styles CSS et mise en page 39 < l i>l e s l i e n s dans un menu pourront a v o i r l e s t y l e d un bouton,</ l i> 40 < l i>a l o r s que l e s l i e n s dans un a r t i c l e auront un aspect bleu s o u l i g n é,</ l i> 41 < l i> 42 ou e n c o r e l e s l i e n s v e r s l e s sponsors dans l e pied de page auront encore 43 un autre aspect. 44 </ l i> 45 </ ol> 46 </body> 47 </html> exemples/chapitrecss/ex07_classes_css.css 1 2 /* s t y l e par défaut du t e x t e */ 3 body { 4 font family : Comic Sans MS ; 5 font s i z e : 18 pt ; 6 background c o l o r : #f f f ; 7 c o l o r : #222 ; 8 } 9 10 /* s t y l e du t i t r e */ 11 h1 { 12 font weight : bold ; 13 font s i z e : 150% ; 14 c o l o r : white ; 15 text a l i g n : c e n t e r ; 16 background image : l i n e a r g r a d i e n t ( black, #bbb ) ; 17 padding : 15 pt ; 18 } 19 20 h2 { 21 font weight : bold ; 22 font s i z e : 120% ; 23 } 24 25 p{ 26 tex a l i g n : j u s t i f y ; 27 } 28 29 p. l a b e l { 30 d i s p l a y : i n l i n e ; 31 background c o l o r : t r a n s p a r e n t ; 32 } 33 34 /* s t y l e des éléments importants */ 35 strong { 36 font v a r i a n t : small caps ; 37 font weight : bolder ; 38 c o l o r : black ; 39 } 40 41 strong. i n s i s t { 42 font s i z e : 130% ; 43

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 43 } 44 45 strong. warning { 46 font s i z e : 150% ; 47 c o l o r : red ; 48 text d e c o r a t i o n : b l i n k ; 49 } 50 51 /* s t y l e des éléments mis en évidence */ 52 em { 53 font s t y l e : i t a l i c ; 54 c o l o r : black ; 55 } 56 57 p { 58 background c o l o r : #ddd ; 59 text a l i g n : j u s t i f y ; 60 padding : 5 pt ; 61 } 62 63 /* s t y l e par défaut des l i e n s */ 64 a { 65 c o l o r : blue ; 66 text d e c o r a t i o n : u n d e r l i n e ; /* non s o u l i g n é */ 67 } 68 69 o l. menu{ 70 d i s p l a y : i n l i n e block ; 71 } 72 o l. menu l i { 73 d i s p l a y : i n l i n e block ; 74 } 75 /* s t y l e de l i e n s s p é c i a l pour l a t a b l e des m a t i è r e s */ 76 a. boutton ombre { 77 c o l o r : white ; 78 border s t y l e : groove ; 79 border width : 3px ; 80 background c o l o r : #333 ; 81 text d e c o r a t i o n : none ; /* s u r l i g n é */ 82 padding : 5px ; 83 border r a d i u s : 15px ; 84 box shadow : 10 px 20 px 5px #777 ; 85 } exemples/chapitrecss/ex08_classes_css_tableaux.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <! I n c l u s i o n de s t y l e s s u p p l é m e n t a i r e s avec import > 7 <style> 8 @import u r l ( ex08_classes_css_tableaux. c s s ) ; 9 </ style> 10 <t i t l e>s t y l e CSS de Tableaux</ t i t l e> 44

Chapitre 2 : Styles CSS et mise en page 11 </head> 12 <body> 13 <! début du corps HTML > 14 <h1>s t y l e <i>css</ i> de Tableaux</h1> 15 16 <div style= margin : 0 auto ; width : 800px ; > 17 <table> 18 <caption> 19 Exemple de t a b l e 20 </ caption> 21 <thead> 22 <tr> 23 <th class= impair >Colonne 1</th> 24 <th class= p a i r >Colonne 2</th> 25 <th class= impair >Colonne 3</th> 26 <th class= p a i r >Colonne4</th> 27 </ tr> 28 </thead> 29 <tbody> 30 <tr> 31 <td class= p a i r >Ceci e s t l a case&nbsp ; 1</td> 32 <td class= impair >Ceci e s t l a case &nbsp ; 2</td> 33 <td class= p a i r >Ceci e s t l a case &nbsp ; 3</td> 34 <td class= impair >Ceci e s t l a case &nbsp ; 4</td> 35 </ tr> 36 <tr> 37 <td class= p a i r >Ceci e s t l a case&nbsp ; 5</td> 38 <td class= impair >Ceci e s t l a case &nbsp ; 6</td> 39 <td class= p a i r >Ceci e s t l a case &nbsp ; 7</td> 40 <td class= impair >Ceci e s t l a case &nbsp ; 8</td> 41 </ tr> 42 <tr> 43 <td class= p a i r >Ceci e s t l a case&nbsp ; 9</td> 44 <td class= impair >Ceci e s t l a case &nbsp ;10</td> 45 <td class= p a i r >Ceci e s t l a case &nbsp ;11</td> 45

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 46 <td class= impair >Ceci e s t l a case &nbsp ;12</td> 47 </ tr> 48 </tbody> 49 </ table> 50 </ div> 51 </body> 52 <! f i n du corps HTML > 53 </html> 54 <! f i n du code HTML > exemples/chapitrecss/ex08_classes_css_tableaux.css 1 2 3 t a b l e { 4 padding : 0px ; 5 v e r t i c a l a l i g n : top ; /* mise en forme des t a b l e s */ 6 background c o l o r : #ddd ; 7 border s t y l e : o u t s e t ; 8 border width : 10px ; 9 border c o l o r : black ; 10 text a l i g n : c e n t e r ; 11 margin : 0 auto ; 12 } 13 14 tr, td { 15 border s t y l e : dashed ; /* mise en forme des c e l l u l e s */ 16 border width : 2px ; 17 border c o l o r : black ; 18 padding : 20px ; 19 } 20 21 tr, td. p a i r { 22 background c o l o r : black ; 23 c o l o r : white ; 24 } 25 26 tr, td. impair { 27 background c o l o r : white ; 28 c o l o r : black ; 29 } 30 31 32 th { 33 border s t y l e : s o l i d ; 34 border width : 2px ; 35 border c o l o r : black ; 36 text a l i g n :center ; 37 font weight : bolder ; 38 background c o l o r : #ddd ; 39 c o l o r : black ; 40 padding : 20px ; 41 } 42 43 th. p a i r { 44 background c o l o r : #ccc ; 46

Chapitre 2 : Styles CSS et mise en page 45 } 46 47 th. impair { 48 background c o l o r : #555 ; 49 } 50 caption { 51 background c o l o r : black ; 52 c o l o r : white ; 53 box shadow : 10 px 20 px 10 px #666 ; 54 width : 50% ; 55 margin : 0 auto 20px auto ; 56 } 2.6 Sélecteurs de style CSS par ID exemples/chapitrecss/ex09_id_selector_css.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta http equiv= Content Type content= t e x t /html ; c h a r s e t=utf 8 /> 5 <link rel= s t y l e s h e e t type= t e x t / c s s href=. / ex09_id_selector_css. c s s /> 6 <t i t l e>s é l e c t e u r s de s t y l e par ID</ t i t l e> 7 </head> 8 <body> 9 <h1>s é l e c t e u r s de s t y l e par ID</h1> 10 <h2 id= p a r t i e 1 >1) Qu est ce qu un <i>id</ i> <i>html</ i>&nbsp ;?</h2> 11 <p id= paragraphe1 > 12 Un développeur web peut a s s o c i e r un <i>id</ i> à tout élément <i>html</ i>. 47

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 13 Cet <i>id</ i> s o i t ê t r e unique dans tout l e document et c a r a c t é r i s e l élément. 14 Pour ce f a i r e, l e développeur web u t i l i s e l a t t r i b u t <code>id</code> de l a b a l i s e 15 qui d é f i n i t l élément. 16 </p> 17 <h2 id= p a r t i e 2 >2) À quoi s e r v e n t l e s <i>id</ i> <i>html</ i>&nbsp ;?</h2> 18 <p id= paragraphe2 > 19 L <i>id</ i> d un élément <i>html</ i> permet de d é s i g n e r l élément parmis 20 tous l e s éléments du document, notamment pour&nbsp ; : 21 <ul> 22 < l i> 23 Accéder à l élément pour a g i r sur son contenu en <i>j a v a s c r i p t</ i> 24 ( par exemple v i a l a méthode <code>getelementbyid</code>). 25 </ l i> 26 < l i> 27 I d e n t i f i e r l élément pour l u i a t t r i b u e r un s t y l e <i>css p a r t i c u l i e r</ i > 28 </ l i> 29 </ ul> 30 </p> 31 <h2 id= p a r t i e 3 >3) D i f f é r e n c e avec l e s c l a s s e s</h2> 32 <p id= paragraphe3 > 33 Contrairement aux c l a s s e s, 34 pour l e s q u e l l e s on peut d é f i n i r autant d éléments qu on veut dans une 35 même c l a s s e de s t y l e, <strong>l élément correspondant à un ID e s t unique</ strong>, 36 c e s t un <em>s i n g l e t o n</em>. 37 </p> 38 </body> 39 </html> 1 2 /* s t y l e par défaut du t e x t e */ 3 body { 4 font family : Comic Sans MS ; 5 font s i z e : 18 pt ; 6 background c o l o r : #f f f ; 7 c o l o r : #222 ; 8 } 9 10 /* s t y l e du t i t r e */ 11 h1 { 12 font weight : bold ; 13 font s i z e : 150% ; 14 c o l o r : white ; 15 text a l i g n : c e n t e r ; 16 background c o l o r : #999 ; 17 padding : 15 pt ; 18 } 19 20 h2 { 21 font weight : bold ; 22 font s i z e : 120% ; exemples/chapitrecss/ex09_id_selector_css.css 48

Chapitre 2 : Styles CSS et mise en page 23 } 24 25 h2#p a r t i e 1 { 26 c o l o r : black ; 27 } 28 29 h2#p a r t i e 2 { 30 c o l o r : red ; 31 } 32 33 h2#p a r t i e 3 { 34 c o l o r : green ; 35 } 36 37 /* s t y l e des éléments importants */ 38 strong { 39 font v a r i a n t : small caps ; 40 font weight : bolder ; 41 c o l o r : black ; 42 } 43 44 45 /* s t y l e des éléments mis en évidence */ 46 em { 47 font s t y l e : i t a l i c ; 48 c o l o r : black ; 49 } 50 51 p { 52 background c o l o r : #ddd ; 53 text a l i g n : j u s t i f y ; 54 padding : 5 pt ; 55 } 56 57 p#pa rag rap he1 { 58 background c o l o r : #aaa ; 59 60 } 61 62 p#pa rag rap he2 { 63 background c o l o r : #ccc ; 64 65 } 66 67 p#pa rag rap he3 { 68 background c o l o r : #eee ; 69 70 } 71 72 /* p#pa rag rap he2 { 73 background c o l o r : #ddd ; 74 75 s t y l e par défaut des l i e n s */ 76 a { 77 c o l o r : blue ; 78 text d e c o r a t i o n : u n d e r l i n e ; /* non s o u l i g n é */ 49

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 79 } 50

Chapitre 2 : Styles CSS et mise en page La position des différents éléments dans une page HTML se définit au niveau du style CSS. 2.7 Marges et bordures Chaque élément (de type inline ou block) se trouve dans une boîte ayant une bordure, une marge intérieure, et une marge extérieure. On définit ainsi les épaisseurs et styles de bordure des différents éléments, les marges extérieures (margin), qui force l élément à un certain éloignement des autres éléments de la page, les marges intérieures (padding), qui force le contenu de l élément à se trouver à une certaine distance du bord de l élément. Voir la figure 2.2 Élément parent margin-top padding margin-left contenu de l élément margin-right Autre élément Bord de l élément considéré Figure 2.2 : Propriétés CSS margin et padding exemples/chapitrecss/ex10_margin_padding.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 div { 8 border width : 2px ; 9 border c o l o r : black ; 10 border s t y l e : s o l i d ; 11 c o l o r : black ; 12 margin : 40px ; 13 padding : 25px ; 51

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 14 background c o l o r : #ddd ; 15 } 16 17 div div { 18 border width : 3px ; 19 border c o l o r : #666 ; 20 border s t y l e : dashed ; 21 c o l o r : black ; 22 margin : 10px ; 23 padding : 35px ; 24 background c o l o r : #aaa ; 25 } 26 </ style> 27 <t i t l e>p r o p r i é t é s Margin et Padding</ t i t l e> 28 </head> 29 <body> 30 <h1>p r o p r i é t é s Margin et Padding</h1> 31 <div> 32 Ceci e s t l e t e x t e f a i s a n t p a r t i e du contenu de l a première b o î t e. 33 <div> 34 Ceci e s t l e texte, contenu de l a p e t i t e b o î t e. 35 Cette p e t i t e b o î t e e s t e l l e même l e contenu de l a grande b o î t e. 36 </ div> 37 </ div> 38 </body> 39 </html> 2.8 Positionnement absolu Dans le positionnement absolu, la position d un élément est définie par rapport à la position du première ancêtre positionné (soit le parent si celui-ci est positionné, sinon on cherche le parent du parent, etc. jusqu à trouver un ancêtre positionné). Si le parent n est pas positionné, on peut le positionner sans changer sa position en mettant sa position relative zéro. Voir la figure 2.3. Un élément positionné en absolu est sorti du flux : il n occupe plus de place dans le flux et l élément suivant est placé comme si l élément positionné en absolu n existait pas. L élément positionné en absolu n occupe pas de place. Premier ancètre positionné Décalage bord top Décalage bord left Figure 2.3 : Positionnement Absolu d un élément 52

Chapitre 2 : Styles CSS et mise en page exemples/chapitrecss/ex11_position_absolute.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 div { 8 border width : 2px ; 9 border c o l o r : black ; 10 border s t y l e : s o l i d ; 11 c o l o r : black ; 12 margin : 20px ; 13 padding : 0px ; 14 background c o l o r : #ddd ; 15 } 16 17 /* positionnement normale dans l e flux, 18 d é f i n i j u s t e pour p o s i t i o n n e r l élément */ 19. p o s i t i o n Z e r o { 20 p o s i t i o n : r e l a t i v e ; 21 top : 0px ; 22 23 l e f t : 0px ; 24 width : 500px ; 25 z index : 1 ; 26 } 27 28 div div { 29 border width : 2px ; 30 border c o l o r : black ; 31 border s t y l e : dashed ; 32 margin : 0px ; 33 padding : 0px ; 34 background c o l o r : #aaa ; 35 } 36 37. p o s i t i o n T r e n t e { 38 p o s i t i o n : a b s o l u t e ; 39 top : 90px ; /* d é c a l a g e e n t r e l e bord haut de l élément et son a n c è t r e */ 53

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 40 l e f t : 30px ;/* d é c a l a g e e n t r e l e bord gauche de l élément et son a n c è t r e */ 41 width : 500px ; 42 z index : 7 ; 43 } 44 45. p o s i t i o n S o i x a n t e { 46 p o s i t i o n : a b s o l u t e ; 47 top : 180px ; /* d é c a l a g e e n t r e l e bord haut de l élément et son a n c è t r e */ 48 l e f t : 60px ; /* d é c a l a g e e n t r e l e bord gauche de l élément et son a n c è t r e */ 49 background c o l o r : #888 ; 50 z index : 15 ; 51 } 52 </ style> 53 <t i t l e>positionnement absolu</ t i t l e> 54 </head> 55 <body> 56 <h1>positionnement absolu</h1> 57 <div class= p o s i t i o n Z e r o > 58 Ceci e s t l e t e x t e f a i s a n t p a r t i e du contenu de l a b o î t e parente. Celle c i e s t 59 p o s i t i o n n é e mais à sa p l a c e normale dans l e f l u x ( marge de 20px ). 60 <div class= p o s i t i o n T r e n t e > 61 Ceci e s t l e t e x t e contenu de l a première sous boîte, dont l e coin s u p é r i e u r 62 gauche p o s i t i o n n é e 30 p i x e l s à d r o i t e et 90 p i x e l s plus bas que son parent. 63 </ div> 64 <div class= p o s i t i o n S o i x a n t e > 65 Ceci e s t l e t e x t e contenu de l a deuxième sous boîte, dont l e coin s u p é r i e u r 66 gauche p o s i t i o n n é e 60 p i x e l s à d r o i t e et 180 p i x e l s plus bas que son parent. 67 </ div> 68 </ div> 69 </body> 70 </html> 2.9 Positionnement relatif Le positionnement relatif permet de déplacer un objet relativement à la position qu il aurait eu dans le flux sans positionnement. Le positionnement relatif s obtient avec l attribut : position : relative; top: 10px; /* déplacer de 10 pixels vers le bas */ left: 20px; /* déplacer de 20 pixels vers la droite */ 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> exemples/chapitrecss/ex12_position_relative.html 54

Chapitre 2 : Styles CSS et mise en page 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <style> 7 /* positionnement normale dans l e flux, 8 d é f i n i j u s t e pour p o s i t i o n n e r l élément */ 9. p o s i t i o n Z e r o { 10 p o s i t i o n : r e l a t i v e ; 11 width : 600px ; 12 z index : 1 ; 13 } 14. p o s i t i o n T r e n t e { 15 border s t y l e : dashed ; 16 background c o l o r : #aaa ; 17 p o s i t i o n : r e l a t i v e ; 18 l e f t : 60px ; 19 width : 600px ; 20 z index : 7 ; 21 } 22. positionnormale { 23 border s t y l e : dashed ; 24 background c o l o r : #888 ; 25 z index : 15 ; 26 } 27 </ style> 28 <t i t l e>positionnement r e l a t i f</ t i t l e> 29 </head> 30 <body> 31 <h1>positionnement r e l a t i f</h1> 32 <div class= p o s i t i o n Z e r o > 33 Ceci e s t l e t e x t e f a i s a n t p a r t i e du contenu de l a b o î t e du haut. Celle c i e s t 34 p o s i t i o n n é e mais à sa p l a c e normale dans l e f l u x. 35 </ div> 36 <div class= p o s i t i o n T r e n t e > 37 Ceci e s t l e t e x t e contenu de l a b o î t e du milieu, dont l e c oin s u p é r i e u r 38 gauche p o s i t i o n n é e 60 p i x e l s à d r o i t e de sa p o s i t i o n normale dans l e f l u x. 39 </ div> 40 41 <div class= positionnormale > 42 Ceci e s t l e t e x t e contenu de l a b o î t e du bas, qui e s t p o s i t i o n n é e 43 normalement dans l e f l u x ( compte tenu de l a p o s i t i o n de l a b o î t e précédente ). 44 </ div> 45 </body> 55

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 46 </html> 2.10 Structuration d une page en HTML5 La mise en page avec header, navigation et pied de page est si courante que des balises spécialisées, appelées balises sémantiques ont été créées en HTML5. On doit les préférer à <div> car elles permettent une plus grande clarté de la structure du document, mais aussi aux moteurs de recherche de mieux percevoir quelle place accorder aux différentes parties d une page web. Les balises sémantiques sont les suivantes : header pour l en-tête ou le bandeau contenant le titre de la page, un logo, etc. footer pour le pied de pas contenant le copyright, des logos ou liens, informations légales, etc. nav pour la partie navigation avec un menu et des liens pour se déplacer dans le site. article contenant un corps de document autosuffisant. aside pour des informations annexes sans grand rapport avec le sujet (publicités, etc.) section représentant une partie regroupant plusieurs contenus liés entre eux. Voici un exemple de mise en page typique utilisant ces balises : 56

Chapitre 2 : Styles CSS et mise en page exemples/chapitrecss/ex13_balises_semantiques.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>b a l i s e s Sémantiques <i>html5</ i></ t i t l e> 7 </head> 8 <body> 9 <header> 10 <h1>b a l i s e s Sémantiques <i>html5</ i></h1> 11 </ header> 12 <div> 13 <nav> 14 <h1>navigation</h1> 15 <ul> 16 < l i> 17 <a href=. / coucou. html >l i e n 1</a> 18 </ l i> 19 < l i> 20 <a href=. / toto. html >l i e n 2</a> 21 </ l i> 22 < l i> 23 <a href=. / t i t i. html >l i e n 2</a> 24 </ l i> 25 </ ul> 26 </ nav> 27 <a r t i c l e> 28 <h1>les b a l i s e s &l t ; header&gt ;, &l t ; nav&gt ;, &l t ; a r t i c l e&gt ;, &l t ; f o o t e r &gt ;</h1> 29 <p> 30 Ces b a l i s e s d é f i n i s s e n t l a s t r u c t u r e g é n é r a l e du document. E l l e s se comportent 31 comme un &l t ; div&gt ; mais e l l e s ont, comme l e u r nom l indique, une s i g n i f i c a t i o n 32 au niveau sémantique&nbsp ; : 33 </p> 34 <o l> 35 < l i> 36 Un élément &l t ; header&gt ; c o n t i e n t l en t ê t e du document avec l e nom g é n é r a l 37 du s i t e, un logo, une banière, éventuellement un slogan, e t c. 38 </ l i> 39 < l i> 40 Un élément &l t ; nav&gt ; c o n t i e n t des éléments de n a v i g a t i o n ( menus, s é r i e s de l i e n s, e t c. ). 41 Les moteurs de r e c h e r c h e peuvent en déduite un <em>sitemap</em>, c e s t à d i r e l a s t r u c t u r e du s i t e 42 pour o p t i m i s e r l e référencement. 43 </ l i> 44 < l i> 45 Un élément &l t ; a r t i c l e&gt ; c o n t i e n t l e contenu de l a page l u i même. C e s t l e t e x t e de l a r t i c l e 46 qui s e r a p r i s en compte fortement pour l i n d e x a t i o n dans l e s moteurs de r e c h e r c h e. 47 </ l i> 57

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 48 < l i> 49 Un élément &l t ; f o o t e r&gt ; c o n t i e n t un pied de page ( souvent avec des i n f o r m a t i o n s l é g a l e s, de copyright, 50 sur l e c r é a t e u r technique du s i t e, l e s l o g o s des sponsors, e t c. ) 51 </ l i> 52 </ ol> 53 <p> 54 Les moteurs de r e c h e r c h e peuvent a i n s i mieux a n a l y s e r l e contenu de l a page&nbsp ; c e l à p a r t i c i p e 55 de l o p t i m i s a t i o n du référencement ; 56 </p> 57 </ a r t i c l e> 58 <f o o t e r> 59 &copy ; RM 2012. 60 </ f o o t e r> 61 </ div> 62 </body> 63 </html> 2.11 Exemples de mise en page exemples/chapitrecss/ex14_exemple_miseenpage.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / ex14_exemple_miseenpage. c s s /> 6 <t i t l e>exemple de mise en page</ t i t l e> 7 </head> 8 <body> 9 <header> 10 <h1>exemple de mise en page</h1> 11 </ header> 12 <div> 13 <nav> 14 <h1>navigation</h1> 15 <ul> 16 < l i> 58

Chapitre 2 : Styles CSS et mise en page 17 <a href=. / coucou. html >l i e n 1</a> 18 </ l i> 19 < l i> 20 <a href=. / toto. html >l i e n 2</a> 21 </ l i> 22 < l i> 23 <a href=. / t i t i. html >l i e n 2</a> 24 </ l i> 25 </ ul> 26 </ nav> 27 <a r t i c l e> 28 <h1>corps du t e x t e</h1> 29 <p> 30 Nous mettons i c i l e corps du t e x t e. Paragraphe 1. 31 </p> 32 <p> 33 Notons que l e s l i e n s dans l e menu n ont pas l e même aspect 34 que l e s l i e n s dans l e t e x t e. Le s t y l e e s t propre à chaque 35 zône de l a page. 36 </p> 37 <p> 38 Ceci e s t <a href=. / toto. html >un l i e n</a> normal 39 </p> 40 </ a r t i c l e> 41 </ div> 42 <f o o t e r> 43 &copy ; RM 2012. 44 </ f o o t e r> 45 </body> 46 </html> exemples/chapitrecss/ex14_exemple_miseenpage.css 1 /*****************************************************\ 2 * STYLE CSS POUR MISE EN PAGE EN LARGEUR FIXE 3 * MENU À GAUCHE 4 * ***************************************************/ 5 6 /* L ensemble du document */ 7 body { 8 font family : times, s e r i f ; /* p o l i c e */ 9 font s i z e : 14 pt ; /* t a i l l e de f o n t e absolue */ 10 background c o l o r : #ccc ; /* c o u l e u r de fond de l a page */ 11 c o l o r : #222 ; /* c o u l e u r de t e x t e g r i s f o n c é */ 12 } 13 14 /* l i e n s par défaut */ 15 a{ 16 /* s t y l e par défaut pour é v i t e r que ne s o i t p r i s par défaut * 17 * l e s t y l e du div nav ul l i a d é f i n i plus bas */ 18 } 19 20 /* Le header : b a n i è r e de t i t r e du s i t e */ 21 header { 22 width : 600px ; /* l a r g e u r t o t a l e du contenu */ 23 background c o l o r : black ; /* fond du header n o i r */ 59

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 24 c o l o r : white ; /* c o u l e u r du t e x t e : blanc */ 25 margin : 0 auto ; /* l e header e s t c e n t r é dans l a page */ 26 padding : 0px ; /* pas de padding */ 27 } 28 29 /* t i t r e p r i n c i p a l du s i t e dans l e header */ 30 header h1 { 31 text a l i g n : c e n t e r ; /* t e x t e c e n t r é dans l e h1 ( l u i même c e n t r é dans l e header ) */ 32 width : i n h e r i t ; /* prend toute l a l a r g e u r du parent */ 33 margin : 0 ; /* pas d espace autour du header et de son t i t r e */ 34 } 35 36 /* sous l e header, l e div c o n t i e n t l e nav et l a r t i c l e */ 37 div { 38 width : 600px ; /* l a r g e u r du contenu : 600px ; */ 39 background c o l o r : white ; /* fond blanc */ 40 margin : 0 auto ; /* c e n t r é dans l a page */ 41 p o s i t i o n : r e l a t i v e ; /* positionnement pour pouvoir u t i l i s e r p o s i t i o n : a b s o l u t e dans l e s f i l s */ 42 top : 0px ; 43 padding : 0px ; /* pas de marge i n t é r i e u r e */ 44 height : 280px ; /* hauteur t o t a l du contenu */ 45 } 46 47 /* bloc de n a v i g a t i o n contenant l e menu */ 48 nav { 49 c o l o r : white ; /* t e x t e blanc */ 50 text a l i g n : c e n t e r ; /* t e x t e c e n t r é */ 51 background c o l o r : #999 ; /* fond g r i s */ 52 width : 180px ; /* l a r g e u r : seulement une p a r t i e des 600px */ 53 margin : 0 ; /* pas de marge e x t é r i e u r e */ 54 padding : 0px ; /* pas de marge i n t é r i e u r e */ 55 p o s i t i o n :absolute ; /* on c a l e l e b loc à gauche sur l e bord du div parent */ 56 l e f t :0px ; 57 height : i n h e r i t ; /* l a hauteur e s t l a même que l a hauteur du div parent */ 58 } 59 60 /* t i t r e du menu */ 61 nav h1{ 62 background c o l o r : black ; /* fond n o i r */ 63 border r a d i u s : 4px ; /* bord légèrement a r r o n d i */ 64 width : 80% ; /* l a r g e u r 80% de l a l a r g e u r du nav */ 65 margin : 20px auto ; /* cantré en h o r i z o n t a l et 20px de marge au dessus et au dessous */ 66 } 67 68 /* L i s t e à puce contenant l e s l i e n s du menu */ 69 div nav ul { 70 text a l i g n : l e f t ; /* t e x t e c a l é à gauche */ 71 l i s t s t y l e : none ; /* pas de p o i n t s devant l e s items de l a l i s t e à puces */ 72 } 73 74 /* items de l a l i s t e à puce contenant l e s l i e n s du menu */ 75 div nav ul l i { 76 margin bottom : 20px ; /* permet d é c a r t e r l e s boutons */ 60

Chapitre 2 : Styles CSS et mise en page 77 } 78 79 /* l i e n s du menu dans l a p a r t i e n a v i g a t i o n */ 80 div nav ul l i a { 81 text d e c o r a t i o n : none ; /* pas de soulignement du l i e n */ 82 font v a r i a n t : small caps ; /* p e t i t e s c a p i t a l e s */ 83 c o l o r : white ; /* t e x t e blanc */ 84 font weight : bolder ; /* c a r a c t è r e s gras */ 85 background image : l i n e a r g r a d i e n t ( black, white ) ; /* fond dégradé */ 86 border r a d i u s : 4px ; /* bord légèrement a r r o n d i */ 87 padding : 10px ; /* marge i n t é r i e u r e au bouton */ 88 } 89 90 /* p a r t i e a r t i c l e contenant l e t e x t e p r i n c i p a l l e l a page */ 91 div a r t i c l e { 92 c o l o r : black ; /* t e x t e n o i r ( sur fond blanc ) */ 93 width : 400 px ; /* encombrement 420 avec l a padding. 600 px = 180 px + 420 px */ 94 padding : 0 10px ; /* compter 20 dans l a l a r g e u r t o t a l e */ 95 margin : 0 ; /* pas de marge e x t é r i e u r e */ 96 p o s i t i o n : r e l a t i v e ; 97 l e f t : 180px ; /* on d é c a l e v e r s l a d r o i t e de l a l a r g e u r du nav */ 98 height : i n h e r i t ; /* prend l a hauteur de son parent */ 99 } 100 101 /* T i t r e p r i n c i p a l de l a page dans l a r t i c l e */ 102 div a r t i c l e h1{ 103 margin : 0 auto ; /* t i t r e c e n t r é dans l a r t i c l e */ 104 text a l i g n : c e n t e r ; /* t e x t e c e n t r é dans l e t i t r e */ 105 } 106 107 /* paragraphes de l a r t i c l e */ 108 div a r t i c l e p { 109 text a l i g n : j u s t i f y ; /* t e x t e j u s t i f i é dans l e s paragraphes */ 110 } 111 112 /* pied de page */ 113 f o o t e r { 114 width : 600px ; /* l a r g e u r 600 p i x e l s */ 115 margin : 0 auto ; /* f o o t e r c e n t r é dans l a page */ 116 background c o l o r : black ; /* fond n o i r */ 117 c o l o r : white ; /* t e x t e blanc */ 118 text a l i g n : c e n t e r ; /* t e x t e c e n t r é */ 119 } La structure du document HTML5 est définie par ces balises, mais pas la disposition de la page. En changeant uniquement le CSS, on peut obtenir : exemples/chapitrecss/ex15_miseenpage_2.css 1 /**************************************************************\ 2 * STYLE CSS POUR MISE EN PAGE EN LARGEUR PROPORTIONNELLE 3 * (LA LARGEUR S ADAPTE À LA PAGE. MENU EN HAUT SOUS LE HEADER 4 * ************************************************************/ 5 6 /* L ensemble du document */ 7 body { 8 font family : times, s e r i f ; /* p o l i c e */ 61

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 9 font s i z e : 14 pt ; /* t a i l l e de f o n t e absolue */ 10 background c o l o r : #ccc ; /* c o u l e u r de fond de l a page */ 11 c o l o r : #222 ; /* c o u l e u r de t e x t e g r i s f o n c é */ 12 } 13 14 /* Tous l e s div */ 15 div { 16 background c o l o r : #f f f ; /* fond blanc */ 17 } 18 19 /* Le header : b a n i è r e de t i t r e du s i t e */ 20 header { 21 width : 60% ; /* l a r g e u r 60% de l a page */ 22 background c o l o r : black ; /* fond n o i r */ 23 c o l o r : white ; /* t e x t e blanc */ 24 margin : 0 auto ; /* l e header e s t c e n t r é dans l a page */ 25 border r a d i u s : 20px 20px 0 0 ; /* a n g l e s du haut a r r o n d i s */ 26 } 27 28 /* t i t r e p r i n c i p a l du s i t e dans l e header */ 29 header h1 { 30 text a l i g n : c e n t e r ; /* t e x t e c e n t r é dans l élément */ 31 width : 100% ; /* occupe toute l a l a r g e u r du parent ( c. a. d. du header ) */ 32 margin : 0 ; /* pas de marge c o l l é au contenu div. content */ 33 } 34 35 /* div contenant l a r t i c l e et l e nav */ 36 div { 37 width : 60% ; /* l a r g e u r 60% de l a page */ 38 background c o l o r : white ; /* fond blanc */ 39 margin : 0 auto ; /* contenu c e n t r é dans l a page */ 40 } 41 42 /* mise en forme de l a p a r t i e n a v i g a t i o n contenant l e menu */ 43 div nav { 44 text a l i g n : c e n t e r ; /* t e x t e c e n t r é */ 45 background c o l o r : #999 ; /* fond g r i s f o n c é */ 46 width : 100% ; /* l a r g e u r 100% du div parent */ 47 height : 45px ; /* hauteur absolue 45px */ 48 } 49 50 /* t i t r e du menu */ 62

Chapitre 2 : Styles CSS et mise en page 51 div nav h1{ 52 d i s p l a y : none ; /* on supprime l e t i t r e */ 53 } 54 55 /* L i s t e à puce contenant l e s l i e n s du menu */ 56 div nav ul { 57 l i s t s t y l e : none ; /* on supprime l e s p o i n t s devant l e s items de l a l i s t e à puces */ 58 margin top : 0 ; /* bord du haut a l i g n é sur l e bord du div parent */ 59 } 60 61 /* items de l a l i s t e à puce contenant l e s l i e n s du menu */ 62 div nav ul l i { 63 d i s p l a y : i n l i n e block ; /* l e s items sont rangés horizontalement au l i e u de v e r t i c a l e m e n t */ 64 } 65 66 /* l i e n s du menu dans l a p a r t i e n a v i g a t i o n : *\ 67 \* p r o p r i é t é s g é n é r a l e s communes aux l i e n s v i s i t é s, hover ou non */ 68 div nav ul l i a { 69 font weight : bolder ; /* c a r a c t è r e s gras */ 70 border s t y l e : none ; /* pas de bord */ 71 margin : 0 10px ; /* marges à d r o i t e et à gauche de chaque l i e n de menu */ 72 padding : 5px 10px ; /* espace autour du t e x t e */ 73 p o s i t i o n : r e l a t i v e ; /* on t r a n s l a t e l élément */ 74 top : 5px ; /* d é c a l a g e v e r s l e bas pour compenser l e padding et a l i g n e r l e bord haut */ 75 border r a d i u s : 0 0 10px 10px ; /* a n g l e s du bas a r r o n d i s */ 76 text d e c o r a t i o n : none ; /* t e x t e non s o u l i g n é */ 77 } 78 79 /* p r o p r i é t é s s p é c i f i q u e s des l i e n s non v i s i t é s non s u r v o l é s */ 80 div nav ul l i a : l i n k { 81 c o l o r : white ; /* t e x t e blanc */ 82 background c o l o r : black ; /* fond n o i r */ 83 } 84 85 /* p r o p r i é t é s s p é c i f i q u e s des l i e n s v i s i t é s non s u r v o l é s */ 86 div nav ul l i a : v i s i t e d { 87 c o l o r : #444 ; /* g r i s foncé */ 88 background c o l o r : #ddd ; /* g r i s c l a i r */ 89 } 90 91 /* p r o p r i é t é s s p é c i f i q u e s des l i e n s s u r v o l é s */ 92 div nav ul l i a :hover { 93 c o l o r : black ; /* t e x t e n o i r */ 94 background c o l o r : white ; /* fond blanc */ 95 } 96 97 /* p a r t i e a r t i c l e contenant l e t e x t e p r i n c i p a l l e l a page */ 98 div a r t i c l e { 99 c o l o r : black ; /* c o u l e u r n o i r e */ 100 background c o l o r : white ; /* fond blanc */ 101 } 102 103 /* T i t r e p r i n c i p a l de l a page dans l a r t i c l e */ 63

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 104 div a r t i c l e h1 { 105 text a l i g n : c e n t e r ; /* t e x t e c e n t r é ( dans l a r t i c l e ) */ 106 padding : 10px ; /* un peu d espace autour du t e x t e */ 107 margin : 0 ; /* pas de marge : bords a l i g n é s */ 108 background image : l i n e a r g r a d i e n t (#999, white ) ; /* dégradé de c o u l e u r s */ 109 } 110 111 /* paragraphes de l a r t i c l e */ 112 div a r t i c l e p { 113 text a l i g n : j u s t i f y ; /* t e x t e j u s t i f i é */ 114 padding : 5px 10px ; /* un peu d espace autou des paragraphes */ 115 } 116 117 /* pied de page */ 118 f o o t e r { 119 width : 60% ; /* l a r g e u r 60% de l a page */ 120 background c o l o r : #444 ; /* fond g r i s f o n c é */ 121 c o l o r : white ; /* t e x t e blanc */ 122 margin : 20px auto ; /* a l i g n é sur l a bas de l a r t i c l e */ 123 text a l i g n : c e n t e r ; /* t e x t e c e n t r é dans l e pied de page */ 124 border r a d i u s : 0 0 20px 20px ; /* a n g l e s du bas */ 125 } 2.12 CSS adaptatifs : Media Queries Les Media Queries permettent de créer des styles différents selon l écran sur lequel la page s affiche. Par exemple, on peut mettre deux feuilles de style différentes selon la mise taille de l écran. L exemple suivant, qui s appuie sur les deux exemples de mise en page précédents, crée une mise en page différente pour les largeur d affichage inférieur ou supérieure à 1000px. On met le menu à gauche pour les écrans suffisamment larges, et un menu en haut pour les écrans un peu étroit. exemples/chapitrecss/ex16_mediaqueries.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <! MISE EN PAGE PAR DÉFAUT : menu à gauche > 6 <link rel= s t y l e s h e e t media= ( min width : 1001px ) href=. / ex14_exemple_miseenpage. c s s /> 7 <! MISE EN PAGE POUR PETITS ÉCRANS : menu en haut > 8 <link rel= s t y l e s h e e t media= (max width : 1000px ) href=. / ex15_miseenpage_2. c s s /> 9 <t i t l e>exemple de mise en page</ t i t l e> 10 </head> 11 <body> 12 <header> 13 <h1>exemple de mise en page</h1> 14 </ header> 15 <div class= content > 16 <nav> 17 <h1>navigation</h1> 18 <ul> 64

Chapitre 2 : Styles CSS et mise en page 19 < l i> 20 <a href=. / coucou. html >l i e n 1</a> 21 </ l i> 22 < l i> 23 <a href=. / toto. html >l i e n 2</a> 24 </ l i> 25 < l i> 26 <a href=. / t i t i. html >l i e n 2</a> 27 </ l i> 28 </ ul> 29 </ nav> 30 <a r t i c l e> 31 <h1>corps du t e x t e</h1> 32 <p> 33 Nous mettons i c i l e corps du t e x t e. Paragraphe 1. 34 </p> 35 <p> 36 Notons que l e s l i e n s dans l e menu n ont pas l e même aspect 37 que l e s l i e n s dans l e t e x t e. Le s t y l e e s t propre à chaque 38 zône de l a page. 39 </p> 40 <p> 41 Ceci e s t <a href=. / toto. html >un l i e n</a> normal 42 </p> 43 </ a r t i c l e> 44 </ div> 45 <f o o t e r> 46 &copy ; RM 2012. 47 </ f o o t e r> 48 </body> 49 </html> Notons qu on peut aussi créer des styles différents selon l écran balise par balise au cas par cas, comme dans l exemple de code suivant : 1 @media ( min width : 400 px ) and ( max width : 500 px ) { 2 t a b l e tbody t r td { 3 padding 10 px ; 4 } 5 } 6 7 @media ( min width : 501px ) { 8 t a b l e tbody t r td { 9 padding 20 px ; 10 } 11 } Ou peut aussi prendre en compte le changement d orientation de l affichage d un mobile en portrait ou paysage : 1 <! MISE EN PAGE POUR L ORIENTATION PAYSAGE : menu à gauche > 2 <link rel= s t y l e s h e e t media= ( o r i e n t a t i o n :landscape ) href=. / ex14_exemple_miseenpage. c s s /> 3 <! MISE EN PAGE POUR POUR L ORIENTATION PORTRAIT : menu en h a u t > 65

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 4 <link rel= s t y l e s h e e t media= ( o r i e n t a t i o n : p o r t r a i t ) href=. / ex15_miseenpage_2. c s s /> 66

Deuxième partie Bases du langage PHP 67

68

Table of Contents 3 PHP procédural 71 3.1 Notion de CGI................................... 71 3.2 Générer du code HTML avec un CGI en PHP.................. 72 3.3 Exemple de fonction en PHP........................... 73 3.4 Inclure un fichier PHP dans un autre....................... 74 3.5 Arithmétique : types int et float........................ 75 3.6 Tableaux indexés : avec une clé de type int................... 76 3.7 Tableaux associatifs : avec une clé de type String................ 77 3.8 Passage de paramètre à un script PHP...................... 79 3.9 Variables Locales ou Globales, Références.................... 82 4 Les classes en PHP 85 4.1 Exemples de classes PHP............................. 86 4.1.1 Classes de Base............................... 86 4.1.2 Structuration des Objets, Vues...................... 88 4.1.3 Utilisation des Classes et Vue HTML................... 92 4.2 Validation en entrée et gestion d une exception................. 94 4.2.1 Qu est-ce que le filtrage?......................... 94 4.2.2 Le Package People\Individuals..................... 94 4.2.3 Classe Personne avec filtrage dans les setters.............. 94 4.2.4 Test de construction de Personnes et récupération des exceptions... 99 4.3 Classe Employe héritant de la classe Personne.................. 103

70 TABLE OF CONTENTS

Chapitre 3 PHP procédural 3.1 Notion de CGI On appelle Common Gateway Interface, ou en abrégé CGI, une interface, utilisée par les serveurs HTTP, qui permet de générer la réponse du serveur par un programme, qui s exécute sur le serveur. Le programme pourra, assez typiquement, générer du code HTML qui sera affiché par un navigateur côté client. L interface CGI est indépendante du langage de programmation utilisée par le serveur, et n utilise que les flux standards et les variables d environnement. Voici un exemple de CGI programmé en C : 1 #i n c l u d e <s t d i o. h> 2 3 extern char ** environ ; 4 5 i n t main ( void ) exemples/cgi-bin/environ.c 71

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 6 { 7 i n t i ; 8 p r i n t f ( %s%c%c \n, Content Type :text /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 f o r ( i =0 ; environ [ i ]!=NULL ; i ++){ 18 p r i n t f ( %s<br/>\n, environ [ i ] ) ; 19 } 20 21 p r i n t f ( </body> ) ; 22 p r i n t f ( </html> ) ; 23 return 0 ; 24 } 3.2 Générer du code HTML avec un CGI en PHP Le PHP est un langage de programmation (ou langage de scripts) qui permet de générer et d afficher des pages webs dynamiques, c est à dire des pages dont le contenu dépend des actions de l utilisateur ou de l état, par exemple, d une base de données. En fin de compte, le code affiché est toujours du code HTML. Ce code HTML est généré par le programme PHP via la commande echo. La protection des caractères spéciaux du HTML (comme les guillemets) et le mélange du code PHP et du code HTML rend souvent le code d un script PHP. Nous verrons plus loin comment atténuer ce problème par une approche modulaire fondée sur la programmation objet. Le script PHP est inséré à l intérieur d une balise <?php > qui peut s insérer au sein du code HTML. exemples/php1/ex01_helloworld.php 72

Chapitre 3 : PHP procédural 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= utf 8 /> 5 <t i t l e>hello World en PHP</ t i t l e> 6 </head> 7 <body> 8 <p> 9 <?php // début du script PHP 10 echo Hello 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 script PHP > 13 </p> 14 </body> 15 </html> 3.3 Exemple de fonction en PHP Ici, nous voyons une fonction PHP qui génère l en-tête XHTML du document et son header. Cette fonction prend en paramètre le titre, le charset et l url d une feuille de style CSS à appliquer dans le header HTML. Le résultat est que lors de l utilisation de la fonction, presque tout le code HTML disparait pour être remplacé par une seule ligne de code, ce qui en fin de compte allégera de beaucoup le code source PHP. exemples/php1/ex02_function.php 1 <?php // début d un script PHP 2 f u n c t i o n outputentetehtml5 ( $ t i t l e, $charset, $css_sheet ) { 3 // s o r t i e du doctype. Les g u i l l e m e t s HTML sont p r o t é g é s par \ 4 echo <!doctype html>\n ; 5 echo <html lang=\ f r \ >\n ; 6 echo <head>\n ; 7 echo <meta c h a r s e t=\ ; 8 echo $ c h a r s e t ; 9 echo \ />\n ; 73

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 10 echo <l i n k r e l =\ s t y l e s h e e t \ h r e f=\ ; 11 echo $css_sheet ; 12 echo \ />\n ; 13 // concaténation de c h a î n e s de c a r a c t è r e s. 14 echo <t i t l e >. $ t i t l e. </ t i t l e >\n ; 15 echo </head>\n<body>\n ; 16 } 17?> 18 <?php 19 f u n c t i o n outputfinfichierhtml5 ( ) 20 { 21 echo </body>\n</html>\n ; 22 } 23?> 24 25 <?php 26 outputentetehtml5 ( Hello world v e r s i o n 2, UTF 8, mystyle. css ) ; 27?> 28 <?php // début du script PHP 29 echo <p>hello World!</p> ; // On a f f i c h e du code HTML s i l a s o r t i e 30 // f i n du script PHP 31?> 32 <?php 33 outputfinfichierhtml5 ( ) ; 34?> 3.4 Inclure un fichier PHP dans un autre Évidemment, si le but des fonctions PHP est de cacher et de réutiliser une partie du code, il est commode de pouvoir écrire une fois pour toutes la fonction dans un seul fichier, puis d utiliser la fonction dans tous nos scripts par la suite. Ici les fonctions outputentetexhtml et outputfinfichierxhtml sont utilisées dans tous les scripts qui affichent du code HTML. (en effet, nous verrons plus loin que certains fichiers PHP sont de la pure programmation et n affichent rien.) exemples/php1/commonfunctions.php 1 <?php // début d un script PHP 2 f u n c t i o n outputentetehtml5 ( $ t i t l e, $charset, $css_sheet ) { 3 // s o r t i e du doctype. Les g u i l l e m e t s HTML sont p r o t é g é s par \ 4 echo <!doctype html>\n ; 5 echo <html lang=\ f r \ >\n ; 6 echo <head>\n ; 7 echo <meta c h a r s e t=\ ; 8 echo $ c h a r s e t ; 9 echo \ />\n ; 10 echo <l i n k r e l =\ s t y l e s h e e t \ h r e f=\ ; 11 echo $css_sheet ; 12 echo \ />\n ; 13 // concaténation de c h a î n e s de c a r a c t è r e s. 14 echo <t i t l e >. $ t i t l e. </ t i t l e >\n ; 15 echo </head>\n<body>\n ; 16 } 17?> 74

Chapitre 3 : PHP procédural 18 19 <?php 20 f u n c t i o n outputfinfichierhtml5 ( ) 21 { 22 echo </body>\n</html>\n ; 23 } 24?> exemples/php1/ex03_include.php 1 <?php r e q u i r e (. / commonfunctions. php ) ; 2 3 outputentetehtml5 ( Hello world v e r s i o n 3, UTF 8, mystyle. css ) ; 4?> 5 <p> 6 <?php // début du script PHP 7 echo Hello World! ; // On a f f i c h e du code HTML s i l a s o r t i e 8 // f i n du script PHP 9?> 10 </p> 11 <?php 12 outputfinfichierhtml5 ( ) ; 13?> 3.5 Arithmétique : types int et float En PHP, on ne déclare pas les types des variables ou des paramètres de fonctions. Celui-ci est défini lors de l initialisation de la fonction. Des fonctions permettent cependant de tester le type ou d accéder au nom du type d une variable. Nous en verrons par la suite. exemples/php1/ex04_arithmetique_types.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 outputentetehtml5 ( Arithmétique f l o t t a n t e et e n t i è r e, UTF 8, mystyle. css ) ; 75

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 5?> 6 <p> 7 <?php // début du script PHP 8 f u n c t i o n appliquetva ( $prixht, $taux ) { 9 $prixttc = $prixht *(1.0+ $taux / 1 0 0. 0 ) ; 10 return $prixttc ; 11 } 12?> 13 <h1>calcul de TVA</h1> 14 <p> 15 <?php 16 $prix = 1 8 2. 0 ; 17 echo Pour un p r i x hors taxe de. $ prix. &euro ; et un taux de 19,6%\n ; 18 echo l e p r i x TTC e s t de : 19. round ( appliquetva ( $prix, 1 9. 6 ), 2 ). &euro ;. \ n ; 20 echo <br/>\ nallez! On a r r o n d i à :. i n t v a l ( appliquetva ( $prix, 1 9. 6 ) ). &euro ;. \ n ; 21?> 22 </p> 23 <?php 24 outputfinfichierhtml5 ( ) ; 25?> 3.6 Tableaux indexés : avec une clé de type int On crée un tableau avec la fonction array. On accéde à ses éléments (ici indexés par un int) en utilisant des crochets [ ]. La taille des tableaux peut être obtenue via la fonction sizeof. exemples/php1/ex05_tableaux_keyint.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 outputentetehtml5 ( Tableaux 1, UTF 8, mystyle. css ) ; 76

Chapitre 3 : PHP procédural 5?> 6 <p> 7 <h1>tableaux avec c l é e n t i è r e s</h1> 8 <p> 9 <?php 10 $tableau = array (23, 45, 41, 6, 04) ; 11 echo ( ; 12 for ( $ i=0 ; $ i < count ( $tableau ) ; $ i++) { 13 echo $tableau [ $ i ] ; 14 i f ( $ i + 1 < count ( $tableau ) ) 15 echo, ; 16 } 17 echo ) \n ; 18?> 19 </p> 20 <?php 21 outputfinfichierhtml5 ( ) ; 22?> 3.7 Tableaux associatifs : avec une clé de type String Il existe en PHP une deuxième sorte de tableaux : les tableaux associatifs, ainsi nommés car ils associent une valeur à une clef qui est une chaîne de caractères. On peut tout de même parcourir l ensemble du tableau en utilisant une boucle foreach. exemples/php1/ex06_tableaux_keystring.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 outputentetehtml5 ( Tableaux 2, UTF 8, mystyle. css ) ; 5?> 6 <p> 7 <h1>tableau avec c l é de type S t r i n g</h1> 8 <p> 9 <?php 77

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 10 $tableau = array ( nom => Caesar, prénom => Jules ) ; 11 echo <ul >\n ; 12 // a c c è s aux éléments : 13 echo <l i >Accès aux éléments du tableau :<br/> ; 14 echo Nom :. $tableau [ nom ]. <br/>\n ; 15 echo Prénom :. $tableau [ prénom ]..<br/></ l i >\n ; 16 17 // a f f i c h a g e de l ensemble des v a l e u r s du tableau par f o r e a c h : 18 echo <l i >Les v a l e u r s du tableau sont :<br/></ l i >\n ; 19 f o r e a c h ( $tableau as $chaine ) { 20 echo $chaine. ; 21 } 22 echo <br/>\n ; 23 24 // a f f i c h a g e des c l é s et des v a l e u r s du tableau 25 echo <l i >Les données du tableau sont :<br> ; 26 f o r e a c h ( $tableau as $ c l e => $chaine ) { 27 echo $ c l e. :. $chaine. <br/></ l i >\n ; 28 } 29 echo </ul >\n ; 30?> 31 </p> 32 <?php 33 outputfinfichierhtml5 ( ) ; 34?> 78

Chapitre 3 : PHP procédural 3.8 Passage de paramètre à un script PHP Dans l exemple suivant, le premier script passe deux paramètes au second : le titre de la page et le texte à afficher. Nous transmettons ici les paramètres par la méthode GET, la méthode POST, qui a l avantage de ne pas faire apparaître les paramètres dans l URL, est similaire au niveau programmation et sera vue plus loin. L url du second script dans le navigateur est ici : http://www.remysprogwebtuto.org/exemples/php1/\ ex08_passages_parametres2.php?texte=bonjour&titre=montitre exemples/php1/ex07_passages_parametres1.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 $ t i t r e = Mon t i t r e par défaut ; 5 i f ( i s s e t ($_GET[ t i t r e ] ) ) { 6 $ t i t r e = $_GET[ t i t r e ] ; 7 } 8 outputentetehtml5 ( $ t i t r e, UTF 8, mystyle. css ) ; 9?> 10 <p> 11 Pour l a n c e r l autre s c r i p t avec comme t e x t e 12 <?php 13 $ t e x t e = Bonjour ; 14 echo $ t e x t e ; 15 echo <br/> et comme t i t r e ; 16 $ t i t r e = montitre ; 17 echo $ t i t r e. ; 18 echo <a h r e f= \ ; 19 echo. / ex08_passages_parametres2. php?t e x t e = 20. $ t e x t e 21. &t i t r e= 22. $ t i t r e 23. >c l i q u e z i c i</a> ; 24?>. 25 </p> 79

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 26 <?php 27 outputfinfichierhtml5 ( ) ; 28?> Le second script peut alors récupérer les paramètres texte et titre dans un tableau associatif $_GET. On peut vérifier que les variables texte et titre ont bien été utilisées via la fonction isset. exemples/php1/ex08_passages_parametres2.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 $ t i t r e = Mon t i t r e par défaut ; 5 i f ( i s s e t ($_GET[ t i t r e ] ) ) { 6 $ t i t r e = $_GET[ t i t r e ] ; 7 } 8 9 outputentetehtml5 ( $ t i t r e, UTF 8, mystyle. css ) ; 10 11?> 12 <p> 13 <?php // début du script PHP 14 i f ( i s s e t ($_GET[ texte ] ) ) { 15 echo $_GET[ texte ] ; 16 } e l s e { 17 echo Hello World! ; // On a f f i c h e du code HTML s i l a s o r t i e 18 } 19 // f i n du script PHP 20?> 21 </p> 22 <?php 23 outputfinfichierhtml5 ( ) ; 24?> 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 : 80

Chapitre 3 : PHP procédural 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 exemples/php1/ex09_passages_parametres3.php 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 $ t i t r e = Mon t i t r e par défaut ; 5 i f ( i s s e t ($_GET[ t i t r e ] ) ) { 6 $ t i t r e = $_GET[ t i t r e ] ; 7 } 8 outputentetehtml5 ( $ t i t r e, UTF 8, mystyle. css ) ; 9?> 10 <p> 11 Pour l a n c e r l autre s c r i p t s avec comme t e x t e 12 <?php 13 $ t e x t e = L é t é va ê t r e chaud c e t t e année ; 14 echo. $ t e x t e. ; 15 echo <br/> et comme t i t r e ; 16 $ t i t r e = Passage de paramètres avec a c c e n t s et e s p a c e s ; 17 echo. $ t i t r e. ; 18 echo \n<a h r e f= \ ; 19 echo. / ex10_passages_parametres4. php?t e x t e = 20. h t m l e n t i t i e s ( $texte, ENT_COMPAT, UTF 8 ) 21. &t i t r e= 22. h t m l e n t i t i e s ( $ t i t r e, ENT_COMPAT, UTF 8 ) 23. \ >\n\ t c l i q u e z i c i \n</a> ; 24?>. 25 </p> 26 <?php 27 outputfinfichierhtml5 ( ) ; 28?> exemples/php1/ex10_passages_parametres4.php 81

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 1 <?php require_once. / commonfunctions. php ;?> 2 3 <?php 4 $ t i t r e = Mon t i t r e par défaut ; 5 i f ( i s s e t ($_GET[ t i t r e ] ) ) { 6 $ t i t r e = html_entity_decode ($_GET[ t i t r e ] ) ; 7 } 8 9 outputentetehtml5 ( $ t i t r e, UTF 8, mystyle. css ) ; 10 11?> 12 <p> 13 <?php // début du script PHP 14 i f ( i s s e t ($_GET[ texte ] ) ) { 15 echo html_entity_decode ($_GET[ texte ] ) ; 16 } e l s e { 17 echo Hello World! ; // On a f f i c h e du code HTML s i l a s o r t i e 18 } 19 // f i n du script PHP 20?> 21 </p> 22 <?php 23 outputfinfichierhtml5 ( ) ; 24?> 3.9 Variables Locales ou Globales, Références exemples/php1/ex11_porteevariables.php 1 <?php require_once. / commonfunctions. php ; 2 3 outputentetehtml5 ( Portée des V a r i a b l e s, UTF 8, mystyle. css ) ; 4?> 5 <h1>v a r i a b l e s l o c a l e s et g l o b a l e s</h1> 6 <?php 7 // D é c l a r a t i o n d une v a r i a b l e g l o b a l e 82

Chapitre 3 : PHP procédural 8 $a = Contenu i n i t i a l de l a v a r i a b l e g l o b a l e ; 9 10 // Fonction avec une v a r i a b l e l o c a l e homonyme 11 f u n c t i o n myfunctionwithlocalvariable ( ) { 12 $a = Contenu de l a v a r i a b l e a f f e c t é dans l a f o n c t i o n ; // v a r i a b l e l o c a l e $a 13 } 14 15 f u n c t i o n myfunctionwithglobalvariableaccess ( ) { 16 g l o b a l $a ; // a c c è s à l a v a r i a b l e g l o b a l e $a 17 $a = Contenu de l a v a r i a b l e a f f e c t é dans l a f o n c t i o n ; 18 } 19 20 myfunctionwithlocalvariable ( ) ; 21 echo Contenu de l a v a r i a b l e <code>a</code> après l a f o n c t i o n <code> myfunctionwithlocalvariable </code>&nbsp ; :<br/>. $a. <br/> ; 22 myfunctionwithglobalvariableaccess ( ) ; 23 echo Contenu de l a v a r i a b l e <code>a</code> après l a f o n c t i o n <code> myfunctionwithglobalvariableaccess </code>&nbsp ; :<br/>. $a. <br/> ; 24?> 25 <?php 26 outputfinfichierhtml5 ( ) ; 27?> exemples/php1/ex12_passageparreference.php 83

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 1 <?php require_once. / commonfunctions. php ; 2 3 outputentetehtml5 ( Portée des V a r i a b l e s, UTF 8, mystyle. css ) ; 4?> 5 <h1>passage par Référence et par Valeur</h1> 6 <?php 7 // D é c l a r a t i o n d une v a r i a b l e g l o b a l e 8 $a = Contenu i n i t i a l de l a v a r i a b l e g l o b a l e ; 9 10 // Fonction avec une v a r i a b l e l o c a l e homonyme 11 f u n c t i o n myfunctionwithlocalvariable ($myparam) { 12 $myparam = Contenu de l a v a r i a b l e a f f a c t é dans l a f o n c t i o n ; 13 } 14 15 f u n c t i o n myfunctionwithglobalvariableaccess(&$myparam) { 16 17 $myparam = Contenu de l a v a r i a b l e a f f e c t é dans l a f o n c t i o n ; 18 } 19 20 myfunctionwithlocalvariable ( $a ) ; 21 echo Contenu de l a v a r i a b l e <code>a</code> après l a f o n c t i o n <code> myfunctionwithlocalvariable </code>&nbsp ; :<br/>. $a. <br/> ; 22 myfunctionwithglobalvariableaccess ( $a ) ; 23 echo Contenu de l a v a r i a b l e <code>a</code> après l a f o n c t i o n <code> myfunctionwithglobalvariableaccess </code>&nbsp ; :<br/>. $a. <br/> ; 24?> 25 <?php 26 outputfinfichierhtml5 ( ) ; 27?> 84

Chapitre 4 Les classes en PHP La programmation objet permet, en développant une bonne fois pour toutes un ensemble de classes appelé framework, de simplifier grandement le travail de développement et de maintenance de logiciels complexes, de manière que ces logiciels soient facilement adaptables. Ainsi, une entreprise telle qu une société de services, d un client à l autre, reprendra tel quel une grande partie de son code, sans même le retoucher. Ce code doit avoir une interface de développement, c est à dire qu il doit mettre à disposition des développeurs un ensemble de méthodes qui permettent de réaliser toutes les tâches de base dont le programmeur peut avoir besoin pour développer chaque application particulière. Les caractéristiques d un framework doivent être : 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 circonscrits à 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. Par rapport à ces quatre objectifs, des outils sont à disposition des développeurs du framework : 1. Robustesse : la visibilité des variables et des méthodes (variables et méthodes privées, protected ou publiques) permet au développeur du framework de garantir que l utilisateur du framework n ira pas faire des bêtises en rentrant dans le code du framework, ce qui pourrait amener les instances de classes du framework dans un état incohérent. 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 et qui permet de séparer différents aspects du développement d une application. 85

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 3. Facilité de maintenance du framework : la conception UML permet d avoir une vision schématique du framework, qui peut souvent contenir des centaines de classes. Chaque classe est si possible très simple et la complexité se situe dans la communication entre classes. La réécriture ou la modification d une classe demande alors une intervention limitée, et ne doit pas affecter les autres classes, pourvu que l interface entre les classes reste la même. 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. 4.1 Exemples de classes PHP 4.1.1 Classes de Base Un classe doit permettre de manipuler un certain type d objets. La classe doit permettre de représenter les caractéristiques des objets, à travers un certain nombre d attributs, qui sont les variables communes à chacun des objets de ce type. La classe doit aussi permettre à un développeur qui l utilise de réaliser toutes les opération nécessaires sur ces objets, à traves des méthodes. Les méthodes d une classe sont les fonctions qui opèrent en interne sur la classe. La manipulation des attributs se fait presque systématiquement à travers des méthodes, cet qui évite que l utilisateur de la classe ne mette les attributs dans un état incohérent (exemple : variables NULL alors qu elle n est pas censée l être, ce qui génère un bug). Pour celà, on met les attributs privés, c est à dire que seules les méthodes de la classe peuvent accéder à ces attributs. Pour les autres classes, ces attributs ne sont pas visibles : elle ne peuvent pas y accéder directement mais uniquement à travers des méthodes. Voici un exemple avec une classe contenant le numéro de téléphone d une personne. 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. exemples/php2/ex01_classetelephone.php 1 <?php 2 namespace People \ Contact ; 3 4 class Telephone { 5 /** Numéro de téléphone, ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 6 p r i v a t e $numero ; 7 /** L i b e l l é du nuéro de téléphone ( domicile, t r a v i l, mobile, e t c ). 8 * Ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 9 p r i v a t e $ l i b e l l e ; 10 11 /** @brief Accesseur : permet d o b t e n i r l e numéro de téléphone. */ 12 p u b l i c f u n c t i o n getnumero ( ) { 13 return $ t h i s >numero ; 86

Chapitre 4 : Les classes en PHP 14 } 15 16 /** @brief Accesseur : permet d o b t e n i r l e l i b e l l é du téléphone */ 17 p u b l i c f u n c t i o n g e t L i b e l l e ( ) { 18 return $ t h i s >l i b e l l e ; 19 } 20 21 /** @brief 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 de téléphone 22 * @param $numero l e numéro de téléphone à u t i l i s e r. peut ê t r e n u l l. 23 * */ 24 p u b l i c f u n c t i o n setnumero ( $numero ) { 25 i f ( empty ( $numero ) ) 26 $ t h i s >numero = ; 27 e l s e 28 $ t h i s >numero = $numero ; 29 } 30 31 /** @brief 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 l i b e l l é de téléphone 32 * @param $numero l e l i b e l l é de téléphone à u t i l i s e r. peut ê t r e n u l l. 33 * */ 34 p u b l i c f u n c t i o n s e t L i b e l l e ( $ l i b e l l e ) { 35 i f ( empty ( $ l i b e l l e ) ) 36 $ t h i s >l i b e l l e = ; 37 e l s e 38 $ t h i s >l i b e l l e = $ l i b e l l e ; 39 } 40 41 /** @brief Constructeur : permet de c o n s t r u i r e et d i n i t i a l i s e r un Objet Telephone 42 * Appelle systématiquement l e s s e t t e r s. 43 */ 44 p u b l i c f u n c t i o n construct ( $ l i b e l l e, $numero ) { 45 $this >s e t L i b e l l e ( $ l i b e l l e ) ; 46 $this >setnumero ( $numero ) ; 47 } 48 49 /** 50 * @brief Méthode de g é n é r a t i o n d HTML. Permet d a f f i c h e r un téléphone en HTML. 51 * Les a t t r i b u t s doivent ê t r e non n u l l. ( mais normalement ça ne r i s q u e pas d a r r i v e r 52 * car l e s a t t r i b u t s sont p r i v é s 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 mettre à n u l l. 53 * Les s e t t e r s et 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 ne peuvent pas ê t r e n u l l. ) 54 * La méthode retourne l e code HTML. 55 */ 56 p u b l i c f u n c t i o n tohtml( ) { 57 return $ t h i s >l i b e l l e. &nbsp ; :. $ t h i s >numero ; 58 } 59 } 60?> Comme on le voit, la classe Telephone fait partie d un sous-namespace People\Contact 87

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web du namespace People. Les namespace sou un bon mayen en PHP de réaliser un package, au sens de la conception objet. 4.1.2 Structuration des Objets, Vues 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). Figure 4.1 : Diagramme de Classes du Package People\Contact 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éveloppé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. Nous développons maintenant le code PHP de la classe Adresse. exemples/php2/ex02_classeadresse.php 1 <?php 2 namespace P eop le \ Contact ; 3 r e q u i r e _ o n c e ( dirname ( FILE ). / e x 0 3 _ c l a s s e A d r e s s e P r o p e r t i e s T r a i t. php ) ; 4 5 /** @ b r i e f La c l a s s e a d r e s s e c o n t i e n t l a d r e s s e d une p e r s o n n e 6 ( q u i peut ê 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... ) 7 */ 8 class Adresse { 9 /** Numéro dans l a rue, ne d o i t pas ê t r e n u l l mais peut ê t r e v i d e */ 88

Chapitre 4 : Les classes en PHP 10 p r o t e c t e d $numerorue ; 11 /** Nom de l a rue, ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 12 p r o t e c t e d $rue ; 13 /** Complément ( l i e u dit, e t c. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 14 p r o t e c t e d $complementaddr ; 15 /** code p o s t a l */ 16 p r o t e c t e d $codepostal ; 17 /** nom de l a v i l l e. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 18 p r o t e c t e d $ v i l l e ; 19 /** nom du pays. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 20 p r o t e c t e d $pays ; 21 22 // 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 et s e t t e r s 23 use A d r e s s e P r o p e r t i e s ; 24 25 /** @brief Constructeur : 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 des paramètres. 26 * Les paramètres correspondent aux v a l e u r s à mettre dans l e s a t t r i b u t s. 27 * Tout o b j e t d o i t ê t r e i n i t i a l i s é avec l e c o n s t r u c t e u r ( appel à new ). 28 * I c i, l e s paramètres peuvent ê t r e n u l l. Les a t t r i b u t s sont a l o r s i n i t i a l i s é s 29 * à une chaîne vide, permettant l a cohérence de l a c l a s s e. 30 */ 31 p u b l i c f u n c t i o n construct ( $numerorue=, $rue=, $complementaddr=, 32 $codepostal=, $ v i l l e=, $pays = France ) { 33 $ t h i s >setnumerorue ( $numerorue ) ; 34 $ t h i s >setrue ( $rue ) ; 35 $ t h i s >setcomplementaddr ( $complementaddr ) ; 36 $ t h i s >setcodepostal ( $codepostal ) ; 37 $ t h i s >s e t V i l l e ( $ v i l l e ) ; 38 $ t h i s >setpays ( $pays ) ; 39 } 40 } // end o f c l a s s Adresse 41?> Voici maintenant le code PHP du trait AdresseProperties. exemples/php2/ex03_classeadressepropertiestrait.php 1 <?php 2 namespace People \ Contact ; 3 /** 4 @brief La c l a s s e a d r e s s e c o n t i e n t l a d r e s s e d une personne 5 ( qui peut ê 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... ) 6 */ 7 t r a i t A d r e s s e P r o p e r t i e s { 8 9 /** @brief Accesseur : permet d o b t e n i r l i d e n t i f i a n t de l i n s t a n c e. */ 10 p u b l i c f u n c t i o n getid ( ) { 11 return $ t h i s >id ; 12 } 13 14 /** @brief Accesseur : permet d o b t e n i r l e numéro dans l a rue. */ 15 p u b l i c f u n c t i o n getnumerorue ( ) { 16 return $ t h i s >numerorue ; 17 } 18 19 /** @brief Accesseur : permet d o b t e n i r l e nom l a rue. */ 89

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 20 p u b l i c f u n c t i o n getrue ( ) { 21 return $ t h i s >rue ; 22 } 23 24 /** @brief Accesseur : permet d o b t e n i r l e nom l e complément d a d r e s s e. */ 25 p u b l i c f u n c t i o n getcomplementaddr ( ) { 26 return $ t h i s >complementaddr ; 27 } 28 29 /** @brief Accesseur : permet d o b t e n i r l e nom l e code p o s t a l. */ 30 p u b l i c f u n c t i o n getcodepostal ( ) { 31 return $ t h i s >codepostal ; 32 } 33 34 /** @brief Accesseur : permet d o b t e n i r l e nom l a v i l l e. */ 35 p u b l i c f u n c t i o n g e t V i l l e ( ) { 36 return $ t h i s >v i l l e ; 37 } 38 39 40 /** @brief Accesseur : permet d o b t e n i r l e pays. */ 41 p u b l i c f u n c t i o n getpays ( ) { 42 return $ t h i s >pays ; 43 } 44 45 /** @brief 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. 46 @param $NumeroRue l e numéro à u t i l i s e r. peut ê t r e n u l l. 47 */ 48 p u b l i c f u n c t i o n s e t I d ( $id ) { 49 $ t h i s >id = empty ( $id )? : $id ; 50 } 51 52 /** @brief 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. 53 @param $NumeroRue l e numéro à u t i l i s e r. peut ê t r e n u l l. 54 */ 55 p u b l i c f u n c t i o n setnumerorue ( $numerorue ) { 56 $ t h i s >numerorue = ( $numerorue == n u l l )? : $numerorue ; 57 } 58 59 /** @brief 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. 60 @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. peut ê t r e n u l l. 61 */ 62 p u b l i c f u n c t i o n setrue ( $rue ) { 63 $ t h i s >rue = ( $rue == n u l l )? : $rue ; 64 } 65 66 /** @brief 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 complément d a d r e s s e. 67 @param $ComplementAddr l e complément d a d r e s s e à u t i l i s e r. peut ê t r e n u l l. 68 */ 69 p u b l i c f u n c t i o n setcomplementaddr ( $complementaddr ) { 70 $ t h i s >complementaddr = ( $complementaddr == n u l l )? : $ComplementAddr ; 71 } 72 73 /** @brief 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. 74 @param $CodePostal l e numéro à u t i l i s e r. peut ê t r e n u l l 90

Chapitre 4 : Les classes en PHP 75 */ 76 p u b l i c f u n c t i o n setcodepostal ( $codepostal ) { 77 $ t h i s >codepostal = ( $codepostal == n u l l )? : $codepostal ; 78 } 79 80 /** @brief 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. 81 @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. peut ê t r e n u l l 82 */ 83 p u b l i c f u n c t i o n s e t V i l l e ( $ v i l l e ) { 84 $ t h i s >v i l l e = ( $ v i l l e == n u l l )? : $ v i l l e ; 85 } 86 87 /** @brief 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 88 @param $pays l e nom du Pays à u t i l i s e r. peut ê t r e n u l l 89 */ 90 p u b l i c f u n c t i o n setpays ( $pays ) { 91 $ t h i s >pays = ( $pays == n u l l )? : $pays ; 92 } 93 } 94?> Voici maintenant le code PHP de la classe AdresseView. exemples/php2/ex04_classeadresseview.php 1 <?php 2 namespace People \ Contact ; 3 require_once ( dirname ( FILE ). / ex02_classeadresse. php ) ; 4 5 6 /** 7 @brief La c l a s s e AdresseView implémente l a g é n é r a t i o n d HTML pour a f f i c h e r 8 * une a d r e s s e dans une vue dans un navigareur. 9 * Implémente a u s s i des u t i l i s 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 10 * 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. 11 */ 12 class AdresseView { 13 14 /** 15 * @brief Méthode de g é n é r a t i o n d HTML. Permet de g é n é r e r l e code HTML d une a d r e s s e. 16 * Les a t t r i b u t s de l a d r e s s e doivent ê t r e non n u l l. 17 * ( mais normalement ça ne r i s q u e pas d a r r i v e r car l e s a t t r i b u t s sont p r i v é s ) 18 * La méthode retourne l e code HTML avec des r e t o u r à l a l i g n e pour un a f f i c h a g e mis en forme. 19 */ 20 p u b l i c s t a t i c f u n c t i o n gethtmldevelopped ( $ a d r e s s e ) { 21 $htmlcode = ; 22 $htmlcode.= <strong >Adresse : </strong ><br/>\n ; 23 $htmlcode.= $adresse >getnumerorue ( ) ; 24 i f (! empty ( $adresse >getnumerorue ( ) ) ) 25 $htmlcode.=, ; 26 $htmlcode.= $adresse >getrue ( ) ; 27 i f (! empty ( $adresse >getrue ( ) ) ) 28 $htmlcode.= <br/> ; 29 $htmlcode.= $adresse >getcomplementaddr ( ) ; 91

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 30 i f (! empty ( $adresse >getcomplementaddr ( ) ) ) 31 $htmlcode.= <br/> ; 32 $htmlcode.= $adresse >getcodepostal ( ). ; 33 $htmlcode.= $adresse >g e t V i l l e ( ) ; 34 i f (! empty ( $adresse >g e t V i l l e ( ) ) ) 35 $htmlcode.= <br/> ; 36 $htmlcode.= $adresse >getpays ( ). <br/> ; 37 38 return $htmlcode ; 39 } 40 41 /** 42 * @brief Méthode 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 en HTML. 43 * Les a t t r i b u t s doivent ê t r e non n u l l. ( mais normalement ça ne r i s q u e pas d a r r i v e r 44 * car l e s a t t r i b u t s sont p r i v é s 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 mettre à n u l l. 45 * Les s e t t e r s et 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 ne peuvent pas ê t r e n u l l. ) 46 * La méthode retourne l e code HTML pour un a f f i c h a g e compact. 47 */ 48 p u b l i c s t a t i c f u n c t i o n gethtmlcompact ( $ a d r e s s e ) { 49 $htmlcode = ; 50 $htmlcode.= $adresse >getnumerorue ( ) ; 51 i f (! empty ( $adresse >getnumerorue ( ) ) ) 52 $htmlcode.=, ; 53 $htmlcode.= $adresse >getrue ( ) ; 54 i f (! empty ( $adresse >getrue ( ) ) ) 55 $htmlcode.=, ; 56 $htmlcode.= $adresse >getcomplementaddr ( ) ; 57 i f (! empty ( $adresse >getcomplementaddr ( ) ) ) 58 $htmlcode.=, ; 59 $htmlcode.= $adresse >getcodepostal ( ). ; 60 $htmlcode.= $adresse >g e t V i l l e ( ) ; 61 i f (! empty ( $adresse >g e t V i l l e ( ) ) ) 62 $htmlcode.=, ; 63 $htmlcode.= $adresse >getpays ( ) ; 64 65 return $htmlcode ; 66 } 67 } // end o f c l a s s AdresseView 68?> 4.1.3 Utilisation des Classes et Vue HTML Voyons maintenant un petit script de test qui crée des adresses et les affiche en générant une vue HTML. Seul le script de test génère du code HTML et comporte un en-tête HTML (même si ce code HTML est en fait généré dans une méthode statique de la classe AdresseView). exemples/php2/ex05_testexampleimportnamespace.php 1 <?php 2 require_once ( dirname ( FILE ). / ex01_classetelephone. php ) ; 3 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 92

Chapitre 4 : Les classes en PHP 4 5 u s e People \ Contact a s Contact ; 6 7 $telephone = new Contact \ Telephone ( T r a v a i l, 01 23 45 67 89 ) ; 8 9 10 // Adresse Complète : 11 $ a d r e s s e 1 = new Contact \ Adresse ( 1 0, a l l é e du net, Quartier de l \ avenir, 12 63000, Clermont Ferrand ) ; 13 14 // Adresse sans code p o s t a l ni complément d a d r e s s e 15 $ a d r e s s e 2 = new Contact \ Adresse ( 1 0, Downing Street, null, 16 null, London, United Kingdom ) ; 17 18 // Génération du code HTML ( vue ) 19 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 20 outputentetehtml5 ( Ma première c l a s s e PHP, UTF 8, mystyle. css ) ; 21 22 echo <h1>test de Classe </h1> ; 23 echo <p> ; 24 echo <strong >Téléphone </strong >. $telephone >tohtml( ). <br/> ; 93

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 25 26 echo <strong >Adresse au format compact</strong > &nbsp ; :<br/>. 27 Contact \ AdresseView : :gethtmlcompact ( $ a d r e s s e 1 ). <br/> ; 28 echo Contact \ AdresseView : :gethtmldevelopped ( $ a d r e s s e 2 ). <br/> ; 29 30 // Adresse vide!!! 31 $ a d r e s s e 3 = new Contact \ Adresse ( ) ; 32 echo <strong >Adresse vide&nbsp ; :</ strong ><br/> 33. Contact \ AdresseView : :gethtmlcompact ( $ a d r e s s e 3 ). <br/> ; 34 echo </p> ; 35 36 outputfinfichierhtml5 ( ) ; 37?> 4.2 Validation en entrée et gestion d une exception 4.2.1 Qu est-ce que le filtrage? Les setters de la classe vont jouer un rôle important de filtrage des données. Le filtrage consiste à réaliser des tests sur les données entrées (généralement des données issues d un utilisateur final), et à générer des erreurs en cas de données incorrectes, ou encore en remplaçant automatiquement des données incorrecte par des données, sinon correctes, au moins inoffensives. En particulier, lorsque les données viendront de la saisie d un formulaire, ces données devront être systématiquement filtrées car l utilisateur, qui n est pas toujours bienveillant, et peut mettre n importe quoi dans les champs d un formulaire. Le filtrage jouera donc un rôle très important pour la sécurité. Par exemple, on prendra soin de limiter la longueur des attributs de type String à la fois au niveau du filtrage, puis au niveau de la base de données (voir chapitres ultérieurs). On pourra aussi utiliser des expressions régulières lors du filtrage grâce aux fonctions preg_match_all ou preg_match (voir man regex(7) pour la formation des expressions régulières). Le gros avantage du PHP par rapport à d autres langages comme javascript, est que PHP s exécute côté serveur donc un pirate n aura pas la possibilité d analyser précisément ce que fait le filtrage. Si une valeur invalide est détectée au niveau du filtrage, on générera une exception avec un message d erreur. Cette exception pourra être gérée à un autre niveau dans l application, ici au niveau du script de test qui affiche quelques employés. Certaines parties ultérieures de ce cours sont dédiées au filtrage précis des données et à garantir la sécurité du code grâce au filtrage. Dans cette partie, nous réalisons un filtrage sommaire, pour illustrer le mecanisme de gestion des erreurs par exceptions. 4.2.2 Le Package People\Individuals 4.2.3 Classe Personne avec filtrage dans les setters Nous voyons ici une classe Personne, suivant un peu le meme schéma de conception que la classe Adresse de la partie précédente. Cependant, au niiveau des setters, nous implémenterons un filtrage (minimal et peu réaliste pour le moment), rejetant une exception en cas de données incorrectes. exemples/php2/ex07_classepersonne.php 94

Chapitre 4 : Les classes en PHP Figure 4.2 : Diagramme de Classes du Package People\Individuals 1 <?php 2 namespace Pe op le \ I n d i v i d u a l s ; 3 r e q u i r e _ o n c e ( dirname ( FILE ). / e x 0 8 _ c l a s s e P e r s o n n e P r o p e r t i e s T r a i t. php ) ; 4 r e q u i r e _ o n c e ( dirname ( FILE ). / e x 0 1 _ c l a s s e T e l e p h o n e. php ) ; 5 6 u s e P eop le \ Contact \ A d r e s s e ; 7 u s e P eop le \ Contact \ Telephone ; 8 9 /** 10 @ b r i e f La c l a s s e Personne r e p r é s e n t e une p e r s o n n e ( c l i e n, employé, f o u r n i s s e u r, contact... ). 11 E l l e c o n t i e n t l i d e n t i t é (nom prénom ), l a d r e s s e, l e noméro de t é l é p h o n e 12 e t l e s a l a i r e mensuel de l employé. 13 */ 14 c l a s s Personne { 15 /** nom de l employé : o b l i g a t o i r e. Le nom de l employé ne peut pas ê t r e n u l l ou v i d e. */ 16 p r o t e c t e d $nom ; 17 /** prénom de l employé */ 18 p r o t e c t e d $prenom ; 19 /** a d r e s s e de l employé */ 20 protected $adresse ; 21 /** Tableau d e s numéros de t é l é p h o n e */ 22 protected $telephones ; 23 24 use PersonneProperties ; 25 26 /** 27 @brief Constructeur : 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 des paramètres. 95

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 28 Les paramètres correspondent aux v a l e u r s à mettre 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 é avec l e c o n s t r u c t e u r ( appel à new ). 30 Des e x c e p t i o n s sont r e j e t é e s en cas de paramètres i n v a l i d e. 31 */ 32 p u b l i c f u n c t i o n construct ($nom, $prenom, $adresse, $ t e l e p h o n e s ) { 33 34 $ t h i s >setnom ($nom) ; 35 $ t h i s >setprenom ( $prenom ) ; 36 $ t h i s >s e t A d r e s s e ( $ a d r e s s e ) ; 37 38 $ t h i s >settelephones ( $ t e l e p h o n e s ) ; 39 } 40 } 41?> exemples/php2/ex08_classepersonnepropertiestrait.php 1 <?php 2 namespace People \ I n d i v i d u a l s ; 3 require_once. / ex02_classeadresse. php ; 4 5 6 use People \ Contact \ Telephone ; 7 use People \ Contact \ Adresse ; 8 9 t r a i t PersonneProperties { 10 /** @brief 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 p u b l i c f u n c t i o n getnom ( ) { 12 return $ t h i s >nom ; 13 } 14 15 /** @brief 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 p u b l i c f u n c t i o n getprenom ( ) { 17 return $ t h i s >prenom ; 18 } 19 20 /** @brief 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 p u b l i c f u n c t i o n getadresse ( ) { 22 return $ t h i s >a d r e s s e ; 23 } 24 25 /** @brief a c c e s s e u r : permet d o b t e n i r l e tableau des t é l é p h o n e s de l employé */ 26 p u b l i c f u n c t i o n gettelephones ( ) { 27 28 return $ t h i s >t e l e p h o n e s ; 29 } 30 31 /** @brief 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é */ 32 p u b l i c f u n c t i o n gettelephone ( $ l i b e l l e ) { 33 i f ( empty ( $ t h i s >telephone [ $ l i b e l l e ] ) ) { 34 throw new \ Exception ( Désolé, Le téléphone. $ l i b e l l e. n \ e x i s t e pas. Have a try in the phonebook... ) ; 35 } 36 return $ t h i s >telephone [ $ l i b e l l e ] ; 37 } 96

Chapitre 4 : Les classes en PHP 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 nom de l a personne 39 @param $Nom l e nom de l a personne. Doit ê t r e non n u l l et comporter 40 au moins 1 c a r a c t è r e. 41 */ 42 p u b l i c f u n c t i o n setnom ($nom) { 43 i f ( empty ($nom) s t r l e n ($nom) > 100) { 44 throw new \ Exception ( Désolé, toute personne d o i t a v o i r un nom et l e nom a au plus 100 c a r a c t è r e s! ) ; 45 } e l s e { 46 $ t h i s >nom = $nom ; 47 } 48 } 49 50 /** 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 personne */ 51 p u b l i c f u n c t i o n setprenom ( $prenom ) { 52 i f ( empty ( $prenom ) s t r l e n ( $prenom ) > 50) { 53 throw new \ Exception ( Désolé, toute personne d o i t a v o i r un prenom et l e prenom a au plus 50 c a r a c t è r e s! ) ; 54 } e l s e { 55 $ t h i s >prenom = $prenom ; 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 a d r e s s e de l a personne */ 60 p u b l i c f u n c t i o n s e t A d r e s s e ( $ a d r e s s e ) { 61 i f ( $ a d r e s s e == n u l l g e t _ c l a s s ( $ a d r e s s e )!= People \ Contact \ Adresse ) { 62 throw new \ Exception ( Erreur : Adresse I n v a l i d e ) ; 63 } e l s e { 64 $ t h i s >a d r e s s e = $ a d r e s s e ; 65 } 66 } 67 68 /** 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 a d r e s s e de l a personne */ 69 p u b l i c f u n c t i o n settelephones ( $ t e l e p h o n e s ) { 70 i f (! is_array ( $ t e l e p h o n e s ) ) { 71 throw new \ Exception ( Erreur : Téléphones I n v a l i d e ) ; 72 } e l s e { 73 $ t h i s >t e l e p h o n e s = $ t e l e p h o n e s ; 74 } 75 } 76 77 /** s e t t e r : permet d a j o u t e r un numéro de téléphone de l a personne */ 78 p u b l i c f u n c t i o n addtelephone ( $ l i b e l l e, $numero ) { 79 i f (! empty ( $numero ) && s t r l e n ( $numero ) <= 15) { 80 i f (! is_array ( $ t h i s >t e l e p h o n e s ) ) { 81 $ t h i s >t e l e p h o n e s = array ( ) ; 82 } 83 $ t h i s >t e l e p h o n e s [ $ l i b e l l e ] = new Telephone ( $ l i b e l l e, $numero ) ; 84 } e l s e { 85 throw new \ Exception ( Erreur : Téléphone I n v a l i d e ) ; 86 } 87 88 } 89 90 /** s e t t e r : permet d a j o u t e r un numéro de téléphone de l a personne */ 91 p u b l i c f u n c t i o n removetelephone ( $ l i b e l l e ) { 97

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 92 i f (! empty ( $ t h i s >telephone [ $ l i b e l l e ] ) ) { 93 unset ( $ t h i s >telephone [ $ l i b e l l e ] ) ; 94 } 95 } 96 97 } 98?> exemples/php2/ex09_classepersonneview.php 1 <?php 2 namespace People \ I n d i v i d u a l s ; 3 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 4 require_once ( dirname ( FILE ). / ex07_classepersonne. php ) ; 5 6 use People \ Contact \ Adresse ; 7 u s e People \ Contact \ AdresseView ; 8 9 class PersonneView { 10 11 /** 12 @brief Méthode de g é n é r a t i o n d une vue HTML. Permet d a f f i c h e r une a d r e s s e en HTML. 13 Les a t t r i b u t s doivent ê t r e non n u l l. ( mais normalement ça ne r i s q u e pas d a r r i v e r 14 car l e s a t t r i b u t s sont p r i v é s 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 mettre à n u l l. 15 Les s e t t e r s et 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 ne peuvent pas ê t r e n u l l. ) 16 */ 17 p u b l i c s t a t i c f u n c t i o n gethtmldevelopped ( $personne ) { 18 $htmlcode = ; 19 $htmlcode.= nom :. $personne >getnom ( ). <br/>\n ; 20 i f ( s t r l e n ( $personne >getprenom )>=1) 21 $htmlcode.= Prénom :. $personne >getprenom ( ). <br/>\n ; 22 $htmlcode.= AdresseView : :gethtmldevelopped ( $personne >getadresse ( ) ) ; 23 $count = 0 ; 24 f o r e a c h ( $personne >gettelephones ( ) as $telephone ) { 25 i f ( $count!= 0) { 26 $htmlcode.= <br/> ; 27 } 28 $count++ ; 29 $htmlcode.= $telephone >tohtml( ) ; 30 } 31 $htmlcode.= <br/>\n ; 32 return $htmlcode ; 33 } 34 35 /** 36 @brief Méthode de g é n é r a t i o n d une vue l i g n e de tablehtml. Permet d a f f i c h e r des Personnes 37 dans une t a b l e HTML. 38 */ 39 p u b l i c s t a t i c f u n c t i o n gethtmltablerow ( $personne ) { 40 $htmlcode = <t r > ; 41 $htmlcode.= <td>. $personne >getnom ( ). </td> ; 98

Chapitre 4 : Les classes en PHP 42 $htmlcode.= <td>. $personne >getprenom ( ). </td> ; 43 $htmlcode.= <td>. AdresseView : :gethtmlcompact ( $personne >getadresse ( ) ). </ td> ; 44 $htmlcode.= <td> ; 45 $count = 0 ; 46 f o r e a c h ( $personne >gettelephones ( ) as $telephone ) { 47 i f ( $count!= 0) { 48 $htmlcode.= <br/> ; 49 } 50 $count++ ; 51 $htmlcode.= $telephone >tohtml( ) ; 52 } 53 $htmlcode.= </td> ; 54 $htmlcode.= </ t r > ; 55 56 return $htmlcode ; 57 } 58 59 60 61 /** 62 * Permet d o b t e n i r une l i g n e de t a b l e HTML avec l e s en t ê t e s de c o l o n n e s 63 * pour a f f i c h a g e d une t a b l e de Personnes. 64 * */ 65 p u b l i c s t a t i c f u n c t i o n gethtmltableheads ( ) { 66 $htmlcode = <t r > ; 67 $htmlcode.= <th>nom</th> ; 68 $htmlcode.= <th>prénom</th> ; 69 $htmlcode.= <th>adresse </th> ; 70 $htmlcode.= <th>téléphone ( s )</th> ; 71 $htmlcode.= </ t r > ; 72 return $htmlcode ; 73 } 74 } // end o f c l a s s PersonneView 75?> 4.2.4 Test de construction de Personnes et récupération des exceptions Voyons tout d abord la construction normale et l affichage d une personne. exemples/php2/ex10_testpersonnes.php 1 <?php 2 require_once ( dirname ( FILE ). / ex01_classetelephone. php ) ; 3 require_once ( dirname ( FILE ). / ex02_classeadresse. php ) ; 4 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 5 require_once ( dirname ( FILE ). / ex09_classepersonneview. php ) ; 6 7 use People \ Contact \ Adresse ; 8 u s e People \ Contact \ AdresseView ; 9 use People \ Contact \ Telephone ; 10 use People \ I n d i v i d u a l s \ Personne ; 11 use People \ I n d i v i d u a l s \ PersonneView ; 12 99

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 13 try { 14 $ a d r e s s e = new Adresse ( 1 0, a l l é e du net, Quartier de l \ avenir, 15 63000, Clermont Ferrand ) ; 16 $ t e l e p h o n e s = array (new Telephone ( Domicile, 04 73 00 00 00 ), 17 new Telephone ( Mobile, 06 78 90 12 34 ) ) ; 18 $personne = new Personne ( Obama, Barack, $adresse, $ t e l e p h o n e s ) ; 19 20 // La personne a bien é t é c o n s t r u i t e, on a f f i c h e 21 r e q u i r e ( ex10_vuenormale. php ) ; 22 } catch ( Exception $e ) { 23 // Une e r r e u r s e s t produite, on l a gère 24 r e q u i r e ( ex10_vueerreur. php ) ; 25 } 26 27?> exemples/php2/ex10_vuenormale.php 1 <?php 2 use People \ I n d i v i d u a l s \ PersonneView ; 3 require_once ( commonfunctions. php ) ; 4 outputentetehtml5 ( Construction et f f i c h a g e d \ une Personne, UTF 8, mystyle. css ) ; 5 6 echo <p> ; 7 echo PersonneView : :gethtmldevelopped ( $personne ) ; 8 echo </p> ; 9 10 outputfinfichierhtml5 ( ) ; 11?> exemples/php2/ex10_vueerreur.php 100

Chapitre 4 : Les classes en PHP 1 <?php 2 require_once ( commonfunctions. php ) ; 3 outputentetehtml5 ( Gestion d \ une exception, UTF 8, mystyle. css ) ; 4 5 echo <h1>une Erreur c e s t produite </h1> ; 6 echo <p>exception reçue :. $e >getmessage ( ). </p> ; 7 8 outputfinfichierhtml5 ( ) ; 9?> Voyons maintenant le test d une vue affichant plusiers personnes dans une table HTML. exemples/php2/ex11_testtableviewpersonnes.php 1 <?php 2 require_once ( dirname ( FILE ). / ex01_classetelephone. php ) ; 3 require_once ( dirname ( FILE ). / ex02_classeadresse. php ) ; 4 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 5 require_once ( dirname ( FILE ). / ex09_classepersonneview. php ) ; 6 7 use People \ Contact \ Adresse ; 8 u s e People \ Contact \ AdresseView ; 9 use People \ Contact \ Telephone ; 10 use People \ I n d i v i d u a l s \ Personne ; 11 12 echo <p> ; 13 try { 14 $ a d r e s s e 1 = new Adresse ( 1 0, a l l é e du net, Quartier de l \ avenir, 15 63000, Clermont Ferrand ) ; 16 $ t e l e p h o n e s 1 = array (new Telephone ( Domicile, 04 73 00 00 00 ) ) ; 17 $personne1 = new Personne ( Obama, Barack, $adresse1, $ t e l e p h o n e s 1 ) ; 18 $ a d r e s s e 2 = new Adresse ( 1 2, Georgy, null, 63000, Trench Town, Jamaica ) ; 19 $ t e l e p h o n e s 2 = array (new Telephone ( Emergency, 911 ) ) ; 20 $personne2 = new Personne ( Modèle, Jean, $adresse2, $ t e l e p h o n e s 2 ) ; 21 $ a d r e s s e 3 = new Adresse ( 1 0, Rock \ n Roll Street, Bronx, 63000, Rackamadour ) ; 22 $personne3 = new Personne ( Génération, igrec, $adresse3, 23 array (new Telephone ( T r a v a i l, 01 23 45 67 89 ) ) ) ; 24 $personnes = array (1 => $personne1, 2 => $personne2, 3 => $personne3 ) ; 25 101

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 26 r e q u i r e ( ex11_vuenormale. php ) ; 27 } catch ( Exception $e ) { 28 r e q u i r e ( ex10_vueerreur. php ) ; 29 } 30?> exemples/php2/ex11_vuenormale.php 1 <?php 2 use People \ I n d i v i d u a l s \ PersonneView ; 3 4 require_once ( commonfunctions. php ) ; 5 6 outputentetehtml5 ( Gestion d \ une exception, UTF 8, mystyle. css ) ; 7 echo <strong >A f f i c h a g e d une t a b l e de Personnes&nbsp ; :</ strong ><br/> ; 8 echo <table > ; 9 echo <thead>. PersonneView : :gethtmltableheads ( ). </thead> ; 10 echo <tbody> ; 11 f o r e a c h ( $personnes as $personne ) { 12 echo PersonneView : :gethtmltablerow ( $personne ) ; 13 } 14 echo </tbody> ; 15 echo </table > ; 16 outputfinfichierhtml5 ( ) ; 17?> 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. exemples/php2/ex12_testexceptionspersonnes.php 1 <?php 2 require_once ( commonfunctions. php ) ; 3 require_once ( dirname ( FILE ). / ex01_classetelephone. php ) ; 4 require_once ( dirname ( FILE ). / ex02_classeadresse. php ) ; 5 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 6 require_once ( dirname ( FILE ). / ex09_classepersonneview. php ) ; 7 8 use People \ Contact \ Adresse ; 102

Chapitre 4 : Les classes en PHP 9 u s e People \ Contact \ AdresseView ; 10 use People \ Contact \ Telephone ; 11 use People \ I n d i v i d u a l s \ Personne ; 12 use People \ I n d i v i d u a l s \ PersonneView ; 13 14 outputentetehtml5 ( Gestion d \ une exception, UTF 8, mystyle. css ) ; 15 16 echo <p> ; 17 echo <strong >Test avec r é c u p é r a t i o n s d e x c e p t i o n s&nbsp ; :</ strong ><br/> ; 18 try { 19 $ a d r e s s e 1 = new Adresse ( 1 0, Downing Street, null, 20 null, London, United Kingdom ) ; 21 $personne1 = new Personne ( Thatcher, Marggy, $adresse1, 22 01 23 45 67 89 ) ; // phony phone number... 23 24 echo PersonneView : :gethtmldevelopped ( $personne1 ) ; 25 } catch ( Exception $e ) { 26 echo Exception reçue :, $e >getmessage ( ), <br/>\n ; 27 } 28 29 try { 30 $ a d r e s s e 2 = new Adresse ( 1 0, a l l é e du net, Quartier de l \ avenir, 31 63000, Clermont Ferrand, Technique ) ; 32 $personne2 = new Personne ( Urluberlu, null, $adresse2, n u l l ) ; // Given name?? 33 echo PersonneView : :gethtmldevelopped ( $personne2 ) ; 34 } catch ( Exception $e ) { 35 echo Exception reçue :, $e >getmessage ( ), \n ; 36 } 37 echo </p> ; 38 39 outputfinfichierhtml5 ( ) ; 40?> 4.3 Classe Employe héritant de la classe Personne Notons l attribut categoriesemployes, qui répertorie dans un tableau toutes les catégories d employés possibles, et la méthode validcategorie, qui détermine si une chaine de catactères correspond à une catégorie d employés. Cette donnée et cette méthode sont déclarées statiques. Il s agit donc d une variable de classe et d une méthodes de classe. Voici le script de test qui crée quelques employés. Lorsque une exception est reçue, au lieu d afficher l employé, on affiche le message d erreur. Nous verrons plus loin comment ce mécanisme de gestion des exceptions permet de renvoyer à l utilisateur des informations sur les attributs invalides qu il a saisi dans le formulaire. exemples/php2/ex13_classeemploye.php 1 <?php 2 namespace People \ I n d i v i d u a l s \Employees ; 3 require_once ( dirname ( FILE ). / ex07_classepersonne. php ) ; 4 require_once ( dirname ( FILE ). / ex14_classeemployeproperties. php ) ; 5 6 use People \ I n d i v i d u a l s \ Personne ; 7 103

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 8 class Employe extends Personne { 9 10 /** s a l a i r e mensuel de l a personne en euros / mois */ 11 p r o t e c t e d $ s a l a i r e M e n s u e l ; 12 13 /** c a t é g o r i e de l employé : s e c r é t a i r e, commercial, technique ou pdg */ 14 p r o t e c t e d $ c a t e g o r i e ; 15 16 /** @brief tableau de t o u t e s l e s c a t é g o r i e s d employés p o s s i b l e s. 17 un a t t r i b u t s t a t i q u e e s t un a t t r i b u t qui e x i s t e en un s e u l exemplaire 18 commun à tous l e s o b j e t s de l a c l a s s e. 19 Cela é v i t e d a v o i r autant de c o p i e s du tableau $categoriesemployes 20 qu i l y a d i n s t a n c e de l a c l a s s e Employe en mémoire. 21 */ 22 p r i v a t e s t a t i c $categoriesemployes = array ( s e c r é t a i r e, commercial, technique, boss ) ; 23 24 use EmployeProperties ; 25 26 p u b l i c f u n c t i o n construct ($nom, $prenom, $adresse, 27 $telephones, $ s a l a i r e, $ c a t e g o r i e ) { 28 parent : : construct ($nom, $prenom, $adresse, $ t e l e p h o n e s ) ; 29 30 $ t h i s >s e t S a l a i r e M e n s u e l ( $ s a l a i r e ) ; 31 $ t h i s >s e t C a t e g o r i e ( $ c a t e g o r i e ) ; 32 } 33 } 34?> exemples/php2/ex14_classeemployeproperties.php 1 <?php 2 namespace People \ I n d i v i d u a l s \Employees ; 3 4 t r a i t EmployeProperties { 5 6 /** Méthode s t a t i q u e de v a l i d a t i o n d un paramètre de c a t é g o r i e. 7 l a v a l e u r d o i t se trouver dans l e s tableau $categoriesemployes. 8 Une méthode s t a t i q u e e s t une méthode qui ne s applique pas à un o b j e t p a r t i c u l i e r. 9 On l u t i l i s e avec s e l f : : ou à l e x t é r i e u r de l a c l a s s e avec Employe : : 10 */ 11 p u b l i c s t a t i c f u n c t i o n i s V a l i d C a t e g o r i e ( $ c a t e g o r i e ) { 12 i f ( $ c a t e g o r i e == n u l l! i s _ s t r i n g ( $ c a t e g o r i e )! in_array ( $ c a t e g o r i e, s e l f : :$categoriesemployes ) ) { 13 return f a l s e ; 14 } 15 return true ; 16 } 17 18 /** @brief a c c e s s e u r : permet d o b t e n i r l a c a t é g o r i e de l employé */ 19 p u b l i c f u n c t i o n g e t C a t e g o r i e ( ) { 20 return $ t h i s >c a t e g o r i e ; 21 } 22 104

Chapitre 4 : Les classes en PHP 23 /** @brief a c c e s s e u r : permet d o b t e n i r l e téléphone 1 de l employé */ 24 p u b l i c f u n c t i o n g e t S a l a i r e M e n s u e l ( ) { 25 return $ t h i s >s a l a i r e M e n s u e l ; 26 } 27 28 /** 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 a c a t é g o r i e de l a personne 29 @param $Categorie d o i t correspondre à une c a t é g o r i e d employé r é p e r t o r i é e. 30 */ 31 p u b l i c f u n c t i o n s e t C a t e g o r i e ( $ c a t e g o r i e ) { 32 i f (! s e l f : :i s V a l i d C a t e g o r i e ( $ c a t e g o r i e ) ) { 33 throw new \ Exception ( Erreur, c a t é g o r i e d employé \. $ c a t e g o r i e. \ i n v a l i d e. ) ; 34 } e l s e { 35 $ t h i s >c a t e g o r i e = $ c a t e g o r i e ; 36 } 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 e s a l a i r e mensuel de l a personne 40 @param $ S a l a i r e s a l a i r e mensuel en euros / mois 41 */ 42 p u b l i c f u n c t i o n s e t S a l a i r e M e n s u e l ( $ s a l a i r e ) { 43 i f ( $ s a l a i r e == n u l l! is_numeric ( $ s a l a i r e ) ) { 44 $ t h i s >s a l a i r e M e n s u e l = 0. 0 ; 45 } e l s e { 46 $ 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 ; 47 } 48 } 49 } 50?> exemples/php2/ex15_classeemployeview.php 1 <?php 2 namespace People \ I n d i v i d u a l s \Employees ; 3 require_once ( dirname ( FILE ). / ex13_classeemploye. php ) ; 4 require_once ( dirname ( FILE ). / ex09_classepersonneview. php ) ; 5 6 use People \ I n d i v i d u a l s \ PersonneView ; 7 8 class EmployeView { 9 10 /** 11 @brief Méthode de g é n é r a t i o n d une vue HTML. Permet d a f f i c h e r un Employe en HTML. 12 Les a t t r i b u t s doivent ê t r e non n u l l. 13 */ 14 p u b l i c s t a t i c f u n c t i o n gethtmldevelopped ( $employe ) { 15 $htmlcode = PersonneView : :gethtmldevelopped ( $employe ) ; 16 $htmlcode.= S a l a i r e mensuel :. $employe >g e t S a l a i r e M e n s u e l ( ). &euro ; par mois<br/>\n ; 17 $htmlcode.= Catégorie :. $employe >g e t C a t e g o r i e ( ). <br/>\n ; 18 return $htmlcode ; 19 } 20 } // end o f c l a s s EmployeView 105

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 21?> exemples/php2/ex16_testemploye.php 1 <?php 2 require_once ( commonfunctions. php ) ; 3 require_once ( dirname ( FILE ). / ex15_classeemployeview. php ) ; 4 require_once ( dirname ( FILE ). / ex01_classetelephone. php ) ; 5 require_once ( dirname ( FILE ). / ex02_classeadresse. php ) ; 6 require_once ( dirname ( FILE ). / ex04_classeadresseview. php ) ; 7 8 use People \ Contact \ Adresse ; 9 u s e People \ Contact \ AdresseView ; 10 use People \ Contact \ Telephone ; 11 use People \ I n d i v i d u a l s \ Personne ; 12 use People \ I n d i v i d u a l s \ PersonneView ; 13 use People \ I n d i v i d u a l s \Employees\Employe ; 14 use People \ I n d i v i d u a l s \Employees\EmployeView ; 15 16 outputentetehtml5 ( Gestion d \ une exception, UTF 8, mystyle. css ) ; 17 18 echo <p> ; 19 try { 20 $ a d r e s s e 1 = new Adresse ( 1 0, a l l é e du net, Quartier de l \ avenir, 21 63000, Clermont Ferrand ) ; 22 23 $ t e l e p h o n e s 1 = array (new Telephone ( Domicile, 04 73 00 00 00 ) ) ; 24 25 echo <strong >Construction et A f f i c h a g e d un Employé&nbsp ; :</ strong ><br/> ; 26 $employe = new Employe ( Obama, Barack, $adresse1, $telephones1, 300000.0, boss ) ; 27 echo EmployeView : :gethtmldevelopped ( $employe ) ; 28 } catch ( Exception $e ) { 29 echo Exception reçue :, $e >getmessage ( ), \n ; 30 } 106

Chapitre 4 : Les classes en PHP 31 32 echo <strong >Test avec r é c u p é r a t i o n s d e x c e p t i o n s&nbsp ; :</ strong ><br/> ; 33 try { 34 $ a d r e s s e 3 = new Adresse ( 1 0, Downing Street, null, 35 null, London, United Kingdom ) ; 36 $employe3 = new Employe ( Thatcher, Margaret, $adresse3, 37 array (new Telephone ( Emergency, 911 ) ), null, badcategory ) ; 38 echo EmployeView : :gethtmldevelopped ( $employe3 ) ; 39 } catch ( Exception $e ) { 40 echo Exception reçue :, $e >getmessage ( ), \n ; 41 } 42 echo </p> ; 43 44 outputfinfichierhtml5 ( ) ; 45?> 107

Troisième partie Formulaires et Filtrage des Données Utilisateur 108

Table of Contents 5 Formulaires HTML/PHP 111 5.1 Formulaires HTML................................. 111 5.1.1 Premier Formulaire HTML........................ 111 5.2 Exemple de style CSS pour formulaire...................... 112 5.2.1 Réception des données en PHP...................... 117 5.3 Validation pour la sécurité : Appel de filter_var................ 118 5.4 Appel des vues................................... 119 5.5 Tableaux $_POST $_GET $_REQUEST........................ 121 5.6 Formulaires dynamiques an javascript....................... 123 6 Injection, Filtrage, Expressions Régulières 126 6.1 Injections HTML et échappement......................... 126 6.1.1 Injections HTML.............................. 126 6.1.2 Prévention des injections HTML par échappement........... 128 6.2 Injections SQL................................... 133 6.3 La fonction filter_var.............................. 139 6.3.1 Principe de la fonction PHP filter_var................. 139 6.3.2 Les filtres de Validation.......................... 140 6.3.3 Les filtres de Nettoyage.......................... 142 6.3.4 Le filtre personnalisé FILTER_CALLBACK................. 142 6.4 Expressions régulières............................... 143 7 Formulaires PHP/HTML, filtrage, exceptions 145 7.1 La Classe Adresse................................. 145 7.2 Filtrage des attributs................................ 147 7.3 Fabrique d Adresse................................. 151 7.4 Génération de formulaires et classe AdresseFormView.............. 152

TABLE OF CONTENTS 7.5 Enchaînement de la saisie à la vue........................ 158 7.6 Les Vues....................................... 160 7.7 Modification d une Adresse............................ 162 110

Chapitre 5 Formulaires HTML/PHP Les formulaires HTML permettent de faire saisir des données par l utilisateur via son navigateur. 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é. 5.1 Formulaires HTML Un formulaire est créé par une balise <form> qui contient la méthode de transmission des données (GET ou POST) et l action, qui est l URL du script (ici un script PHP) qui va récupérer les données du formulaire. Chaque input a son label, qui explique à l utilisateur ce qu il doit saisir dans ce champ. La correspondance entre les inputs et le labels se fait via l attribut for du label qui doit correspondre à l attribut id de l input. L attribut name de l input servira lors de la récupération des données. Les attributs id et name de l input peuvent être égaux si on veut simplifier. 5.1.1 Premier Formulaire HTML exemples/forms1/ex01_form_html.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <t i t l e>mon premier f o r m u l a i r e HTML</ t i t l e> 6 </head> 7 <body> 8 <h1>s a i s i e d un employé</h1> 9 <form method= post action= ex02_reception. php > 10 <p> 11 <label for= nomemploye >Nom</ label> 12 <input type= t e x t name= nom id= nomemploye size= 30 /> 13 </p> 14 <p> 15 <label for= prenomemploye >Prénom</ label> 16 <input type= t e x t name= prenom id= prenomemploye size= 30 /><br/> 17 </p> 18 <p> 111

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 19 <label for= telephone >Téléphone</ label> 20 <input type= t e x t name= telephone id= telephone size= 15 /><br/> 21 </p> 22 <p> 23 <label for= email >e mail</ label> 24 <input type= t e x t name= email id= email size= 20 /><br/> 25 </p> 26 <p> 27 <label for= c a t e g o r i e >Catégorie</ label> 28 <select name= c a t e g o r i e > 29 <option value= s e c r e t a i r e selected= s e l e c t e d >S e c r é t a i r e</option> 30 <option value= commercial >Commercial</ option> 31 <option value= technique >Technique</option> 32 <option value= b o s s />The Big Boss</ option> 33 </ select> 34 </p> 35 <p> 36 <input type= submit value= Envoyer ></ input> 37 </p> 38 </form> 39 </body> 40 </html> 5.2 Exemple de style CSS pour formulaire 112

Chapitre 5 : Formulaires HTML/PHP exemples/forms1/mystyle.css 1 2 /* s t y l e par défaut du t e x t e */ 3 body { 4 font family : Comic Sans MS ; 5 font s i z e : 18 pt ; 6 background c o l o r : #f f f ; 7 c o l o r : #222 ; 8 } 9 10 /* s t y l e du t i t r e */ 11 h1 { 12 font weight : bold ; 13 font s i z e : 150% ; 14 c o l o r : white ; 15 text a l i g n : c e n t e r ; 16 background c o l o r : #999 ; 17 padding : 15px ; 18 } 19 20 /****************************************** 21 mise en forme du f o r m u l a i r e 22 \*****************************************/ 23 24 /* Largeur minimale pour que l a mise en page ne c a s s e pas */ 25 form { 26 min width : 800 px ; 27 } 28 29 /* tous 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 nputs */ 30 form p l a b e l { 113

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 31 f l o a t : l e f t ; 32 width : 400px ; 33 text a l i g n : r i g h t ; 34 padding : 6px ; 35 font weight : bold ; 36 } 37 38 form p input { 39 padding : 6px ; 40 margin l e f t : 20px ; 41 background c o l o r : #ddd ; 42 border s t y l e : groove ; 43 border width : 5px ; 44 border c o l o r : #444 ; 45 border r a d i u s :10px ; 46 } 47 48 form p s e l e c t { 49 padding : 1px 6px ; 50 margin l e f t : 20px ; 51 background c o l o r : #ddd ; 52 border s t y l e : groove ; 53 border width : 5px ; 54 border c o l o r : #444 ; 55 border r a d i u s :10px ; 56 font s i z e : 110% ; 57 } 58 59 /* input s p é c i a l pour l e boutton submit */ 60 form p input. sanslabel { 61 margin l e f t : 432px ; /* 400+6+6+20 : a l i g n é sur l e s a u t r e s i nputs */ 62 font s i z e : 130% ; 63 font weight : bolder ; 64 background c o l o r :#f f 3 3 3 3 ; 65 c o l o r :white ; 66 } 67 68 form p { 69 background c o l o r : #f f f ; 70 padding : 0px ; 71 } 72 73 form p span. errormsg { 74 c o l o r :red ; 75 font weight :bolder ; 76 } 77 78 /****************************************/ 79 80 81 /* s t y l e par défaut des l i e n s */ 82 a : l i n k { 83 text 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 é */ 84 c o l o r : #00e ; 85 } 86 114

Chapitre 5 : Formulaires HTML/PHP 87 /* s t y l e des l i e n s v i s i t é s */ 88 a : v i s i t e d { 89 text 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 : #00c ;/* bleu c l a i r */ 91 } 92 93 /* s t y l e des l i e n s v i s i t é s */ 94 a :hover { 95 text 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 : #e40 ;/* rouge v i f */ 97 } 98 99 /* s t y l e des éléments importants */ 100 strong { 101 font v a r i a n t : small caps ; 102 font weight : bolder ; 103 c o l o r : black ; 104 } 105 106 /* s t y l e des éléments mis en évidence */ 107 em { 108 font s t y l e : i t a l i c ; 109 c o l o r : black ; 110 } 111 112 p { 113 background c o l o r : #ddd ; 114 text a l i g n : j u s t i f y ; 115 padding : 5 pt ; 116 } exemples/forms1/mystyle.css 1 2 /* s t y l e par défaut du t e x t e */ 3 body { 4 font family : Comic Sans MS ; 5 font s i z e : 18 pt ; 6 background c o l o r : #f f f ; 7 c o l o r : #222 ; 8 } 9 10 /* s t y l e du t i t r e */ 11 h1 { 12 font weight : bold ; 13 font s i z e : 150% ; 14 c o l o r : white ; 15 text a l i g n : c e n t e r ; 16 background c o l o r : #999 ; 17 padding : 15px ; 18 } 19 20 /****************************************** 21 mise en forme du f o r m u l a i r e 22 \*****************************************/ 23 115

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 24 /* Largeur minimale pour que l a mise en page ne c a s s e pas */ 25 form { 26 min width : 800 px ; 27 } 28 29 /* tous 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 nputs */ 30 form p l a b e l { 31 f l o a t : l e f t ; 32 width : 400px ; 33 text a l i g n : r i g h t ; 34 padding : 6px ; 35 font weight : bold ; 36 } 37 38 form p input { 39 padding : 6px ; 40 margin l e f t : 20px ; 41 background c o l o r : #ddd ; 42 border s t y l e : groove ; 43 border width : 5px ; 44 border c o l o r : #444 ; 45 border r a d i u s :10px ; 46 } 47 48 form p s e l e c t { 49 padding : 1px 6px ; 50 margin l e f t : 20px ; 51 background c o l o r : #ddd ; 52 border s t y l e : groove ; 53 border width : 5px ; 54 border c o l o r : #444 ; 55 border r a d i u s :10px ; 56 font s i z e : 110% ; 57 } 58 59 /* input s p é c i a l pour l e boutton submit */ 60 form p input. sanslabel { 61 margin l e f t : 432px ; /* 400+6+6+20 : a l i g n é sur l e s a u t r e s i nputs */ 62 font s i z e : 130% ; 63 font weight : bolder ; 64 background c o l o r :#f f 3 3 3 3 ; 65 c o l o r :white ; 66 } 67 68 form p { 69 background c o l o r : #f f f ; 70 padding : 0px ; 71 } 72 73 form p span. errormsg { 74 c o l o r :red ; 75 font weight :bolder ; 76 } 77 78 /****************************************/ 79 116

Chapitre 5 : Formulaires HTML/PHP 80 81 /* s t y l e par défaut des l i e n s */ 82 a : l i n k { 83 text 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 é */ 84 c o l o r : #00e ; 85 } 86 87 /* s t y l e des l i e n s v i s i t é s */ 88 a : v i s i t e d { 89 text 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 : #00c ;/* bleu c l a i r */ 91 } 92 93 /* s t y l e des l i e n s v i s i t é s */ 94 a :hover { 95 text 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 : #e40 ;/* rouge v i f */ 97 } 98 99 /* s t y l e des éléments importants */ 100 strong { 101 font v a r i a n t : small caps ; 102 font weight : bolder ; 103 c o l o r : black ; 104 } 105 106 /* s t y l e des éléments mis en évidence */ 107 em { 108 font s t y l e : i t a l i c ; 109 c o l o r : black ; 110 } 111 112 p { 113 background c o l o r : #ddd ; 114 text a l i g n : j u s t i f y ; 115 padding : 5 pt ; 116 } 5.2.1 Réception des données en PHP La réception des données se fait ici par la méthode POST (comme indiqué dans la balise <form>). Les données sont récupérées dans un tableau associatif $_POST, dont les clefs sont les attributs name des inputs du formulaire précédent. On teste si ces attributs existent bien via la fonction isset. exemples/forms1/ex02_reception.php 1 <?php 2 $nom = i s s e t ($_POST[ nom ] )? $_POST[ nom ] : ; 3 $prenom = i s s e t ($_POST[ prenom ] )? $_POST[ prenom ] : ; 4 $telephone = i s s e t ($_POST[ telephone ] )? $_POST[ telephone ] : ; 5 $email = i s s e t ($_POST[ email ] )? $_POST[ email ] : ; 6 $ c a t e g o r i e = i s s e t ($_POST[ c a t e g o r i e ] )? $_POST[ c a t e g o r i e ] : ; 7 8 r e q u i r e ( ex04_validation. php ) ; 117

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 9 10 i f ( empty ( $dataerrors ) ) { 11 r e q u i r e ( ex05_vuesuccess. php ) ; 12 } e l s e { 13 r e q u i r e ( ex06_vueerror. php ) ; 14 } 15?> 5.3 Validation pour la sécurité : Appel de filter_var Pour des raisons de sécurité (voir le chpitre 6), un filtrage systématique doit être effectué sur les données reçus dans les tableaux $_GET, $_POST, $_COOCKIE, etc. Pour cela, on fait généralement un script de validation qui valide ou nettoie les données, par exemple en utilisant la fonction filter_var. exemples/forms1/ex04_validation.php 1 <?php 2 require_once ( e x 0 3 _ v a l i d U t i l s. php ) ; 3 4 $dataerrors = array ( ) ; 5 6 // v a l i d a t i o n du nom 7 $nom = f i l t e r _ v a r ($nom, g e t S a n i t i z e F i l t e r ( string ) ) ; 8 9 // v a l i d a t i o n du prénom 10 $prenom = f i l t e r _ v a r ( $prenom, g e t S a n i t i z e F i l t e r ( string ) ) ; 11 12 // v a l i d a t i o n du téléphone 13 $telephone = f i l t e r _ v a r ( $telephone, g e t S a n i t i z e F i l t e r ( string ) ) ; 14 15 // v a l i d a t i o n de l a d r e s s e e mail 16 17 i f ( f i l t e r _ v a r ( $email, g e t V a l i d a t e F i l t e r ( email ) )===f a l s e ) { 18 $dataerrors [ email ] = Erreur : l a d r e s s e e mail e s t i n v a l i d e. ; 19 } 20 21 // v a l i d a t i o n de l a c a t é g o r i e 22 $ c a t e g o r i e = f i l t e r _ v a r ( $ c a t e g o r i e, g e t S a n i t i z e F i l t e r ( string ) ) ; 23?> exemples/forms1/ex03_validutils.php 1 <?php 2 // Méthode retournant l e f i l t r e de v a l i d a t i o n à u t i l i s e r 3 // dans l a f o n c t i o n f i l t e r _ v a r 4 f u n c t i o n g e t V a l i d a t e F i l t e r ( $type ) 5 { 6 switch ( $type ) { 7 case email : 8 $ f i l t e r = FILTER_VALIDATE_EMAIL; 9 break ; 10 case i n t : 11 $ f i l t e r = FILTER_VALIDATE_INT; 118

Chapitre 5 : Formulaires HTML/PHP 12 break ; 13 case boolean : 14 $ f i l t e r = FILTER_VALIDATE_BOOLEAN; 15 break ; 16 case ip : 17 $ f i l t e r = FILTER_VALIDATE_IP; 18 break ; 19 case u r l : 20 $ f i l t e r = FILTER_VALIDATE_URL; 21 break ; 22 d e f a u l t : // important!!! 23 $ f i l t e r = f a l s e ; // Si type 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éthode retournant l e f i l t r e de nettoyage à 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 f u n c t i o n 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 d e f a u l t : // important!!! 43 $ f i l t e r = f a l s e ; // Si type e s t faux, l a v a l i d. échoue. 44 } 45 return $ f i l t e r ; 46 } 47 48?> 5.4 Appel des vues Comme nous l avons vu dans la partie 5.2.1, un test permet, à la suite dee la validation, de savoir si une erreur s est produite. Suivant le cas, La vue normale affiche les données saisies ; Une vue d erreurs affiche les messages d erreur. exemples/forms1/ex05_vuesuccess.php 1 <?php 2 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 3 4 outputentetehtml5 ( A f f i c h a g e des données s a i s i e s, UTF 8, mystyle. css ) ; 5 119

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 6 echo <h1>données reçues </h1>\n ; 7 echo <p>\n ; 8 echo nom :. $nom. <br/>\n ; 9 echo prenom :. $prenom. <br/>\n ; 10 echo Téléphone :. $telephone. <br/>\n ; 11 echo E mail :. $email. <br/>\n ; 12 echo Catégorie :. $ c a t e g o r i e. <br/>\n ; 13 echo </p>\n ; 14 15 outputfinfichierhtml5 ( ) ; 16 17?> exemples/forms1/ex06_vueerror.php 1 <?php 2 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 3 outputentetehtml5 ( Erreurs données s a i s i e s, UTF 8, mystyle. css ) ; 4 5 echo <h1>données r e ç u e s i n c o r r e c t e s </h1>\n ; 6 7 echo <ul> ; 8 f o r e a c h ( $dataerrors as $ f i e l d => $message ) { 9 echo < l i>problème avec l \ a t t r i b u t <code>. $ f i e l d 10. </code>. <span style= c o l o r : red ; >. $message. </span></ l i> ; 11 } 120

Chapitre 5 : Formulaires HTML/PHP 12 echo </ul> ; 13 14 echo <p>merci de bien v o u l o i r <a href= ex01_form_html. html >Essayer à nouveau </a></p> ; 15 16 outputfinfichierhtml5 ( ) ; 17?> Dans tous les cas, seuls les scripts implémentant des vues envoie du code HTML sur la sortie standard. 5.5 Tableaux $_POST $_GET $_REQUEST Nous avons vu, pour le moment, deux méthodes pour transmettre des données d un script PHP à l autre : la méthode GET et la méthode POST. On réceptionne alors les données (respectivement) dans des tableaux associatifs $_POST $_GET. On peut aussi utiliser un tableau associatif $_REQUEST, qui contient à la fois les éléments du tableau $_POST et les éléments du tableau $_GET. Remarque : le tableau $_REQUEST contient aussi les éléments du tableau $_COOKIE. exemples/forms1/ex07_get_vs_posthidden.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>transmission de Paramètres</ t i t l e> 7 </head> 121

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 8 <body> 9 <h1>transmission de Paramètres<br/>(<i>POST v e r s u s GET</ i>)</h1> 10 <! Ce f o r m u l a i r e transmet 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= post action= ex08_get_post_request_param. php?language=f r&r e g i o n =eu > 12 <input type= hidden name= referredfrom value= searchengine > 13 <p> 14 <label for= prenomemploye >Prénom</ label> 15 <input type= t e x t name= prenom id= prenomemploye size= 30 /><br/> 16 </p> 17 <p> 18 <input type= submit value= Envoyer class= sanslabel ></input> 19 </p> 20 </form> 21 </body> 22 </html> exemples/forms1/ex08_get_post_request_param.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>transmission de Paramètres</ t i t l e> 7 </head> 8 <body> 9 <h1>réception de paramètres<br/>(<code>$_post</code>, <code>$_get</code> et < code>$_request</code>)</h1> 10 <?php 11 f o r e a c h ($_GET as $key => $val ) { 12 echo h t m l e n t i t i e s ( \$_GET[. $key. ] =. $val, ENT_COMPAT, UTF 8 ). <br /> ; 13 } 14 f o r e a c h ($_POST as $key => $val ) { 15 echo h t m l e n t i t i e s ( \$_POST[. $key. ] =. $val, ENT_COMPAT, UTF 8 ). <br /> ; ; 16 } 17 f o r e a c h ($_REQUEST as $key => $val ) { 122

Chapitre 5 : Formulaires HTML/PHP 18 echo h t m l e n t i t i e s ( \$_REQUEST[. $key. ] =. $val, ENT_COMPAT, UTF 8 ). <br/> ; ; 19 } 20?> 21 </body> 22 </html> 5.6 Formulaires dynamiques an javascript Nous voyons ici un exemple d utilisation du Javascript pour créer un formulaire dont les attributs dépendent de la valeur d un premier champ. Lorsqu on sélectionne deuxième année, un nouveau champ apparaît. Pour celà, on utilise l événement onchange sur l input de l année, qui est géré par la fonction anneechange. On teste alors la valeur de l attribut, puis le cas échéant on génère un nouveau champ dans un div d id attributsupplementaire. Pour plus d information sur les pages web dynamiques en Javascript, voir le cours correspondant sur www.malgouyres.org. 123

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web exemples/javascript/formulaire_dynamique.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <t i t l e>formulaire dynamique</ t i t l e> 6 </head> 7 <body> 8 <form method= post action= r e c e p t i o n. php > 9 <p> 10 <l a b e l for= nom >Nom</ l a b e l><input name= nom id= nom /> 11 </p> 12 <p> 13 <select name= annee id= annee pattern= ( premiere ) ( deuxieme ) onchange= anneechange ( ) ; > 14 <option value= c h o i s i s s e z selected disabled> c h o i s i s s e z </option> 15 <option value= premiere >Première année</option> 16 <option value= deuxième >Deuxième année</ option> 17 </ select> 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 <input type= submit value= OK /> 24 </p> 25 </form> 26 <script> 27 f u n c t i o n anneechange ( ) { 28 var paragraphe = 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 paragraphe. innerhtml=document. getelementbyid ( annee ). value+ année. ; 30 i f ( document. getelementbyid ( annee ). value == deuxième ) { 31 paragraphe. innerhtml+= <l a b e l >O r i e n t a t i o n prévue pour l année prochaine :</l a b e l > 32 + <select 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=\ inge \ >Ecole d ingé </option> 36 + <option value= boulot >Boulot</option> 37 + <option value= autre >Autre</option> 38 + </ select> ; 39 40 } 124

Chapitre 5 : Formulaires HTML/PHP 41 } 42 anneechange ( ) ; 43 </ script> 44 </body> 45 </html> exemples/javascript/reception.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <t i t l e>formulaire dynamique</ t i t l e> 6 </head> 7 <body> 8 <?php 9 $nom= ( i s s e t ($_POST[ nom ] ) )? $_POST[ nom ] : nom indéterminé ; 10 $annee = ( i s s e t ($_POST[ annee ] ) )? $_POST[ annee ] : année indéteminée ; 11 echo Nom :. $nom. <br/> ; 12 echo Année :. $annee. <br/> ; 13 i f ( $annee== deuxième ) 14 echo O r i e n t a t i o n :.$_POST[ o r i e n t a t i o n ] ; 15 16 17?> 18 </body> 19 </html> 125

Chapitre 6 Injection, Filtrage, Expressions Régulières 6.1 Injections HTML et échappement 6.1.1 Injections HTML Les injections XSS sont un moyen pour un pirate d exécuter du code non prévu en exploitant les interfaces entre PHP et d autres langages (HTML, Javascript, SQL, etc...). Pour celà, le pirate rentre dans un input du code, qui n est pas détecté par PHP (on a simplement une chaîne de caractères au niveau de PHP), mais qui est interprété par un autre langage interfacé avec PHP. Voyons un exemple d injection HTML. L utilisateur malveillant va entrer dans un textarea, de nom desctiption, du code HTML pour introduire dans le site victime un lien vers un site pirate. Si l utilisateur inaverti ou distrait clique sur ce lien, le pirate peut alors demander à l utilisateur de rentrer ses identifiants (usurpation d identité) ou ses données de carte bancaire (escroquerie), etc. Voyons tout d abord de formulaire et sa réception dans le cadre de son utilisation normale. Figure 6.1 : Un gentil formulaire 126

Chapitre 6 : Injection, Filtrage, Expressions Régulières Figure 6.2 : Le site affiche en HTML les données saisies dans le gentil formulaire Le code source du formulaire et de sa réception est le suivant : exemples/filtrage/ex00_1_postparamforhtml_inject.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>post un Nom</ t i t l e> 7 </head> 8 <body> 9 <h1>post d une chaîne</h1> 10 <form method= p o s t action= ex00_2_receptparamforhtml_inject. php > 11 <label for= d e s c r i p t i o n style= margin r i g h t : 10px ; v e r t i c a l a l i g n :top ; > D e s c r i p t i o n :</ label> 12 <textarea name= d e s c r i p t i o n id= d e s c r i p t i o n cols= 50 row= 6 style= v e r t i c a l a l i g n :top ; > 13 </ textarea> 14 <input type= submit value= Envoyer /> 15 </form> 16 </body> 17 </html> exemples/filtrage/ex00_2_receptparamforhtml_inject.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /><link rel= s t y l e s h e e t href=. / mystyle. c s s /> 5 <t i t l e>réception Vulnérable à I n j e c t i o n s XSS</ t i t l e> 6 </head> 7 <body> 8 <h1>réception Vulnérable à I n j e c t i o n s <i>xss</ i></h1> 9 <p> 10 <strong>la D e s c r i p t i o n du c l i e n t e s t&nbsp ; :</strong><br/> 11 <?php 127

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 12 i f ( i s s e t ($_POST[ d e s c r i p t i o n ] ) ) { 13 echo $_POST[ d e s c r i p t i o n ] ; 14 } 15?> 16 <br/>ceci e s t l a s u i t e du document. 17 </p> 18 </body> 19 </html> Le pirate entre alors dans un input du code HTML : Figure 6.3 : Injection HTML ajoutant un lien au site Le résultat est l apparition d un lien non prévu sur le site : Figure 6.4 : L affichage des données du formulaire sort le code HTML entré par le pirate 6.1.2 Prévention des injections HTML par échappement 6.1.2.a Échappement par htmlentities Différents outils de filtrage sont disponibles en PHP. Le plus simple pour la sécurité consiste à utiliser la méthode htmlentities qui tranforme dans une chaîne tous les caractères spéciaux en leurs entités HTML (code spécial pour afficher un caractère en HTML). 128

Chapitre 6 : Injection, Filtrage, Expressions Régulières Il faut cependant prendre garde que si l utilisateur ne rentre pas les caratères en entrée avec le même encodage que celui utilisé par PHP en sortie, les caractères spéciaux n ont pas le même code et la fonction htmlentities ne fonctionnera pas bien, laissant la porte ouverte à des attaques. On peut spécifier l encoding de sortie de htmlentities dans son troisième paramètre. Dans l exemple d injection HTML ajoutant un lien ci-dessus, on obtiendrait lors de l affichage : Figure 6.5 : Un gentil formulaire Le code HTML produit par le CGI est le suivant : exemples/filtrage/ex00_5_htmlentitieshtml_output.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /><link rel= s t y l e s h e e t href=. / mystyle. c s s /> 5 <t i t l e>réception avec échappement</ t i t l e> 6 </head> 7 <body> 8 <h1>réception avec échappement par <code>h t m l e n t i t i e s</code></h1> 9 <p> 10 Le nom du c l i e n t e s t&nbsp ; : 11 Ceci e s t une d e s c r i p t i o n innocente. 12 &l t ; span s t y l e=&quot ; p o s i t i o n : r e l a t i v e ; r i g h t :50px ; top :70px ;&quot ;&gt ; 13 Pour payer avec une CB 14 &l t ; a h r e f=http :// s i t e P i r a t e. com&gt ; Cliquez i c i&l t ; / a&gt ; 15 &l t ; / span&gt ; <br/>ceci e s t l a s u i t e du document. 16 </p> 17 </body> 18 </html> Ç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. 6.1.2.b Options d échappement Nous voyons ici trois exemples d échappement qui traitent différemment les guillemets et les apostrophes (doubles et simples quotes). Les chaines positées sont les suivantes : 129

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web exemples/filtrage/ex02_postparam.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>post de deux c h a î n e s</ t i t l e> 7 </head> 8 <body> 9 <h1>post de deux c h a î n e s</h1> 10 <form method= p o s t action= ex03_ escapetestrequest. php > 11 <input type= hidden name= chaine1 value= Ceci e s t l exemple de chaîne avec apostrophe /> 12 <input type= hidden name= chaine2 value= Ceci e s t s o i t d i s a n t un &quot ; autre&quot ; exemple. /> 13 <input type= submit value= Envoyer class= sanslabel /> 14 </form> 15 </body> 16 </html> À la réception, on observe la chose suivante suivant les options données en paramètre de htmlentities : exemples/filtrage/ex03_escapetestrequest.php 1 <?php r e q u i r e (. / commonfunctions. php ) ; 2 3 outputentetehtml5 ( Réception et échappement HTML, UTF 8, mystyle. css ) ; 4 5 echo <h1>réception et échappement <i >HTML</i ></h1> ; 6 7 $chaine1 = $_REQUEST[ chaine1 ] ; 8 $chaine2 = $_REQUEST[ chaine2 ] ; 9 130

Chapitre 6 : Injection, Filtrage, Expressions Régulières 10 echo <p>\n ; 11 echo Apostrophe avec a d d s l a s h e s :. a d d s l a s h e s ( $chaine1 ). <br>\n ; 12 echo Guillemets avec a d d s l a s h e s :. a d d s l a s h e s ( $chaine2 ). <br>\n ; 13 echo </p>\n ; 14 15 echo <p>\n ; 16 echo Apostrophe avec h t m l e n t i t i e s et ENT_COMPAT :. h t m l e n t i t i e s ( $chaine1, ENT_COMPAT, UTF 8, f a l s e ). <br>\n ; 17 echo Guillemets avec a d d s l a s h e s ENT_COMPAT :. h t m l e n t i t i e s ( $chaine2, ENT_COMPAT, UTF 8, f a l s e ). <br>\n ; 18 echo </p>\n ; 19 20 echo <p>\n ; 21 echo Apostrophe avec h t m l e n t i t i e s et ENT_QUOTES :. h t m l e n t i t i e s ( $chaine1, ENT_QUOTES, UTF 8, f a l s e ). <br>\n ; 22 echo Guillemets avec a d d s l a s h e s ENT_QUOTES :. h t m l e n t i t i e s ( $chaine2, ENT_QUOTES, UTF 8, f a l s e ). <br>\n ; 23 echo </p>\n ; 24 25 echo <p>\n ; 26 echo Apostrophe avec h t m l e n t i t i e s et ENT_NOQUOTES :. h t m l e n t i t i e s ( $chaine1, ENT_NOQUOTES, UTF 8, f a l s e ). <br>\n ; 27 echo Guillemets avec a d d s l a s h e s ENT_NOQUOTES :. h t m l e n t i t i e s ( $chaine2, ENT_NOQUOTES, UTF 8, f a l s e ). <br>\n ; 28 echo </p> ; 29 30?> 31 <form method= p o s t action= ex03_ escapetestrequest. php > 32 <input type= t e x t name= chaine1 value= <?php echo $chaine1 ;?> > 33 <input type= t e x t name= chaine2 value= <?php echo $chaine2 ;?> > 34 <input type= submit value= Envoyer class= sanslabel ></input> 35 </form> 36 <?php 37 outputfinfichierhtml5 ( ) ; 38?> Le code source HTML généré par le CGI est le suivant : exemples/filtrage/ex03_escapetestrequest_php_htmloutput.html 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href= mystyle. c s s /> 6 <t i t l e>réception et échappement HTML</ t i t l e> 7 </head> 8 <body> 9 <h1>réception et échappement <i>html</ i></h1><p> 10 Apostrophe avec a d d s l a s h e s : Ceci e s t l \ exemple de chaîne avec apostrophe<br> 11 Guillemets avec a d d s l a s h e s : Ceci e s t s o i t d i s a n t un \ autre \ exemple.<br> 12 </p> 13 <p> 14 Apostrophe avec h t m l e n t i t i e s et ENT_COMPAT : Ceci e s t l exemple de cha&i c i r c ; ne avec apostrophe<br> 15 Guillemets avec a d d s l a s h e s ENT_COMPAT : Ceci e s t s o i t d i s a n t un &quot ; autre&quot ; exemple.<br> 131

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 16 </p> 17 <p> 18 Apostrophe avec h t m l e n t i t i e s et ENT_QUOTES : Ceci e s t l &#039 ;exemple de cha& i c i r c ; ne avec apostrophe<br> 19 Guillemets avec a d d s l a s h e s ENT_QUOTES : Ceci e s t s o i t d i s a n t un &quot ; autre&quot ; exemple.<br> 20 </p> 21 <p> 22 Apostrophe avec h t m l e n t i t i e s et ENT_NOQUOTES : Ceci e s t l exemple de cha&i c i r c ; ne avec apostrophe<br> 23 Guillemets avec 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 autre exemple.<br> 24 </p> <form method= p o s t action= ex03_ escapetestrequest. php > 25 <input type= t e x t name= chaine1 value= Ceci e s t l exemple de chaîne avec apostrophe > 26 <input type= t e x t name= chaine2 value= Ceci e s t s o i t d i s a n t un autre exemple. > 27 <input type= submit value= Envoyer class= sanslabel ></input> 28 </form> 29 </body> 30 </html> 6.1.2.c Inverser l échappement Après un échappement à réception des données, on peut inverser cet échappement pour restaurer les données bruttes d origine, par exemple pour renvoyer ces données dans les inputs d un formulaire : exemples/filtrage/ex05_htmlentitiesent_quotes_forminput.php 132

Chapitre 6 : Injection, Filtrage, Expressions Régulières 1 <?php r e q u i r e (. / commonfunctions. php ) ; 2 3 outputentetehtml5 ( html_entity_decode, UTF 8, mystyle. css ) ; 4 5 echo <h1>annuler l échappement avec <code>html_ entity_ decode </code ></h1> ; 6 7 $chaine1 = h t m l e n t i t i e s ($_REQUEST[ chaine1 ], ENT_QUOTES, UTF 8, f a l s e ) ; 8 $chaine2 = h t m l e n t i t i e s ($_REQUEST[ chaine2 ], ENT_QUOTES, UTF 8, f a l s e ) ; 9 10 echo <p s t y l e =\ font size :80% ;\ >\n ; 11 echo $chaine1. <br/>( codée avec. h t m l e n t i t i e s ( h t m l e n t i t i e s (\$_REQUEST[ chaine1 ], ENT_QUOTES, UTF 8, f a l s e ), ENT_QUOTES, UTF 8, f a l s e ). )<br >\n ; 12 echo $chaine2. <br/>( codée avec. h t m l e n t i t i e s ( h t m l e n t i t i e s (\$_REQUEST[ chaine2 ], ENT_QUOTES, UTF 8, f a l s e ), ENT_QUOTES, UTF 8, f a l s e ). )<br >\n ; 13 echo </p>pour r e p o s t e r l e s c h a î n e s dans un f o r m u l a i r e, on \ décode l échappement\ <br/>\n ; 14?> 15 <form method= p o s t action= ex05_htmlentitiesent_quotes_forminput. php > 16 <input style= font s i z e :100% ; type= t e x t name= chaine1 value= <?php echo $chaine1 ;?> size= 30 /> 17 <input style= font s i z e :100% ; type= t e x t name= chaine2 value= <?php echo $chaine2 ;?> size= 30 /> 18 <input type= submit value= Envoyer class= sanslabel /> 19 </form> 20 <?php 21 echo <p>\n ; 22 echo html_entity_decode ( $chaine1, ENT_QUOTES, UTF 8 ). <br>\n ; 23 echo html_entity_decode ( $chaine2, ENT_QUOTES, UTF 8 ). <br>\n ; 24 echo </p>\n ; 25 26 outputfinfichierhtml5 ( ) ; 27?> 6.2 Injections SQL Une injection SQL consiste à entre dans les inputs utilisateur du code SQL. Ces attaques sont particulièrement dansgereuses car elles peuvent etre exploitées par un pirtae pour : 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. exemples/filtrage/ex06_0_postparamfordb.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 133

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 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 transmet 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= ex07_ exinjectmysql. php > 12 <label for= chaine1 >Entrez une chaîne</ label> 13 <input type= t e x t e id= chaine1 name= chaine1 size= 45 /><br/> 14 15 <input type= submit value= Envoyer class= sanslabel ></input> 16 </form> 17 </body> 18 </html> exemples/filtrage/ex07_exinjectmysql.php 1 2 <?php 3 i n c l u d e (. / commonfunctions. php ) ; 4 outputentetehtml5 ( Exemple d \ i n j e c t i o n SQL, UTF 8, mystyle. css ) ; 5 6 echo <h1>réception v u l n é r a b l e à une i n j e c t i o n </h1> ; 7 8 // On se connecte au s e r v e u r de bases de données. 9 // Adapter l e nom d hote où se trouve l e s e r v e u r mysql 10 // mysqli ( $sql_server_url, $sql_user, $sql_user_password, $database_name ) 11 $mysqli = new mysqli ( progweb, t e s t U s e r, motdepasse, basetest ) ; 12 13 // V é r i f i c a t i o n de l a connexion : 14 i f ( mysqli_connect_errno ( ) ) { 15 p r i n t f ( Échec de l a connexion : %s \n, mysqli_connect_error ( ) ) ; 16 e x i t ( ) ; 17 } 18 echo Connecté au s e r v e u r de bases de données mysql.<br/> ; 19 20 $chaine1= ; 21 i f ( i s s e t ($_POST[ chaine1 ] ) ) { 22 $chaine1 = $_POST[ chaine1 ] ; 23 } 24 echo Chaîne e n t r é e par l u t i l i s a t e u r : <code>. $chaine1. </code><br/> ; 25 26 // I n s e r t i o n de l a chaîne dans l a t a b l e Table1 ( r e q u ê t e SQL) : 27 $requete = INSERT INTO Table1 ( chaine ) VALUES (. $chaine1. ) ; 28 29 echo Requête exécutée :<br/><code>. $requete. </code><br/> ; 30 31 $ r e s u l t = $mysqli >multi_query ( $requete ) or d i e ( Query f a i l e d :. mysql_error ( ). <br/> ) ; 32 33 // On ferme l a connection 34 $mysqli >c l o s e ( ) ; 35 36 outputfinfichierhtml5 ( ) ; 37?> 134

Chapitre 6 : Injection, 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 : Figure 6.6 : L état des données avant l injection SQL par le pirate Figure 6.7 : Données saisies par le pirate pour l injection SQL Le deuxième exemple, plus méchant, consiste pour le pirate à supprimer toutes les données contenues dans la table : exemples/filtrage/ex09_mysqlescapestring.php 1 2 <?php 3 i n c l u d e (. / commonfunctions. php ) ; 4 outputentetehtml5 ( Echappement mysqli : :real_escape_string, UTF 8, mystyle. css ) ; 5 6 echo <h1>réception avec échappement <code>mysqli : :real_escape_string </code></ h1> ; 7 8 // On se connecte au s e r v e u r de bases de données. 9 // Adapter l e nom d hote où se trouve l e s e r v e u r mysql 10 // mysqli ( $sql_server_url, $sql_user, $sql_user_password, $database_name ) 11 $mysqli = new mysqli ( progweb, t e s t U s e r, motdepasse, basetest ) ; 12 13 // V é r i f i c a t i o n de l a connexion : 135

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web Figure 6.8 : Requête exécutée lors de l injection SQL Figure 6.9 : L état des données après l injection SQL par le pirate Figure 6.10 : Données saisies par le pirate pour l injection SQL Figure 6.11 : Requête exécutée lors de l injection SQL 136

Chapitre 6 : Injection, Filtrage, Expressions Régulières Figure 6.12 : L état des données près l injection SQL par le pirate 14 i f ( mysqli_connect_errno ( ) ) { 15 p r i n t f ( Échec de l a connexion : %s \n, mysqli_connect_error ( ) ) ; 16 e x i t ( ) ; 17 } 18 echo Connecté au s e r v e u r de bases de données mysql.<br/> ; 19 20 $chaine1= ; 21 i f ( i s s e t ($_POST[ chaine1 ] ) ) { 22 $chaine1 = $mysqli >r e a l _ e s c a p e _ s t r i n g ($_POST[ chaine1 ] ) ; 23 } 24 echo Chaîne e n t r é e par l u t i l i s a t e u r : <code>.$_post[ chaine1 ]. </code><br /> ; 25 echo Chaîne e n t r é e par l u t i l i s a t e u r échapée : <code>. $chaine1. </code><br/> ; 26 27 // I n s e r t i o n de l a chaîne dans l a t a b l e Table1 ( r e q u ê t e SQL) : 28 $requete = INSERT INTO Table1 ( chaine ) VALUES (. $chaine1. ) ; 29 30 echo Requête exécutée :<br/><code>. $requete. </code><br/> ; 31 32 $ r e s u l t = $mysqli >multi_query ( $requete ) or d i e ( Query f a i l e d :. mysql_error ( ). <br/> ) ; 33 34 // On ferme l a connection 137

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 35 $mysqli >c l o s e ( ) ; 36 37 outputfinfichierhtml5 ( ) ; 38?> Figure 6.13 : Données dans la base après tentative d injection SQL avec échappement exemples/filtrage/ex11_mysqlescapestringoutput.php 1 2 <?php 3 i n c l u d e (. / commonfunctions. php ) ; 4 outputentetehtml5 ( En s o r t i e de BD, UTF 8, mystyle. css ) ; 5 6 echo <h1>a p p l i c a t i o n d <code>h t m l e n t i t i e s </code><br/>en s o r t i e de BD</h1> ; 7 8 // On se connecte au s e r v e u r de bases de données. 9 // Adapter l e nom d hote où se trouve l e s e r v e u r mysql 10 // mysqli ( $sql_server_url, $sql_user, $sql_user_password, $database_name ) 11 $mysqli = new mysqli ( progweb, t e s t U s e r, motdepasse, basetest ) ; 12 13 // V é r i f i c a t i o n de l a connexion : 138

Chapitre 6 : Injection, Filtrage, Expressions Régulières 14 i f ( mysqli_connect_errno ( ) ) { 15 p r i n t f ( Échec de l a connexion : %s \n, mysqli_connect_error ( ) ) ; 16 e x i t ( ) ; 17 } 18 echo Connecté au s e r v e u r de bases de données mysql.<br/> ; 19 20 // I n s e r t i o n de l a chaîne dans l a t a b l e Table1 ( r e q u ê t e SQL) : 21 $requete = SELECT * FROM Table1 ; 22 23 $ r e s u l t = $mysqli >query ( $requete ) or d i e ( Query f a i l e d :. mysql_error ( ). < br/> ) ; 24 25 while ( $ligneresreq = mysqli_fetch_array ( $ r e s u l t, MYSQL_ASSOC) ) { 26 echo Donnée s o r t i e de l a t a b l e :<br/><code>. h t m l e n t i t i e s ( $ligneresreq [ chaine ], ENT_QUOTES, UTF 8 ). </code><br/> ; 27 } 28 // On ferme l a connection 29 $mysqli >c l o s e ( ) ; 30 31 outputfinfichierhtml5 ( ) ; 32?> 6.3 La fonction filter_var 6.3.1 Principe de la fonction PHP filter_var La fonction PHP filter_var permet 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 caractères inattendus compte tenu du type de données (exemple : élimination d un caractère inattendu @ dans un nombre entier). le prototype de la fonction filter_var est : mixed filter_var(mixed $variable, int $filter = FILTER_DEFAULT, mixed $options) 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. $variable est la valeur à filtrer ; $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). 139

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 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. 6.3.2 Les filtres de Validation Les filtres de validation sont les valeurs possibles du deuxième paramètre filter de la fonction filter_var qui commencent par FILTER_VALIDATE_. Le but d un filtre de validation est de dire si une chaîne satisfait certaines condition ; si la forme de la chaîne est confrome à ce qu on attend d un certain type de données. La liste n est pas très longue. La plus grosse difficultés vient, comme d habitude, des conversions automatiques entre formats de nombre et booléens, qui produisent des résultats conteintuitifs qui peuvent conduire à des bugs. 6.3.2.a Le filtre FILTER_VALIDATE_BOOLEAN Ce filtre admet pas d option et admet FILTER_NULL_ON_FAILURE pour seul flag. Retourne TRUE pour 1, true, on et yes. RetourneFALSE sinon. Si le flag FILTER_NULL_ON_FAILURE est activé, FALSE n est retourné que pour les valeurs 0, false, off, no,, et NULL est retourné pour les valeurs non-booléennes. Ce filtre s applique à une chaine de caractères et ne donne pas le bon résultat sur une variable de type booléen (car les booléens FALSE ou TRUE ne sont pas des chaines de caractères représentant un booléen)! if (!is_bool($value)) { $value= filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } 6.3.2.b Le filtre FILTER_VALIDATE_EMAIL Ce filtre valide une adresse e mail. N admet ni option, ni flag. Rien à signaler sur ce filtre. 6.3.2.c Le filtre FILTER_VALIDATE_FLOAT Ce filtre valide un nombre décimal. Le nombre flottant égal à zéro ($x = 0) est un nombre flottant valide, mais la fonction filter_var avec le filtre FILTER_VALIDATE_FLOAT, comme les données sont valides, va retourner la variable égale à 0, qui serait dans un test convertie en le booléen false). Le bon usage consiste à tester l identité de la donnée retournée par filter_var sans conversion, en utilisant les opérateurs === (vrai si deux variables ont des valeurs égales et on même type) ou!== (vrai si deux variables ont des valeurs différentes ou sont de types différents). 140

Chapitre 6 : Injection, Filtrage, Expressions Régulières exemples/filtrage/ex12_filtervarvalidatefloat.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>f i l t r e VALDATE_FLOAT</ t i t l e> 7 </head> 8 <body> 9 <h1>tests de <code>f i l t e r _ v a r</code><br/>avec f i l t r e <code> FILTER_VALIDATE_FLOAT</code></h1> 10 <?php 11 $x = 0 ; 12 i f ( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT) ) { 13 echo $x e s t un f l o a t v a l i d e car. h t m l e n t i t i e s ( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT), ENT_QUOTES, UTF 8 ) 14. vaut ; 15 var_dump( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT) ) ; 16 echo <br/> ; 17 } e l s e { 18 echo $x n e s t pas un f l o a t v a l i d e car. h t m l e n t i t i e s ( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT), ENT_QUOTES, UTF 8 ) 19. vaut ; 20 var_dump( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT) ) ; 21 echo <br/> ; 22 } 23 i f ( f i l t e r _ v a r ( $x, FILTER_VALIDATE_FLOAT)!== f a l s e ) { 24 echo $x e s t bien sûr un f l o a t v a l i d e! <br/> ; 25 } e l s e { 26 echo $x n e s t pas un f l o a t v a l i d e <br/> ; 27 } 28?> 29 </body> 30 </html> if (filter_var($x, FILTER_VALIDATE_FLOAT)!== false) { echo "$x est un float valide"; } else { echo "$x n'est pas un float valide"; } 6.3.2.d Le filtre FILTER_VALIDATE_INT Même remarque que pour les nombres réels à propos de l identité des variables à tester avec === ou!==, en raison du problème d un nombre égal à 0 (zéro) qui, converti en booléen, donnerait FALSE. Il y a des options permettant de tester un intervalle et des flags autorisant les écritures octales (style 0 123 ) ou hexadécimales (style 0 x2c3f ). 6.3.2.e Le filtre FILTER_VALIDATE_URL Ne fonctionne pas avec les URLs internationalisées (c est à dire avec des caractères non ASCII). Ces URLs doivent etre échappées auparavant. 141

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 6.3.2.f Le filtre FILTER_VALIDATE_IP Valide une adresse IP? Admet des flags pour autoriser de manière sélective une adresse IPV4, IPV6, ou avec des plages d adresses réservées. 6.3.3 Les filtres de Nettoyage Les filtres de nettoyage permettent d appliquer un traitement à une chaîne pour la rendre conforme à la forme attendue des données. C est aussi une manière de sécuriser des données incorrectes sans renvoyer les données vers l utilisateur. Les filtres de nettoyage sont les valeurs possibles du deuxième paramètre de filter_var qui commencent par FILTER_SANITIZE, ce qui signifie en anglais rendre raisonnable, rendre hygiennique ou ramener à la raison. Le fait d appliquer un filtre de nettoyage améliore la sécurité mais, en général, cela ne permet pas de rendre coorectes des données incorrectes. Cela permet juste de rendre les données raisonnables. 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). 6.3.4 Le filtre personnalisé FILTER_CALLBACK Ce filtre est un exemple dans lequel on va fournir à filter_var une fonction callback personnalisée, que l on codera soi-même, et qui sera appelée automatiquement filter_var pour valider ou nettoyer une chaîne. Voici un exemple de validation par expression régulière (voir plus loin dans ce chapitre). exemples/filtrage/ex13_filtervarcallback.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>post un Nom</ t i t l e> 7 </head> 8 <body> 9 <h1>tests de <code>f i l t e r _ v a r</code><br/>avec f i l t r e <code>filter_callback</ code></h1> 10 <?php 11 f u n c t i o n numerotelephone ( $ t e l ) { 12 i f ( preg_match ( /^(((\+33 ) 0 ) {1}[0 9]{1}([ ]{0,1}[0 9]{2}) {4}) $ /, $ t e l ) ) { 13 return $ t e l ; 14 } e l s e { 15 return f a l s e ; 16 } 17 } 18 19 $telephone = +33 1 23 45 689 ; 20 i f ( f i l t e r _ v a r ( $telephone, FILTER_CALLBACK, 21 array ( options => numerotelephone ) )!==f a l s e ) { 142

Chapitre 6 : Injection, Filtrage, Expressions Régulières 22 echo numéro de téléphone v a l i d e.<br/> ; 23 } e l s e { 24 echo numéro de téléphone i n v a l i d e.<br/> ; 25 } 26?> 27 </body> 28 </html> 6.4 Expressions régulières Les expressions régulières sont un moyen de vérifier d une manière très générale qu une chaîne de caractère a une certaine forme. L extension PRCE en PHP permet, via des fonctions comme preg_match, de vérifier qu une chaîne est conforme à une expression régulière. Un bon tutorial sur la syntaxe et l utilisation des expressions régulières en PHP se trouve à l adresse suivante : 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\;) (\&szlig\;) (\&[a-za-z]tilde\;)'.' (\-) ( ) (\&\#039\;) (\&quot\;) (\.)))+$/' Le filtrage avec preg_match se fait alors par un code du genre : 143

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web exemples/filtrage/ex14_regexaccents.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>v a l i d a t i o n de chaîne accentuée</ t i t l e> 7 </head> 8 <body> 9 <h1>v a l i d a t i o n de chaîne accentuée échappée<br/> ( au moins en f r a n ç a i s )</h1> 10 <?php 11 $chaine = h t m l e n t i t i e s ( àà àèèà ÈéÉed atjjê ÊËä æ œ \., ENT_QUOTES) ; 12 echo Chaîne. h t m l e n t i t i e s ( $chaine, ENT_QUOTES) ; 13 i f ( preg_match ( / ^ ( [ a za Z ] 14. ( \ & [ a za Z ] grave \ ; ) ( \ & [ a za Z ] acute \ ; ) ( \ & [ a za Z ] c i r c \ ; ) ( \ & [ a za Z ] uml \ ; ) // c a r a c t è r e s accentués 15. ( \ & [ a za Z ] c e d i l \ ; ) ( \ & [ a za Z ] [ a za Z ] l i g \ ; ) (\& s z l i g \ ; ) ( \ & [ a za Z ] t i l d e \ ; ) // c a r a c t è r e s accentués 16. ( \ ) ( ) (\&\#039\ ;) (\& quot \ ; ) ( \. ) )+$ /, // Espaces, t r a i t d union, s i m p l e s et doubles quotes 17 $chaine ) ) { 18 echo <strong>v a l i d e</strong> ; 19 } e l s e { 20 echo <strong>i n v a l i d e</strong> ; 21 } 22?> 23 </body> 24 </html> 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 : /^(((\+33 ) 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 : /^(((\+33 ) 0){1}[0-9]{1}([ ]{0,1}[0-9]{2}){4})$/ 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) : /^(((\+33( \- \.)) 0){1}[0-9]{1}(( \- \.)[0-9]{2}){4})$/ 144

Chapitre 7 Formulaires PHP/HTML, filtrage, exceptions Dans ce chapitre, nous proposons une conception de classes métiers et classes d utilitaires pour générer des vues HTML. La gestion des données saisies par l utilisateur nous conduit, au vu du chapitre 6, à gérer plus rigoureusement le filtrage. Nous distinguons deux types de filtrage des données : 1. Le filtrage pour la sécurité, qui sera géré par des fonctions de validation ou de nettoyage 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. 2. Le filtrage pour la cohérence des données, qui nécessite généralement un connaissance de la sémantique des objets métiers et de leurs attributs, est se fonde le plus souvent sur des tests d expressions régulières. Dans notre implémentation, ce filtrage sera réalisé dans les setters des classes de représentation des données métier. 7.1 La Classe Adresse Nous reprenons à peu près la classe adresse de la partie 4.1.2. Nous ajoutons : 1. Un filtrage pour la cohérence des données un peu plus réaliste au niveau des setters ; 2. Une méthode statique permettant d avoir une adresse par défaut (exemple : les champs vides pour initialiser un formulaire en utilisant la classe AdresseFormView ci-dessous). exemples/forms2/ex01_classeadresse.php 1 <?php 2 require_once ( dirname ( FILE ). / ExpressionsRegexUtils. php ) ; 3 require_once ( dirname ( FILE ). / A d r e s s e P r o p e r t i e s T r a i t. php ) ; 4 5 //////////////////////////////////////////////////////////// 6 // Classe Adresse : 7 8 /** 9 @brief La c l a s s e a d r e s s e c o n t i e n t l a d r e s s e d une personne 10 ( qui peut ê 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... ) 145

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 11 */ 12 class Adresse { 13 p r i v a t e $id ; 14 /** Numéro dans l a rue, ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 15 p r i v a t e $numerorue ; 16 /** Nom de l a rue, ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 17 p r i v a t e $rue ; 18 /** Complément ( l i e u dit, e t c. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 19 p r i v a t e $complementadresse ; 20 /** code p o s t a l */ 21 p r i v a t e $codepostal ; 22 /** nom de l a v i l l e. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 23 p r i v a t e $ v i l l e ; 24 /** nom du pays. ne d o i t pas ê t r e n u l l mais peut ê t r e vide */ 25 p r i v a t e $pays ; 26 27 // 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 et s e t t e r s 28 use A d r e s s e P r o p e r t i e s ; 29 /** @brief : Accesseur : permet d o b t e n i r l e numéro dans l a rue. */ 30 31 /** 32 * @brief 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 ) : 33 */ 34 p r i v a t e s t a t i c f u n c t i o n generaterandomid ( ) 35 { 36 // Génération de 5 o c t e t s ( pseudo ) a l é a t o i r e s codés en hexa 37 $cryptostrong = f a l s e ; // Variable pour passage par r é f é r e n c e 38 $ o c t e t s = openssl_random_pseudo_bytes ( 5, $cryptostrong ) ; 39 return bin2hex ( $ o c t e t s ) ; 40 } 41 42 /** 43 @brief Constructeur : 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 des paramètres. 44 Les paramètres correspondent aux v a l e u r s à mettre dans l e s a t t r i b u t s. 45 Tout o b j e t d o i t ê t r e i n i t i a l i s é avec l e c o n s t r u c t e u r ( appel à new ). 46 Des e x c e p t i o n s sont r e j e t é e s en cas de paramètre i n v a l i d e. 47 */ 48 p u b l i c f u n c t i o n construct ( $id, $numerorue, $rue, $complementadresse, $codepostal, $ v i l l e, $pays ) { 49 $ t h i s > setnumerorue ( $numerorue ) ; 50 $ t h i s > setrue ( $rue ) ; 51 $ t h i s > setcomplementadresse ( $complementadresse ) ; 52 $ t h i s > setcodepostal ( $codepostal ) ; 53 $ t h i s > s e t V i l l e ( $ v i l l e ) ; 54 $ t h i s > setpays ( $pays ) ; 55 } 56 57 /** 58 * @brief c o n s t r u i t une Adresse par défaut 59 * Remarque : on ne peut pas s u r c h a r g e r l e s c o n s t r u c t e u r s en PHP 5... 60 */ 61 p u b l i c s t a t i c f u n c t i o n g etdefaultadresse ( ) { 62 // On a p p e l l e l e c o n s t r u c t e u r avec des arguments convenables 63 // en terme d e x p r e s s i o n s r é g u l i è r e s 64 $ a d r e s s e = new Adresse ( 33, 2, Rue,, 12345, V i l l e, Pays ) ; 65 $adresse >id = s e l f : :generaterandomid ( ) ; 146

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 66 $adresse >numerorue = ; 67 $adresse >rue = ; 68 $adresse >complementadresse = ; 69 $adresse >codepostal = ; 70 $adresse >v i l l e = ; 71 $adresse >pays = France ; 72 return $ a d r e s s e ; 73 } 74 } 75?> 7.2 Filtrage des attributs Nous proposons tout d abord des méthodes génériques de test d expressions régulières pour la langue française, avec ou sans chiffres. Ces expressions régulières doivent être testées après échappement par htmlentities, ce qui permet une approche générique du traitement des accents (exemple : é, des apostrophes, guillemets (simple ou doubles quotes), etc. qui peuvent apparaître en français. exemples/forms2/ex02_expressionsregexutils.php 1 <?php 2 ///////////////////////////////////////////////////////////////// 3 // Expressions r é g u l i è r e s u t i l e s. 4 class ExpressionsRegexUtils { 5 6 /** 7 * @brief : e x p r e s s i o n r é g u l i è r e pour l a langue Française avec a c c e n t s 8 * @warning La chaîne d o i t ê t r e échappée par h t m l e n t i t i e s 9 */ 10 p r i v a t e s t a t i c f u n c t i o n getregexfrlang ( ) { 11 return / ^ ( [ a za Z ] 12. ( \ & [ a za Z ] grave \ ; ) ( \ & [ a za Z ] acute \ ; ) ( \ & [ a za Z ] c i r c \ ; ) ( \ & [ a za Z ] uml \ ; ) 13. ( \ & [ a za Z ] c e d i l \ ; ) ( \ & [ a za Z ] [ a za Z ] l i g \ ; ) (\& s z l i g \ ; ) ( \ & [ a za Z ] t i l d e \ ; ) 14. ( \ ) ( ) (\&amp\ ;\#39\ ;) (\&\#039\ ;) (\&amp\ ;\#34\ ;) (\&\#034\ ;) (\& quot \ ; ) ( \. ) ) *$ / ; 15 } 16 17 /** 18 * @brief : e x p r e s s i o n r é g u l i è r e pour l a langue Française avec a c c e n t s et c h i f f r e s 19 * @warning La chaîne d o i t ê t r e échappée par h t m l e n t i t i e s 20 */ 21 p r i v a t e s t a t i c f u n c t i o n getregexfrlangwithnumbers ( ) { 22 return / ^ ( [ a za Z0 9] 23. ( \ & [ a za Z ] grave \ ; ) ( \ & [ a za Z ] acute \ ; ) ( \ & [ a za Z ] c i r c \ ; ) ( \ & [ a za Z ] uml \ ; ) 24. ( \ & [ a za Z ] c e d i l \ ; ) ( \ & [ a za Z ] [ a za Z ] l i g \ ; ) (\& s z l i g \ ; ) ( \ & [ a za Z ] t i l d e \ ; ) 25. ( \ ) ( ) (\&amp\ ;\#39\ ;) (\&\#039\ ;) (\&amp\ ;\#34\ ;) (\&\#034\ ;) (\& quot \ ; ) ( \. ) ) *$ / ; 26 } 147

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 27 28 /** 29 * @brief : Test e x p r e s s i o n r é g u l i è r e pour l a langue Française avec a c c e n t s 30 * avec c o n d i t i o n s de longueur ( par exemple pour un champ o b l i g a t o i r e ) 31 */ 32 p u b l i c s t a t i c f u n c t i o n isvalidregexfrlang ( $chaine, $minlenth, $maxlenth ) { 33 return ( i s s e t ( $chaine ) && 34 s t r l e n ( $chaine ) >= $minlenth && s t r l e n ( $chaine ) <= $maxlenth 35 && preg_match ( s e l f : :getregexfrlang ( ), $chaine ) ) ; 36 } 37 38 /** 39 * @brief : Test e x p r e s s i o n r é g u l i è r e pour l a langue Française avec a c c e n t s et c h i f f r e s 40 * avec c o n d i t i o n s de longueur ( par exemple pour un champ o b l i g a t o i r e ) 41 */ 42 p u b l i c s t a t i c f u n c t i o n isvalidregexfrlangwithnumbers ( $chaine, $minlenth, $maxlenth ) { 43 return ( i s s e t ( $chaine ) && 44 s t r l e n ( $chaine ) >= $minlenth && s t r l e n ( $chaine ) <= $maxlenth 45 && preg_match ( s e l f : :getregexfrlangwithnumbers ( ), $chaine ) ) ; 46 } 47 48 /** 49 * @brief : Test e x p r e s s i o n r é g u l i è r e passée en paramètre 50 * avec c o n d i t i o n s de longueur ( par exemple pour un champ o b l i g a t o i r e ) 51 */ 52 p u b l i c s t a t i c f u n c t i o n i s V a l i d S t r i n g ( $chaine, $regexp, $minlenth, $maxlenth ) { 53 return ( i s s e t ( $chaine ) && 54 s t r l e n ( $chaine ) >= $minlenth && s t r l e n ( $chaine ) <= $maxlenth 55 && preg_match ( $regexp, $chaine ) ) ; 56 } 57 } 58?> Dans notre implémentation, nous réalisons les tests de cohérence des données par expressions régulières au niveau des setters des classes métier. Nous réalisons au préalable, dans le setter, un échappement par htmlentities, de manière à pouvoir gérer les apostrophes ou guillemets, qui seraient sinon rejetées lors du filtrage destiné à éviter les injections SQL (par exemple dans les requêtes préparées PDO). Cet échappement par htmlentities nous permet aussi d utiliser les expressions régulières génériques ci-dessus. exemples/forms2/ex03_classeadressepropertiestrait.php 1 <?php 2 /** 3 @brief La c l a s s e a d r e s s e c o n t i e n t l a d r e s s e d une personne 4 ( qui peut ê 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 */ 6 t r a i t A d r e s s e P r o p e r t i e s { 7 /** @brief Accesseur : permet d o b t e n i r l id de l a d r e s s e. */ 8 p u b l i c f u n c t i o n getid ( ) { 9 return $ t h i s >id ; 10 } 11 12 /** @brief Accesseur : permet d o b t e n i r l e numéro dans l a rue. */ 148

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 13 p u b l i c f u n c t i o n getnumerorue ( ) { 14 return html_entity_decode ( $ t h i s >numerorue, ENT_QUOTES, UTF 8 ) ; 15 } 16 17 /** @brief Accesseur : permet d o b t e n i r l e nom l a rue. */ 18 p u b l i c f u n c t i o n getrue ( ) { 19 return html_entity_decode ( $ t h i s >rue, ENT_QUOTES, UTF 8 ) ; 20 } 21 22 /** @brief Accesseur : permet d o b t e n i r l e nom l e complément d a d r e s s e. */ 23 p u b l i c f u n c t i o n getcomplementadresse ( ) { 24 return html_entity_decode ( $ t h i s >complementadresse, ENT_QUOTES, UTF 8 ) ; 25 } 26 27 /** @brief Accesseur : permet d o b t e n i r l e nom l e code p o s t a l. */ 28 p u b l i c f u n c t i o n getcodepostal ( ) { 29 return html_entity_decode ( $ t h i s >codepostal, ENT_QUOTES, UTF 8 ) ; 30 } 31 32 /** @brief Accesseur : permet d o b t e n i r l e nom l a v i l l e. */ 33 p u b l i c f u n c t i o n g e t V i l l e ( ) { 34 return html_entity_decode ( $ t h i s >v i l l e, ENT_QUOTES, UTF 8 ) ; 35 } 36 37 38 /** @brief Accesseur : permet d o b t e n i r l e pays. */ 39 p u b l i c f u n c t i o n getpays ( ) { 40 return html_entity_decode ( $ t h i s >pays, ENT_QUOTES, UTF 8 ) ; 41 } 42 43 /** 44 * @brief 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. 45 * @param $id l i d e n t i f i a n t de l a d r e s s e (10 c h i f f r e s hexa ). 46 */ 47 p u b l i c f u n c t i o n s e t I d ( $id ) { 48 i f (! i s s e t ( $id )! preg_match ( /^[0 9a f ]{10} $/, $id ) ) { 49 throw new Exception ( Erreur, i d e n t i f i a n t i n c o r r e c t ) ; 50 } 51 $ t h i s >id = $id ; 52 } 53 54 /** @brief 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. 55 @param $NumeroRue l e numéro à u t i l i s e r. peut ê t r e n u l l. 56 */ 57 p u b l i c f u n c t i o n setnumerorue ( $numerorue ) { 58 $escaped = h t m l e n t i t i e s ( $numerorue, ENT_QUOTES, UTF 8 ) ; 59 i f (! ExpressionsRegexUtils : :isvalidregexfrlangwithnumbers ( $escaped, 0, 50) ) { 60 throw new Exception ( Erreur, l e numéro de l a rue d o i t comporter 61. au plus 50 c a r a c t è r e s 62. ( alphabétiques, c h i f f r e s ou ponctuation ) ) ; 63 } 64 $ t h i s >numerorue = empty ( $escaped )? : $escaped ; 65 } 66 67 /** @brief 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. 68 @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. peut ê t r e n u l l. 149

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 69 */ 70 p u b l i c f u n c t i o n setrue ( $rue ) { 71 $escaped = h t m l e n t i t i e s ( $rue, ENT_QUOTES, UTF 8 ) ; 72 i f (! ExpressionsRegexUtils : :isvalidregexfrlangwithnumbers ( $escaped, 1, 150) ) { 73 throw new Exception ( Erreur, l e nom de l a rue, o b l i g a t o i r e 74. d o i t comporter au plus 150 c a r a c t è r e s 75. ( alphabétiques, c h i f f r e s ou ponctuation ) ) ; 76 } 77 $ t h i s >rue = empty ( $escaped )? : $escaped ; 78 } 79 80 /** @brief 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 complément d a d r e s s e. 81 @param $complementadresse l e complément d a d r e s s e à u t i l i s e r. peut ê t r e n u l l. 82 */ 83 p u b l i c f u n c t i o n setcomplementadresse ( $complementadresse ) { 84 $escaped = h t m l e n t i t i e s ( $complementadresse, ENT_QUOTES, UTF 8 ) ; 85 i f (! ExpressionsRegexUtils : :isvalidregexfrlangwithnumbers ( $escaped, 0, 150) ) { 86 throw new Exception ( Erreur, l e Complément d a d r e s s e \. $complementadresse 87. \ d o i t comporter au plus 150 c a r a c t è r e s 88. ( alphabétiques, c h i f f r e s ou ponctuation ) ) ; 89 } 90 $ t h i s >complementadresse = empty ( $escaped )? : $escaped ; 91 } 92 93 /** @brief 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. 94 @param $CodePostal l e numéro à u t i l i s e r. peut ê t r e n u l l 95 */ 96 p u b l i c f u n c t i o n setcodepostal ( $codepostal ) { 97 $escaped = h t m l e n t i t i e s ( $codepostal, ENT_QUOTES, UTF 8 ) ; 98 i f (! ExpressionsRegexUtils : :isvalidregexfrlangwithnumbers ( $escaped, 1, 20) ) { 99 throw new Exception ( Erreur, l e code p o s t a l n e s t pas v a l i d e 100. ( code p o s t a l f r a n c e m é t r o p o l i t a i n e sans cedex ni B.P. ) ) ; 101 } 102 $ t h i s >codepostal = empty ( $escaped )? : $escaped ; 103 } 104 105 /** @brief 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. 106 @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. peut ê t r e n u l l 107 */ 108 p u b l i c f u n c t i o n s e t V i l l e ( $ v i l l e ) { 109 $escaped = h t m l e n t i t i e s ( $ v i l l e, ENT_QUOTES, UTF 8 ) ; 110 i f (! ExpressionsRegexUtils : :isvalidregexfrlang ( $escaped, 1, 150) ) { 111 throw new Exception ( Erreur, l e nom de l a v i l l e \. $ v i l l e. \, 112. o b l i g a t o i r e d o i t comporter au plus 150 c a r a c t è r e s 113. ( a l p h a b é t i q u e s ou ponctuation ) ) ; 114 } 115 $ t h i s >v i l l e = empty ( $escaped )? : $escaped ; 116 } 117 150

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 118 /** @brief 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 119 @param $pays l e nom du Pays à u t i l i s e r. peut ê t r e n u l l 120 */ 121 p u b l i c f u n c t i o n setpays ( $pays ) { 122 $escaped = h t m l e n t i t i e s ( $pays, ENT_QUOTES, UTF 8 ) ; 123 i f (! ExpressionsRegexUtils : :isvalidregexfrlang ( $escaped, 1, 100) ) { 124 throw new Exception ( Erreur, l e nom du Pays, o b l i g a t o i r e d o i t 125. comporter au plus 100 c a r a c t è r e s 126. ( a l p h a b é t i q u e s ou ponctuation ) ) ; 127 } 128 $ t h i s >pays = empty ( $escaped )? : $escaped ; 129 } 130 } 131?> 7.3 Fabrique d Adresse Nous présentons aussi une fabrique d adresses qui construit des instances à partir de données issues d un formulaire, tout en construisant un tableau d erreurs en cas d exception générée au niveau des setters. Le tableau d erreurs $dataerrors, passé par références, contiendra des couples clé/valeur, dont la clé sera le nom de l attribut de la classe Adresse et la valeur sera le messages de l exception générée dans le setter de cet attribut. Si aucune exception n est générée dans les setter, le tableau d erreurs est vide. exemples/forms2/ex06_classeadressefabrique.php 1 <?php 2 require_once ( dirname ( FILE ). / Adresse. php ) ; 3 4 /** 5 @brief La c l a s s e AdresseFabrique implémente l a c o n s t r u c t i o n d un o b j e t Adresse 6 * à p a r t i r des données s a i s i e s dans un f o r m u l a i r e 7 * Les e r r e u r s g é n é r é e s dans l e s s e t t e r s ( r e ç u e s via des e x c e p t i o n s ) sont accumulées 8 * dans un tableau a s s o c i a t i f d e r r e u r s, pour g é n é r e r l e cas échéant une vue d e r r e u r. 9 **/ 10 class AdresseFabrique { 11 12 /** 13 @brief Obtension d un o b j e t de c l a s s e Adresse à p a r t i r des 14 données s a i s i e s dans un f o r m u l a i r e. 15 Cette méthode prend l e s mêmes paramètres que l e c o n s t r u c t e u r 16 plus un paramètre passé par r é f é r e n c e qui r e t o u r n e l e s messages d e x c e p t i o n. 17 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 des paramètre. 18 Pour chaque a t t r i b u t e de l a c l a s s e, s i une e x c e p t i o n e s t générée 19 au niveau du s e t t e r, l e message d e x c e p t i o n e s t a j o u t é dans un tableau a s s o c i a t i f d e r r e u r s. 20 * Ces messages d e x c e p t i o n sont 21 a i n s i renvoyés au c o n t r ô l e u r. 22 */ 23 p u b l i c s t a t i c f u n c t i o n getadresse (&$dataerrors, $id, $numerorue, $rue, 24 $complementadresse, $codepostal, $ v i l l e, $pays ) { 25 $adr = Adresse : :g etdefaultadresse ( ) ; 151

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 26 $dataerrors = array ( ) ; 27 28 try { 29 $adr > s e t I d ( $id ) ; 30 } catch ( Exception $e ) { 31 $dataerrors [ id ] = $e >getmessage ( ). <br/>\n ; 32 } 33 try { 34 $adr > setnumerorue ( $numerorue ) ; 35 } catch ( Exception $e ) { 36 $dataerrors [ numerorue ] = $e >getmessage ( ). <br/>\n ; 37 } 38 try { 39 $adr > setrue ( $rue ) ; 40 } catch ( Exception $e ) { 41 $dataerrors [ rue ] = $e >getmessage ( ). <br/>\n ; 42 } 43 try { 44 $adr > setcomplementadresse ( $complementadresse ) ; 45 } catch ( Exception $e ) { 46 $dataerrors [ complementadresse ] = $e >getmessage ( ). <br/>\n ; 47 } 48 try { 49 $adr > setcodepostal ( $codepostal ) ; 50 } catch ( Exception $e ) { 51 $dataerrors [ codepostal ] = $e >getmessage ( ). <br/>\n ; 52 } 53 try { 54 $adr > s e t V i l l e ( $ v i l l e ) ; 55 } catch ( Exception $e ) { 56 $dataerrors [ v i l l e ] = $e >getmessage ( ). <br/>\n ; 57 } 58 try { 59 $adr > setpays ( $pays ) ; 60 } catch ( Exception $e ) { 61 $dataerrors [ pays ] = $e >getmessage ( ). <br/>\n ; 62 } 63 return $adr ; 64 } 65 } 66?> 7.4 Génération de formulaires et classe AdresseFormView Nous définissons ensuite la classe AdresseFormView qui présente (essentiellement) deux méthodes pour générer des formulaires, avec ou sans gestion d erreur dans des vues. Un méthode permet aussi de générer un formulaire avec tous les champs cachés pour transmettre tous les champs d une adresse par la méthode post de manière transparente pour l utilisateur. Pour générer des formulaires, on utilise une classe template de génération de formulaires dont le code est donné ci-dessous. Dans la méthode permettant de générer le formulaire avec un éventuel message d erreur pour chaque attribut, on utilise le format du tableau d erreurs construit par la fabrique d adresse (partie 7.3). 152

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions exemples/forms2/ex04_classeadresseformview.php 1 <?php 2 require_once ( dirname ( FILE ). / Adresse. php ) ; 3 require_once ( dirname ( FILE ). / FormManager. php ) ; 4 5 /** 6 @brief La c l a s s e AdresseFormView implémente l a g é n é r a t i o n d un f o r m u l a i r e HTML pour s a i s i r 7 * une a d r e s s e dans une vue dans un navigareur. 8 * Implémente a u s s i des u t i l i s 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 9 * 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. 10 */ 11 class AdresseFormView { 12 13 /** 14 * @brief Méthode 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 en HTML. 15 * La méthode retourne l e code HTML avec des r e t o u r à l a l i g n e pour un a f f i c h a g e c o n v i v i a l. 16 */ 17 p u b l i c s t a t i c f u n c t i o n getdefaultformhtml ( $ a c t i o n ) { 18 return s e l f : :getformhtml ( $action, Adresse : :g e t D e f a u l t A d r e s s e ( ) ) ; 19 } 20 21 /** 22 * @brief Méthode 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 en HTML. 23 * La méthode retourne l e code HTML avec des r e t o u r à l a l i g n e pour un a f f i c h a g e c o n v i v i a l. 24 */ 25 p u b l i c s t a t i c f u n c t i o n getformhtml ( $action, $ a d r e s s e ) { 26 $htmlcode = FormManager : :beginform ( post, $ a c t i o n ) ; 27 $htmlcode.= FormManager : :addhiddeninput ( id, id, $adresse >g e t I d ( ) ) ; 28 $htmlcode.= FormManager : :addtextinput ( Numéro, numerorue, numerorue, 4, 29 $adresse >getnumerorue ( ) ). <br/> ; 30 $htmlcode.= FormManager : :addtextinput ( Rue/ p l a c e, rue, rue, 30, 31 $adresse >getrue ( ) ). <br/> ; 32 $htmlcode.= FormManager : :addtextinput ( Complément d a d r e s s e, 33 complementadresse, complementadresse, 34 30, $adresse >getcomplementadresse ( ) ). <br/> ; 35 $htmlcode.= FormManager : :addtextinput ( Code p o s t a l, codepostal, codepostal, 10, $adresse > getcodepostal ( ) ). <br/> ; 36 $htmlcode.= FormManager : :addtextinput ( V i l l e, v i l l e, v i l l e, 20, 37 $adresse >g e t V i l l e ( ), ENT_QUOTES, UTF 8 ). <br /> ; 38 $htmlcode.= FormManager : :addtextinput ( Pays, pays, pays, 15, 39 $adresse >getpays ( ) ). <br/> ; 40 $htmlcode.= FormManager : :addsubmitbutton ( Envoyer, c l a s s =\ sanslabel \ ). <br/> ; 41 $htmlcode.= FormManager : :endform ( ) ; 42 43 return $htmlcode ; 44 } 45 153

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 46 47 p r i v a t e s t a t i c f u n c t i o n adderrormsg ( $dataerrors, $fieldname ) { 48 i f (! empty ( $dataerrors [ $fieldname ] ) ) { 49 $htmlcode.= <span c l a s s =\ errormsg \ >. $dataerrors [ $fieldname ]. </span ><br/> ; 50 } 51 return $htmlcode ; 52 } 53 54 /** 55 * @brief Méthode 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 en HTML 56 * en a f f i c h a n t l e s e r r e u r s précédement d é t e c t é e sur l e s d i f f é r e n t s a t t r i b u t s. 57 * La méthode retourne l e code HTML avec des r e t o u r à l a l i g n e pour un a f f i c h a g e c o n v i v i a l. 58 */ 59 p u b l i c s t a t i c f u n c t i o n getformerrorshtml ( $action, $adresse, $dataerrors ) { 60 $htmlcode = FormManager : :beginform ( post, $ a c t i o n ) ; 61 $htmlcode.= FormManager : :addhiddeninput ( id, id, $adresse >g e t I d ( ) ) ; 62 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, numerorue ) ; 63 $htmlcode.= FormManager : :addtextinput ( Numéro, numerorue, numerorue, 4, 64 $adresse >getnumerorue ( ) ). <br/> ; 65 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, rue ) ; 66 $htmlcode.= FormManager : :addtextinput ( Rue/ p l a c e, rue, rue, 30, 67 $adresse >getrue ( ) ). <br/> ; 68 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, complementadresse ) ; 69 $htmlcode.= FormManager : :addtextinput ( Complément d a d r e s s e, 70 complementadresse, complementadresse, 71 30, $adresse >getcomplementadresse ( ) ). <br/> ; 72 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, codepostal ) ; 73 $htmlcode.= FormManager : :addtextinput ( Code p o s t a l, codepostal, codepostal, 10, $adresse > getcodepostal ( ) ). <br/> ; 74 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, v i l l e ) ; 75 $htmlcode.= FormManager : :addtextinput ( V i l l e, v i l l e, v i l l e, 20, 76 $adresse >g e t V i l l e ( ), ENT_QUOTES, UTF 8 ). <br /> ; 77 $htmlcode.= s e l f : :adderrormsg ( $dataerrors, pays ) ; 78 $htmlcode.= FormManager : :addtextinput ( Pays, pays, pays, 15, 79 $adresse >getpays ( ) ). <br/> ; 80 $htmlcode.= FormManager : :addsubmitbutton ( Envoyer, c l a s s =\ sanslabel \ ). <br/> ; 81 $htmlcode.= FormManager : :endform ( ) ; 82 83 return $htmlcode ; 84 } 85 86 /** 87 * @brief Méthode 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 en HTML. 88 * La méthode retourne l e code HTML avec des r e t o u r à l a l i g n e pour un a f f i c h a g e c o n v i v i a l. 89 */ 90 p u b l i c s t a t i c f u n c t i o n gethiddenformhtml ( $action, $adresse, $buttontext ) { 91 $htmlcode = FormManager : :beginform ( post, $ a c t i o n ) ; 154

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 92 $htmlcode.= FormManager : :addhiddeninput ( id, id, $adresse >g e t I d ( ) ) ; 93 $htmlcode.= FormManager : :addhiddeninput ( numerorue, numerorue, 94 $adresse >getnumerorue ( ) ) ; 95 $htmlcode.= FormManager : :addhiddeninput ( rue, rue, $adresse >getrue ( ) ) ; 96 $htmlcode.= FormManager : :addhiddeninput ( complementadresse, complementadresse, 97 $adresse >getcomplementadresse ( ) ) ; 98 $htmlcode.= FormManager : :addhiddeninput ( codepostal, codepostal, 99 $adresse >getcodepostal ( ) ) ; 100 $htmlcode.= FormManager : :addhiddeninput ( v i l l e, v i l l e, $adresse > g e t V i l l e ( ) ) ; 101 $htmlcode.= FormManager : :addhiddeninput ( pays, pays, $adresse >getpays ( ) ) ; 102 $htmlcode.= FormManager : :addsubmitbutton ( $buttontext, c l a s s =\ sanslabel \ ) ; 103 $htmlcode.= FormManager : :endform ( ) ; 104 105 return $htmlcode ; 106 } 107 108 } 109?> La classe template de génération de formulaires utilisée ci-dessous est la suivante : exemples/forms2/ex05_classeformmanager.php 1 <?php 2 /** 3 @brief Cette c l a s s e s e r t à f a c i l i t é l a g é n é r a t i o n de f o r m u l a i r e s HTML en PHP. 4 * E l l e f o u r n i t de méthodes pour g é n é r e r l e début, l a f i n du f o r m u l a i r e, 5 * a i n s i que l e s inputs avec l e s o p t i o n s de base. 6 * Les o p t i o n s complémentaires des i nputs peuvent ê t r e s é l e c t i o n n é e s 7 * via une v a r i a b l e $extraoptions des méthodes ( mais c e s t un peu plus complexe ). 8 **/ 9 class FormManager { 10 /** 11 @brief génère l a b a l i s e form avec sa méthode ( Post ou Get ) et sont action ( u r l ) 12 */ 13 p u b l i c s t a t i c f u n c t i o n beginform ( $method, $action, $ c s s _ c l a s s=, $extraoptions= ) { 14 i f (! empty ( $ c s s _ c l a s s ) ) 15 $css_class_option = c l a s s =\. $ c s s _ c l a s s. \ ; 16 return <form method=\. $method. \ a c t i o n=\. $ a c t i o n. \. $css_class_option. $extraoptions. >\n ; 17 } 18 19 /** 20 @brief ferme l e f o r m u l a i r e 21 */ 22 p u b l i c s t a t i c f u n c t i o n endform ( ) { 23 return </form> ; 24 } 25 155

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 26 /** 27 méthode g énérique de g é n é r a t i o n d un input 28 @param $labeltext t e x t e du label correspondant à l input 29 @param $type type d input : t e x t e textarea, chackbox, radio, submit... 30 @param $id ID de l input pour l a correspondance label /input 31 @param $value v a l e u r i n i t i a l e du champs de l input 32 @paarm $extraoptions chaine de c a r a c t è r e s contenant l e s o p t i o n s supplémentaires 33 de l input suivant l a syntaxe HTML. 34 */ 35 p u b l i c s t a t i c f u n c t i o n addinput ( $labeltext, $type, $name, $id, $value=null, $extraoptions=, $nobr=f a l s e ) { 36 $valueoption = ( $value == n u l l )? : value=\. $value. \ ; 37 i f ( $extraoptions == n u l l ) { 38 $extraoptions= ; 39 } 40 41 i f ( $labeltext!= n u l l && $labeltext!= ) { 42 $returntext.= <l a b e l f o r=\. $id. \ >. $labeltext. </l a b e l >\n ; 43 } 44 $returntext.= <input type=\. $type. \ name=\. $name. \ id=\. $id. \. $valueoption.. $extraoptions. />\n ; 45 46 i f (! $nobr) { 47 $returntext.= <br/>\n ; 48 } 49 return $returntext ; 50 } 51 52 /** 53 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type text 54 */ 55 p u b l i c s t a t i c f u n c t i o n addtextinput ( $labeltext, $name, $id, $ s i z e, $value=null, $extraoptions= ) { 56 return s e l f : :addinput ( $labeltext, t e x t, $name, $id, $value, s i z e =\. $ s i z e. \. $extraoptions ) ; 57 } 58 59 /** 60 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type password 61 */ 62 p u b l i c s t a t i c f u n c t i o n addpasswordinput ( $labeltext, $name, $id, $ s i z e, $value= null, $extraoptions= ) { 63 return s e l f : :addinput ( $labeltext, password, $name, $id, $value, s i z e =\. $ s i z e. \. $extraoptions ) ; 64 } 65 66 /** 67 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type r a d i o 68 */ 69 p u b l i c s t a t i c f u n c t i o n addradioinput ( $labeltext, $name, $id, $checked, $value= null, $extraoptions= ) { 70 return s e l f : :addinput ( $labeltext, r a d i o, $name, $id, $value, ( strcmp ( $checked, checked ) ==0)? checked =\ checked\ :. $extraoptions ) ; 71 } 72 156

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 73 /** 74 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type r a d i o 75 */ 76 p u b l i c s t a t i c f u n c t i o n addcheckboxinput ( $labeltext, $name, $id, $checked, $value, $extraoptions= ) { 77 return s e l f : :addinput ( $labeltext, checkbox, $name, $id, $value, ( strcmp ( $checked, checked ) ==0)? checked =\ checked\ :. $extraoptions ) ; 78 } 79 80 /** 81 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type textarea 82 */ 83 p u b l i c s t a t i c f u n c t i o n addtextareainput ( $labeltext, $name, $id, $rows, $ c o l s, $value=null, $extraoptions= ) { 84 $valueoption = ( $value == n u l l )? : $value ; 85 i f ( $extraoptions == n u l l ) { 86 $extraoptions= ; 87 } 88 $returntext.= <p>\n ; 89 i f ( $labeltext!= n u l l && $labeltext!= ) { 90 $returntext.= <l a b e l f o r=\. $id. \ >. $labeltext. </l a b e l >\n ; 91 } 92 $returntext.= <t e x t a r e a name=\. $name. \ id=\. $id. \ rows=\. $rows. \ c o l s =\. $ c o l s. \. $extraoptions. >. $valueoption. </textarea >\n ; 93 $returntext.= </p>\n ; 94 return $returntext ; 95 } 96 97 /** 98 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type f i l e ( upload ) 99 */ 100 p u b l i c s t a t i c f u n c t i o n adduploadinput ( $labeltext, $name, $id, $ s i z e, $value=, $extraoptions= ) { 101 $valueoption = ( $value == n u l l )? value=\ \ : value=\. $value. \ ; 102 i f ( $extraoptions == n u l l ) { 103 $extraoptions= ; 104 } 105 return s e l f : :addinput ( $labeltext, f i l e, $name, $id, $value, s i z e =\. $ s i z e. \. $valueoption.. $extraoptions ) ; 106 } 107 108 /** 109 @brief méthode pour commencer un select 110 */ 111 p u b l i c s t a t i c f u n c t i o n b e g i n S e l e c t ( $labeltext, $name, $id, $ m u l t i p l e=f a l s e, $ s i z e =6) { 112 $returntext = ; 113 i f ( $ m u l t i p l e ) 114 $multipleoption= m u l t i p l e=\ multiple\ s i z e =\. $ s i z e. \ ; 115 e l s e 116 $multipleoption= ; 117 i f ( $labeltext!= n u l l && $labeltext!= ) { 118 $returntext.= <p><l a b e l f o r =\. $id. \ >. $labeltext. </l a b e l >\n ; 119 } 120 $returntext.= <s e l e c t name=\. $name. \ id=\. $id. \. $multipleoption. >\n ; 157

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 121 return $returntext ; 122 } 123 124 /** 125 @brief méthode s i m p l i f i é e pour terminer un select 126 */ 127 p u b l i c s t a t i c f u n c t i o n e n d S e l e c t ( ) { 128 $returntext = </ s e l e c t ></p>\n ; 129 return $returntext ; 130 } 131 132 /** 133 @brief méthode s i m p l i f i é e pour a j o u t e r une option de select 134 */ 135 p u b l i c s t a t i c f u n c t i o n addselectoption ( $value, $displaytext, $ s e l e c t e d=f a l s e ) { 136 $returntext = ; 137 i f ( $ s e l e c t e d ) 138 $ s e l e c t e d O p t i o n= s e l e c t e d =\ selected \ ; 139 e l s e 140 $ s e l e c t e d O p t i o n= ; 141 $returntext.= <option value=\. $value. \. $ s e l e c t e d O p t i o n. >. $displaytext. </option >\n ; 142 return $returntext ; 143 } 144 145 /** 146 @brief méthode s i m p l i f i é e pour g é n é r e r un input de type r a d i o 147 */ 148 p u b l i c s t a t i c f u n c t i o n addhiddeninput ( $name, $id, $value, $extraoptions= ) { 149 return s e l f : :addinput (, hidden, $name, $id,. $value, $extraoptions, true ) ; 150 } 151 152 /** 153 @brief méthode s i m p l i f i é e pour g é n é r e r un bouton submit 154 */ 155 p u b l i c s t a t i c f u n c t i o n addsubmitbutton ( $value= Envoyer, $extraoptions= ) { 156 return s e l f : :addinput ( null, submit,,, $value,. $extraoptions ) ; 157 } 158 } 159?> 7.5 Enchaînement de la saisie à la vue Nous montrons enfin comment enchaîner le filtrage initial, la construction des instances, la détection des erreurs et la génération de la vue HTML qui convient. Nous proposerons aussi de modifier une adresse, en transmettant tous les attributs d une instance dans des champs cachés (hidden). Voici tout d abord la vue permettant de saisir une adresse : exemples/forms2/ex07_vuedefaultformadresse.php 1 <?php 2 require_once ( dirname ( FILE ). / c l a s s e s / VueHtmlUtils. php ) ; 158

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 3 require_once ( dirname ( FILE ). / c l a s s e s /AdresseFormView. php ) ; 4 5 echo VueHtmlUtils : :entetehtml5 ( S a i s i e d \ une Adresse, UTF 8, mystyle. css ) ; 6 7 echo AdresseFormView : :getdefaultformhtml ( ex09_receptionadresse. php ) ; 8 9 echo VueHtmlUtils : :finfichierhtml5 ( ) ; 10?> La classe d utilitaires de génération de code HTML, relativement sommaire, est donnée ci-dessous : exemples/forms2/ex08_vuehtmlutils.php 1 <?php 2 class VueHtmlUtils { 3 p u b l i c s t a t i c f u n c t i o n entetehtml5( $ t i t l e, $charset, $css_sheet ) { 4 // s o r t i e du doctype. Les g u i l l e m e t s HTML sont p r o t é g é s par \ 5 $htmlcode = <! doctype html>\n ; 6 $htmlcode.= <html lang=\ f r \ >\n ; 7 $htmlcode.= <head>\n ; 8 $htmlcode.= <meta c h a r s e t=\ ; 9 $htmlcode.= $ c h a r s e t ; 10 $htmlcode.= \ />\n ; 11 $htmlcode.= <l i n k r e l =\ s t y l e s h e e t \ h r e f=\ ; 12 $htmlcode.= $css_sheet ; 13 $htmlcode.= \ />\n ; 14 // concaténation de c h a î n e s de c a r a c t è r e s. 15 $htmlcode.= <t i t l e >. $ t i t l e. </ t i t l e >\n ; 16 $htmlcode.= </head>\n<body>\n ; 17 return $htmlcode ; 159

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 18 } 19 20 p u b l i c s t a t i c f u n c t i o n finfichierhtml5 ( ) 21 { 22 return </body>\n</html>\n ; 23 } 24 } 25?> Le script qui reçoit les données saisies dans le formulaire, effectue le filtrage pour la sécurité (ici un nettoyage systématique par filter_var), puis construit l instance d adresse et appelle une vue (vue normale ou vue d erreur, selon le cas). exemples/forms2/ex09_receptionadresse.php 1 <?php 2 require_once ( dirname ( FILE ). / c l a s s e s / AdresseFabrique. php ) ; 3 4 r e q u i r e ( ex10_validation. php ) ; 5 6 $ a d r e s s e = AdresseFabrique : :getadresse ( $dataerrors, $id, $numerorue, $rue, 7 $complementadresse, $codepostal, $ v i l l e, $pays ) ; 8 9 i f ( empty ( $dataerrors ) ) { 10 r e q u i r e ( dirname ( FILE ). / ex11_vuenormaleadresse. php ) ; 11 } e l s e { 12 r e q u i r e ( dirname ( FILE ). / ex12_vueerreuradresse. php ) ; 13 } 14?> exemples/forms2/ex10_validation.php 1 <?php 2 $id = i s s e t ($_POST[ id ] )? f i l t e r _ v a r ($_POST[ id ], FILTER_SANITIZE_STRING) : ; 3 $numerorue = i s s e t ($_POST[ numerorue ] )? f i l t e r _ v a r ($_POST[ numerorue ], FILTER_SANITIZE_STRING) : ; 4 $rue = i s s e t ($_POST[ rue ] )? f i l t e r _ v a r ($_POST[ rue ], FILTER_SANITIZE_STRING ) : ; 5 $complementadresse = i s s e t ($_POST[ complementadresse ] )? f i l t e r _ v a r ($_POST[ complementadresse ], FILTER_SANITIZE_STRING) : ; 6 $codepostal = i s s e t ($_POST[ codepostal ] )? f i l t e r _ v a r ($_POST[ codepostal ], FILTER_SANITIZE_STRING) : ; 7 $ v i l l e = i s s e t ($_POST[ v i l l e ] )? f i l t e r _ v a r ($_POST[ v i l l e ], FILTER_SANITIZE_STRING) : ; 8 $pays = i s s e t ($_POST[ pays ] )? f i l t e r _ v a r ($_POST[ pays ], FILTER_SANITIZE_STRING) : ; 9?> 7.6 Les Vues La vue normale affiche simplement l instance d adresse saisie, qui est en principe sans erreurs. exemples/forms2/ex11_vuenormaleadresse.php 160

Chapitre 7 : Formulaires PHP/HTML, filtrage, exceptions 1 <?php 2 require_once ( dirname ( FILE ). / c l a s s e s / VueHtmlUtils. php ) ; 3 require_once ( dirname ( FILE ). / c l a s s e s / AdresseView. php ) ; 4 require_once ( dirname ( FILE ). / c l a s s e s /AdresseFormView. php ) ; 5 6 echo VueHtmlUtils : :entetehtml5 ( L\ a d r e s s e a bien é t é s a i s i e, UTF 8, mystyle. css ) ; 7 8 echo AdresseView : :gethtmldevelopped ( $ a d r e s s e ) ; 9 10 echo AdresseFormView : :gethiddenformhtml ( ex13_receptionmodifadresse. php, $adresse, M odifier ) ; 11 12 echo VueHtmlUtils : :finfichierhtml5 ( ) ; 13?> La vue d erreur affiche un formulaire partiellement rempli avec les données correctes, et affiche le message d erreur (initialement généré dans le setter dee l attribut) pour les données incorrectes. exemples/forms2/ex12_vueerreuradresse.php 1 <?php 2 require_once ( dirname ( FILE ). / c l a s s e s / VueHtmlUtils. php ) ; 3 require_once ( dirname ( FILE ). / c l a s s e s /AdresseFormView. php ) ; 4 5 echo VueHtmlUtils : :entetehtml5 ( S a i s i e d \ une adresse, UTF 8, mystyle. css ) ; 6 7 echo AdresseFormView : :getformerrorshtml ( ex09_receptionadresse. php, 8 $adresse, $dataerrors ) ; 9 10 echo VueHtmlUtils : :finfichierhtml5 ( ) ; 11?> 161

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 7.7 Modification d une Adresse Lors de l affichage de la vue normale de l adresse ci-dessus, un formulaire avec toutes les valeurs des attributs de l adresse sous forme de champs cachés est inclus dans la vue, avec un bouton submit pour éditer les valeurs. On affiche alors une vue normale avec un formulaire pré-rempli pour modifier l adresse. exemples/forms2/ex13_receptionmodifadresse.php 1 <?php 2 require_once ( dirname ( FILE ). / c l a s s e s / AdresseFabrique. php ) ; 3 4 r e q u i r e ( ex10_validation. php ) ; 5 6 $ a d r e s s e = AdresseFabrique : :getadresse ( $dataerrors, $id, $numerorue, $rue, 7 $complementadresse, $codepostal, $ v i l l e, $pays ) ; 8 9 r e q u i r e ( dirname ( FILE ). / ex12_vueerreuradresse. php ) ; 10?> 162

Quatrième partie Persistance 163

164

Table of Contents 8 Cookies 169 8.1 Création d un cookie................................ 169 8.2 Récupération d un cookie.............................. 171 8.3 Suppression d un cookie.............................. 172 8.4 Mise à jour d un cookie............................... 173 9 Sessions 174 9.1 Concept de Session et Problèmes de Sécurité................... 174 9.2 Créer une session.................................. 175 9.3 Création d une session commune à tous les utilisateurs............. 175 9.4 Durée et SID d une session............................. 176 9.5 Destruction d une Session............................. 177 9.6 Exemple de Session avec SID aléatoire transmis par GET........... 178 9.7 Exemple de Session avec SID aléatoire transmis par COOKIE......... 180 9.8 Exemple Politique de Sécurité en Matière de Session.............. 182 10 Bases de Données et PHP Data Objects 191 10.1 Créer un Base de Données dans phpmyadmin.................. 191 10.1.1 Création d une Base de Données Relationnelle.............. 191 10.1.2 Créer un Utilisateur MySql Responsable d une BD........... 192 10.2 Initiation à PDO : connexion, query, destruction................ 195 10.2.1 Établir la Connexion à une Base de Données............... 195 10.2.2 Parcourir les Résultats d une Requête.................. 198 10.3 Requêtes Préparées................................. 202 10.4 Classe Singleton de Connexion à une Base de Données............. 206

166 TABLE OF CONTENTS

Introduction : Mécanismes de la Persistence Le protocole HTTP est un protocole sans état. Cela signifie que, dans le protocole HTTP, aucune information n est conservée entre deux transaction. Théoriquement, suivant un tel protocole, 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 identifier 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 cookies. 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 167

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. En général, il faut trouver un compromis, dépendant de l application, entre le confort du client et la sécurité, et éviter les politiques de sécurité trop bâteau, qu un pirate pourra facilement deviner. 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éattribué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 quantité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. 168

Chapitre 8 Cookies 8.1 Création d un cookie On crée un cookie en PHP à l aide de la fonction setcookie. Cette fonction a le prototypes suivant (seul le premier argument est obligatoire) : bool setcookie(string $name, string $value, int $expire = 0, string $path, string $domain, bool $secure = false, bool $httponly = false) 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, contrairement à setcookie. bool setrawcookie(string $name, string $value, int $expire = 0, string $path, string $domain, bool $secure = false, bool $httponly = false) La signification des paramètres est la suivante : Name : nom du cookie, qui permet de stocker plusieurs cookies sur un même client avec différentes fonctions. On récupère ensuite les valeurs des cookie grâce au tableau associatif $_COOKIE, qui est indexé par les attributs name des différents cookie. value : La valeur du cookie, qui est stockée sur l ordinateur du client. Ne stockez pas d informations sensibles chez le client, ou alors en chiffrant les données (mais un chiffrement peut toujours se casser...). expire : la date (timestamp Unix : nombre de secondes depuis le 1er janvier 1970 à 0h00) limite de validité du cookie. La fonction time retourne le timestamp de la date actuelle, permettant de fixer la date d expiration en ajoutant un certain nombre de secondes par rapport au présent. La fonction mktime retourne le timestamp d une date donnée par son heure, minute, seconde, année, etc. path : chemin vers le répertoire sur le serveur dans lequel le cookie est disponible dans les scripts PHP (Exemple : / pour la racine du site). La valeur par défaut est le répertoire contenant le script courant définissant le cookie (donné par dirname( FILE ). 169

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 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 : exemples/cookies/ex01_setcookie.php 1 <?php 2 // Fonction qui retourne l heure l o c a l e sous fomr de string : 3 f u n c t i o n getlocaltimefrenchformat ( ) { 4 $heurelocalearray = l o c a l t i m e ( time ( ), true ) ; 5 $dayofmonth = str_pad ( i n t v a l ( $heurelocalearray [ tm_mday ], 10), 2, 0, STR_PAD_LEFT) ; 6 $monthofyear = str_pad ( i n t v a l ( $heurelocalearray [ tm_mon ], 10) +1, 2, 0, STR_PAD_LEFT) ; 7 $yearsinceera = str_pad ( i n t v a l ( $heurelocalearray [ tm_year ], 10) +1900, 4, 0,STR_PAD_LEFT) ; 8 $hourofday = str_pad ( i n t v a l ( $heurelocalearray [ tm_hour ], 10), 2, 0, STR_PAD_LEFT) ; 9 $minofhour = str_pad ( i n t v a l ( $heurelocalearray [ tm_min ], 10), 2, 0, STR_PAD_LEFT) ; 10 $secofmin = str_pad ( i n t v a l ( $heurelocalearray [ tm_sec ], 10), 2, 0, STR_PAD_LEFT) ; 11 12 $heurelocaleformatee = $dayofmonth. /. $monthofyear. /. $yearsinceera 13. à. $hourofday. :. $minofhour. :. $secofmin ; 14 return $heurelocaleformatee ; 15 } 170

Chapitre 8 : Cookies 16 17 // t r o i s chaîne s é p a r é e s par des v i r g u l e s ( c e s t j u s t e un exemple avec explode... ) 18 $valeur = ma chaîne 1, ma chaîne 2, ma chaîne 3,. getlocaltimefrenchformat ( ) ; 19 s e t c o o k i e ( e s s a i C o o k i e, $valeur, time ( ) +3600) ; 20 21 // Code de l a de l a vue : 22 require_once (. / commonfunctions. php ) ; 23 outputentetehtml5 ( Création d un Cookie, UTF 8, mystyle. css ) ; 24 echo <h1>création d un <i >cookie </i ></h1> ; 25 echo <p><a h r e f=\ ex02_retrievecookie. php\ >Cliquez i c i </a> 26. pour v o i r s i l e <i >cookie </i > a bien é t é s t o c k é chez l e c l i e n t.</p> ; 27 outputfinfichierhtml5 ( ) ; 28?> 8.2 Récupération d un cookie Les cookies peuvent être obtenus, jusqu à expiration, dans le tableau associatif (qui est un superglobal) $_COOKIE. Les clés de ce tableau associatif sont les noms des cookies, et les valeurs du tableau sont les valeurs respectives des cookies. exemples/cookies/ex02_retrievecookie.php 1 <?php 2 i f ( i s s e t ($_COOKIE[ essaicookie ] ) ) { 3 // Le contenu d un c o o k i e d o i t ê t r e f i l t r é comme l e s inputs 4 $valeur = $_COOKIE[ essaicookie ] ; 5 $valeur = f i l t e r _ v a r ( $valeur, FILTER_SANITIZE_STRING) ; 6 $tabchaines = explode (,, $ valeur ) ; 7 } e l s e { 8 $dataerror = array ( cookie => e s s a i C o o k i e i n t r o u v a b l e&nbsp ;! ) ; 9 } 10 11 // Appel des vues : 12 require_once (. / commonfunctions. php ) ; 13 i f ( empty ( $dataerror ) ) { // Code de l a vue normale : 14 outputentetehtml5 ( Récupération d un Cookie, UTF 8, mystyle. css ) ; 15 echo <h1>récupération d un <i >cookie </i ></h1> ; 16 echo Les c h a î n e s contenues dans l e <i >cookie </i > sont : ; 17 echo <ul> ; 18 f o r e a c h ( $tabchaines as $chaine ) { 19 echo <l i >. $chaine. </ l i l i > ; 20 } 21 echo </ul> ; 22 outputfinfichierhtml5 ( ) ; 23 } e l s e { // Appel de l a vue d e r r e u r : 24 r e q u i r e ( ex02_vueerreur. php ) ; 25 } 26 27 28?> exemples/cookies/ex02_vueerreur.php 171

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 1 <?php 2 outputentetehtml5 ( Problème de r é c u p é r a t i o n de Cookie, UTF 8, mystyle. css ) ; 3 echo <h1>erreur de r é c u p é r a t i o n de <i >cookie </i ></h1> ; 4 echo <p> ; 5 f o r e a c h ( $dataerror as $ f i e l d => $message ) { 6 echo <i>. $ f i e l d. </i > :. $message. <br/> ; 7 } 8 echo </p> ; 9 outputfinfichierhtml5 ( ) ; 10?> 8.3 Suppression d un cookie Pour supprimer un cookie, on le recrée, avec le même nom, une valeur false (ou chaîne vide), et une date d expiration antérieure au présent. exemples/cookies/ex03_unsetcookie.php 1 <?php 2 // On met une v a l e u r vide et une date d e x p i r a t i o n a n t é r i e u r e au p r é s e n t 3 s e t c o o k i e ( e s s a i C o o k i e,, time ( ) 3600) ; 4 5 // Code de l a vue : 6 require_once (. / commonfunctions. php ) ; 7 outputentetehtml5 ( Suppression d un Cookie, UTF 8, mystyle. css ) ; 8 echo <h1>suppression d un <i >cookie </i ></h1> ; 9 echo <p><a h r e f=\ ex02_retrievecookie. php\ >Cliquez i c i </a> 10. pour v é r i f i e r que l e <i >cookie </i > a bien é t é supprimé chez l e c l i e n t.</p> ; 11 outputfinfichierhtml5 ( ) ; 12?> Le fait de faire unset($_cookie[ essaicookie ]) ne modifiera pas, et ne supprimera pas, le cookie chez le client. 172

Chapitre 8 : Cookies 8.4 Mise à jour d un cookie Il n y a pas d autre méthodes pour mettre à jour un cookie que d en créer une nouveau, de même nom, avec la fonction setcookie. On peut par exemple mettre à jour la date d expiration à chaque chargement de page, pour prolonger la validité tant que l utilisateur est actif, sans changer la valeur du cookie : exemples/cookies/ex04_setandprolongcookie.php 1 <?php 2 i f ( i s s e t ($_COOKIE[ essaicookie ] ) ) { // s i l e c o o k i e e x i s t e 3 $valeur = $_COOKIE[ essaicookie ] ; 4 $valeur = f i l t e r _ v a r ( $valeur, FILTER_SANITIZE_STRING) ; 5 } e l s e { // s i l e c o o k i e n e x i s t e pas, on l e c r é e avec l a date : 6 $valeur = Je s u i s l a v a l e u r dans l e c o o k i e :. time ( ) ; 7 } 8 // Le c o o c k i e e s t prolongé tant que l u t i l s a t e u r ne r e s t e pas i n a c t i f 15mn 9 s e t c o o k i e ( e s s a i C o o k i e, $valeur, time ( ) +15*60) ; 10 11 // Code de l a vue : 12 require_once (. / commonfunctions. php ) ; 13 outputentetehtml5 ( Création d un Cookie, UTF 8, mystyle. css ) ; 14 echo <h1>prolongement de l a V a l i d i t é d un <i >cookie </i ></h1> ; 15 echo <p>valeur courante du c o o k i e : <i >. $ v a l e u r. </i ></p> ; 16 // Lien sur ce même script : 17 echo <p><a h r e f=\. basename ($_SERVER[REQUEST_URI],. php ).. php\ >Cliquez i c i </a> 18. pour v o i r s i l e <i >cookie </i > a bien é t é s t o c k é chez l e c l i e n t.</p> ; 19 outputfinfichierhtml5 ( ) ; 20?> 173

Chapitre 9 Sessions 9.1 Concept de Session et Problèmes de Sécurité Les sessions sont des données, mémorisées sur le serveur, qui peuvent rester accessible d un script à l autre. Pour utiliser les sessions en PHP, il faut démarrer la session dans chaque script qui devra utiliser les données ce cette session. Si la session n existe pas, elle sera créée et ne contiendra initialement aucune donnée. Si une session existe et est active, les données de cette session seront chargées dans le tableau associatif superglobal $_SESSION. Ce tableau associatif est aussi accessible en écriture pour ajouter des données en session. Les données de session doivent être sérialisées pour être stockées sur le serveur. La sauvegarde des sessions a un comportement par défaut, qui peut être modifié, sur le serveur. Pour retrouver une session d un script à l autre, un numéro de session (SID) doit être transmis entre les scripts. Il y a trois manières de transmettre le numéro de session, qui doivent chacune s accompagner d une politique de sécurité, pour éviter l usurpation malveillante de l accès à une session. Voici (par ordre décroissant de sécurité supposée) ces trois manières : 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 ; La méthode GET, en clair dans l URL accessible au client ; Du fait qu il y a toujours une possibilité pour une personne malveillante d accéder aux donné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é). 174

Chapitre 9 : Sessions 9.2 Créer une session 9.3 Création d une session commune à tous les utilisateurs Voici un exemple de session contenant un compteur du nombre de chargement du script, global pour tous les utilisateurs. Les fonctions utilisées pour la gestion de la session sont : session_id : permet de définir l identifiant (SID) de session (ou d y accéder) ; session_start : permet la création d une session (avec le SID précédemment défini), ou son chargement si la session existe sur le disque et n a pas expiré. session_write_close : Permet d écrire immédiatement la session et de la fermer, permettant éventuellement à d autres scripts de charger la session. (si on n appelle pas explicitement la fonction session_write_close, la session sera quand même écrite (sauf erreur), mais il peut y avoir une latence pour les accès concurrents. exemples/sessions/ex01_createsessionfordummies.php 1 <?php 2 // Création d un i d e n t i f i a n t de s e s s i o n v a l a b l e pour tous l e s u t i l i s a t e u r s 3 s e s s i o n _ i d ( a l l users s e s s i o n ) ; 4 5 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 6 s e s s i o n _ s t a r t ( ) ; 7 8 // Si l a v a r i a b l e de s e s s i o n du j o u r e x i s t e ( i l y a déjà eu un script chargé aujourd hui ) 9 i f ( i s s e t ($_SESSION [ counter ] ) ) { 10 $counter = i n t v a l ($_SESSION [ counter ], 10) ; 11 $counter++ ; 12 $_SESSION [ counter ] =. $counter ; 13 } e l s e { 14 $_SESSION [ counter ] = 1 ; 15 } 16 17 // Mémorisation de l a donnée de s e s s i o n avant fermeture 175

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 18 $countervalue = $_SESSION [ counter ] ; 19 // Flush des Données de Session, ( sauvegarde immédiate sur l e disque ) 20 // Libère instantanément l e verrou 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 21 s e s s i o n _ w r i t e _ c l o s e ( ) ; 22 23 // Code de l a vue : 24 require_once (. / commonfunctions. php ) ; 25 outputentetehtml5 ( U t i l i s a t i o n basique d une s e s s i o n, UTF 8, mystyle. css ) ; 26 echo <h1>u t i l i s a t i o n Basique d une Session <br/>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 é chargé. $countervalue. f o i s depuis l a c r é a t i o n de l a s e s s i o n.</p> ; 28 outputfinfichierhtml5 ( ) ; 29?> 9.4 Durée et SID d une session exemples/sessions/ex02_createsessionbasicid.php 1 <?php 2 require_once (. / commonfunctions. php ) ; 3 4 // On f i x e à 24 heures l a durée de p e r s i s t a n c e de l a s e s s i o n sur l e s e r v e u r 5 // à p a r t i r de chaque connexion 6 session_cache_expire (60*24) ; 7 8 // Création d un i d e n t i f i a n t de s e s s i o n v a l a b l e pour tous l e s u t i l i s a t e u r s 9 s e s s i o n _ i d ( a l l users s e s s i o n ) ; 10 11 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 12 s e s s i o n _ s t a r t ( ) ; 13 14 // Chaîne qui code l a date d aujourd hui 15 $heurelocalearray = l o c a l t i m e ( time ( ), true ) ; 16 $dayofmonth = str_pad ( i n t v a l ( $heurelocalearray [ tm_mday ], 10), 2, 0, STR_PAD_LEFT) ; 176

Chapitre 9 : Sessions 17 $monthofyear = str_pad ( i n t v a l ( $heurelocalearray [ tm_mon ], 10) +1, 2, 0, STR_PAD_LEFT) ; 18 $yearsinceera = str_pad ( i n t v a l ( $heurelocalearray [ tm_year ], 10) +1900, 4, 0,STR_PAD_LEFT) ; 19 $datesting = $yearsinceera.. $monthofyear.. $dayofmonth ; 20 21 // Si l a v a r i a b l e de s e s s i o n du j o u r e x i s t e ( i l y a déjà eu un script chargé aujourd hui ) 22 i f ( i s s e t ($_SESSION [ counter. $datesting ] ) ) { 23 $counter = i n t v a l ($_SESSION [ counter. $datesting ], 10) ; 24 $counter++ ; 25 $_SESSION [ counter. $datesting ] =. $counter ; 26 } e l s e { 27 // Chaîne qui code l a date d h i e r 28 $yesterdaylocalearray = l o c a l t i m e ( time ( ) 60*60*24, true ) ; 29 $yestadaydayofmonth = str_pad ( i n t v a l ( $yesterdaylocalearray [ tm_mday ], 10), 2, 0,STR_PAD_LEFT) ; 30 $yestadaymonthofyear = str_pad ( i n t v a l ( $yesterdaylocalearray [ tm_mon ], 10) +1, 2, 0,STR_PAD_LEFT) ; 31 $yestadayyearsinceera = str_pad ( i n t v a l ( $yesterdaylocalearray [ tm_year ], 10) +1900, 4, 0,STR_PAD_LEFT) ; 32 $yesterdaydatestring = $yestadayyearsinceera.. $yestadaymonthofyear.. $yestadaydayofmonth ; 33 // 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... 34 unset ($_SESSION [ counter. $yesterdaydatestring ] ) ; 35 // On i n i t i a l i s e l e compteur du j o u r 36 $_SESSION [ counter. $datesting ] = 1 ; 37 } 38 // Mémorisation de l a donnée de s e s s i o n avant fermeture 39 $countervalue = $_SESSION [ counter. $datesting ] ; 40 // Flush des Données de Session, ( sauvegarde immédiate sur l e disque ) 41 // Libère instantanément l e verrou 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 42 s e s s i o n _ w r i t e _ c l o s e ( ) ; 43 44 outputentetehtml5 ( U t i l i s a t i o n basique d une s e s s i o n, UTF 8, mystyle. css ) ; 45 echo <h1>u t i l i s a t i o n d une Session <br/>commune à Tous l e s C l i e n t s </h1> ; 46 47 echo <p>le s c r i p t a é t é chargé. $countervalue. f o i s aujourd hui ( l e. $dayofmonth. /. $monthofyear. /. $yearsinceera. ).</p> ; 48 outputfinfichierhtml5 ( ) ; 49?> 9.5 Destruction d une Session exemples/sessions/ex03_destroysession.php 1 <?php 2 // Récupération de l a s e s s i o n à l a ide d un i d e n t i f i a n t de s e s s i o n 3 s e s s i o n _ i d ( a l l users s e s s i o n ) ; 4 5 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 177

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 6 s e s s i o n _ s t a r t ( ) ; 7 8 // Détruit t o u t e s l e s v a r i a b l e s de s e s s i o n 9 session_unset ( ) ; 10 // Détruit toute l a s e s s i o n ( a u s s i l e s données préalablement sauvegardées ) 11 s e s s i o n _ d e s t r o y ( ) ; 12?> 9.6 Exemple de Session avec SID aléatoire transmis par GET Voici un exemple qui crée une session spécifique pour chaque utilisateur pour la configuration de sa langue préférée (français ou anglais). Il s agit d une donnée peu sensible, donc l essentiel est de ne pas mélanger les utilisateur. Dans cet exemple, l usurpation d identité n aura pas de conséquences. On ne s intéresse donc pas à la question d un sniffeur qui piraterait l URL passée par GET, permettant au sniffeur d obtenir le SID. exemples/sessions/ex04_sessionrandomidget.php 1 <?php 2 /** Fonction qui retourne un message de bienvenue dans l a langue c h o i s i e */ 3 f u n c t i o n getgreeting ($PREF_LANG) { 4 $htmlgreeting = ; 5 switch ($PREF_LANG) { 6 case en : $htmlgreeting.= Hi, guys, Welcome to <code>mysite. com</ code>&nbsp ;! ; 7 break ; 8 case f r : $htmlgreeting.= Salut l a compagnie, bienvenue sur <code> monsite. f r </code>&nbsp ;! ; 9 break ; 10 11 d e f a u l t : $htmlgreeting.= Wilkommen, Bienvenue, Welcomme!<br/> ; 12 break ; 13 } 14 return $htmlgreeting ; 15 } 16 17 $dataerror = array ( ) ; 18 // 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 et s i l a donnée a l a bonne forme 19 // (10 c h i f f r e s hexa e n t r e 0 et f ) 20 i f ( i s s e t ($_GET[ s e s s i o n id ] ) && preg_match ( /^[0 9a fa F]{10} $/, $_GET[ s e s s i o n id ] ) ) { 21 // On a bien v é r i f i é l a forme par e x p r e s s i o n r é g u l i è r e donc, pas d autre précaution 22 $mysid = $_GET[ s e s s i o n id ] ; 23 } e l s e { 24 i f ( i s s e t ($_GET[ s e s s i o n id ] ) ) { 25 $dataerror [ s e s s i o n id ] = I d e n t i f i a n t de s e s s i o n i n c o r r e c t. P i r a t e s s a b s t e n i r... ; 26 } 27 // Génération d un SID par des o c t e t s ( pseudo ) a l é a t o i r e s codés en hexa 28 $cryptostrong = f a l s e ; // Variable pour passage par r é f é r e n c e 178

Chapitre 9 : Sessions 29 $ o c t e t s = openssl_random_pseudo_bytes ( 5, $cryptostrong ) ; 30 $mysid = bin2hex ( $ o c t e t s ) ; 31 } 32 s e s s i o n _ i d ( $mysid ) ; 33 34 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 35 s e s s i o n _ s t a r t ( ) ; 36 37 // I n i t i a l i s a t i o n des paramètres régionaux 38 39 // Si un choix de langage e s t p r é 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 s e s s i o n 40 i f ( i s s e t ($_GET[ pref_lang ] ) ) { 41 i f ($_GET[ pref_lang ] == en $_GET[ pref_lang ] == f r ) { 42 // Les données e n t r é e s en s e s s i o n doivent ê t r e f i l t r é e s, 43 // même s i, dans ce cas, i l n y a pas de danger car on a t e s t é avec == 44 $_SESSION [ preferred_language ] = f i l t e r _ v a r ($_GET[ pref_lang ], FILTER_SANITIZE_STRING) ; 45 } e l s e { 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 cas où 47 unset ($_SESSION [ preferred_language ] ) ; 48 } 49 } 50 // Si une p r é f é r e n c e de langage a é t é d é f i n i e, s o i r dans l URL, s o i t en s e s s i o n 51 i f ( i s s e t ($_SESSION [ preferred_language ] ) ) { 52 $PREFERRED_LANG = $_SESSION [ preferred_language ] ; 53 } e l s e { 54 $PREFERRED_LANG = undef ; 55 } 56 57 // Flush des Données de Session, ( sauvegarde simmédiate ur l e disque ) 58 s e s s i o n _ w r i t e _ c l o s e ( ) ; 59 60 // Si aucun SID i n c o r r e c t dans l URL 61 require_once (. / commonfunctions. php ) ; 62 i f ( empty ( $dataerror ) ) { // Code de l a vue normale : 63 outputentetehtml5 ( S e s s i o n avec SID A l é a t o i r e, UTF 8, mystyle. css ) ; 64 echo <h1>s e s s i o n avec <i >SID</i > A l é a t o i r e <br/>transmis par <code>get</code ></h1> ; 65 echo <p> ; 66 // Message de bienvenue dans l a langue 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 getgreeting ($PREFERRED_LANG). <br/> ; 68 echo <a h r e f=\.$_server[ SCRIPT_NAME ].?s e s s i o n id=. $mysid. &pref_lang= f r \ >Français </a> ou 69. <a h r e f=\.$_server[ SCRIPT_NAME ].?s e s s i o n id=. $mysid. &pref_lang=en \ >English </a> ; 70 echo </p> ; 71 outputfinfichierhtml5 ( ) ; 72 } e l s e { // Appel de l a vue d e r r e u r : 73 r e q u i r e ( ex04_vueerreur. php ) ; 74 } 75 76 179

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 77?> Figure 9.1 : Accueil d un nouveau client (pas de session en cours) Figure 9.2 : Accueil d un client avec langue préférée en anglais Figure 9.3 : Accueil d un client avec SID incorrect 9.7 Exemple de Session avec SID aléatoire transmis par COOKIE Comme dans l exemple précédent, le script crée une session spécifique pour chaque utilisateur pour la configuration de sa langue préférée (français ou anglais). La différence est dans le mode de transmission du SID par cookie. Les données de session sont peu sensibles, donc l usurpation d identité n aura pas de conséquences. On ne s intéresse pas à la question d un vol de cookie qui permettrait à un pirate d obtenir le SID. 1 <?php exemples/sessions/ex05_sessionrandomidcookie.php 180

Chapitre 9 : Sessions 2 /** Fonction qui retourne un message de bienvenue dans l a langue c h o i s i e */ 3 f u n c t i o n getgreeting ($PREF_LANG) { 4 $htmlgreeting = ; 5 switch ($PREF_LANG) { 6 case en : $htmlgreeting.= Hi, guys, Welcome to <code>mysite. com</ code>&nbsp ;! ; 7 break ; 8 case f r : $htmlgreeting.= Salut l a compagnie, bienvenue sur <code> monsite. f r </code>&nbsp ;! ; 9 break ; 10 11 d e f a u l t : $htmlgreeting.= Wilkommen, Bienvenue, Welcomme!<br/> ; 12 break ; 13 } 14 return $htmlgreeting ; 15 } 16 17 $dataerror = array ( ) ; 18 // 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 et s i l a donnée a l a bonne forme 19 // (10 c h i f f r e s hexa e n t r e 0 et f ) 20 i f ( i s s e t ($_COOKIE[ s e s s i o n id ] ) && preg_match ( /^[0 9a fa F]{10} $/, $_COOKIE[ s e s s i o n id ] ) ) { 21 // On a bien v é r i f i é l a forme par e x p r e s s i o n r é g u l i è r e donc, pas d autre précaution 22 $mysid = $_COOKIE[ s e s s i o n id ] ; 23 } e l s e { 24 i f ( i s s e t ($_COOKIE[ s e s s i o n id ] ) ) { 25 $dataerror [ s e s s i o n id ] = I d e n t i f i a n t de s e s s i o n i n c o r r e c t. P i r a t e s s a b s t e n i r... ; 26 } 27 // Génération d un SID par des o c t e t s ( pseudo ) a l é a t o i r e s codés en hexa 28 $cryptostrong = f a l s e ; // Variable pour passage par r é f é r e n c e 29 $ o c t e t s = openssl_random_pseudo_bytes ( 5, $cryptostrong ) ; 30 $mysid = bin2hex ( $ o c t e t s ) ; 31 } 32 s e s s i o n _ i d ( $mysid ) ; 33 // Création ( ou mise à j o u r ) du c o o k i e. Nouvelle v a l i d i t é du c o o k i e : 10 j o u r s 34 s e t c o o k i e ( s e s s i o n id, $mysid, time ( ) +60*60*24*10) ; 35 36 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 37 s e s s i o n _ s t a r t ( ) ; 38 39 // I n i t i a l i s a t i o n des paramètres régionaux 40 41 // Si un choix de langage e s t p r é 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 s e s s i o n 42 i f ( i s s e t ($_GET[ pref_lang ] ) ) { 43 i f ($_GET[ pref_lang ] == en $_GET[ pref_lang ] == f r ) { 44 // Les données e n t r é e s en s e s s i o n doivent ê t r e f i l t r é e s, 45 // même s i, dans ce cas, i l n y a pas de danger car on a t e s t é avec == 46 $_SESSION [ preferred_language ] = h t m l e n t i t i e s ($_GET[ pref_lang ], ENT_QUOTES, UTF 8 ) ; 47 } e l s e { 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 cas où 181

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 49 unset ($_SESSION [ preferred_language ] ) ; 50 } 51 } 52 // Si une p r é f é r e n c e de langage a é t é d é f i n i e, s o i r dans l URL, s o i t en s e s s i o n 53 i f ( i s s e t ($_SESSION [ preferred_language ] ) ) { 54 $PREFERRED_LANG = $_SESSION [ preferred_language ] ; 55 } e l s e { 56 $PREFERRED_LANG = undef ; 57 } 58 59 // Flush des Données de Session, ( sauvegarde simmédiate sur l e disque ) 60 s e s s i o n _ w r i t e _ c l o s e ( ) ; 61 62 require_once (. / commonfunctions. php ) ; 63 i f ( empty ( $dataerror ) ) { // Code de l a vue normale 64 outputentetehtml5 ( S e s s i o n avec SID A l é a t o i r e, UTF 8, mystyle. css ) ; 65 echo <h1>s e s s i o n avec <i >SID</i > A l é a t o i r e <br/>transmis par <code>cookie</ code ></h1> ; 66 echo <p> ; 67 // Message de bienvenue dans l a langue 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 68 echo getgreeting ($PREFERRED_LANG). <br/> ; 69 echo <a h r e f=\.$_server[ SCRIPT_NAME ].?pref_lang=f r \ >Français </a> ou 70. <a h r e f=\.$_server[ SCRIPT_NAME ].?pref_lang=en\ >English </a> ; 71 echo </p> ; 72 outputfinfichierhtml5 ( ) ; 73 } e l s e { // Appel de l a vue d e r r e u r : 74 r e q u i r e ( ex04_vueerreur. php ) ; 75 } 76?> 9.8 Exemple Politique de Sécurité en Matière de Session Nous voyons maintenant un exemple d utilisation d une session et de cookie un peu mieux sécurisé. Il s agit d un exemple à vocation pédagogique. L auteur décline toute responsabilité en cas d utilisation, telle quelle ou avec adaptation, de cette politique de sécurité. This example is to be taken on an as is basis. We accept no liability for consequences of direct or indirect use of this security policy whatsoever. Le numéro de session (SID) est composé de deux parties concaténées : Une première partie aléatoire ; Une deuxième partie codant l adresse IP du client, ou un hash de celle-ci composé de caractères valides pour un numéro de session. Seule la première partie est envoyée chez le client via un cookie. De plus, le cookie et la session ont une durée de validité de 2mn, temps laissé au client pour charger le script suivant. 182

Chapitre 9 : Sessions Lors du chargement du script suivant, la première partie (aléatoire) est récupérée via le cookie. La deuxième partie est calculée par l adresse IP du client. Si les adresses IP ne correspondent pas, la probabilité pour qu on charge par hasard la session, conduisant à une usurpation d identité involontaire, est très faible. Enfin, à chaque chargement de script, on change la partie aléatoire du SID, en copiant les données de session dans une nouvelle, et on re-génère le cookie. exemples/sessions/ex07_authentification.php 1 <?php 2 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 3 require_once ( dirname ( FILE ). / ex06_formpasswdutils. php ) ; 4 outputentetehtml5 ( Login Form, UTF 8, mystyle. css ) ; 5 echo <h1>page d A u t h e n t i f i c a t i o n </h1> ; 6 echo gethtml_loginform ( ) ; 7 outputfinfichierhtml5 ( ) ; 8?> Si le mot de passe est trop simple, on appelle une vue d erreur qui demande un nouveau mot de passe : exemples/sessions/ex07_receivepassword.php 1 <?php 2 require_once ( dirname ( FILE ). / ex06_formpasswdutils. php ) ; 3 4 $wouldbepasswd = $_POST[ motdepasse ] ; 5 6 // Test sur l a forme des données de l o g i n et mot de passe : 7 i f ( empty ( $wouldbepasswd )! isstrongpassword ( $wouldbepasswd ) 183

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 8! f i l t e r _ v a r ($_POST[ email ], FILTER_VALIDATE_EMAIL) ) { 9 // Échec de l a u t h e n t i f i c a t i o n : l e s données n ont même pas l a même forme. 10 // S o r t i e du code HTML ( s a i s i e des i d e n t i f i a n t s ) 11 $dataerror [ l o g i n ] = Erreur : l e l o g i n e s t i n c c o r e c t ou mot de passe trop simple ; 12 } e l s e { // l e s données d a u t h e n t i f i c a t i o n ont l a bonne forme. 13 // On v é r i f i e que l e mot de passe ( après hashage SHA512) 14 // e s t bien c e l u i en base de donnée. 15 i f (! userpasswordcheckindatabase ($_POST[ email ], hash ( sha512, $wouldbepasswd ) ) ) { 16 // S o r t i e du code HTML ( s a i s i e des i d e n t i f i a n t s ) 17 $dataerror [ l o g i n ] = Erreur : l o g i n ou mot de passe i n c o r r e c t ; 18 } e l s e { 19 // Le numéro de s e s s i o n c o n t i e n t l i n f o r m a t i o n de l a d r e s s e IP 20 // Quelqu un avec une autre a d r e s s e IP ne pourra pas accéder à c e t t e s e s s i o n 21 // suivant notre implémentation ( s a u f à g é n é r e r une c o l i s i o n sur md5 ( Hahaha! ) 22 $mysid = generatesessionidandcookie ($_SERVER[ REMOTE_ADDR ], $mysid_part1 ) ; 23 s e s s i o n _ i d ( $mysid ) ; 24 // Création du c o o k i e avec l a p a r t i e a l é a t o i r e du SID. Nouvelle v a l i d i t é du c o o k i e : 2mn 25 // Un p i r a t e aura besoin de temps pour v o l e r l e c o o k i e. Ça l u i complique l a v i e... 26 s e t c o o k i e ( s e s s i o n id part1, $mysid_part1, time ( ) +60*2) ; 27 28 // L u t i l i s a t e u r v i e n t de s i d e n t i f i e r. Dans l e cas improbable d une c o l l i s i o n sur l e SID, 29 // Mais s u r t o u t d une usurpation d i d e n t i t é, on d é t r u i t l a s e s s i o n 30 // avant de redémarer une s e s s i o n vide 31 s e s s i o n _ s t a r t ( ) ; 32 s e s s i o n _ d e s t r o y ( ) ; 33 // On f i x e à 2mn l a durée de p e r s i s t a n c e de l a s e s s i o n sur l e s e r v e u r 34 // à p a r t i r de chaque connexion. Cela l i m i t e l e temps pour un hackeur 35 // pour deviner l e numéro de s e s s i o n... 36 session_cache_expire ( 2 ) ; 37 s e s s i o n _ i d ( $mysid ) ; 38 // Démarrage de l a s e s s i o n 39 s e s s i o n _ s t a r t ( ) ; 40 // 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 mail.... 184

Chapitre 9 : Sessions 41 $_SESSION [ email ] = h t m l e n t i t i e s ($_POST[ email ], ENT_QUOTES, UTF 8 ) ; 42 $_SESSION [ ip_ address ] = $_SERVER[ REMOTE_ADDR ] ; 43 // Flush des Données de Session, ( sauvegarde simmédiate ur l e disque ) 44 s e s s i o n _ w r i t e _ c l o s e ( ) ; 45 } 46 } 47 48 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 49 i f ( empty ( $dataerror ) ) { // Code de l a vue normale : 50 outputentetehtml5 ( Welcome Page, UTF 8, mystyle. css ) ; 51 echo <h1>p e r s i s t e n c e d une connexion<br/>exemple de p o l i t i q u e de s é c u r i t é </h1> ; 52 echo Bienvenue! Vous ê t e s convenablement a u t h e n t i f i é.<br/> ; 53 echo Pour accéder encore à des données s e n s i b l e s, 54. <a h r e f=\. / ex08_sessiontestip_randomidcookie. php\ >c l i q u e z i c i </a>. ; 55 outputfinfichierhtml5 ( ) ; 56 } e l s e { // Appel de l a vue d e r r e u r : 57 r e q u i r e ( ex07_vueerreur. php ) ; 58 } 59?> exemples/sessions/ex06_formpasswdutils.php 1 <?php 2 /** Fonction qui t e s t e s i un mot de passe e s t suffisemment d i f f i c i l e */ 3 f u n c t i o n isstrongpassword ( $wouldbepasswd ) { 4 $lengthcondition = ( s t r l e n ( $wouldbepasswd ) >= 8 && s t r l e n ( $wouldbepasswd ) <= 35) ; 5 // On peut sûrement f a i r e plus e f f i c a c e pour l é v a l u a t i o n des e x p r e s s i o n s r é g u l i è r e s... 6 $CharacterDiversityCondition = preg_match ( / [ a z ] /, $wouldbepasswd ) 7 && preg_match ( / [A Z ] /, $wouldbepasswd ) 8 && preg_match ( /[0 9]/, $wouldbepasswd ) 9 && preg_match ( /[\#\ \ \.\@\[\]\=\!\&]/, $wouldbepasswd ) ; 10 return $lengthcondition && $CharacterDiversityCondition ; 11 } 12 13 /** Fonction qui retourne l e code HTML d un f o r m u l a i r e de l o g i n */ 14 f u n c t i o n gethtml_loginform ( ) { 15 $htmlcode = ; 16 // Test de connexion SSL et l e cas échéant, warning. 17 i f (! i s s e t ($_SERVER[ HTTPS ] ) $_SERVER[ HTTPS ] == o f f ) { 18 $htmlcode.= <p><strong >Warning :</strong > Vous n ê t e s pas sur une connexion s é c u r i s é e <i >HTTPS</i > avec <i >SSL</i >.<br/> 19. Votre c o n f i d e n t i a l i t é n e s t pas g a r a n t i e!!! </p> ; 20 } 21 // Code du f o r m u l a i r e : 22 $htmlcode.= <form method= POST action=. / ex07_receivepassword. php > ; 23 $htmlcode.= <p><label for= e mail >e mail</ label><input type= email name= email size= 25 /></p> ; 24 $htmlcode.= <p><label for= motdepasse >Mot de passe</ label><input type= password name= motdepasse size= 25 /></p> ; 25 $htmlcode.= <input class= sanslabel value= Envoyer type= submit /> ; 26 $htmlcode.= </form> ; 27 $htmlcode.= <p>l a d r e s s e <i >e mail </i > d o i t ê t r e v a l i d e et 185

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 28. votre mot de passe d o i t c o n t e n i r au moins 8 c a r a c t è r e s, une minuscule, une majuscule, un c h i f f r e, 29. et un c a r a c t è r e parmis. h t m l e n t i t i e s ( #.@[]=!&, ENT_QUOTES, UTF 8 )., merci de votre compréhension... < / p> ; 30 return $htmlcode ; 31 } 32 33 // f o n c t i o n de g é n é r a t i o n de l ID de s e s s i o n avec 34 // p a r t i e a l é a t o i r e et p a r t i e c o n t r ô l e par a d r e s s e IP 35 f u n c t i o n generatesessionidandcookie ( $ipaddress, &$mysid_part1 ) { 36 // Génération de 5 o c t e t s ( pseudo ) a l é a t o i r e s codés en hexa 37 $cryptostrong = f a l s e ; // Variable pour passage par r é f é r e n c e 38 $ o c t e t s = openssl_random_pseudo_bytes ( 5, $cryptostrong ) ; 39 $mysid_part1 = bin2hex ( $ o c t e t s ) ; 40 41 // On applique un hash sur l a d r e s s e IP pour é v i t e r l usurpation d i d e n t i t é 42 // Un p i r a t e aura besoin de temps pour d e v i n e r l IP et l usurper, 43 // en devinant a u s s i l a p a r t i e a l é a t o i r e du SID, s u r t o u t avec une connexion SSL... 44 $mysid_part2 = hash ( md5, $ipaddress ) ; 45 // Le numéro de s e s s i o n c o n t i e n t l i n f o r m a t i o n de l a d r e s s e IP 46 // Quelqu un avec une autre a d r e s s e IP ne pourra pas accéder à c e t t e s e s s i o n 47 // suivant notre implémentation ( s a u f à g é n é r e r une c o l i s i o n sur md5 ( Hahaha! ) 48 $mysid = $mysid_part1. $mysid_part2 ; 49 return $mysid ; 50 } 51 52 // Fonction à implémenter : t e s t d e x i s t a n c e du l o g i n /mot de passe en BD 53 f u n c t i o n userpasswordcheckindatabase ( $email, $hashedpassword ) { 54 // TODO : t e s t e r s i l e couple e mail et mot de passe ( après hashage SHA512) 55 // sont bien p r é s e n t s dans l a base de données 56 return true ; 57 } 58?> Si tout se passe bien, on reconstitue bien l ID de session avec contrôle d adresse IP, et on reconnaît l identificateur comme préalablement identifié. exemples/sessions/ex07_receivepassword.php 186

Chapitre 9 : Sessions 1 <?php 2 require_once ( dirname ( FILE ). / ex06_formpasswdutils. php ) ; 3 4 $wouldbepasswd = $_POST[ motdepasse ] ; 5 6 // Test sur l a forme des données de l o g i n et mot de passe : 7 i f ( empty ( $wouldbepasswd )! isstrongpassword ( $wouldbepasswd ) 8! f i l t e r _ v a r ($_POST[ email ], FILTER_VALIDATE_EMAIL) ) { 9 // Échec de l a u t h e n t i f i c a t i o n : l e s données n ont même pas l a même forme. 10 // S o r t i e du code HTML ( s a i s i e des i d e n t i f i a n t s ) 11 $dataerror [ l o g i n ] = Erreur : l e l o g i n e s t i n c c o r e c t ou mot de passe trop simple ; 12 } e l s e { // l e s données d a u t h e n t i f i c a t i o n ont l a bonne forme. 13 // On v é r i f i e que l e mot de passe ( après hashage SHA512) 14 // e s t bien c e l u i en base de donnée. 15 i f (! userpasswordcheckindatabase ($_POST[ email ], hash ( sha512, $wouldbepasswd ) ) ) { 16 // S o r t i e du code HTML ( s a i s i e des i d e n t i f i a n t s ) 17 $dataerror [ l o g i n ] = Erreur : l o g i n ou mot de passe i n c o r r e c t ; 18 } e l s e { 19 // Le numéro de s e s s i o n c o n t i e n t l i n f o r m a t i o n de l a d r e s s e IP 20 // Quelqu un avec une autre a d r e s s e IP ne pourra pas accéder à c e t t e s e s s i o n 21 // suivant notre implémentation ( s a u f à g é n é r e r une c o l i s i o n sur md5 ( Hahaha! ) 22 $mysid = generatesessionidandcookie ($_SERVER[ REMOTE_ADDR ], $mysid_part1 ) ; 23 s e s s i o n _ i d ( $mysid ) ; 24 // Création du c o o k i e avec l a p a r t i e a l é a t o i r e du SID. Nouvelle v a l i d i t é du c o o k i e : 2mn 25 // Un p i r a t e aura besoin de temps pour v o l e r l e c o o k i e. Ça l u i complique l a v i e... 26 s e t c o o k i e ( s e s s i o n id part1, $mysid_part1, time ( ) +60*2) ; 27 28 // L u t i l i s a t e u r v i e n t de s i d e n t i f i e r. Dans l e cas improbable d une c o l l i s i o n sur l e SID, 29 // Mais s u r t o u t d une usurpation d i d e n t i t é, on d é t r u i t l a s e s s i o n 30 // avant de redémarer une s e s s i o n vide 31 s e s s i o n _ s t a r t ( ) ; 32 s e s s i o n _ d e s t r o y ( ) ; 33 // On f i x e à 2mn l a durée de p e r s i s t a n c e de l a s e s s i o n sur l e s e r v e u r 34 // à p a r t i r de chaque connexion. Cela l i m i t e l e temps pour un hackeur 35 // pour deviner l e numéro de s e s s i o n... 36 session_cache_expire ( 2 ) ; 37 s e s s i o n _ i d ( $mysid ) ; 38 // Démarrage de l a s e s s i o n 39 s e s s i o n _ s t a r t ( ) ; 40 // 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 mail.... 41 $_SESSION [ email ] = h t m l e n t i t i e s ($_POST[ email ], ENT_QUOTES, UTF 8 ) ; 42 $_SESSION [ ip_ address ] = $_SERVER[ REMOTE_ADDR ] ; 43 // Flush des Données de Session, ( sauvegarde simmédiate ur l e disque ) 44 s e s s i o n _ w r i t e _ c l o s e ( ) ; 45 } 46 } 47 48 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 187

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 49 i f ( empty ( $dataerror ) ) { // Code de l a vue normale : 50 outputentetehtml5 ( Welcome Page, UTF 8, mystyle. css ) ; 51 echo <h1>p e r s i s t e n c e d une connexion<br/>exemple de p o l i t i q u e de s é c u r i t é </h1> ; 52 echo Bienvenue! Vous ê t e s convenablement a u t h e n t i f i é.<br/> ; 53 echo Pour accéder encore à des données s e n s i b l e s, 54. <a h r e f=\. / ex08_sessiontestip_randomidcookie. php\ >c l i q u e z i c i </a>. ; 55 outputfinfichierhtml5 ( ) ; 56 } e l s e { // Appel de l a vue d e r r e u r : 57 r e q u i r e ( ex07_vueerreur. php ) ; 58 } 59?> Lorsque l utilisateur poursuit la navigation, il reste reconnu et peut accéder à ses données personnelles : exemples/sessions/ex08_sessiontestip_randomidcookie.php 1 <?php 2 require_once ( dirname ( FILE ). / ex06_formpasswdutils. php ) ; 3 4 $dataerror = array ( ) ; 5 // 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 et s i l a donnée a l a bonne forme 6 // (10 c h i f f r e s hexa e n t r e 0 et f ) 7 i f (! i s s e t ($_COOKIE[ s e s s i o n id part1 ] ) 8! preg_match ( /^[0 9a fa F]{10} $/, $_COOKIE[ s e s s i o n id part1 ] ) ) { 9 $dataerror [ no cookie ] = Votre c o o k i e a peut ê t r e expirée, 10. Merci de vous connecter à nouveau... ; 11 } e l s e { 12 // On a bien v é r i f i é l a forme par e x p r e s s i o n r é g u l i è r e donc, pas d autre précaution 13 $mysid_part1 = $_COOKIE[ s e s s i o n id part1 ] ; 188

Chapitre 9 : Sessions 14 // On applique l e même hash sur l a d r e s s e IP que l o r s de l a c r é a t i o n i n i t i a l e de l a s e s s i o n 15 // pour r e t r o u v e r notre numéro de s e s s i o n i n i t i a l. 16 $mysid_part2 = hash ( md5, $_SERVER[ REMOTE_ADDR ] ) ; 17 // On r e c o n s t i t u e l e SID complet : 18 $mysid = $mysid_part1. $mysid_part2 ; 19 // On r écupère l e s données de s e s s i o n : 20 s e s s i o n _ i d ( $mysid ) ; 21 // Le démarage de s e s s i o n d o i t a v o i r l i e u avant toute s o r t i e de code HTML via echo, print, e t c. 22 s e s s i o n _ s t a r t ( ) ; 23 // Prolongement de l a v a l i d i t é du c o o k i e. Nouvelle v a l i d i t é du c o o k i e : 2mn 24 s e t c o o k i e ( s e s s i o n id part1, $mysid_part1, time ( ) +60*2) ; 25 i f ( empty ($_SESSION [ email ] ) ) { 26 $dataerror [ no s e s s i o n ] = Votre s e s s i o n a peut ê t r e expirée, 27. Merci de vous connecter à nouveau... ; 28 s e s s i o n _ d e s t r o y ( ) ; 29 } e l s e { 30 // Raffinement : on change l a p a r t i e a l é a t o i r e du SID, en copiant 31 // l a s e s s i o n dans une n o u v e l l e. On r e g é n è r e e n s u i t e l e c o o k i e 32 // 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, et l ID de s e s s i o n a u s s i 33 // ce qui 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 hacker 34 $backupsession_ Email = $_SESSION [ email ] ; 35 // On d é t r u i t l ancienne s e s s i o n 36 s e s s i o n _ d e s t r o y ( ) ; 37 $mysid = generatesessionidandcookie ($_SERVER[ REMOTE_ADDR ], $mysid_part1 ) ; 38 s e s s i o n _ i d ( $mysid ) ; 39 // Création du c o o k i e avec l a p a r t i e a l é a t o i r e du SID. V a l i d i t é du c o o k i e : 2mn 40 // Un p i r a t e aura besoin de temps pour v o l e r l e c o o k i e. Ça l u i complique l a v i e... 41 // D autant qu on c r é e un c o o k i e tout neuf à chaque chargement de script... 42 s e t c o o k i e ( s e s s i o n id part1, $mysid_part1, time ( ) +60*2) ; 43 s e s s i o n _ s t a r t ( ) ; 44 $_SESSION [ email ] = $backupsession_ Email ; 45 // Flush des Données de Session, ( sauvegarde simmédiate ur l e disque ) 46 s e s s i o n _ w r i t e _ c l o s e ( ) ; 47 } 48 } 49 50 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 51 i f ( empty ( $dataerror ) ) { // Code de l a vue normale 52 outputentetehtml5 ( Consultation des Données P e r s o n n e l l e s, UTF 8, mystyle. css ) ; 53 echo <h1>consultation des Données P e r s o n n e l l e s </h1> ; 54 echo <p> ; 55 echo Ne l e d i t e à personne : l e <i >SID</i > e s t : <br/>. $mysid ; 56 echo </p><p> ; 57 echo Votre a d r e s s e e mail e s t :. $_SESSION [ email ]. <br/> ; 58 echo Grâce à votre a d r e s s e e mail, l e s e r v e u r peur r e t r o u v e r vos données p e r s o n n e l l e s <br/> ; 59 echo et vous l e s a f f i c h e r. Et d a i l l e u r s, l e s v o i c i... < br/> ; 60 echo Pour accéder encore à des données s e n s i b l e s, 61. <a h r e f=\. / ex08_sessiontestip_randomidcookie. php\ >c l i q u e z i c i </a>. 189

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web ; 62 echo </p> ; 63 outputfinfichierhtml5 ( ) ; 64 } e l s e { // Appel de l a vue d e r r e u r : 65 r e q u i r e ( ex07_vueerreur. php ) ; 66 } 67?> Figure 9.4 : Re-chargement du script. La connexion persiste, mais le SID a changé. Figure 9.5 : Re-chargement du script. Expiration du cookie. 190

Chapitre 10 Bases de Données et PHP Data Objects 10.1 Créer un Base de Données dans phpmyadmin 10.1.1 Création d une Base de Données Relationnelle Figure 10.1 : Création d une nouvelle base de données Figure 10.2 : Création d une nouvelle table 191

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web Figure 10.3 : Exemple de base de données avec deux tables Figure 10.4 : Vue Relationnelle de base de données avec deux tables 10.1.2 Créer un Utilisateur MySql Responsable d une BD Pour éviter qu un éventuel piratage de la configuration de l authentification pour l accès aux bases de données, qui se trouve en clair dans les sources PHP, ne donnée accès à toutes les bases de données, nous pratiquons des droits étanches entre nos différentes bases de données. Dans notre cas, l utilisateur remy aura les droits uniquement sur la base ExampleDataBase. Figure 10.5 : Ajout d un Utilisateur MySQL 192

Chapitre 10 : Bases de Données et PHP Data Objects Figure 10.6 : Accès de l Utilisateur MySQL Uniquement sur le Serveur Local Figure 10.7 : Ajout de Privilèges Spécifiques d un Utilisateur sur une Base de Données 193

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web Figure 10.8 : Exemple : Donner tous les Droits à l Utilisateur sur une Base 194

Chapitre 10 : Bases de Données et PHP Data Objects 10.2 Initiation à PDO : connexion, query, destruction L extension du langage PHP appelée PHP Data Objects fournit une couche d abstraction pour accéder à des données, à l aide de différents drivers. Comme exemples de drivers, on peut citer MySQL, Oracle, SQLite, PostgreSQL, MS SQL Sever, etc. L intérêt de PDO est de permettre d utiliser tous ces drivers, qui accèdent à des bases de données différentes, avec les mêmes fonction : les méthodes de PDO. 10.2.1 Établir la Connexion à une Base de Données La connexion à la base de données se fait avec le nom du driver (ici mysql), le nom d hôte, le nom de la base de données, le nom d utilisateur ayant les droits sur la base de données, et son mot de passe. Une éventuelle exception issue du constructeur de PDO doit absolument être gérée avec try...catch (ou avec un handler), car sinon le message de l exception s affiche, révélant le nom et le mot de passe de l utilisateur ayant les droits sur la base. exemples/pdo/ex01_connexionpdo.php 1 <?php 2 $mysqluser = remy ; 3 $mysqlpassword = my_password ; 4 $database = ExampleDataBase ; 5 6 $dataerror = array ( ) ; 7 8 // ON DOIT ABSOLUMENT GÉRER CETTE EXCEPTION, FAUTE DE QUOI 9 // L UTILISATEUR DE LA BASE DE DONNÉES ET LE MOT DE PASSE 10 // APPARAÎSSENT EN CLAIR!!!! 11 try { 12 // Création de l i n s t a n c e de PDO ( database handler ). 13 $dbh = new PDO( mysql :host=l o c a l h o s t ; dbname=. $database, $mysqluser, $mysqlpassword ) ; 14 } catch ( PDOException $e ) { 15 $dataerror [ connection ] = Erreur de connexion à l a base de données. 16. Vous n avez pas besoin d en s a v o i r plus... ; 17 r e q u i r e ( vueerreur. php ) ; 18 d i e ( ) ; 19 } 20 // Requête : chaîne de c a r a c t è r e s contenant une r e q u ê t e v a l i d e en SQL 21 $requete = INSERT INTO Adresse ( id, numerorue, rue, complementadresse, codepostal, v i l l e, pays ) 195

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 22. VALUES ( 123456 abea, 11, A l l é e des Pies Jaunes, Bâtiment 2D, 63000, Clermont Ferrand, France ) ; 23 24 // Exécution de l a r equête et mémorisation du r é s u l t a t : 25 $ r e s u l t E x e c = $dbh >exec ( $requete ) ; 26 27 i f ( $ r e s u l t E x e c === f a l s e ) { 28 $dataerror [ r equete ] = Problème d e x é c u t i o n de l a r e q u ê t e. 29. ( par exemple, une l i g n e avec c e t t e c l é p r i m a i r e e x i s t e déjà, 30. ou encore l a requête n e s t pas une r e q u ê t e v a l i d e sur l a base en q u e s t i o n... ) ; 31 r e q u i r e ( vueerreur. php ) ; 32 d i e ( ) ; 33 } 34 35 // $ r e s u l t E x e c d o i t donner l e nombre de l i g n e s a f f e c t é e s ( i n s é r é e s en l occurence ) 36 i f ( $ r e s u l t E x e c === 0) { 37 $dataerror [ r equete ] = Problème d e x é c u t i o n de l a requête, Aucune l i g n e n a é t é a f f e c t é e par l a r equête. ; 38 r e q u i r e ( vueerreur. php ) ; 39 d i e ( ) ; 40 } 41 42 // Fermeture de l a connexion ( connexion non p e r s i s t a n t e ) 43 $ r e s u l t E x e c = n u l l ; 44 $dbh = n u l l ; 45 46 // Code de l a vue : 47 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 48 outputentetehtml5 ( Ma Première Connexion PDO, UTF 8, mystyle. css ) ; 49 echo <h1>i n i t i e r une Connexion <i >PDO</i ></h1> ; 50 echo La requête a bien é t é exécutée... ; 51 outputfinfichierhtml5 ( ) ; 52?> exemples/pdo/ex01_vueerreur.php 1 <?php 2 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 3 outputentetehtml5 ( Erreur BD, UTF 8, mystyle. css ) ; 4 echo <h1>une e r r e u r s e s t produite </h1> ; 5 f o r e a c h ( $dataerror as $errormsg ) { 196

Chapitre 10 : Bases de Données et PHP Data Objects 6 echo <p>. $errormsg. </p> ; 7 } 8 outputfinfichierhtml5 ( ) ; 9?> Figure 10.9 : 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. exemples/pdo/ex02_withnotrycatchleakproblem.php 1 <?php 2 $mysqluser = remy ; 3 $mysqlpassword = my_password ; 4 $database = ExampleMisSpelledDataBase ; 197

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 5 6 $dbh = new PDO( mysql :host=l o c a l h o s t ; dbname=. $database, $mysqluser, $mysqlpassword ) ; 7 8 $requete = INSERT INTO Adresse ( id, numerorue, rue, complementadresse, codepostal, v i l l e, pays ) 9. VALUES ( 0 fda5a80a, 11, A l l é e des Pies Jaunes, Bâtiment 2D, 63000, Clermont Ferrand, France ) ; 10 $dbh >query ( $requete ) ; 11 12 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 13 outputentetehtml5 ( Ma Première Connexion PDO, UTF 8, mystyle. css ) ; 14 // Code de l a vue : 15 f o r e a c h ( $dbh >query ( SELECT * from Adresse ) as $row ) { 16 print_r ( $row ) ; 17 } 18 $dbh = n u l l ; 19 outputfinfichierhtml5 ( ) ; 20?> 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 : exemples/pdo/ex03_connecttodatabasepdo.php 1 <?php 2 $mysqluser = remy ; 3 $mysqlpassword = my_password ; 4 $database = ExampleDataBase ; 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éation de l i n s t a n c e de PDO ( database handler ). 11 $dbh = new PDO( mysql :host=l o c a l h o s t ; dbname=. $database, $mysqluser, $mysqlpassword ) ; 12 } catch ( PDOException $e ) { 13 $dataerror [ connexion bd ] = Erreur de connexion à l a base de données. 14. Vous n avez pas besoin d en s a v o i r plus... ; 15 r e q u i r e ( vueerreur. php ) ; 16 d i e ( ) ; 17 } 18?> 10.2.2 Parcourir les Résultats d une Requête Voici un exemple qui récupère les lignes des résultats d une requête (de type SELECT) sous une forme associative. Les clés du tableau associatif, pour chaque ligne, sont les noms de colonnes du résultat de la requête. exemples/pdo/ex03_queryforeachmodeassoc.php 1 <?php 2 // Connexion à l a base de données : 3 require_once ( dirname ( FILE ). / ex03_connecttodatabasepdo. php ) ; 198

Chapitre 10 : Bases de Données et PHP Data Objects 4 5 // Stockage des données 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 type PDOStatement 7 $statement = $dbh >query ( SELECT * from Adresse ) ; 8 // On veut r é c u p é r e r l e s l i g n e s comme des tableaux A s s o c i a t i f s 9 $statement >setfetchmode (PDO : :FETCH_ASSOC) ; 10 11 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 12 outputentetehtml5 ( P a r c o u r i r l e s R é s u l t a t s d une Requête, UTF 8, mystyle. css ) ; 13 14 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ête</h1> ; 15 16 echo <p>le r é s u l t a t de l a r equête possède. $statement >columncount ( ). colonnes.</p> ; 17 18 echo <p> ; 19 echo <strong >U t i l i s a t i o n comme tableau a s s o c i a t i f :</strong > ; 20 echo </p> ; 21 f o r e a c h ( $statement as $row ) { 22 echo <p> ; 23 echo $row [ numerorue ].,. $row [ rue ]., ; 24 i f (! empty ( $row [ complementadresse ] ) ) 25 echo $row [ complementadresse ]., ; 26 echo $row [ codepostal ]. ; 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 connexion 33 // i l f a u t d é t r u i r e tous l e s o b j e c t s l i é s à l a connexion SANS EN OUBLIER 34 // ( en l e s mettant à null, pour que l a connexion se ferme ). 35 $statement = n u l l ; 36 $dbh = n u l l ; 37 199

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 38 outputfinfichierhtml5 ( ) ; 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). exemples/pdo/ex04_fetchall_fetchmodeboth.php 1 <?php 2 // Connexion à l a base de données : 3 require_once ( dirname ( FILE ). / ex03_connecttodatabasepdo. php ) ; 4 5 // Stockage des données 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 type PDOStatement 7 $statement = $dbh >query ( SELECT * from Adresse ) ; 8 i f ( $statement === f a l s e ) { 9 $dataerror [ query ] = Problème d e x é c u t i o n de l a r e q u ê t e. 10. ( par exemple, l a connexion n e s t pas ouverte ou l a t a b l e n e x i s t e pas... ) ; 11 d i e ( ) ; 12 } 13 14 $statement >setfetchmode (PDO : :FETCH_BOTH) ; 15 16 // Pour pouvoir 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 tableau. 18 // Ça peut 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... 200

Chapitre 10 : Bases de Données et PHP Data Objects 19 $ t a b R e s u l t a t s = $statement >f e t c h A l l ( ) ; 20 21 // Code de l a vue : 22 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 23 outputentetehtml5 ( P a r c o u r i r l e s R é s u l t a t s d une Requête, UTF 8, mystyle. css ) ; 24 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ête ( 2 )</h1> ; 25 echo <p> ; 26 echo <strong >A f f i c h a g e brut de chaque l i g n e </strong > ; 27 echo </p> ; 28 29 f o r e a c h ( $ t a b R e s u l t a t s as $row ) { 30 echo <p> ; 31 print_r ( $row ). <br/><br/> ; 32 echo </p> ; 33 } 34 35 echo <p> ; 36 echo <strong >U t i l i s a t i o n comme tableau a s s o c i a t i f :</strong > ; 37 echo </p> ; 38 f o r e a c h ( $ t a b R e s u l t a t s as $row ) { 39 echo <p> ; 40 echo $row [ numerorue ].,. $row [ rue ]., ; 41 i f (! empty ( $row [ complementadresse ] ) ) 42 echo $row [ complementadresse ]., ; 43 echo $row [ codepostal ]. ; 44 echo $row [ v i l l e ]. ; 45 echo $row [ pays ] ; 46 echo </p> ; 47 } 48 echo </p> ; 49 50 echo <p> ; 51 echo <strong >U t i l i s a t i o n comme tableau numérique :</strong > ; 52 echo </p> ; 53 f o r e a c h ( $ t a b R e s u l t a t s as $row ) { 54 echo <p>( ; 55 f o r ( $ i = 1 ; $ i < $statement >columncount ( ) ; $ i++){ 56 i f ( $i >1){ 57 echo, ; 58 } 59 echo $row [ $ i ] ; 60 } 61 echo )</p> ; 62 } 63 outputfinfichierhtml5 ( ) ; 64 65 // Connexion non p e r s i s t a n t e : on ferme l a connexion 66 // i l f a u t d é t r u i r e tous l e s o b j e c t s l i é s à l a connexion SANS EN OUBLIER 67 // ( en l e s mettant à null, pour que l a connexion de ferme. 68 $statement = n u l l ; 69 $dbh = n u l l ; 70?> 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 201

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 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 ; 10.3 Requêtes Préparées L idée des requêtes préparées est la suivante : 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. 3. Avant d exécuter la requête préparée, ou au moment de l exécution de la requête préparée, on spécifie les valeurs (attributs des tables...) qui viennent remplace les? dans la 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. Nous en voyons une. Voyons déjà un exemple d insertion d une adresse dans une table. L adresse est saisie dans un formulaire : exemples/pdo/ex05_formadresse.php 1 <! doctype html> 2 <html lang= f r > 3 <head> 4 <meta charset= UTF 8 /> 5 <link rel= s t y l e s h e e t href=. / mystyle. c s s /> 6 <t i t l e>s a i s i e d une Adresse</ t i t l e> 7 </head> 8 <body> 9 <h1>s a i s i e d une a d r e s s e</h1> 10 <form method= post action= ex07_requetespreparees. php > 11 <p> 12 <label for= numerorue >Numéro</ label> 13 <input type= t e x t name= numerorue id= numerorue size= 4 /><br/> 14 </p> 15 <p> 16 <label for= rue >Place /Rue*</ label> 17 <input type= t e x t name= rue id= numerorue size= 30 /> 202

Chapitre 10 : Bases de Données et PHP Data Objects 18 </p> 19 20 <p> 21 <label for= complementadresse >Complément d a d r e s s e</ label> 22 <input type= t e x t name= complementadresse id= complementadresse s i z e= 30 /> <br/> 23 </p> 24 <p> 25 <label for= codepostal >Code p o s t a l *</ label> 26 <input type= t e x t name= codepostal id= codepostal size= 10 /><br/> 27 </p> 28 <p> 29 <label for= v i l l e >V i l l e *</ label> 30 <input type= t e x t name= v i l l e id= v i l l e size= 10 /><br/> 31 </p> 32 <p> 33 <input type= submit value= Envoyer class= sanslabel ></input> 34 </p> 35 </form> 36 </body> 37 </html> Les valeurs saisies par l utilsateur 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 : exemples/pdo/ex06_retrieveinputposts.php 1 <?php 2 $numerorue= ; 3 i f ( i s s e t ($_POST[ numerorue ] ) ) { 4 $numerorue = f i l t e r _ v a r ($_POST[ numerorue ], FILTER_SANITIZE_STRING) ; 5 } 6 7 $rue= ; 8 i f ( i s s e t ($_POST[ rue ] ) ) { 9 $rue = f i l t e r _ v a r ($_POST[ rue ], FILTER_SANITIZE_STRING) ; 10 } 11 12 $complementadresse= ; 13 i f ( i s s e t ($_POST[ complementadresse ] ) ) { 14 $complementadresse = f i l t e r _ v a r ($_POST[ complementadresse ], FILTER_SANITIZE_STRING) ; 15 } 16 $codepostal= ; 17 i f ( i s s e t ($_POST[ codepostal ] ) ) { 18 $codepostal = f i l t e r _ v a r ($_POST[ codepostal ], FILTER_SANITIZE_STRING) ; 19 } 20 $ v i l l e= ; 21 i f ( i s s e t ($_POST[ v i l l e ] ) ) { 22 $ v i l l e = f i l t e r _ v a r ($_POST[ v i l l e ], FILTER_SANITIZE_STRING) ; 23 } 24 $pays= France ; 25 i f ( i s s e t ($_POST[ pays ] ) && $_POST[ pays ]!= ) { 26 $pays = f i l t e r _ v a r ($_POST[ pays ], FILTER_SANITIZE_STRING) ; 27 } 28?> 203

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web Voici enfin l exemple qui effectue : 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 ; 3. Exécute la requête (en effectuant les tests d erreur). exemples/pdo/ex07_requetespreparees.php 1 <?php 2 // Connexion à l a base de données 3 require_once ( dirname ( FILE ). / ex03_connecttodatabasepdo. php ) ; 4 5 // Préparation de l a r equête ( chaîne r e p r é s e n t a n t une r e q u ê t e SQL 6 // s a u f que l e s v a l e u r s à i n s é r e r dont des?) 7 $statement = $dbh >prepare ( INSERT INTO Adresse ( id, numerorue, rue, complementadresse, codepostal, v i l l e, pays ) 8. VALUES (?,?,?,?,?,?,?) ) ; 9 10 // Test d e r r e u r en supposant l e mode de g e s t i o n des e r r e u r s PDO : : ERRMODE_SILENT 11 // ( sinon, avec l e mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r avec try... catch ) 12 i f ( $statement === f a l s e ) { 13 $dataerror [ preparation query ] = Problème l o r s de l a p r é p a r a t i o n de l a requête. 14. ( par exemple, l a syntaxe de l a r e q u ê t e e s t i n v a l i d e 15. pour l e d r i v e r u t i l i s é... ) ; 16 r e q u i r e ( vueerreur. php ) ; 17 d i e ( ) ; 18 } 19 20 // L i a i s o n de v a r i a b l e s avec l e s? de l a r e q u ê t e préparée : 21 // Le premier paramètre de bindparam e s t i c i l e numéro du? 22 // en commençant par 1. 23 // Lors de l e x é c u t i o n de l a requête, chaque? s e r a remplacé par 24 // l e contenu de l a v a r i a b l e correspondante. 25 $statement >bindparam ( 1, $id ) ; 26 $statement >bindparam ( 2, $numerorue ) ; 27 $statement >bindparam ( 3, $rue ) ; 28 $statement >bindparam ( 4, $complementadresse ) ; 29 $statement >bindparam ( 5, $codepostal ) ; 30 $statement >bindparam ( 6, $ v i l l e ) ; 31 $statement >bindparam ( 7, $pays ) ; 32 33 // Récupération des données du f o r m u l a i r e s et a f f e c t a t i o n des v a r i a b l e s 34 // $numerorue, $rue, $complementadresse, $codepostal, $ v i l l e, $pays 35 // à p a r t i r des données u t i l i s a t e u r ( tableau $_POST) 36 r e q u i r e ( dirname ( FILE ). / ex06_retrieveinputposts. php ) ; 37 38 // Génération d un $id d i f f i c i l e à d e v i n e r. 39 $id = hash ( sha512, $numerorue. $rue. $complementadresse. $codepostal. $ v i l l e. $pays ) ; 40 204

Chapitre 10 : Bases de Données et PHP Data Objects 41 // Exécution de l a r equête. ( Tous l e s? de l a r e q u ê t e ont é t é l i é s à des v a r i a b l e s ) 42 i f ( $statement >execute ( ) === f a l s e ) { 43 $dataerror [ execute query ] = Problème d e x é c u t i o n de l a r e q u ê t e. 44. ( par exemple, une l i g n e avec c e t t e c l é p r i m a i r e $id e x i s t e déjà... ) ; 45 r e q u i r e ( vueerreur. php ) ; 46 } e l s e { // Code de l a vue : 47 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 48 outputentetehtml5 ( Requêtes Préparées, UTF 8, mystyle. css ) ; 49 echo <h1>requêtes Préparées ( 1 )</h1> ; 50 echo <p>la r equête a é t é exécutée.</p> ; 51 outputfinfichierhtml5 ( ) ; 52 } 53 54 // Fermeture de l a connexion ( connexion non p e r s i s t a n t e ) 55 $statement = n u l l ; 56 $dbh = n u l l ; 57?> Voici un autre exemple de requête préparée avec une requête de type SELECT. exemples/pdo/ex08_requetesprepareesselect.php 1 <?php 2 // Connexion à l a base de données : 3 require_once ( dirname ( FILE ). / ex03_connecttodatabasepdo. php ) ; 4 5 // Préparation de l a r equête ( chaîne r e p r é s e n t a n t une r e q u ê t e SQL 6 // s a u f que l e s v a l e u r s à i n s é r e r dont des? 7 $statement = $dbh >prepare ( SELECT * FROM Adresse WHERE codepostal =? ) ; 8 9 // Test d e r r e u r en supposant l e mode de g e s t i o n des e r r e u r s PDO : : ERRMODE_SILENT 10 // ( sinon, avec l e mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r avec try... catch ) 11 i f ( $statement === f a l s e ) { 12 $dataerror [ preparation query ] = Problème l o r s de l a p r é p a r a t i o n de l a requête. 13. ( par exemple, l a syntaxe 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 r e q u i r e ( vueerreur. php ) ; 16 d i e ( ) ; 17 } 18 19 // L i a i s o n de l a v a r i a b l e $_GET[ codepostal ] avec l e? de l a r e q u ê t e préparée : 20 // Le premier paramètre de bindparam e s t i c i l e numéro du?, à s a v o i r 1 21 $statement >bindparam ( 1, $_GET[ codepostal ] ) ; 22 23 // Test d e r r e u r en supposant l e mode de g e s t i o n des e r r e u r s PDO : : ERRMODE_SILENT 24 // ( sinon, avec l e mode PDO : :ERRMODE_EXCEPTION i l f a u d r a i t u t i l i s e r avec try... catch ) 25 i f ( $statement >execute ( )!== f a l s e ) { // Code de l a vue : 26 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 27 outputentetehtml5 ( Requêtes Préparées, UTF 8, mystyle. css ) ; 28 echo <h1>requêtes Préparées ( 2 )</h1> ; 205

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 29 // A f f i c h a g e des r é s u l t a t s de l a r e q u ê t e 30 f o r e a c h ( $statement as $row ) { 31 echo <p> ; 32 echo $row [ numerorue ].,. $row [ rue ]., ; 33 i f (! empty ( $row [ complementadresse ] ) ) 34 echo $row [ complementadresse ]., ; 35 echo $row [ codepostal ]. ; 36 echo $row [ v i l l e ]. ; 37 echo $row [ pays ] ; 38 echo </p> ; 39 } 40 outputfinfichierhtml5 ( ) ; 41 } e l s e { // Erreur l o r s de l e x é c u t i o n de l a r e q u ê t e 42 $dataerror [ execute query ] = Problème d e x é c u t i o n de l a r e q u ê t e. 43. ( par exemple, une l i g n e avec c e t t e c l é p r i m a i r e $id e x i s t e déjà... ) ; 44 r e q u i r e ( vueerreur. php ) ; 45 d i e ( ) ; 46 } 47 48 // Fermeture de l a connexion ( connexion 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?> 10.4 Classe Singleton de Connexion à une Base de Données Nous présentons ici une classe de gestionnaire de connexion à une base de données. La connexion est persistante, c est à dire que l on ne va pas réinitialiser la connexion sans arrêt. Cette gestion de la connexion permet l exécution plus rapide de requêtes, en évitant d établir à chaque fois la connexion. Pour cela, la classe suit me Design Pattern du Singleton. Cela garantit que nous n aurons qu une seule instance de la classe à la fois. La méthode prepareandexecutequery prend deux arguments $requete et $args : 1. la requête avec des? 2. un tableau des arguments qui doivent remplacer les? dans la requête. exemples/pdo/ex12_classedatabasemanager.php 1 <?php 2 3 /** 4 @brief Classe permettant de g é r e r l a connection au s e r v e u r de bases de données 5 L e x é c u t i o n de r e q u ê t e s SQL avec p r é p a r a t i o n o f f e r t e s e r v i c e compris. 6 La c l a s s e e s t g é r é e avec l e pattern SINGLETON, qui permet 7 d a v o i r un exemplaire unique du g e s t i o n a i r e de connection, 8 pour une connexion p e r s i s t a n t e. 9 */ 10 class DataBaseManager{ 206

Chapitre 10 : Bases de Données et PHP Data Objects 11 // G e s t i o n n a i r e de connection à l a base de données avec PDO 12 // Variable de c l a s s e. 13 s t a t i c p r i v a t e $dbh = n u l l ; 14 15 // Référence de l unique i n s t a n c e de l a c l a s s e. 16 // Variable de c l a s s e, i n i t i a l e m e n t n u l l 17 s t a t i c p r i v a t e $ i n s t a n c e=n u l l ; 18 19 // Données n é c e s s a i r e s à l a connexion par 20 // l e c o n s t r u c t e u r de PDO : 21 s t a t i c p r i v a t e $db_host= mysql :host=l o c a l h o s t ; ; 22 s t a t i c p r i v a t e $db_name= dbname=exampledatabase ; 23 s t a t i c p r i v a t e $db_user= remy ; 24 s t a t i c p r i v a t e $db_password= my_password ; 25 26 /** 27 * @brief Constructeur p r i v é. 28 * Personne ne peut c r é e r des i n s t a n c e s à t i r e l a r i g o t 29 * car 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 30 */ 31 p r i v a t e f u n c t i o n construct ( ) { 32 try { 33 // Création de l i n s t a n c e de PDO ( database handler ). 34 s e l f : :$dbh = new PDO( s e l f : :$db_host. s e l f : :$db_name, s e l f : :$db_user, s e l f : : $db_password ) ; 35 // Rendre l e s e r r e u r s PDO d é t e c t a b l e s et g é r a b l e s par e x c e p t i o n s : 36 s e l f : :$dbh >s e t A t t r i b u t e (PDO : :ATTR_ERRMODE, PDO : :ERRMODE_EXCEPTION) ; 37 } catch ( PDOException $e ) { 38 echo <p>erreur de connexion à l a base de données.<br/> 39. Vous n avez pas besoin d en s a v o i r plus... 40. </p> ; 41 d i e ( ) ; 42 } 43 } 44 45 /** 46 * @brief Méthode s t a t i q u e p l u b l i q u e d a c c è s à l unique i n s t a n c e. 47 * Si l i n s t a n c e n e x i s t e pas, on l a c r é e. 48 * On retourne e n s u i t e l unique i n s t a n c e. 49 */ 50 p u b l i c s t a t i c f u n c t i o n g e t I n s t a n c e ( ) 51 { 52 i f ( n u l l === s e l f : :$ i n s t a n c e ) { 53 s e l f : :$ i n s t a n c e = new s e l f ; 54 } 55 return s e l f : :$ i n s t a n c e ; 56 } 57 58 /** 59 * @brief Prépare et exécute une r e q u ê t e. 60 * @param s t r i n g $requete : r e q u ê t e avec des? 61 * @param s t r i n g [ ] $args : arguments à l i e r ( binder ) aux? dans l a r e q u ê t e 62 */ 63 p u b l i c f u n c t i o n prepareandexecutequery ( $requete, $args ) { 64 // r é c u p é r a t i o n du nombre d arguments : 65 $numargs = count ( $args ) ; 207

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 66 // Test de r equête préparée v a l a b l e 67 // Une r equête 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!!! 68 i f ( empty ( $requete )! i s _ s t r i n g ( $requete ) 69 preg_match ( / ( \ \ ) +/, $requete )!== 0) 70 { 71 return f a l s e ; 72 } 73 // Préparation de l a r equête 74 $statement = s e l f : :$dbh >prepare ( $requete ) ; 75 i f ( $statement === f a l s e ) { 76 return f a l s e ; 77 } 78 // On parcours l e s arguments en commençant au deuxième 79 // on commence après l e paramètre $requete 80 f o r ( $ i=1 ; $ i <= $numargs ; $ i++){ 81 // Lien e n t r e l argument et l e? numéro i 82 // ( rappel : l e s? sont numérotés à p a r t i r de 1) 83 $statement >bindparam ( $i, $args [ $i 1]) ; 84 } 85 86 // Exécution de l a r equête préparée : 87 $statement >execute ( ) ; 88 89 i f ( $statement === f a l s e ) { 90 return f a l s e ; 91 } 92 93 try { 94 // T r a n s f e r t des r é s u l t a t s de l a r e q u ê t e dans un array 95 $ r e s u l t s = $statement >f e t c h A l l (PDO : :FETCH_ASSOC) ; 96 } catch ( PDOException $e ) { 97 // La requête a é t é exécutée mais pas de r é s u l t a t s 98 // La requête n e s t pas de type SELECT... 99 $ r e s u l t s = true ; 100 } 101 102 // d e s t r u c t i o n des données du PDOstatement 103 $statement >c l o s e C u r s o r ( ) ; 104 $statement = n u l l ; 105 106 return $ r e s u l t s ; // r e t o u r des données de r e q u ê t e 107 } 108 109 /** 110 * @brief on i n t e r d i t l e clonage ( pour l e pattern s i n g l e t o n. 111 */ 112 p r i v a t e f u n c t i o n clone ( ) {} 113 } 114?> 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. exemples/pdo/ex13_testsingletonpdo.php 1 <?php 2 require_once ( dirname ( FILE ). / ex12_classedatabasemanager. php ) ; 208

Chapitre 10 : Bases de Données et PHP Data Objects 3 4 $statement = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 5 SELECT * FROM Adresse WHERE codepostal =?, 6 array ($_GET[ codepostal ] ) ) ; 7 8 require_once ( dirname ( FILE ). / commonfunctions. php ) ; 9 outputentetehtml5 ( Test de Fonction de Préparation de Requête, 10 UTF 8, mystyle. css ) ; 11 i f ( $statement!== f a l s e ) { 12 // A f f i c h a g e des r é s u l t a t s de l a r e q u ê t e 13 f o r e a c h ( $statement as $row ) { 14 echo <p> ; 15 echo $row [ numerorue ].,. $row [ rue ]., ; 16 i f (! empty ( $row [ complementaddr ] ) ) 17 echo $row [ complementaddr ]., ; 18 echo $row [ codepostal ]. ; 19 echo $row [ v i l l e ]. ; 20 echo $row [ pays ] ; 21 echo </p> ; 22 } 23 } e l s e { // Erreur l o r s de l e x é c u t i o n de l a r e q u ê t e 24 $dataerror [ ] = Problème l o r s de l a p r é p a r a t i o n de l a r e q u ê t e. 25. ( par exemple, l a donnée codepostal passée par GET e s t i n v a l i s e... ) ; 26 r e q u i r e ( vueerreur. php ) ; 27 d i e ( ) ; 28 } 29 outputfinfichierhtml5 ( ) ; 30?> 209

Cinquième partie Conception d Architectures Avancées 210

Table of Contents 11 Analyse Fonctionnelle 213 11.1 Storyboards..................................... 213 11.2 Diagrammes de Cas d Utilisations......................... 214 12 Organisation des Répertoires et Configuration 215 12.1 Organisation des Répertoires............................ 215 12.2 Autoload....................................... 216 12.3 La classe Config : éviter les URL en dûr..................... 217 13 Architectures MVC et DAL 220 13.1 Le Contrôleur.................................... 220 13.2 Le Modèle...................................... 223 13.3 Les Vues....................................... 226 13.4 La Gateway pour les instances d Adresse.................... 227 14 Utilisateurs et Front Controller 231 14.1 Storyboards..................................... 231 14.2 Diagramme de Cas d Utilisation.......................... 232 14.3 Le Front-Controller................................. 232 14.4 Gestion de l Authentification............................ 237 14.4.1 Utilitaires d Authentification....................... 237 14.4.2 Modèle et Gateway de la table User................... 238 14.4.3 Gestion des sessions et des cookies.................... 239

212 TABLE OF CONTENTS

Chapitre 11 Analyse Fonctionnelle 11.1 Storyboards 11.1.0.a Storyboards (b) La vue affichant toutes les adresses (a) Vues normale d une instance Figure 11.1 : Storyboards : Vues d affichage d instances et de collection d instances d Adresse 213

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web (a) La vue de saisie d une instance (b) La vue d erreur de saisie Figure 11.2 : Storyboards : Vue normale et vue d erreur de saisie d une instance d Adresse 11.2 Diagrammes de Cas d Utilisations Dans les storyboards précédents, tous les liens et les boutons correspondent à des actions (événements utilisateur) que nous résumons dans un diagramme de cas d utilisation. Figure 11.3 : Use Case Diagram : Les actions possibles pour l utilisateur 214

Chapitre 12 Organisation des Répertoires et Configuration 12.1 Organisation des Répertoires Nous allons adopter une organisation des répertoire très précise (voir arborescence ci-contre) pour permettre à la classe Autoload, décrite dans la partie 12.2, de charger automatiquement les classes. La liste des sous-répertoire contenant des classes (ici config, controlleur, metier, etc.) sera fournie à l autoload pour lui permettre de trouver les fichiers sources des classes. Les classes du répertoire metier on été étudiées dans la chapitre 7. Les classes du répertoire vue/classes ont été étudiées dans ce même chapitre 7. et dans le chapitre 4. La classe DataBaseManager du répertoire persistance a été étudiée dans la partie 10.4. La classe AdresseGateway qui gère, via la classe DataBaseManager, la génération et l exécution des requêtes SQL concernant la table Adresse, sera étudiée dans la partie 13.4. Les classes des répertoires controleur et modele, ainsi que les vues à la racine du répertoire vue, qui constitue le coeur de l architecture dite Modèle, Vue, Contrôleur (MVC), seront étudiées au chapitre 13. -- index.php --config -- Autoload.php -- Config.php -- controleur -- Controleur.php -- validationadresse.php -- css -- defaultstyle.css -- metier -- AdresseFabrique.php -- Adresse.php -- AdressePropertiesTrait.php -- ExpressionsRegexUtils.php -- modeles -- ModelAdresse.php -- ModelCollectionAdresse.php -- Model.php -- persistance -- AdresseGateway.php -- DataBaseManager.php -- vue -- classes -- AdresseFormView.php -- AdresseView.php -- FormManager.php -- VueHtmlUtils.php -- vueaccueil.php -- vueafficheadresse.php -- vuecollectionadresse.php -- vueeditionadresse.php -- vueerreurdefault.php -- vuesaisieadresseerror.php -- vuesaisieadresse.php 215

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 12.2 Autoload La classe Autoload déclare et implémente une méthode callback qui sera appelée lors de l utilisation dans le programme d une classe inconnue. La méthode callback 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 vollée. exemples/mvclatex/expoly/ex01_autoload.php 1 <?php 2 /** 3 * @brief c l a s s e Autoload : permet de charger automatiquement l e s c l a s s e s. 4 * La méthode autoloadcallback ( ) permer de charger l e code source 5 * d une c l a s s e dont l e nom e s t passé en paramètre. 6 * Pour cela, l a méthode load ( ) d é c l a r e autoloadcallback ( ) 7 * par un appel à s p l _ a u t o l o a d _ r e g i s t e r ( ) 8 */ 9 class Autoload 10 { 11 // r é f é r e n c e v e r s l unique i n s t a n c e d Autoload 12 p r i v a t e s t a t i c $m_instance = n u l l ; 13 14 /** 15 * @brief Chargement de l unique i n s t a n c e et d é c l a r a t i o n du c a l l b a c k d autoload. 16 */ 17 p u b l i c s t a t i c f u n c t i o n load ( ) 18 { 19 i f ( n u l l!== s e l f : :$m_instance ) { // Test : s i l i n s t a n c e e x i s t e. 20 throw new Exception ( Erreur l autoload ne peut ê t r e chargée qu une f o i s :. CLASS ) ; 21 } 22 // A l l o c a t i o n de l i n s t a n c e ( c o n s t r u c t e u r par défaut ) : 23 s e l f : :$m_instance = new s e l f ( ) ; 24 // D é c l a r a t i o n du c a l l b a c k chargé d i n c l u r e l e s c l a s s e s : 25 i f (! s p l _ a u t o l o a d _ r e g i s t e r ( array ( s e l f : :$m_instance, autoloadcallback ), f a l s e ) ) { 26 throw new Exception ( I m p o s s i b l e de l a n c e r l autoload :. CLASS ) ; 27 } 28 } 29 30 /** 31 * @brief D é s a c t i v a t i o n du c a l l b a c k d autoload et d e s t r u c t i o n de l i n s t a n c e. 32 */ 33 p u b l i c s t a t i c f u n c t i o n shutdown ( ) 34 { 35 i f ( n u l l!== s e l f : :$m_instance ) { 36 i f (! spl_autoload_unregister ( array ( s e l f : :$m_instance, _autoload ) ) ) { 37 throw new Exception ( I m p o s s i b l e d a r r ê t e r l autoload :. CLASS ) ; 38 } 39 s e l f : :$m_instance = n u l l ; 40 } 41 } 42 43 /** 216

Chapitre 12 : Organisation des Répertoires et Configuration 44 * @brief Callback d Autoload. 45 * Cette méthode e s t appelée automatiquement en cas d i n s t a n c i a t i o n 46 * d une c l a s s e inconnue. La méthode charge a l o r s l a c l a s s e en q u e s t i o n. 47 * 48 * @param class : nom de l a c l a s s e à charger. 49 * 50 * @note L a r b o r e s c e n c e des r é p e r t o i r e s et l e s noms de f i c h i e r s PHP 51 * contenant l e s c l a s s e s sont imposés pour permettre àà c e t t e f o n c t i o n 52 * de trouver l e nom du f i c h i e r PHP à p a r t i r du nom de l a c l a s s e. 53 */ 54 p r i v a t e s t a t i c f u n c t i o n autoloadcallback ( $ c l a s s ) 55 { 56 // Racine du s i t e 57 g l o b a l $ r o o t D i r e c t o r y ; 58 // Nom du f i c h i e r PHP contenant l a c l a s s e : 59 $sourcefilename = $ c l a s s.. php ; 60 // L i s t e des sous r é p e r t o i r e s contenant des d é f i n i t i o n s de c l a s s e s 61 $ d i r e c t o r y L i s t =array (, c o n f i g /, modeles /, 62 c o n t r o l e u r /, metier /, p e r s i s t a n c e /, 63 vue/ c l a s s e s / ) ; 64 // Parcours de tous l e s sous r é p e r t o i r e s 65 f o r e a c h ( $ d i r e c t o r y L i s t as $subdir ) { 66 // Chemin v e r s l e f i c h i e r 67 $ f i l e P a t h=$ r o o t D i r e c t o r y. $subdir. $sourcefilename ; 68 // s i l e f i c h i e r e x i s t e 69 i f ( f i l e _ e x i s t s ( $ f i l e P a t h ) ) 70 { 71 // Chargement de l a c l a s s e : 72 i n c l u d e ( $ f i l e P a t h ) ; 73 } 74 } 75 76 } 77 } 78 79 80?> 12.3 La classe Config : éviter les URL en dûr La classe Config permet de compléter les informations sur l arborescence des répertoires, en indiquant les chemins vers les vues, les vues d erreurs, ou des ressources comme des feuilles de style CSS, à partir de la racine du site. Ceci permet ensuite, dans le code, d éviter les URL en dur en obtenant le chemin dans un tableau. Ainsi, si on change l emplacement des fichiers de ressources ou de vues par la suite, il n y a alors pas besoin de chercher toutes les occurrences de liens cassés dans tous les fichiers sources, il suffit de changer la classe Config. Cela facilite fortement la maintenance du site. exemples/mvclatex/expoly/ex02_config.php 1 <?php 2 /** 3 * @brief Classe de c o n f i g u r a t i o n 4 * Donne a c c è s aux paramères s p é c i f i q u e s concernant l a p p l i c a t i o n 217

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 5 * t e l l e s que l e s chemins v e r s l e s vues, l e s vues d erreur, 6 * l e s hash pour l e s ID de s e s s i o n s, e t c. 7 */ 8 class Config 9 { 10 /** 11 * @brief r etourne l e tableau des ( chemins v e r s ) l e s vues 12 */ 13 p u b l i c s t a t i c f u n c t i o n getvues ( ) { 14 // Racine du s i t e 15 g l o b a l $ r o o t D i r e c t o r y ; 16 // R é p e r t o i r e contenant l e s vues 17 $vuedirectory = $ r o o t D i r e c t o r y. vue/ ; 18 return array ( d e f a u l t => $vuedirectory. vueaccueil. php, 19 s a i s i e A d r e s s e => $vuedirectory. v u e S a i s i e A d r e s s e. php, 20 e d i t i o n A d r e s s e => $vuedirectory. vueeditionadresse. php, 21 a f f i c h e A d r e s s e => $vuedirectory. vueafficheadresse. php, 22 a f f i c h e C o l l e c t i o n A d r e s s e => $vuedirectory. v u e C o l l e c t i o n A d r e s s e. php ) ; 23 } 24 25 /** 26 * @brief r etourne l e tableau des ( chemins v e r s ) l e s vues d e r r e u r 27 */ 28 p u b l i c s t a t i c f u n c t i o n getvueserreur ( ) { 29 // Racine du s i t e 30 g l o b a l $ r o o t D i r e c t o r y ; 31 // R é p e r t o i r e contenant l e s vues 32 $vuedirectory = $ r o o t D i r e c t o r y. vue/ ; 33 return array ( d e f a u l t => $vuedirectory. vueerreurdefault. php, 34 s a i s i e A d r e s s e => $vuedirectory. v u e S a i s i e A d r e s s e E r r o r. php ) ; 35 } 36 37 /** 38 * @brief r etourne l e tableau des ( chemins v e r s ) l e s f e u i l l e s de s t y l e CSS 39 */ 40 p u b l i c s t a t i c f u n c t i o n getstylesheetsurl ( ) { 41 42 // R é p e r t o i r e contenant l e s s t y l e s c s s 43 $cssdirectoryurl = http ://.$_SERVER[ HTTP_HOST ]. / exemples /mvc/ c s s / ; 44 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 ) ; 45 } 46 47 /** 48 * @brief 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 ) : 49 */ 50 p u b l i c s t a t i c f u n c t i o n generaterandomid ( ) 51 { 52 // Génération de 5 o c t e t s ( pseudo ) a l é a t o i r e s codés en hexa 53 $cryptostrong = f a l s e ; // Variable pour passage par r é f é r e n c e 54 $ o c t e t s = openssl_random_pseudo_bytes ( 5, $cryptostrong ) ; 55 return bin2hex ( $ o c t e t s ) ; 56 } 57 58 /** 218

Chapitre 12 : Organisation des Répertoires et Configuration 59 * @brief génère un ID de s e s s i o n pour c o n t r ô l e par a d r e s s e IP 60 * 10 c h i f f r e s hexa a l é a t o i r e s + hash de l a d r e s s e IP. 61 */ 62 p u b l i c s t a t i c f u n c t i o n g e n e r a t e S e s s i o n I d ( ) 63 { 64 return generaterandomid ( ). hash ( md5, $_SERVER[ REMOTE_ADDR ] ) ; 65 } 66 } 67?> 219

Chapitre 13 Architectures MVC et DAL 13.1 Le Contrôleur Le contrôleur est chargé de : 1. Reconnaître l action (événement) à réaliser pour l exécuter. 2. Demander la construction du modèle. 3. Tester les erreurs et récupérer les éventuelles exceptions pour éviter un éventuel caca. 4. Appeler la vue (ou la vue d erreur) pour afficher le résultat de l action. L index initialise la donnée deu répertoire racine, charge le code source de l Autoload, puis exécute la méthode load qui déclare le callback chargé d inclure le code source des classes utilisées dans le programme. L index crée ensuite une instance du contrôleur. C est le constructeur du contrôleur qui fait le reste du travail. exemples/mvclatex/expoly/ex03_index.php 1 <?php 2 $ r o o t D i r e c t o r y = dirname ( FILE ). / ; 3 4 // chargement de l a c l a s s e Autoload pour autochargement des c l a s s e s 5 require_once ( $ r o o t D i r e c t o r y. / c o n f i g / Autoload. php ) ; 6 7 try { 8 Autoload : :load ( ) ; 9 } catch ( Exception $e ) { 10 r e q u i r e ( Config : :getvues ( ) [ d e f a u l t ] ) ; 11 } 12 13 // Création de l i n s t a n c e du c o n t r ô l e u r ( v o i r Controleur. php ) 14 $cont = new Controleur ( ) ; 15?> Le constructeur du contrôleur récupère dans le tableau $_REQUEST (réunion de $_GET, de $_POST et de $_COOKIE), l action à réaliser. Ces actions sont déterminées lors de l analyse dans le diagramme de cas d utilisation (voir la partie 11.2). On fait un switch pour distinguer tous les cas correspondant aux actions, sans oublier le cas default, qui renverra généralement vers la page d accueil, ou encore une vue d erreur par défaut, en cas d action non définie. 220

Chapitre 13 : Architectures MVC et DAL exemples/mvclatex/expoly/ex04_controleur.php 1 <?php 2 /** 3 * @brief La c l a s s e Controleur i d e n t i f i e l action et a p p e l l e l a mthode 4 * pour c o n s t r u i r e l e modle correspondant l action. 5 * Le c o n t r o l e u r a p p e l l e a u s s i l a vue correspondante. 6 * I l gre a u s s i l e s e x c e p t i o n s et a p p e l l e l e cas chant une vue d e r r e u r. 7 */ 8 class Controleur { 9 10 /** 11 * @brief 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. 12 */ 13 f u n c t i o n construct ( ) { 14 try 15 { 16 // Rcupration de l action 17 $ a c t i o n=$_request[ action ] ; 18 19 // On d i s t i n g u e des cas d u t i l i s a t i o n, s u i v a n t l action 20 switch ( $ a c t i o n ) { 21 case get : // A f f i c h a g e d une Adresse p a r t i r de son ID 22 $id = f i l t e r _ v a r ($_REQUEST[ id ], FILTER_SANITIZE_STRING) ; 23 $modele = ModelAdresse : :getmodeladresse ( $ i d ) ; 24 i f ( $modele >geterror ( ) === f a l s e ) { 25 r e q u i r e ( Config : :getvues ( ) [ a f f i c h e A d r e s s e ] ) ; 26 } e l s e { 27 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 28 } 29 break ; 30 case get a l l : // A f f i c h a g e de t o u t e s l e s Adresse s 31 $modele = ModelCollectionAdresse : :getmodeladresseall ( ) ; 32 i f ( $modele >geterror ( ) === f a l s e ) { 33 r e q u i r e ( Config : :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 ] ) ; 34 } e l s e { 35 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 36 } 37 break ; 38 case s a i s i e : // S a i s i e d une n o u v e l l e Adresse 39 $modele = ModelAdresse : :getmodeldefaultadresse ( ) ; 40 r e q u i r e ( Config : :getvues ( ) [ s a i s i e A d r e s s e ] ) ; 41 break ; 42 case e d i t : // S a i s i e des m o d i f i c a t i o n s d une Adresse 43 $id = f i l t e r _ v a r ($_REQUEST[ id ], FILTER_SANITIZE_STRING) ; 44 $modele = ModelAdresse : :getmodeladresse ( $ i d ) ; 45 i f ( $modele >geterror ( ) === f a l s e ) { 46 r e q u i r e ( Config : :getvues ( ) [ e d i t i o n A d r e s s e ] ) ; 47 } e l s e { 48 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 49 } 50 break ; 51 case post : // Met j o u r une Adresse dans l a BD 52 r e q u i r e ( dirname ( FILE ). / v a l i d a t i o n A d r e s s e. php ) ; 53 $modele = ModelAdresse : :getmodeladressepost ( $id, $numerorue, $rue, 54 $complementadresse, $codepostal, $ v i l l e, $pays ) ; 55 i f ( $modele >geterror ( ) === f a l s e ) { 221

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 56 r e q u i r e ( Config : :getvues ( ) [ a f f i c h e A d r e s s e ] ) ; 57 } e l s e { 58 i f (! empty ( $modele >geterror ( ) [ p e r s i s t a n c e ] ) ) { 59 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 60 } e l s e { 61 r e q u i r e ( Config : :getvueserreur ( ) [ s a i s i e A d r e s s e ] ) ; 62 } 63 } 64 break ; 65 case put : // Cration d une n o u v e l l e Adresse dans l a BD 66 r e q u i r e ( dirname ( FILE ). / v a l i d a t i o n A d r e s s e. php ) ; 67 $modele = ModelAdresse : :getmodeladresseput ( $numerorue, $rue, 68 $complementadresse, $codepostal, $ v i l l e, $pays ) ; 69 i f ( $modele >geterror ( ) === f a l s e ) { 70 r e q u i r e ( Config : :getvues ( ) [ a f f i c h e A d r e s s e ] ) ; 71 } e l s e { 72 i f (! empty ( $modele >geterror ( ) [ p e r s i s t a n c e ] ) ) { 73 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 74 } e l s e { 75 r e q u i r e ( Config : :getvueserreur ( ) [ s a i s i e A d r e s s e ] ) ; 76 } 77 } 78 break ; 79 case d e l e t e : // Supression d une Adresse p a r t i r de son ID 80 $id = f i l t e r _ v a r ($_REQUEST[ id ], FILTER_SANITIZE_STRING) ; 81 $modele = ModelAdresse : :d e l e t e A d r e s s e ( $id ) ; 82 i f ( $modele >geterror ( ) === f a l s e ) { 83 r e q u i r e ( Config : :getvues ( ) [ a f f i c h e A d r e s s e ] ) ; 84 } e l s e { 85 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 86 } 87 break ; 88 d e f a u l t : // L a c t i o n i n d f i n i e ( page par dfaut, i c i a c c u e i l ) 89 r e q u i r e ( Config : :getvues ( ) [ d e f a u l t ] ) ; 90 break ; 91 } 92 } 93 catch ( Exception $e ) // Page d e r r e u r par dfaut 94 { 95 $modele = new Model ( array ( exception => $e >getmessage ( ) ) ) ; 96 r e q u i r e ( Config : :getvueserreur ( ) [ d e f a u l t ] ) ; 97 } 98 } 99 } 100?> Comme expliqué au chapitre 7, si les données issues du tableau $_REQUEST sont utilisées, elles doivent être systématiquement filtrées. Un appel de méthode construit un modèle, instance de classe qui contiendra les données nécessaires à la vue, et un tableau d erreur, éventuellement non vide. La construction du modèle est décrite dans la partie 13.2 ci-dessous. Le contrôleur appelle ensuite la vue, qui sera éventuellement une vue d erreur en cas de tableau d erreurs non vide. 222

Chapitre 13 : Architectures MVC et DAL 13.2 Le Modèle 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). Dans notre implémentation, le modèle contient aussi du texte (ici le titre) à afficher dans la vue. exemples/mvclatex/expoly/ex05_model.php 1 <?php 2 class Model{ 3 /** 4 * @brief D i c t i o n n a i r e d e r r e u r s ( c o u p l e s type => mmessage ) 5 */ 6 p r o t e c t e d $dataerror ; 7 8 /** 9 * @brief return f a l s e en l absence d e r r e u r s, l a c o l l e c t i o n d e r r e u r s sinon 10 */ 11 p u b l i c f u n c t i o n geterror ( ) { 12 i f ( empty ( $ t h i s >dataerror ) ) { 13 return f a l s e ; 14 } 15 return $ t h i s >dataerror ; 16 } 17 18 p u b l i c f u n c t i o n construct ( $dataerror ) { 19 $ t h i s >dataerror = $dataerror ; 20 } 21 } 22?> La classe ModelAdresse, qui hérite de Model contient les données d une instance d Adresse, avec son accesseur getdata(). 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 appelle des méthodes d accès aux données de la classe AdresseGateway pour implémenter la persistence. exemples/mvclatex/expoly/ex06_modeladresse.php 1 <?php 2 /** 3 * @brief Classe Modèle pour s t o c k e r une Adresse 4 * Construit un modèle de données pour l e s vues 5 * a f f i c h a n t une unique a d r e s s e. 6 * Les données peuvent v e n i r d un f o r m u l a i r e ou d un a c c è s à l a BD. 7 */ 8 class ModelAdresse extends Model 9 { 10 /** 11 * @brief I n s t a n c e d adresse, données métier du modèle 12 */ 13 p r i v a t e $ a d r e s s e ; 14 15 /** 16 * @brief T i t r e p r i n c i p a l de l a vue 17 */ 18 p r i v a t e $ t i t l e ; 223

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 19 20 /** 21 * 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 22 */ 23 p u b l i c f u n c t i o n getdata ( ) 24 { 25 return $ t h i s >a d r e s s e ; 26 } 27 28 /** 29 * 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 30 */ 31 p u b l i c f u n c t i o n g e t T i t l e ( ) 32 { 33 return $ t h i s >t i t l e ; 34 } 35 36 /** 37 * @brief Retourne un modèle avec une a d r e s s e à p a r t i r de son ID 38 * par a c c è s à l a base de données. 39 */ 40 p u b l i c s t a t i c f u n c t i o n getmodeldefaultadresse ( ) { 41 $model = new s e l f ( array ( ) ) ; 42 // Appel de l a couche d a c c è s aux données : 43 $model >a d r e s s e = Adresse : :g e t d e f a u l t A d r e s s e ( ) ; 44 $model >t i t l e = S a i s i e d une a d r e s s e ; 45 return $model ; 46 } 47 48 /** 49 * @brief Retourne un modèle avec une a d r e s s e à p a r t i r de son ID 50 * par a c c è s à l a base de données. 51 */ 52 p u b l i c s t a t i c f u n c t i o n getmodeladresse ( $id ) { 53 $model = new s e l f ( array ( ) ) ; 54 // Appel de l a couche d a c c è s aux données : 55 $model >a d r e s s e = AdresseGateway : :getadressebyid ( $model >dataerror, $id ) ; 56 $model >t i t l e = A f f i c h a g e d une a d r e s s e ; 57 return $model ; 58 } 59 /** 60 * @brief I n s è r e une a d r e s s e en c r é a n t un nouvel ID 61 * par a c c è s à l a base de données. 62 */ 63 p u b l i c s t a t i c f u n c t i o n getmodeladressepost ( $id, $numerorue, $rue, 64 $complementaddr, 65 $codepostal, $ v i l l e, $pays ) { 66 $model = new s e l f ( array ( ) ) ; 67 68 // Appel de l a couche d a c c è s aux données : 69 $model >a d r e s s e = AdresseGateway : :postadresse ( $model >dataerror, $id, 70 $numerorue, $rue, $complementaddr, 71 $codepostal, $ v i l l e, $pays ) ; 72 $model >t i t l e = L a d r e s s e a é t é mise à j o u r ; 73 return $model ; 74 } 224

Chapitre 13 : Architectures MVC et DAL 75 76 /** 77 * @brief I n s è r e une a d r e s s e en c r é a n t un nouvel ID 78 * par a c c è s à l a base de données. 79 */ 80 p u b l i c s t a t i c f u n c t i o n getmodeladresseput ( $numerorue, $rue, $complementaddr, 81 $codepostal, $ v i l l e, $pays ) { 82 $model = new s e l f ( array ( ) ) ; 83 84 // Appel de l a couche d a c c è s aux données : 85 $model >a d r e s s e = AdresseGateway : :putadresse ( $model >dataerror, 86 $numerorue, $rue, $complementaddr, 87 $codepostal, $ v i l l e, $pays ) ; 88 $model >t i t l e = L a d r e s s e a é t é i n s é r é e ; 89 return $model ; 90 } 91 92 /** 93 * @brief Retourne un modèle avec une a d r e s s e à p a r t i r de son ID 94 * par a c c è s à l a base de données. 95 */ 96 p u b l i c s t a t i c f u n c t i o n d e l e t e A d r e s s e ( $id ) { 97 $model = new s e l f ( array ( ) ) ; 98 // Appel de l a couche d a c c è s aux données : 99 $model >a d r e s s e = AdresseGateway : :d e l e t e A d r e s s e ( $model >dataerror, $id ) ; 100 $model >t i t l e = Adresse supprimée ; 101 return $model ; 102 } 103 } 104?> La classe ModelCollectionAdresse, qui hérite de Model contient les données d une collection d instances d Adresse, avec son accesseur getdata(), qui cette fois renvoie une collection. 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). Ces méthodes appelle des méthodes d accès aux données de la classe AdresseGateway pour implémenter la persistence. exemples/mvclatex/expoly/ex07_modelcollectionadresse.php 1 <?php 2 /** @brief Classe Modle pour s t o c k e r une c o l l e c t i o n de Adresses 3 * 4 */ 5 class ModelCollectionAdresse extends Model 6 { 7 /** 8 * @brief C o l l e c t i o n d a d r e s s e s, donnes mtier du modle 9 */ 10 p r i v a t e $ c o l l e c t i o n A d r e s s e ; 11 12 /** 13 * Donne accs l a c o l l e c t i o n d a d r e s s e s 14 */ 15 p u b l i c f u n c t i o n getdata ( ) 16 { 225

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 17 return $ t h i s >c o l l e c t i o n A d r e s s e ; 18 } 19 20 /** 21 * @brief Constructeur par dfaut (priv, c r e des c o l l e c t i o n s v i d e s ) 22 */ 23 p r i v a t e f u n c t i o n contruct ( ) 24 { 25 $ t h i s >c o l l e c t i o n A d r e s s e = array ( ) ; 26 $ t h i s >dataerror = array ( ) ; 27 } 28 29 /** 30 * @brief Retourne un modle avec 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 31 * par accs l a base de donnes. 32 */ 33 p u b l i c s t a t i c f u n c t i o n getmodeladresseall ( ) { 34 $model = new s e l f ( array ( ) ) ; 35 // Appel de l a couche d accs aux donnes : 36 $model >c o l l e c t i o n A d r e s s e = AdresseGateway : :g e t A d r e s s e A l l ( $model >dataerror ) ; 37 return $model ; 38 } 39 } 40?> Notons qu il ne s agit pas vraiment ici de polymorphisme. L héritage de la classe de base Model, qui correspond bien à une relation de spécialisation, n a pas la propriété de substitution, car les données dans les classes spécialisées (instance dans un cas et collection dans l autre, ne se correspondent pas. L héritage est ici utilisé pour factoriser uniquement. Ce type de relation pourrait aussi (devraient plutôt?) être implémenté par une composition. On pourrait aussi implémenter l instance d adresse comme une collection avec un seul élément pour n avoir qu une seule classe. 13.3 Les Vues Les vues ne font aucun test et se contentent d afficher le modèle qui, en l absence de bug, doit s afficher correctement. exemples/mvclatex/expoly/ex08_vueafficheadresse.php 1 <?=VueHtmlUtils : :entetehtml5 ( Bienvenue sur notre s i t e, UTF 8, 2 Config : :getstylesheetsurl ( ) [ d e f a u l t ] )?> 3 <h1><?=$modele >g e t T i t l e ( )?></h1> 4 <?=AdresseView : :gethtmldevelopped ( $modele >getdata ( ) )?> 5 6 <a href=? >Revenir à l a c c u e i l</a> 7 <?=VueHtmlUtils : :f i n F i c h i e r H t m l 5 ( ) ;?> exemples/mvclatex/expoly/ex09_vuecollectionadresse.php 1 <?=VueHtmlUtils : :entetehtml5 ( Bienvenue sur notre s i t e, UTF 8, 226

Chapitre 13 : Architectures MVC et DAL 2 Config : :getstylesheetsurl ( ) [ d e f a u l t ] )?> 3 <h1>toutes l e s a d r e s s e s</h1> 4 <a href=? >Revenir à l a c c u e i l</a> 5 <?php 6 echo <table ><tbody> ; 7 f o r e a c h ( $modele >getdata ( ) as $ a d r e s s e ) { 8 echo <tr> ; 9 echo <td><a h r e f=\?a c t i o n=d e l e t e&id=. $adresse >g e t I d ( ). \ >supprimer </a ></td> ; 10 echo <td><a h r e f=\?a c t i o n=e d i t&id=. $adresse >g e t I d ( ). \ >modifier </a></td > ; 11 echo <td>. AdresseView : :gethtmlcompact ( $ a d r e s s e ). </td> ; 12 echo <tr> ; 13 } 14 echo </tbody></table > ; 15?> 16 <?=VueHtmlUtils : :f i n F i c h i e r H t m l 5 ( ) ;?> exemples/mvclatex/expoly/ex10_vuesaisieadresseerror.php 1 <?=VueHtmlUtils : :entetehtml5 ( Bienvenue sur notre s i t e, UTF 8, 2 Config : :getstylesheetsurl ( ) [ d e f a u l t ] )?> 3 <h1>erreur de s a i s i e d une a d r e s s e</h1> 4 <?=AdresseFormView : :getformerrorshtml (?a c t i o n=. $action, $modele >getdata ( ), $modele >geterror ( ) )?> 5 <a href=? >Revenir à l a c c u e i l</a> 6 <?=VueHtmlUtils : :f i n F i c h i e r H t m l 5 ( ) ;?> 13.4 La Gateway pour les instances d Adresse La Gateway pour les instances d Adresse est une fabrique concrète qui permet de construire les instances d objets métiers (ici de type Adresse) obtenues par des requêtes (ici des requêtes préparées exécutées sur la classe de connection DataBaseManager sur la base de données SQL basée sur PDO). Les méthodes de la classe AdresseGateway construisent les requêtes SQL nécessaires pour implémenter l action, demande leur exécution par la classe de connection, puis appellent la fabrique d adresse (partie 7.3). exemples/mvclatex/expoly/ex11_adressegateway.php 1 <?php 2 class AdresseGateway { 3 /** 4 * Permet de r é c u p é r e r une a d r e s s e à p a r t i r de son ID. 5 * @param dataerror : données d e r r e u r s ( couple type => message ) par r é f é r e n c e 6 * @param id : c l é p rimaire de l a d r e s s e à r é c u p é r e r 7 * @return i n s t a n c e d Adresse en cas de succès, undefined sinon. 8 */ 9 p u b l i c s t a t i c f u n c t i o n getadressebyid(&$dataerror, $id ) { 10 i f ( i s s e t ( $id ) ) { 11 12 // Exécution de l a requête via l a c l a s s e de connexion ( s i n g l e t o n ) 13 // On r écupère l e s e x c e p t i o n PDO pour é v i t e r l e u r propagation 227

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 14 // On p e r s o n n a l i s e l a g e s t i o n de l e r r e u r 15 try { 16 $queryresults = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 17 SELECT * FROM Adresse WHERE id =?, array ( $id ) ) ; 18 } Catch ( Exception $e ) { 19 $dataerror [ requete ] = I m p o s s i b l e d accéder aux données. ; 20 } 21 22 // Si l e x é c u s s i o n de l a r e q u ê t e a f o n c t i o n n é e 23 i f ( is_array ( $queryresults ) && count ( $queryresults ) == 1) { 24 $row = $queryresults [ 0 ] ; 25 $ a d r e s s e = AdresseFabrique : :getadresse ( 26 $dataerror, 27 $row [ id ], $row [ numerorue ], $row [ rue ], 28 $row [ complementadresse ], $row [ codepostal ], 29 $row [ v i l l e ], $row [ pays ] ) ; 30 } e l s e { 31 $dataerror [ p e r s i s t a n c e ] = Adresse i n t r o u v a b l e. ; 32 } 33 } e l s e { 34 $dataerror [ p e r s i s t a n c e ] = I m p o s s i b l e d accéder aux données. ; 35 } 36 return $ a d r e s s e ; 37 } 38 39 /** 40 * Permet de r é c u p é r e r une c o l l e c t i o n d a d r e s s e s p r é s e n t e s dans l a t a b l e. 41 * @param dataerror : données d e r r e u r s ( couple type => message ) par r é f é r e n c e 42 * @return c o l l e c t i o n d Adresses en cas de succès, c o l l e c t i o n vide sinon. 43 */ 44 p u b l i c s t a t i c f u n c t i o n g e t A d r e s s e A l l (&$dataerror ) { 45 46 // Exécution de l a requête via l a c l a s s e de connexion ( s i n g l e t o n ) 47 // On récupère l e s e x c e p t i o n PDO pour é v i t e r l e u r propagation 48 // On p e r s o n n a l i s e l a g e s t i o n de l e r r e u r 49 try { 50 $queryresults = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 51 SELECT * FROM Adresse, array ( ) 52 ) ; 53 } Catch ( Exception $e ) { 54 $dataerror [ p e r s i s t a n c e ] = I m p o s s i b l e d accéder aux données. ; 55 } 56 57 $ c o l l e c t i o n A d r e s s e = array ( ) ; 58 59 // Si l e x é c u s s i o n de l a r equête a f o n c t i o n n é e 60 i f ( $queryresults!== f a l s e ) { 61 // Parcours des l i g n e s du r é s u l t a t de l a r e q u ê t e : 62 f o r e a c h ( $queryresults as $row ) { 63 // Ajour d une a d r e s s e dans l a c o l l e c t i o n : 64 $ a d r e s s e = AdresseFabrique : :getadresse ( 65 $dataerror, 66 $row [ id ], $row [ numerorue ], $row [ rue ], 67 $row [ complementadresse ], $row [ codepostal ], 68 $row [ v i l l e ], $row [ pays ] ) ; 228

Chapitre 13 : Architectures MVC et DAL 69 $ c o l l e c t i o n A d r e s s e [ ] = $ a d r e s s e ; 70 } 71 } e l s e { 72 $dataerror [ p e r s i s t a n c e ] = Aucune a d r e s s e trouvée. ; 73 } 74 75 return $ c o l l e c t i o n A d r e s s e ; 76 } 77 78 /** 79 * @brief I n s è r e une n o u v e l l e a d r e s s e ( Create ) 80 * @return l i n s t a n c e d Adresse ( e r r e u r s + données de l a a d r e s s e i n s é r é e ) 81 */ 82 p u b l i c s t a t i c f u n c t i o n postadresse (&$dataerror, $id, $numerorue, 83 $rue, $complementaddr, 84 $codepostal, $ v i l l e, $pays ) { 85 $ a d r e s s e = AdresseFabrique : :getadresse ( $dataerror, $id, 86 $numerorue, $rue, $complementaddr, 87 $codepostal, $ v i l l e, $pays ) ; 88 $queryresults = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 89 UPDATE Adresse SET numerorue=?, rue =?, 90. complementadresse=?, codepostal =?, v i l l e =?, pays=? 91. WHERE id =?, 92 array ( $adresse >getnumerorue ( ), 93 $adresse >getrue ( ), 94 $adresse >getcomplementadresse ( ), 95 $adresse >getcodepostal ( ), 96 $adresse >g e t V i l l e ( ), 97 $adresse >getpays ( ), 98 $adresse >g e t I d ( ) 99 ) 100 ) ; 101 i f ( $queryresults === f a l s e ) { 102 $dataerror [ p e r s i s t a n c e ] = Problème d e x é c u t i o n de l a r e q u ê t e. ; 103 } 104 105 return $ a d r e s s e ; 106 } 107 108 /** 109 * @brief I n s è r e une n o u v e l l e a d r e s s e ( Create ) 110 * @return l i n s t a n c e d Adresse ( e r r e u r s + données de l a a d r e s s e i n s é r é e ) 111 */ 112 p u b l i c s t a t i c f u n c t i o n putadresse(&$dataerror, $numerorue, 113 $rue, $complementaddr, 114 $codepostal, $ v i l l e, $pays ) { 115 $ a d r e s s e = AdresseFabrique : :getadresse ( $dataerror, 0000000000, 116 $numerorue, $rue, $complementaddr, 117 $codepostal, $ v i l l e, $pays ) ; 118 i f (! empty ( $dataerror ) ) { // Si e r r e u r de s a i s i e, on ne m o d i f i e pas l a BD 119 return $ a d r e s s e ; 120 } 121 122 $queryresults = f a l s e ; 123 $count = 0 ; 229

Rémy Malgouyres, http://www.malgouyres.org/ Programmation Web 124 // Boucle en cas de c o l l i s i o n de l ID 125 // Autre p o s s i b i l i t é : u t i l i s e r l e nombre de l i g n e s (COUNT) 126 // ou l e maximum par ordre alpha ou hexa des ID 127 // de l a t a b l e pour c a l c u l e r un ID qui n e s t pas p r é s e n t dans l a t a b l e. 128 while ( $queryresults === f a l s e && $count <= 3) { 129 $adresse >s e t I d ( Config : :generaterandomid ( ) ) ; // I d e n t i f i a n t a l é a t o i r e 130 $count++ ; 131 $queryresults = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 132 INSERT INTO Adresse ( id, numerorue, rue, 133. complementadresse, codepostal, v i l l e, pays ) 134. VALUES (?,?,?,?,?,?,?), 135 array ( $adresse >g e t I d ( ), 136 $adresse >getnumerorue ( ), 137 $adresse >getrue ( ), 138 $adresse >getcomplementadresse ( ), 139 $adresse >getcodepostal ( ), 140 $adresse >g e t V i l l e ( ), 141 $adresse >getpays ( ) 142 ) 143 ) ; 144 } 145 // 4 c o l l i s i o n s d a f f i l é e, c e s t t r è s louche... 146 i f ( $queryresults === f a l s e ) { 147 $dataerror [ p e r s i s t a n c e ] = Problème d e x é c u t i o n de l a r e q u ê t e. ; 148 } 149 150 return $ a d r e s s e ; 151 } 152 153 /** 154 * @brief Supprime une a d r e s s e à p a r t i r de son ID. 155 * Retourne l e modèle de données ( e r r e u r s + données de l Adresse supprimée ) 156 */ 157 p u b l i c s t a t i c f u n c t i o n d e l e t e A d r e s s e (&$dataerror, $id ) { 158 // Test s i l a d r e s s e e x i s t e et r é c u p é r a t i o n s données à supprimer 159 $ a d r e s s e = s e l f : :getadressebyid ( $dataerror, $id ) ; 160 161 i f ( empty ( $dataerror ) ) { 162 $queryresults = DataBaseManager : :g e t I n s t a n c e ( ) >prepareandexecutequery ( 163 DELETE FROM Adresse WHERE id =?, 164 array ( $id ) ) ; 165 i f ( $queryresults === f a l s e ) { 166 $dataerror [ p e r s i s t a n c e ] = Problème d e x é c u t i o n de l a r e q u ê t e. ; 167 } 168 } 169 170 return $ a d r e s s e ; 171 } 172 } 173?> 230

Chapitre 14 Utilisateurs et Front Controller 14.1 Storyboards (a) Vues d accueil (b) La vue d authentification Figure 14.1 : Storyboards : Vues d accueil pour visiteur, pour l administrateur, et vue de login (a) La vue visiteur de toutes les adresses (b) Vue admin de toutes les adresses Figure 14.2 : Storyboards : Vue de toutes les adresses suivant le rôle. 231