Général

Comment uploader un fichier vers son site via http ?

Comme ça revient très souvent sur les forums voici un tutorial extrait de la documentation de php. Celui-ci est basé sur l'exemple d'upload d'image gif d'un poids inférieur à 20ko et une taille inférieure ou égale à 100 x 100 pixel maximum !
Le fichier final sera copié dans le répertoire images_up qui se trouve à la racine du fichier de traitement du formulaire d'upload.

Upload simple

Le formulaire :

<html>
<head>
<title>Upload de fichier</title>
</head>
<body>
<form name="formu" action="traitement.php" method="post" enctype="multipart/form-data">
On remarque qu'il faut ajouter entype="multipart/form-data" pour uploader un fichier
Votre fichier <input type="file" name="fichier" accept="image/gif" /><br/>
<input type="submit" value="Go !!!!" />
</form>
</body>
</html>

Maintenant le traitement du formulaire. Dans ce tutorial les codes sont écrits pour la configuration suivante :

  • Short tags = Off
  • Registers globals = Off

Dans traitement.php nous récupérons les informations de notre fichier dans un tableau super global $_FILES ! celui ci contient :

  • name : le nom de l'image sur l'ordinateur du client
  • tmp_name : le nom temporaire de l'image sur le serveur (depuis la racine du disque)
  • size : la taille en octets du fichier
  • type : le type mime du fichier sélectionné par le client
  • error : l'erreur rapportée par php lors de l'upload de l'image

Voici un exemple de traitement du formulaire précédent :

  1. <?php
  2. if (isset($_FILES['fichier']))
  3. {
  4.     //$_FILES existe on récupère les infos qui nous intéressent
  5.     $fichier=$_FILES['fichier']['name'];//nom réel de l'image
  6.     $size=$_FILES['fichier']['size']; //poids de l'image en octets
  7.     $tmp=$_FILES['fichier']['tmp_name'];//nom temporaire de l'image (sur le serveur)
  8.     $type=$_FILES['fichier']['type'];//type de l'image
  9.     //On récupère la taille de l'image
  10.     list($width,$height)=getimagesize($tmp);
  11.     if (is_uploaded_file($tmp)) //permet de vérifier si le fichier a été uplodé via http
  12.     {
  13.         //vérification du type de l'img, son poids et sa taille
  14.         if ($type=="image/gif" && $size<=20500 && $width<=100 && $height<=100 )
  15.         {
  16.             // type mime gif, poids < à 20500 octets soit environ 20Ko, largeur = hauteur = 100px
  17.             //Pour supprimer les espaces dans les noms de fichiers car celà entraîne une erreur lorsque vous voulez l'afficher
  18.             $fichier = preg_replace ("` `i","",$fichier);//ligne facultative :)
  19.             //On vérifie s'il existe une image qui a le même nom dans le répertoire
  20.             if (file_exists('./images_up/'.$fichier))
  21.             {
  22.                 //Le fichier existe on rajoute dans son nom le timestamp du moment pour le différencier de la première (comme cela on est sûr de ne pas avoir 2 images avec le même nom :) )
  23.                 $nom_final= preg_replace("`.gif`is",date("U").".gif",$fichier);
  24.             }
  25.             else {
  26.                 $nom_final=$fichier; //l'image n'existe pas on garde le même nom
  27.             }
  28.             //on déplace l'image dans le répertoire final
  29.             move_uploaded_file($tmp,'./images_up/'.$nom_final);
  30.             //Message indiquant que tout s'est bien passé
  31.             echo "L'image a été uploadée avec succès<br/>";
  32.         }
  33.         else {
  34.             //Le type mime, ou la taille ou le poids est incorrect
  35.             echo 'Votre image a été rejetée (poids, taille ou type incorrect)';
  36.         }
  37.     }
  38. }
  39. //Pour tester si l'image est bien à sa place
  40. echo '<img src="./images_up/'.$nom_final.'" border="0" />';
  41. echo '<br/>';
  42. echo '<a href="javascript:history.back();">Retour</a>';
  43. ?>

Upload multiple:

Pour l'upload multiple il `suffit` d'utiliser la notation tableau (fichier[]) dans le nom des balises input de type file Le formulaire devient donc :

<html>
<head>
<title>Upload de fichier</title>
</head>
<body>
<form name="formu" action="traitement.php" method="post" enctype="multipart/form-data">
On remarque qu'il faut ajouter entype="multipart/form-data" pour uploader un fichier
fichier 1 <input type="file" name="fichier[]" accept="image/gif" /><br />
fichier 2 <input type="file" name="fichier[]" accept="image/gif" /><br />
fichier 3 <input type="file" name="fichier[]" accept="image/gif" /><br />
fichier 4 <input type="file" name="fichie[]" accept="image/gif" /><br />
fichier 5 <input type="submit" value="Go !!!!" />
</form>
</body>
</html>

Pour le traitement, on utilisera une boucle foreach dans laquelle on vérifiera les informations relatives à nos fichiers et on validera ou non ces fichiers !

  1. <?php
  2. if (isset($_FILES['fichier']))
  3. {
  4.     //$_FILES existe
  5.     foreach ($_FILES['fichier']['name'] as $key => $value) {
  6.         $fichier=$value;//nom reel de l'image
  7.         $size=$_FILES['fichier']['size'][$key]; //poids de l'image en octets
  8.         $tmp=$_FILES['fichier']['tmp_name'][$key];//nom temporaire de l'image (sur le serveur)
  9.         $type=$_FILES['fichier']['type'][$key];//type de l'image
  10.         //On récupère la taille de l'image
  11.         list($width,$height)=getimagesize($tmp);
  12.         if (is_uploaded_file($tmp)) //permet de vérifier si le fichier a été uplodé via http
  13.         {
  14.             //vérification du type de l'img, son poids et sa taille
  15.             if ($type=="image/gif" && $size<=20500 && $width<=100 && $height<=100 )
  16.             {
  17.                 // type mime gif, poids < à 20500 octets soit environ 20Ko, largeur = hauteur = 100px
  18.                 //Pour supprimer les espaces dans les noms de fichiers car celà entraîne une erreur lorsque vous voulez l'afficher
  19.                 $fichier = preg_replace ("` `i","",$fichier);//ligne facultative :)
  20.                 //On vérifie s'il existe une image qui a le même nom dans le répertoire
  21.                 if (file_exists('./images_up/'.$fichier))
  22.                 {
  23.                     //Le fichier existe on rajoute dans son nom le timestamp du moment pour le différencier de la première (comme cela on est sûr de ne pas avoir 2 images avec le même nom :) )
  24.                     $nom_final= preg_replace("`.gif`is",date("U").".gif",$fichier);
  25.                 }
  26.                 else {
  27.                     $nom_final=$fichier; //l'image n'existe pas on garde le même nom
  28.                 }
  29.                 //on déplace l'image dans le répertoire final
  30.                 if (move_uploaded_file($tmp,'./images_up/'.$nom_final)) {
  31.                     //Message indiquant que tout s'est bien passé
  32.                     //Pour le test on affiche l'image
  33.                     echo '<img src="./images_up/'.$nom_final.'" border="0" />';
  34.                     echo '<br/>';
  35.                 }
  36.                 else {
  37.                     //l'image ne peut être déplacée, on supprime le fichier temporaire
  38.                     @ unlink ($tmp);
  39.                     echo 'L\'image n\'a pu être déplacée !';
  40.                 }
  41.  
  42.             }
  43.             else {
  44.                 //Le type mime, ou la taille ou le poids est incorrect
  45.                 echo 'Votre image a été rejetée (poids, taille ou type incorrect)';
  46.             }
  47.         }
  48.     }
  49. }
  50. echo '<a href="javascript:history.back();">Retour</a>';
  51. ?>

Gestion des erreurs d'upload

Les erreurs qui se produisent pendant l'upload sont renseignées par le champ error du tableau $_FILES Les différentes erreurs :

  • 0 : pas d'erreur
  • 1 : le fichier dépasse la taille maximale d'upload autorisée par le webmestre (avec le champ caché MAXFILESIZE)
  • 2 : Votre fichier dépasse la taille maximale demandée par le Webmestre
  • 3 : fichier pas totalement uploadé sur le serveur
  • 4 : aucun fichier téléchargé

Pour effectuer la gestion des erreurs, une petite fonction (afin d'alléger un peu le code)

  1. <?php
  2. function up_error($code,$nom) {
  3.     switch ($code) {
  4.         case '0' : $erreur = 'Pas d\'erreur';$valid = true;break;
  5.         case '1' : $erreur = 'Votre fichier `'.$nom.'` dépasse la taille maximale d\'upload autorisée par PHP( '.get_cfg_var('upload_max_filesize').' )';$valid = false;break;
  6.         case '2' : $erreur = 'Votre fichier dépasse la taille maximale demandée par le Webmestre';$valid = false;break;
  7.         case '3' : $erreur = 'Le fichier n\'a pas été totalement uploadé !!!';$valid = false;break;
  8.         case '4' : $erreur = 'Aucun fichier téléchargé !!!';$valid = false;break;
  9.         default : $erreur = 'L\'upload a rencontré une erreur inconnue !!!';$valid = false; break;
  10.     }
  11.     $return[] = $valid;
  12.     $return[] = $erreur;
  13.     return $return;
  14. }
  15. ?>

Le 1er script avec la gestion d'erreurs :

  1. <?php
  2. if (isset($_FILES['fichier']))
  3. {
  4.     //$_FILES existe on récupère les infos qui nous intéressent
  5.     $fichier=$_FILES['fichier']['name'];//nom réel de l'image
  6.     $size=$_FILES['fichier']['size']; //poid de l'image en octets
  7.     $tmp=$_FILES['fichier']['tmp_name'];//nom temporaire de l'image (sur le serveur)
  8.     $type=$_FILES['fichier']['type'];//type de l'image
  9.     $error = $_FILES['fichier']['error'];
  10.     $retour = up_error($error,$fichier);
  11.     if ($retour[0] === true) {
  12.         //On récupère la taille de l'image
  13.         list($width,$height)=getimagesize($tmp);
  14.         if (is_uploaded_file($tmp)) //permet de vérifier si le fichier a été uploadé via http
  15.         {
  16.             //vérification du type de l'img, son poids et sa taille
  17.             if ($type=="image/gif" && $size<="20500" && $width<="100" && $height<="100" )
  18.             {
  19.                 // type mime gif, poids < à 20500 octets soit environ 20Ko, largeur = hauteur = 100px
  20.                 //Pour supprimer les espaces dans les noms de fichiers car celà entraîne une erreur lorsque vous voulez l'afficher
  21.                 $fichier = preg_replace ("` `i","",$fichier);//ligne facultative :)
  22.                 //On vérifie s'il existe une image qui a le même nom dans le répertoire
  23.                 if (file_exists('./images_up/'.$fichier))
  24.                 {
  25.                     //Le fichier existe on rajoute dans son nom le timestamp du moment pour le différencier de la première (comme cela on est sur de ne pas avoir 2 images avec le meme nom :) )
  26.                     $nom_final= preg_replace("`.gif`is",date("U").".gif",$fichier);
  27.                 }
  28.                 else {
  29.                     $nom_final=$fichier; //l'image n'existe pas on garde le même nom
  30.                 }
  31.                 //on déplace l'image dans le répertoire final
  32.                 move_uploaded_file($tmp,'./images_up/'.$nom_final);
  33.                 //Message indiquant que tout s'est bien passé
  34.                 echo "L'image a été uploadée avec succès<br/>";
  35.             }
  36.             else {
  37.                 //Le type mime, ou la taille ou le poids est incorrect
  38.                 echo 'Votre image a été rejetée (poids, taille ou type incorrect)';
  39.             }
  40.         }
  41.         else {
  42.             echo $retour[1],'<br />';
  43.         }
  44.     }
  45. }
  46. //Pour tester si l'image est bien à sa place
  47. echo '<img src="./images_up/'.$nom_final.'" border="0" />';
  48. echo '<br/>';
  49. echo '<a href="javascript:history.back();">Retour</a>';
  50. ?>

Conclusion

Voilà avec tout cela vous avez de quoi faire un gestionnaire d'upload, sans trop de problèmes. Rappelez-vous de toujours vérifier les informations fournies par l'utilisateur ( $_GET, $_POST, $_COOKIE, $_FILES ....) afin d'éviter au maximum les trous de sécurité.
Pour compléter vous pouvez consulter cette liste de types mime
Ceci n'est pas forcément exclu d'erreur (oublie bête) ils vous est extrêmement conseillé de lire et comprendre le code avant de l'utiliser !

Merci à rafaelle pour son aimable relecture et correction d'orthographe :)