2.3 Mise à jour d’une base par formulaire 83 pas non plus placer directement un caractère « & » dans un document (X)HTML. On lui préférera la référence à l’entité « & ». Quand l’URL est produite dyna- miquement, on doit lui appliquer la fonction PHP urlEncode() afin d’éviter ces problèmes. Le script principal Pour finir, voici le script principal, affichant la page de la figure 2.5. Toutes les instructions require_once pour inclure les différents fichiers de l’application, ainsi que les déclarations de constantes, ont été placées dans un seul fichier, UtilFilmSimple.php, inclus lui-même dans le script. Cela comprend notamment le fichier contenant la fonction NormalisationHTTP() (voir page 70) pour normaliser les entrées HTTP, que nous utiliserons maintenant systématiquement. Figure 2.5 — Page de mise à jour des films Exemple 2.19 exemples/FilmSimple.php : Script de gestion de la table FilmSimple <?xml version=" 1.0 " encoding=" iso −8959−1"?> <!DOCTYPE ht ml 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 >Opérations sur la table FilmSimple </ title > < link rel=’ stylesheet ’ href="films . css" type="text / css" /> </head> <body> 84 Chapitre 2. Techniques de base <h2>Opérations sur la table <i>FilmSimple </i ></h2> <?php require_once ("UtilFilmSimple .php"); // On normalise les entrées HTTP Normalisation() ; // Tableau "vide" utilisé comme valeurs par défaut pour les // insertions $NULL_FILM = array("titre" => "" , "annee"=>"" ,"nom_realisateur"=>"" , "annee_naissance"=>"","prenom_realisateur"=>""); $connexion = Connexion (NOM, PASSE, BASE, SERVEUR) ; if ( !isSet($_POST[ ’action ’]) and !isSet($_GET[ ’mode’]) ) { // L’exécution n’est pas lancée depuis le formulaire // ou depuis l ’une des ancres créées dans TableauFilms() // donc on affiche le tableau des films . TableauFilms ($connexion) ; // On place une ancre pour ajouter un film echo "<a h r e f = ’ F il m S im p le . php ? mode= " . MODE_INSERTION . "’>Ajouter un film </a>\n" ; } else { / / Tr ai te me nt d e s é v é n e me n t s utilisateurs recueillis par // l ’application if ( i s S e t ($_GET [ ’ mode ’ ] ) ) { // L’utilisateur a cliqué l ’une des ancres permettant de // modifier // ou d’ajouter un film if ($_GET [ ’ mode ’ ] == MODE_MAJ) { // On récupère les données du film à modifier et on affiche // le formulaire pré−rempli à l ’aide de ces données. $slash_titre = mysql_real_escape_string($_GET[ ’ titre ’]) ; $ r e q u e t e = "SELECT ∗ FROM FilmSimple WHERE titre =’ $slash_titre ’"; $resultat = ExecRequete ($requete , $connexion); $film = LigneSuivante ($resultat) ; FormFilmSimple (MODE_MAJ, $film); } else if ( $_GET [ ’ mode ’ ] == MODE_INSERTION) { // On affiche un formulaire de saisie vierge Fo r mF i lm S im p le (MODE_INSERTION, $NULL_FILM ) ; } } else if ( i s S e t ($_POST [ ’ a c t i o n ’ ] ) ) { // L’ utilisateur a saisi des données dans le formulaire pour 2.3 Mise à jour d’une base par formulaire 85 // modifier ou insérer un film , puis a cliqué sur "Exécuter" // On contrôle la saisie , met à jour la base et affiche // le tableau actualisé des films. // Contrôle des données if (ControleFilm ($_POST)) { MAJFilmSimple($_POST[ ’mode ’ ] , $_POST, $connexion) ; TableauFilms ($connexion) ; } } } ?> </body> </html> L’affichage est déterminé par le paramètre $mode (qui indique dans quel mode on doit afficher le formulaire) et par le paramètre $action qui, quand il est présent, indique que le formulaire a été soumis. Quand ces paramètres sont absents, on affiche simplement le tableau et l’ancre d’insertion. Quand $mode vaut MODE_INSERTION, c’est qu’on a utilisé l’ancre d’in- sertion : on appelle le formulaire en lui passant un tableau des valeurs par défaut vide. Quand $mode vaut MODE_MAJ, on sait qu’on reçoit également le titre du film à modifier : on le recherche dans la base et on passe le tableau obtenu à la fonction FormFilmSimple() pour tenir lieu de valeurs par défaut. La variable $action, si elle est définie, indique qu’une mise à jour avec le formulaire a été effectuée. On effectue d’abord différents contrôles avec la fonc- tion ControleFilmSimple() que nous détaillerons par la suite. Si cette fonction renvoie true, ce qui indique qu’il n’y a pas de problèmes, on appelle la fonction MAJFilmSimple() en lui passant le tableau des valeurs provenant du formulaire. Le système obtenu permet d’effectuer des mises à jour (insertions et modifica- tions) en suivant uniquement des URL dans lesquelles on a placé les informations décrivant l’action à effectuer. Il est très représentatif des techniques utilisées cou- ramment pour accéder aux informations dans une base de données et les modifier. L’utilisation des fonctions permet de conserver un code relativement concis, dans lequel chaque action (mise à jour, affichage, contrôle) est bien identifiée et codée une seule fois. Sur le même principe, il est facile d’ajouter, dans le tableau HTML des films, une ancre pour détruire le film. Nous laissons cette évolution au lecteur, à titre d’exercice. FilmSimple.php illustre encore une technique assez courante consistant à utiliser un seul script dans lequel des opérations différentes sont déclenchées en fonction de l’action précédemment effectuée par l’utilisateur. Cette technique peut être assez troublante dans un premier temps puisqu’elle nécessite de se représenter correcte- ment la succession des interactions client/serveur pouvant mener à un état donné. Elle s’avère en pratique très utile, en évitant d’avoir à multiplier le nombre de scripts traitant d’une fonctionnalité bien identifiée. 86 Chapitre 2. Techniques de base Le point faible est la production du formulaire avec valeurs par défaut, assez lourde et qui le serait bien plus encore s’il fallait gérer de cette manière les listes déroulantes. Nous verrons dans le chapitre consacré à la programmation objet comment dévelop- per des outils automatisant dans une large mesure ce genre de tâche. 2.3.2 Validation des données et expressions régulières Revenons une nouvelle et dernière fois sur les contrôles à effectuer lors de la réception des données soumises via un formulaire (voir page 70 pour une première approche). On peut effectuer des contrôles du côté client, avec JavaScript, ou du côté serveur, en PHP. Les contrôles JavaScript sont les plus agréables pour l’uti- lisateur puisqu’il n’a pas besoin d’attendre d’avoir saisi toutes ses données dans le formulaire et de les avoir transmises au serveur pour prendre connaissance des éventuels messages d’erreurs. En revanche la programmation JavaScript n’est pas une garantie puisqu’un esprit malfaisant peut très bien supprimer les contrôles avant de transmettre des informations à votre script. Il est donc indispensable d’ajouter dans tous les cas une validation des données côté serveur. Les exemples qui suivent donnent quelques exemples de contrôles plus avancés que ceux donnés page 70. Nous prenons comme cas d’école la fonction de contrôle ControleFilmSimple() qui doit vérifier la validité des données avant insertion ou mise à jour de la table FilmSimple (voir ce qui précède). Voici tout d’abord la structure de cette fonction : function ControleFilm ($film) { // Ici des contrôles . Si une erreur est rencontrée , la variable // $message est définie // Fin des contrôles , affichage éventuel de $message if ($message) { echo "<b>Erreurs rencontrées :</b><br/>$message"; FormFilmSimple (MODE_INSERTION, $film); return false ; } else return true ; } On prend donc en argument les données à placer dans la table (le tableau associatif $film) et on vérifie que tout est correct. Comment faire si une erreur a été rencontrée ? Une solution brutale est d’afficher le message et de redemander à l’utilisateur toute la saisie. Il faut s’attendre à une grosse colère de sa part s’il doit saisir à nouveau 20 champs de formulaire pour une erreur sur un seul d’entre eux. La solution adoptée ici (et recommandée dans tous les cas) est de réafficher le formulaire avec les données saisies, en donnant également le message indi- quant où la correction doit être faite. Il suffit bien sûr de reprendre la fonction 2.3 Mise à jour d’une base par formulaire 87 FormFilmSimple() (voilà qui devrait vous convaincre de l’utilité des fonctions ?) en lui passant le tableau des valeurs. Suivent quelques contrôles possibles. Existence, type d’une variable, présence d’une valeur Rappelons tout d’abord comment vérifier l’existence des variables attendues. En principe le tableau $film doit contenir les éléments titre, annee, prenom_realisateur, nom_realisateur et annee_naissance. C’est toujours le cas si les données proviennent de notre formulaire de saisie, mais comme rien ne le garantit il faut tester l’existence de ces variables avec la fonction isSet(). if (! isSet ($film [ ’ titre ’ ])) $message = "Pourquoi n’y a−t−il pas de titre ???<br/>" ; Il faut également penser à vérifier que l’utilisateur a bien saisi un champ. Voici le test pour le nom du metteur en scène (l’expression « $a .= $b » est un abrégé pour « $a=$a.$b»). if ( empty($film [ ’nom_realisateur ’]) ) $message .= "Vous devez saisir le nom du metteur en scène<br/> "; Si les variables existent, on peut tester le type avec les fonctions PHP is_string(), is_numeric(), is_float(), etc. (voir annexe C). Voici comment tester que l’année est bien un nombre. if (!is_numeric ($film [ ’annee ’ ])) $message = $message . "L’année doit être un entier : $film [ annee]<br/>" ; Les tests sur le contenu même de la variable sont d’une très grande variété et dépendent fortement de l’application. On pourrait vérifier par exemple que l’année a une valeur raisonnable, que le nom et le prénom débutent par une capitale, ne contiennent pas de caractère blanc en début de chaîne, ne contiennent pas de chiffre, que le metteur en scène est né avant de réaliser le film (!), etc. Une partie des tests, celle qui concerne le format des valeurs saisies, peut s’effec- tuer par des expressions régulières. Validation par expressions régulières Les expressions régulières 4 permettent de définir des « patterns », ou motifs, que l’on peut ensuite rechercher dans une chaîne de caractères (pattern matching). Un exemple très simple, déjà rencontré, est le test d’une occurrence d’une sous-chaîne dans une chaîne avec l’opérateur LIKE de SQL. La requête suivante sélectionne ainsi tous les films dont le titre contient la sous-chaîne « ver ». SELECT * FROM FilmSimple WHERE titre LIKE ’%ver%’ 4. On parle aussi d’expressions rationnelles. . ’application if ( i s S e t ($_GET [ ’ mode ’ ] ) ) { // L’utilisateur a cliqué l ’une des ancres permettant de // modifier // ou d’ajouter un film if ($_GET [ ’ mode ’ ] == MODE_MAJ) { // On récupère. représentatif des techniques utilisées cou- ramment pour accéder aux informations dans une base de données et les modifier. L’utilisation des fonctions permet de conserver un code relativement. pas de caractère blanc en début de chaîne, ne contiennent pas de chiffre, que le metteur en scène est né avant de réaliser le film (!), etc. Une partie des tests, celle qui concerne le format des