Outils pour utilisateurs

Outils du site


php:pth

Transmettre des données avec les formulaires

1. Créer la base du formulaire


Pour insérer un formulaire on utilise l'élément HTML <form>.

<form method="post" action="cible.php">
 <p>
    On insèrera ici les éléments de notre formulaire.
</p>
 </form>

Les attributs les plus importants de l'élément HTML <form> sont :

  • method
  • action

La méthode

C'est ce qui va déterminer la manière d'envoyer les données du formulaire.

  • get: les données transiteront par l'URL et on pourra les récupérer grâce à l'array $_GET[ ]. Avec ce type de méthode on est limité à 256 caractères.
  • post: les données ne transiteront pas par la barre d'URL et elles seront récupérées grâce à à l'array $_POST[ ].. Cette méthode permet d'envoyer autant de données que l'on veut.

Attention : Que l'on utilise la méthode get ou post on ne dois JAMAIS plus faire confiance aux formulaires qu'aux URL !

Dans 99% des cas on utilise la méthode post pour envoyer les données du formulaires.

La cible

L'attribut action sert à définir la page cible, c'est à dire la page qui recevra les données du formulaire et qui sera chargée de les traiter.

Le nom de la page cible est défini grâce à l'attribut action.

Attention : La page cible peut être aussi celle qui envoie les donnée si l'attribut action est réglé comme ceci action=“#

Une fois de plus on fait du Ping-Pong :-)

2. Les éléments du formulaire


Dans un formulaire on peut insérer pas mal d'éléments différents comme :

  • zones de texte
  • boutons
  • cases à cocher
  • etc …

Mais pour ces différents type de formulaires il y a deux attributs à connaître obligatoirement :

  • name : (obligatoire): c'est le nom de la zone de texte, du bouton, de la case à cocher ou va venir se mettre le ou la donnée(s) qui sera envoyées lors de la méthode
  • value: (facultatif) : ce que contient la zone de texte au départ (par défaut elle est vide), la valeur du bouton, la case à cocher par défaut …


Les petites zones de texte

<form action="cible.php" method="post">
<p>
    <input type="text" name="prenom" />
    <input type="submit" value="Valider" />
</p>
</form>

Rappel de HTML : le champ <input type=“submit” /> permet de créer le bouton de validation du formulaire qui commande l'envoi des données, et donc la redirection du visiteur vers la page cible.


Les grandes zone de textes

<textarea name="message" rows="8" cols="45">
Votre message ici.
</textarea>

Les attributs rows et cols permettent de définir la taille de la zone de texte en hauteur et en largeur respectivement.


La liste déroulante

<select name="choix">
    <option value="choix1">Choix 1</option>
    <option value="choix2">Choix 2</option>
    <option value="choix3">Choix 3</option>
    <option value="choix4">Choix 4</option>
</select>

Vous pouvez aussi définir le choix par défaut de la liste. Normalement c'est le premier, mais si vous rajoutez l'attribut selected=“selected” à une balise <option>, alors ce sera le choix par défaut.


Les cases à cocher

<input type="checkbox" name="case" id="case" /> <label for="case">Ma case à cocher</label>

L'utilisation de la balise <label> n'est pas obligatoire mais je la recommande fortement. Elle permet d'associer le libellé à la case à cocher qui a le même id que son attribut for, ce qui permet de cliquer sur le libellé pour cocher la case. On y gagne donc en ergonomie.

Là encore, on donne un nom à la case à cocher via l'attribut name (ici : « case »).
Ce nom va générer une variable dans la page cible, par exemple $_POST['case'].

  • Si la case a été cochée, alors $_POST['case'] aura pour valeur « on ».
  • Si elle n'a pas été cochée, alors $_POST['case'] n'existera pas.

Vous pouvez faire un test avec isset($_POST['case']) pour vérifier si la case a été cochée ou non.

Les boutons d'option

<input type="radio" name="frites" value="oui" id="oui" checked="checked" /> <label for="oui">Oui</label>
<input type="radio" name="frites" value="non" id="non" /> <label for="non">Non</label>


Les champs cachés

<input type="hidden" name="pseudo" value="Mateo21" />

On croit par erreur que, parce que ces champs sont cachés, le visiteur ne peut pas les voir. C'est faux ! En effet, n'importe quel visiteur peut afficher le code source de la page et voir qu'il y a des champs cachés en lisant le code HTML.
Mieux, il peut même modifier la valeur du champ caché s'il a les outils appropriés.
Que faut-il retenir ? Ce n'est pas parce que le champ est caché que vous devez considérer qu'il est inviolable. N'importe quel visiteur (un peu malin) peut le lire, modifier sa valeur et même le supprimer.
Ne faites pas confiance aux données envoyées par le visiteur !

3. La faille XSS


Never trust user input

La règle d'or: Ne jamais faire confiance au visiteur, aux données d'URL, aux données de formulaire !

Comment exploiter une faille?

Vu qu'un utilisateur peut avoir accès aux code HTML avec un simple clic droit “Afficher la source” ou en utilisant sous Mozilla le plugin “Firebug” lui permettant de lire et de modifier le code HTML, cela lui permet de:

  • récupérer les données du formulaire
  • modifier en live les données du formulaire (outils firebug, etc…)
  • de copier le formulaire d'envoi autre part sur sa propre machine ou sur une machine zombie sur puis en modifiant l'attribut action mettre la destination complète de la page cible à attaquer
  • créer un formulaire et d'utiliser des dictionnaires pour une attaque par brute force
  • d'injecter du code dans les champs formulaire et de les envoyer à la pas cible

C'est quoi la faille XSS

XSS pour: pour cross-site scripting, est une faille qui permet d'injecter du code HTML contenant du JavaScript dans vos pages pour le faire exécuter à vos visiteurs mais également du code SQL permettant d’interroger la base de données si les variables ne sont pas protégés.

Résoudre la faille XSS en échappant le code HTML

C'est facile : il faut protéger le code HTML en l'échappant, c'est-à-dire en affichant les balises (ou en les retirant) plutôt que de les faire exécuter par le navigateur.

Pour échapper le code HTML, il suffit d'utiliser la fonction htmlspecialchars() qui va transformer les chevrons des balises HTML <> en &lt; et &gt; respectivement.
Cela provoquera l'affichage de la balise plutôt que son exécution.

<p>Je sais comment tu t'appelles, hé hé. Tu t'appelles <?php echo htmlspecialchars($_POST['prenom']); ?> !</p>

Il faut penser à utiliser cette fonction sur tous les textes envoyés par l'utilisateur qui sont susceptibles d'être affichés sur une page web.
Sur un forum par exemple, il faut penser à échapper les messages postés par vos membres, mais aussi leurs pseudos (ils peuvent s'amuser à y mettre du HTML !) ainsi que leurs signatures.
Bref, tout ce qui est affiché et qui vient à la base d'un visiteur, vous devez penser à le protéger avec la fonction htmlspecialchars().
htmlspecialchars() — Convertit les caractères spéciaux en entités HTML

Si vous préférez retirer les balises HTML que le visiteur a tenté d'envoyer plutôt que de les afficher, utilisez la fonction strip_tags().
strip_tags() — Supprime les balises HTML et PHP d'une chaîne


4. L'envoi de fichiers avec un formulaire


Comment cela se passe ?

  1. Le visiteur arrive sur votre formulaire et le remplit (en indiquant le fichier à envoyer).
    Une simple page HTML suffit pour créer le formulaire.
  2. PHP réceptionne les données du formulaire et, s'il y a des fichiers dedans, il les « enregistre » dans un des dossiers du serveur.

Procédure :

a. Le formulaire d'envoi de fichier

Dès l'instant où votre formulaire propose aux visiteurs d'envoyer un fichier, il faut ajouter l'attribut enctype=“multipart/form-data” à la balise <form>.

<form action="cible_envoi.php" method="post" enctype="multipart/form-data">
<p>Formulaire d'envoi de fichier</p>
</form>

Grâce à enctype, le navigateur du visiteur sait qu'il s'apprête à envoyer des fichiers.

Maintenant que c'est fait, nous pouvons ajouter à l'intérieur du formulaire une balise permettant d'envoyer un fichier.
C'est une balise très simple de type <input type=“file” />. Il faut penser comme toujours à donner un nom à ce champ de formulaire (grâce à l'attribut name) pour que PHP puisse reconnaître le champ par la suite.

<form action="cible_envoi.php" method="post" enctype="multipart/form-data">
  <p>
    Formulaire d'envoi de fichier :<br />
    <input type="file" name="monfichier" /><br />
    <input type="submit" value="Envoyer le fichier" />
  </p>
</form>

On peut ajouter d'autres champs plus classiques au formulaire (champ de texte, cases à cocher).
On peut aussi proposer d'envoyer plusieurs fichiers en même temps. :-)


b. Le traitement de l'envoi en PHP

le formulaire pointe vers une page PHP qui s'appelle cible_envoi.php. Le visiteur sera donc redirigé sur cette page après l'envoi du formulaire.

C'est maintenant que ça devient important. Il faut que l'on écrive le code de la page cible_envoi.php pour traiter l'envoi du fichier.

« Traiter l'envoi du fichier » ? C'est-à-dire ?
Si le fichier a été envoyé sur le serveur c'est bon, non ?
Qu'est-ce que PHP aurait besoin de faire ?

En fait, au moment où la page PHP s'exécute, le fichier a été envoyé sur le serveur mais il est stocké dans un dossier temporaire.
C'est à vous de décider si vous acceptez définitivement le fichier ou non. Vous pouvez par exemple vérifier si le fichier a la bonne extension (si vous demandiez une image et qu'on vous envoie un « .txt », vous devrez refuser le fichier).

Si le fichier est bon, vous l'accepterez grâce à la fonction move_uploaded_file(), et ce, d'une manière définitive.

Mais comment je sais si « le fichier est bon » ?

Pour chaque fichier envoyé, une variable $_FILES['nom_du_champ'] est créée. Dans notre cas, la variable s'appellera $_FILES['monfichier'].
Cette variable est un tableau qui contient plusieurs informations sur le fichier :

Si vous avez mis un second champ d'envoi de fichier dans votre formulaire, il y aura une seconde variable $_FILES['nom_de_votre_autre_champ'] découpée de la même manière que le tableau qu'on vient de voir ici.
$_FILES['nom_de_votre_autre_champ']['size'] contiendra donc la taille du second fichier, et ainsi de suite.

Je vous propose de faire les vérifications suivantes pour décider si l'on accepte le fichier ou non.

  1. Vérifier tout d'abord si le visiteur a bien envoyé un fichier (en testant la variable $_FILES['monfichier'] avec isset() ) et s'il n'y a pas eu d'erreur d'envoi (grâce à $_FILES['monfichier']['error']).
  2. Vérifier si la taille du fichier ne dépasse pas 1 Mo par exemple (environ 1 000 000 d'octets) grâce à $_FILES['monfichier']['size'].
  3. Vérifier si l'extension du fichier est autorisée (il faut interdire à tout prix que les gens puissent envoyer des fichiers PHP, sinon ils pourraient exécuter des scripts sur votre serveur). Dans notre cas, nous autoriserons seulement les images (fichiers .png, .jpg, .jpeg et .gif). \\Nous analyserons pour cela la variable $_FILES['monfichier']['name'].
    Nous allons donc faire une série de tests dans notre page cible_envoi.php.

1. Tester si le fichier a bien été envoyé

On commence par vérifier qu'un fichier a été envoyé. Pour cela, on va tester si la variable $_FILES['monfichier'] existe avec isset().
On vérifie dans le même temps s'il n'y a pas d'erreur d'envoi.

<?php
// Testons si le fichier a bien été envoyé et s'il n'y a pas d'erreur
if (isset($_FILES['monfichier']) AND $_FILES['monfichier']['error'] == 0)
{
}
?>

2. Vérifier la taille du fichier

On veut interdire que le fichier dépasse 1 Mo, soient environ 1 000 000 d'octets (j'arrondis pour simplifier). On doit donc tester $_FILES['monfichier']['size'] :

<?php
// Testons si le fichier a bien été envoyé et s'il n'y a pas d'erreur
if (isset($_FILES['monfichier']) AND $_FILES['monfichier']['error'] == 0)
{
        // Testons si le fichier n'est pas trop gros
        if ($_FILES['monfichier']['size'] <= 1000000)
        {
 
        }
}
?>

3. Vérifier l'extension du fichier

On peut récupérer l'extension du fichier dans une variable grâce à ce code :

<?php
$infosfichier = pathinfo($_FILES['monfichier']['name']);
$extension_upload = $infosfichier['extension'];
?>

La fonction pathinfo() renvoie un array contenant entre autres l'extension du fichier dans $infosfichier['extension']. On stocke ça dans une variable $extension_upload.

Une fois l'extension récupérée, on peut la comparer à un tableau d'extensions autorisées (un array) et vérifier si l'extension récupérée fait bien partie des extensions autorisées à l'aide de la fonction in_array().

Ouf ! On obtient ce code au final :

<?php
// Testons si le fichier a bien été envoyé et s'il n'y a pas d'erreur
if (isset($_FILES['monfichier']) AND $_FILES['monfichier']['error'] == 0)
{
        // Testons si le fichier n'est pas trop gros
        if ($_FILES['monfichier']['size'] <= 1000000)
        {
                // Testons si l'extension est autorisée
                $infosfichier = pathinfo($_FILES['monfichier']['name']);
                $extension_upload = $infosfichier['extension'];
                $extensions_autorisees = array('jpg', 'jpeg', 'gif', 'png');
                if (in_array($extension_upload, $extensions_autorisees))
                {
                }
        }
}
?>

4. Valider l'upload du fichier

Si tout est bon, on accepte le fichier en appelant move_uploaded_file(). Cette fonction prend deux paramètres :

  • le nom temporaire du fichier (on l'a avec $_FILES['monfichier']['tmp_name']) ;l
  • e chemin qui est le nom sous lequel sera stocké le fichier de façon définitive. On peut utiliser le nom d'origine du fichier $_FILES['monfichier']['name'] ou générer un nom au hasard.

Je propose de placer le fichier dans un sous-dossier « uploads ».
On gardera le même nom de fichier que celui d'origine. Comme $_FILES['monfichier']['name'] contient le chemin entier vers le fichier d'origine (C:\dossier\fichier.png par exemple), il nous faudra extraire le nom du fichier. On peut utiliser pour cela la fonction basename() qui renverra juste « fichier.png ».

<?php
// Testons si le fichier a bien été envoyé et s'il n'y a pas d'erreur
if (isset($_FILES['monfichier']) AND $_FILES['monfichier']['error'] == 0)
{
        // Testons si le fichier n'est pas trop gros
        if ($_FILES['monfichier']['size'] <= 1000000)
        {
                // Testons si l'extension est autorisée
                $infosfichier = pathinfo($_FILES['monfichier']['name']);
                $extension_upload = $infosfichier['extension'];
                $extensions_autorisees = array('jpg', 'jpeg', 'gif', 'png');
                if (in_array($extension_upload, $extensions_autorisees))
                {
                        // On peut valider le fichier et le stocker définitivement
                        move_uploaded_file($_FILES['monfichier']['tmp_name'], 'uploads/' . basename($_FILES['monfichier']['name']));
                        echo "L'envoi a bien été effectué !";
                }
        }
}
?>

Lorsque vous mettrez le script sur Internet à l'aide d'un logiciel FTP, vérifiez que le dossier « uploads » sur le serveur existe et qu'il a les droits d'écriture. Pour ce faire, sous FileZilla par exemple, faites un clic droit sur le dossier et choisissez « Attributs du fichier ». Cela vous permettra d'éditer les droits du dossier (on parle de CHMOD). Mettez les droits à 733, ainsi PHP pourra placer les fichiers uploadés dans ce dossier.

Ce script est un début, mais en pratique il vous faudra sûrement encore l'améliorer. Par exemple, si le nom du fichier contient des espaces ou des accents, ça posera un problème une fois envoyé sur le Web. D'autre part, si quelqu'un envoie un fichier qui a le même nom que celui d'une autre personne, l'ancien sera écrasé !

La solution consiste en général à « choisir » nous-mêmes le nom du fichier stocké sur le serveur plutôt que de se servir du nom d'origine. Vous pouvez faire un compteur qui s'incrémente : 1.png, 2.png, 3.jpg, etc.

Soyez toujours très vigilants sur la sécurité, vous devez éviter que quelqu'un puisse envoyer des fichiers PHP sur votre serveur.

En résumé

  • Les formulaires sont le moyen le plus pratique pour le visiteur de transmettre des informations à votre site. PHP est capable de récupérer les données saisies par vos visiteurs et de les traiter.
  • Les données envoyées via un formulaire se retrouvent dans un array $_POST.
  • De la même manière que pour les URL, il ne faut pas donner sa confiance absolue aux données que vous envoie l'utilisateur. Il pourrait très bien ne pas remplir tous les champs voire trafiquer le code HTML de la page pour supprimer ou ajouter des champs. Traitez les données avec vigilance.
  • Que ce soit pour des données issues de l'URL ($_GET) ou d'un formulaire ($_POST), il faut s'assurer qu'aucun texte qui vous est envoyé ne contient du HTML si celui-ci est destiné à être affiché sur une page. Sinon, vous ouvrez une faille appelée XSS qui peut être néfaste pour la sécurité de votre site.
  • Pour éviter la faille XSS, il suffit d'appliquer la fonction htmlspecialchars() sur tous les textes envoyés par vos visiteurs que vous afficherez.
  • Les formulaires permettent d'envoyer des fichiers. On retrouve les informations sur les fichiers envoyés dans un array $_FILES. Leur traitement est cependant plus complexe.

Retour d'un niveau
Retour à l'accueil

php/pth.txt · Dernière modification : de 127.0.0.1