88 Chapitre 2. Techniques de base Les expressions régulières autorisent une recherche par motif beaucoup plus puissante. Une expression décrit un motif en indiquant d’une part le caractère ou la sous-chaîne attendu(e) dans la chaîne, et en spécifiant d’autre part dans quel ordre et avec quel nombre d’occurrences ces caractères ou sous-chaînes peuvent apparaître. L’expression régulière la plus simple est celle qui représente une sous-chaîne constante comme, par exemple, le « ver » dans ce qui précède. Une recherche avec cette expression a la même signification que la requête SQL ci-dessus. Il est possible d’indiquer plus précisément la place à laquelle doit figurer le motif : 1. le « ˆ » indique le début de la chaîne : l’expression « ∧ ver » s’applique donc à toutes les chaînes commençant par « ver » ; 2. le $ indique la fin de la chaîne : l’expression « ver$ » s’applique donc à toutes les chaînes finissant par « ver » ; On peut exprimer de manière concise toute une famille de motifs en utilisant les symboles d’occurrence suivants : 1. « m* » indique que le motif m doit être présent 0 ou plusieurs fois ; 2. « m+ » indique que le motif m oit être présent une (au moins) ou plusieurs fois, ce qu’on pourrait également exprimer par « mm* » ; 3. « m? » indique que le motif m peut être présent 0 ou une fois ; 4. « m{p,q} » indique que le motif m peut être présent au moins p fois et au plus q fois (la syntaxe {p,} indique simplement le « au moins », sans maximum, et {p} est équivalent à{p,p}). Par défaut, les symboles d’occurrence s’appliquent au caractère qui précède, mais on peut généraliser le mécanisme avec les parenthèses qui permettent de créer des séquences. Ainsi (ver)+ est une expression qui s’applique aux chaînes contenant au moins une fois la sous-chaîne ver, alors que ver+ s’applique aux sous-chaînes qui contiennent ve suivi d’un ou plusieurs r. Le choix entre plusieurs motifs peut être indiqué avec le caractère « | ». Par exemple l’expression ver+|lie+ s’applique aux chaînes qui contiennent au moins une fois ver ou au moins une fois lie. Pour vérifier qu’une chaîne contient un chiffre, on peut utiliser l’expression 0|1|2|3|4|5|6|7|8|9 mais on peut également encadrer tous les caractères acceptés entre crochets : [0123456789]. Une expression constituée d’un ensemble de caractères entre crochets s’applique à toutes les chaînes contenant au moins un de ces caractères. Si le premier caractère entre les crochets est ∧ , l’interprétation est inversée : l’expression s’applique à toutes les chaînes qui ne contiennent pas un des caractères. Voici quelques exemples : • [ver] : toutes les chaînes avec un v, un e ou un r ; • [a-f] : toutes les chaînes avec une des lettres entre a et f ; 2.3 Mise à jour d’une base par formulaire 89 • [a-zA-Z] : toutes les chaînes avec une lettre de l’alphabet. • [ ∧ 0-9] : toutes les chaînes sans chiffre. Pour simplifier l’écriture des expressions certains mot-clés représentent des classes courantes de caractères, données dans la table 2.2. Ils doivent apparaître dans une expression régulière encadrés par « : » pour éviter toute ambiguité comme, par exemple, « :alpha: ». Tableau 2.2 — Classes de caractères Mot-clé Description alpha N’importe quel caractère alphanumérique. blank Espaces et tabulations. cntrl Tous les caractères ayant une valeur ASCII inférieure à 32. lower Toutes les minuscules. upper Toutes les majuscules. space Espaces, tabulations et retours à la ligne. xdigit Chiffres en hexadécimal. Enfin le point « . » représente n’importe quel caractère, sauf le saut de ligne NEWLINE. Le point, comme tous les caractères spéciaux ( ∧ ,.,[,],(,),*, +, ?, {, , }, \) doit être précédé par un \ pour être pris en compte de manière littérale dans une expression régulière. Expressions régulières et PHP Les deux principales fonctions PHP pour traiter des expressions régulières sont ereg() et ereg_replace(). La première prend trois arguments : l’expression régu- lière, la chaîne à laquelle on souhaite appliquer l’expression, enfin le dernier para- mètre (optionnel) est un tableau dans lequel la fonction placera toutes les occur- rences de motifs, rencontrés dans la chaîne, satisfaisant l’expression régulière. Voici un exemple pour notre fonction de contrôle. On veut tester si l’utilisateur place des balises dans les chaînes de caractères, notamment pour éviter des problèmes à l’affichage. Voyons d’abord l’expression représentant une balise. Il s’agit de toute chaîne commençant par « < », suivi de caractères à l’exception de « > », et se terminant par « > ». L’expression représentant une balise est donc <[^>]*> Voici le test appliqué au nom du metteur en scène : if ( ereg ("<[^>]∗ >" , $film [ ’nom_realisateur ’] , $balises )) $message .= "Le nom contient la balise : " . htmlEntities ($balises [0]) ; La fonction ereg() recherche dans le nom toutes les balises, et les place dans le tableau $balises. Elle renvoie true si au moins un motif a été trouvé dans la chaîne. 90 Chapitre 2. Techniques de base On donne alors dans le message d’erreur la balise rencontrée (on pourrait les affi- cher toutes avec une boucle). Attention : pour qu’une balise apparaisse textuellement dans la fenêtre d’un navigateur, il faut l’écrire sous la forme <balise> pour éviter qu’elle ne soit interprétée comme une directive de mise en forme. La fonction htmlEntities() remplace dans une chaîne tous les caractères non-normalisés d’un texte HTML par l’entité HTML correspondante. Voici un autre exemple testant que le nom du metteur en scène ne contient que des caractères alphabétiques. Si on trouve un tel caractère, on le remplace par une «*»aveclafonctionereg_replace() afin de marquer son emplacement. if ( ereg ("[^A−Za−z ]" , $film [ ’ nom_realisateur ’ ])) $message .= "Le nom contient un ou plusieurs caractères " ." non−alphabétiques : " . ereg_replace ("[^A−Za−z]", "∗ " , $film [ ’ nom_realisateur ’ ]) ."<br/>"; La fonction ereg_replace() a pour but de remplacer les motifs trouvés dans la chaîne (troisième argument) par une sous-chaîne donnée dans le second argument. Les expressions régulières sont indispensables pour valider toutes les chaînes dont le format est contraint, comme les nombres, les unités monétaires, les adresses élec- troniques ou HTTP, etc. Elles sont également fréquemment utilisées pour inspecter la variable USER_AGENT et tester le navigateur utilisé par le client afin d’adapter l’affichage aux particularités de ce navigateur (voir également la fonction PHP get_browser()). 2.4 TRANSFERT ET GESTION DE FICHIERS Nous montrons maintenant comment échanger des fichiers de type quelconque entre le client et le serveur. L’exemple pris est celui d’un album photo en ligne (très limité) dans lequel l’internaute peut envoyer des photos stockées sur le serveur avec une petite description, consulter la liste des photos et en récupérer certaines. La première chose à faire est de vérifier que les transferts de fichier sont autorisés dans la configuration courante de PHP. Cette autorisation est configurée par la directive suivante dans le fichier php.ini : ; Whether to allow HTTP file uploads. file_uploads = On Une seule table suffira pour notre application. Voici le script de création. Exemple 2.20 exemples/Album.sql : Table pour l’album photos # Création d ’une table pour un petit album photo CREATE TABLE Album ( i d INTEGER AUTO_INCREMENT NOT NULL , description TEXT, 2.4 Transfert et gestion de fichiers 91 compteur INTEGER DEFAULT 0, PRIMARY KEY ( i d ) ) ; L’attribut compteur, de valeur par défaut 0, donnera le nombre de télécharge- ments de chaque photo. 2.4.1 Transfert du client au serveur Voici le formulaire permettant d’entrer le descriptif et de choisir le fichier à transmettre au serveur. Il est très important, pour les formulaires transmettant des fichiers, d’utiliser le mode post et de penser à placer l’attribut enctype à la valeur multipart/form-data dans la balise <form> (voir chapitre 1, page 10). Le transfert d’un fichier donne en effet lieu à un message HTTP en plusieurs parties. En cas d’oubli de cet attribut le fichier n’est pas transmis. Rappelons que les champs <input> de type file créent un bouton de formulaire permettant de parcourir les arborescences du disque local pour choisir un fichier. Dans notre formulaire, ce champ est nommé maPhoto. Notez le champ caché max_file_size qui limite la taille du fichier à transférer. Exemple 2.21 exemples/FormTransfert.html : Formulaire pour sélectionner le fichier à transmettre <?xml version=" 1.0 " encoding=" iso −8959−1"?> <!DOCTYPE h t m l PUBLIC " −/ /W3C / / DTD XHTML 1 . 0 S t r i c t / / EN " "http ://www.w3. org/TR/xhtml1/DTD/xhtml1−strict .dtd"> <html xmlns="http ://www.w3. org/1999/xhtml" xml: lang=" fr " > <head> < title>Formulaire de transfert de photographie</ title> < link rel =’stylesheet ’ href="films .css" type=" text / css " /> </head> <body> <h1>Transfert de photographies dans l ’album</h1> <form enctype=" multipart /form−data" action="TransfertFichier .php " method=’post ’> <p> < textarea name="description" cols =’50’ rows=’3’>Entrez ici la description de la photographie </ textarea> </p><p> Choisissez le fichier : <br /> <input type =’hidden ’ name=’max_file_size ’ value= ’2000000 ’/> <input type =’file ’ size=’40’ name=’maPhoto ’ /> 92 Chapitre 2. Techniques de base </p> <input type =’submit ’ value=’Transférer ’/> </form> </body> </html> Voici maintenant le script TransfertFichier.php associé à ce formulaire, montrant comment le fichier est traité à l’arrivée sur le serveur. L’instruction switch,analogue à celle du C ou du C++, permet de choisir une action à effectuer en fonction de la valeur d’une variable (ici $codeErreur) ou d’une expression : voir page 431 pour plus de détails. Les informations relatives aux fichiers transférés sont disponibles dans un tableau $_FILES à deux dimensions. La première est le nom du champ de formulaire d’où provient le fichier (dans notre cas, maPhoto) ; la seconde est un ensemble de propriétés décrivant le fichier reçu par le serveur, énumérées dans la table 2.3. La propriété error permet de savoir si le transfert s’est bien passé ou, si ce n’est pas le cas, quel type de problème est survenu. Les valeurs possibles du code d’erreur sont les suivantes : • UPLOAD_ERR_OK : pas d’erreur, le transfert s’est bien effectué ; • UPLOAD_ERR_INI_SIZE : le fichier transmis dépasse la taille maximale auto- risée, cette dernière étant paramétrée dans le fichier php.ini : ; Maximum allowed size for uploaded files. upload_max_filesize = 2M • UPLOAD_ERR_FORM_SIZE : la taille du fichier dépasse celle indiquée dans la directive max_file_size qui peut être spécifiée dans le formulaire HTML ; • UPLOAD_ERR_PARTIAL : le fichier a été transféré seulement partiellement ; • UPLOAD_ERR_NO_FILE : aucun fichier n’a été transféré. Tableau 2.3 — Variables décrivant un transfert de fichier (seconde dimension du tableau $_FILES) Nom Description name Nom du fichier sur la machine du client. tmp_name Nom du fichier temporaire sur la machine du serveur. size Taille du fichier, en octets. type Le type MIME du fichier, par exemple « image/gif» error Code d’erreur si le fichier n’a pu être transmis correctement (depuis la version 4.2 de PHP). Exemple 2.22 exemples/TransfertFichier.php : Script de traitement du fichier <?xml version=" 1.0" encoding="iso −8959−1"?> <!DOCTYPE htm l PUBLIC " −/ /W3C / / DTD XHTML 1 . 0 S t r i c t / / EN " "http ://www.w3. org /TR/xhtml1/DTD/xhtml1−strict .dtd"> <html xmlns="http ://www.w3. org/1999/xhtml" xml:lang=" fr "> . formulaire permettant d’entrer le descriptif et de choisir le fichier à transmettre au serveur. Il est très important, pour les formulaires transmettant des fichiers, d’utiliser le mode post et de penser. envoyer des photos stockées sur le serveur avec une petite description, consulter la liste des photos et en récupérer certaines. La première chose à faire est de vérifier que les transferts de fichier. : toutes les chaînes avec une des lettres entre a et f ; 2.3 Mise à jour d’une base par formulaire 89 • [a-zA-Z] : toutes les chaînes avec une lettre de l’alphabet. • [ ∧ 0-9] : toutes les chaînes