48 Chapitre 1. Introduction à MySQL et PHP Histoire : <input type=’checkbox ’ name=’genre [] ’ value=’H’/> Suspense : <input type=’checkbox ’ name=’genre [] ’ value=’S ’/> </p><p> France : <input type=’radio ’ name=’pays ’ value=’FR’ checked =’1’/> Etats−Unis : <input type=’radio ’ name=’pays ’ value=’US’/> Allemagne : <input type=’radio ’ name=’pays ’ value=’DE’/> Japon : <input type=’radio ’ name=’pays ’ value=’JP ’/> </p> <p> Metteur en scène (prénom − nom) : <input type =’text ’ size =’20’ name="prenom" /> <input type =’text ’ size =’20’ name="nom"> <br /> Année de naiss an ce : <input type=’text ’ size=’4’ maxlength=’4’ name="annee_naissance" value = ’2000 ’/> </p> Résumé : <textarea name=’resume ’ cols =’30’ rows=’3’>Résumé du film </ textarea> <h1>Votre choix</h1> <input type =’submit ’ value=’Insérer ’ name=’inserer ’/> <input type =’submit ’ value=’Modifier ’ name=’modifier ’/> <input type =’submit ’ value=’Détruire ’ name=’detruire ’/> <input type =’reset ’ value=’Annuler ’ / > </form> </body> </html> Il est assez proche de celui de l’exemple 1.2, page 13, avec quelques différences notables. Tout d’abord, le nom du champ genre est genre[]. Comédie : <input type=’checkbox ’ name=’genre [] ’ value=’C’/> Drame : <input type=’checkbox ’ name=’genre [] ’ value=’D’/> Histoire : <input type=’checkbox ’ name=’genre [] ’ value=’H’/> Suspense : <input type=’checkbox ’ name=’genre [] ’ value=’S ’/> Pour comprendre l’utilité de cette notation, il faut se souvenir que les paramètres issus du formulaire sont passés au script sur le serveur sous la forme de paires nom=valeur. Ici on utilise un champ checkbox puisqu’on peut affecter plusieurs genres à un film. Si on clique sur au moins deux des valeurs proposées, par exemple « Histoire » et « Suspense », la chaîne transmise au serveur aura la forme suivante : &genre[]=H&genre[]=S& Pour le script PHP exécuté par le serveur, cela correspond aux deux instructions suivantes : $genre[] = ’H’; $genre[] = ’S’; 1.4 Accès à MySQL avec PHP 49 Imaginons un instant que l’on utilise un nom de variable $genre, sans les crochets []. Alors pour PHP la deuxième affectation viendrait annuler la première et $genre n’aurait qu’une seule valeur, ’S’. La notation avec crochets indique que $genre est en fait un tableau, donc une liste de valeurs. Mieux : PHP incrémente automatiquement l’indice pour chaque nouvelle valeur placée dans un tableau. Les deux instructions ci-dessus créent un tableau avec deux entrées, indicées respective- ment par 0 et 1, et stockant les deux valeurs ’H’ et ’S’. Une autre particularité du formulaire est l’utilisation de plusieurs boutons submit, chacun associé à un nom différent. <input type =’submit ’ value=’Insérer ’ name=’inserer ’/> <input type =’submit ’ value=’Modifier ’ name=’modifier ’/> <input type =’submit ’ value=’Détruire ’ name=’detruire ’/> Quand l’utilisateur clique sur l’un des boutons, une seule variable PHP est créée, dont le nom correspond à celui du bouton utilisé. Le script peut tirer parti de ce mécanisme pour déterminer le type d’action à effectuer. Le script PHP La troisième composante de cette application de mise à jour est le script PHP. Exemple 1.13 exemples/ExMyPHP3.php : Le script de mise à jour de FilmComplet <?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 >Résultat de la mise à jour </title > < link rel=’stylesheet ’ href="films . css" type="text/ css"/> </head> <body> <h1>Résultat de la mise à jour par formulaire </h1> <?php require ("Connect . php" ) ; // Récupération des variables. // Quelques contrôles seraient nécessaires $ t i t r e = $_POST [ ’ t i t r e ’ ] ; $annee = $_POST[ ’annee ’ ]; $pays = $_POST[ ’ pays ’ ]; $prenom = $_POST[ ’prenom ’ ] ; $nom = $_POST [ ’nom ’ ] ; $annee_naissance = $_POST[ ’ annee_naissance ’ ]; $resume = $_POST[ ’resume ’ ]; 50 Chapitre 1. Introduction à MySQL et PHP // Il peut n’y avoir aucun genre saisi if (! i sS et ($_POST [ ’ genr e ’ ] ) ) $genre=array () ; else $genre = $_POST[ ’genre ’ ]; echo "<hr/><h2>\n" ; // Test du type de la mise à jour effectuée if (isSet($_POST[ ’ inserer ’])) echo "Insertion du film $titre "; else if (isSet($_POST[ ’modifier ’ ])) echo "Modification du film $titre" ; else if (isSet($_POST[ ’detruire ’])) echo "Destruction du film $titre "; echo "</h2><hr/>\n"; // Affichage des données du formulaire echo "Titre : $titre <br/> annee: $annee<br/>Pays : $pays<br/>\n" ; // Préparation de la chaîne pour insérer $chaine_genre = ""; $separateur = ""; for ($i=0; $i < count ($genre) ; $i++) { $chaine_genre .= $separateur . $genre[$i ]; $separateur = " ,"; } echo "Genres = $chaine_genre<br/>"; echo "Résumé = $resume<br/>\n" ; echo "Mis en scène par $prenom $nom\n" ; // Connexion à la base , et création de l ’ ordre SQL $connexion = mysql_pconnect (SERVEUR, NOM, PASSE) ; mysql_select_db (BASE, $connexion) ; if (isSet($_POST[ ’ inserer ’])) $requete = "INSERT INTO FilmComplet ( titre , annee , " . "prenom_realisateur , nom_realisateur , annee_naissance , " . "pays , genre , resume) VALUES ( ’ $titre ’ , $annee , " . " ’$prenom ’ , ’$nom ’, $annee_naissance , " . " ’$pays ’, ’$chaine_genre ’ , ’$resume ’) " ; if (isSet($_POST[ ’modifier ’ ])) $requete = "UPDATE FilmComplet SET annee=$annee , " . "prenom_realisateur = ’$prenom ’, nom_realisateur=’$nom ’ , " . "annee_naissance=$annee_naissance , pays=’$pays ’ , " . "genre = ’$chaine_genre ’ , resume=’$resume ’ " ."WHEREtitre=’$titre’"; 1.4 Accès à MySQL avec PHP 51 if ( i s S e t ($_POST [ ’ d e tr u i r e ’ ] ) ) $ r e qu e te = " DELETE FROM FilmComplet WHERE t i t r e = ’ $ t i t r e ’ " ; // Exécution de l ’ordre SQL (un test d’erreur serait bienvenu) $resultat = mysql_query ($requete , $connexion); if ($resultat) echo "<hr/>La requête ’$requete ’ a été effectuée.\n"; else { echo "La requête n ’a pu être exécutée pour la raison suivante :" . mysql_error ($connexion) ; } ?> </body> </html> Ce script procède en plusieurs étapes, chacune donnant lieu à une insertion dans la page HTML fournie en retour au serveur. Tout d’abord, on récupère les paramètres transmis en principe par le formulaire. En pratique rien ne garantit, encore une fois, qu’un utilisateur malicieux ne va pas appeler le script sans utiliser le formulaire et sans même passer un paramètre. Il faudrait tester l’existence des paramètres attendus, si la sécurité était importante. Ce test peut être effectué avec la fonction isSet(), et un exemple est ici donné pour le paramètre genre : // Il peut n’y avoir aucun genre saisi if ( ! i s S e t ($_POST [ ’ g enr e ’ ] ) ) $genre=array () ; else $genre = $_POST[ ’genre ’ ]; Si on constate qu’aucun genre n’est transmis (ce qui peut arriver même si l’on utilise le formulaire puisque ce dernier ne comprend pas de contrôles), on initialise la variable $genre avec un tableau vide (array()). Ce type de contrôle pourrait/de- vrait être effectué pour tous les paramètres : c’est fastidieux mais souvenez-vous qu’un script est un programme en accès libre pour le monde entier On contrôle ensuite le bouton de déclenchement utilisé. Selon le cas, on trouve un élément ’inserer’, ’modifier’,ou’detruire’ dans le tableau $_POST,eton en déduit le type de mise à jour effectué. On l’affiche alors pour informer l’utilisateur que sa demande a été prise en compte. On utilise encore la fonction isSet() de PHP pour tester l’existence d’une variable (ici une entrée dans un tableau). if (isSet($_POST[ ’inserer ’])) echo "Insertion du film $titre "; elseif (isSet ($_POST[ ’modifier ’ ])) echo "Modification du film $titre" ; elseif ( i sS et ($_POST [ ’ d e t r u ir e ’ ] ) ) echo "Destruction du film $titre "; 52 Chapitre 1. Introduction à MySQL et PHP La construction if-elseif permet de contrôler successivement les différentes valeurs possibles. On pourrait aussi utiliser une structure switch, ce qui permettrait en outre de réagir au cas où aucune des variables ci-dessus n’est définie. On récupère ensuite les valeurs provenant du formulaire et on les affiche. La variable $genre est traitée de manière particulière. $chaine_genre = ""; $separateur = ""; for ($i=0; $i < count ($genre) ; $i++) { $chaine_genre .= $separateur . $genre[$i ]; $separateur = " ,"; } echo "Genres = $chaine_genre<br/>"; Notez l’initialisation des variables $chaine_genre et $separateur. PHP peut parfois se montrer assez laxiste et accepter l’utilisation de variables non déclarées, en leur donnant alors la valeur 0 ou la chaîne vide selon le contexte. On peut envisager d’en tirer parti, mais dans certaines configurations – de plus en plus courantes – le niveau de contrôle (défini par l’option error_reporting dans le fichier de configu- ration) est très élevé et ce genre de pratique engendre des messages d’avertissement très désagréables. Mieux vaut donc prendre l’habitude d’initialiser les variables. Rappelons que $genre est un tableau, dont chaque élément correspond à un des choix de l’utilisateur. La fonction count() permet de connaître le nombre d’éléments, puis la boucle for est utilisée pour parcourir un à un ces éléments. Au passage, on crée la variable $chaine_genre, une chaîne de caractères qui contient la liste des codes de genres, séparés par des virgules, selon le format attendu par MySQL. Si, par exemple, on a choisi « Histoire » et « Suspense » $chaine_genre contiendra "H,S". Enfin on construit la requête INSERT, UPDATE ou DELETE selon le cas. Discussion Le script précédent a beaucoup de défauts qui le rendent impropre à une véritable utilisation. Une première catégorie de problèmes découle de la conception de la base de données elle-même. Il est par exemple possible d’insérer plusieurs fois le même film, une mise à jour peut affecter plusieurs films, il faut indiquer à chaque saisie l’année de naissance du metteur en scène même s’il figure déjà dans la base, etc. Nous décrirons dans le chapitre 4 une conception plus rigoureuse qui permet d’éviter ces problèmes. Si on se limite à la combinaison HTML/PHP en laissant pour l’instant de côté la base MySQL, les faiblesses du script sont de deux natures. Pas de contrôles. Aucun test n’est effectué sur les valeurs des données, et en par- ticulier des chaînes vides peuvent être transmises pour tous les champs. De plus, la connexion à MySQL et l’exécution des requêtes peuvent échouer pour des quantités de raisons : cet échec éventuel devrait être contrôlé. . l’instant de côté la base MySQL, les faiblesses du script sont de deux natures. Pas de contrôles. Aucun test n’est effectué sur les valeurs des données, et en par- ticulier des chaînes vides peuvent. ou DELETE selon le cas. Discussion Le script précédent a beaucoup de défauts qui le rendent impropre à une véritable utilisation. Une première catégorie de problèmes découle de la conception de. transmises pour tous les champs. De plus, la connexion à MySQL et l’exécution des requêtes peuvent échouer pour des quantités de raisons : cet échec éventuel devrait être contrôlé.