PHP (PHP Hypertext Preprocessor)

Auteur: Mohamed CHINY Durée necessaire pour le cours de PHP (PHP Hypertext Preprocessor) Niveau recommandé pour le cours de PHP (PHP Hypertext Preprocessor) Supports vidéo non disponibles pour ce cours Exercices de renforcement disponibles pour ce cours Quiz disponible pour ce cours

Page 20: Chargement de fichiers: upload

Toutes les pages

Chargement de fichiers en PHP

Le chargement de fichiers (ou upload) consiste à envoyer des fichiers au serveur. L'opération inverse s'appelle téléchargement (ou download), c'est d'ailleurs la plus connue.

Il est parfois utile, voir important, d'envoyer des fichiers au serveur. Par exemple, ajouter une photo de profil sur facebook, publier une vidéo sur youtube ou joindre une pièce à un email.

Contrairement à ce que l'on peut penser, le chargement de fichier se passe à travers le protocole HTTP et non pas FTP (bien que ce dernier semble plus adapté). Alors, pour prévoir l'upload sur une page Web, il faut renseigner au formulaire qu'en plus du texte qui provient des zones de saisie ou autres champs de formulaire, il y a aussi des fichiers (ou binaires) qui vont être postés.

Le chargement de fichier peut être traité sur deux parties, la partie HTML où on va s’intéresser au formulaire qui accueillera le champ approprié, et la partie PHP où on va voir comment manipuler le fichier posté au serveur.

Partie HTML: le formulaire

Si vous souhaitez prévoir un chargement de fichiers dans un formulaire, alors laissez tomber la méthode GET. En effet seule la méthode POST fonctionne dans ce cas. Mais ce n'est pas tout, car un autre attribut sera mis en valeur, il s'agit de l'attribut enctype qui aura la valeur multipart/form-data.

La balise <form> ressemblera donc à cela:
<form method="post" action="" enctype="multipart/form-data">
</form>

L'attribut enctype désigne le type d'encodage. Bien qu'on n'avait pas l'habitude de le déclarer, il est présent d'une manière implicite avec la valeur par défaut qui est application/x-www-form-urlencoded. Mais quand il s'agit d'upload, il faut le renseigner en lui attribuant la valeur multipart/form-data qui signifie que des fichiers (binaires) vont être inclus aux données postées.

Le champs qui permet naturellement de joindre des fichiers à un document HTML est de type file. Cependant, il y a un autre champ qui va avec (bien qu'il est optionnel), il s'agit d'un champ caché qui a comme nom MAX_FILE_SIZE et comme valeur un entier qui représente la taille maximale du fichier à uploader en octets.

Supposons maintenant que l'on veut créer un formulaire qui nous permettra d'uploader des fichiers dont la taille ne dépasse pas 2 Mo. Le code ressemblerait donc à ceci:
<form method="post" action="" enctype="multipart/form-data">
   <input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
   <input type="file" name="monfichier" /><br />
   <input type="submit" name="valider" value="Uploader" />
</form>
Pour les néophytes, 2 Mo (Méga octets) = 2x106 = 2000000 octets et 2Mio (dite Mébi octets) = 2 x 220 = 2097152 octets
Maintenant qu'on en a fini avec la partie HTML, nous allons nous intéresser à la partie PHP.

Parie PHP: la variable $_FILES

Sachez que vous n'aurez pas forcement besoin de PHP pour réussir l'upload. Le code HTML précédent fait largement l'affaire. Cependant, même si votre fichier est chargé sur le serveur, il n'y est stocké que temporairement. Pour le faire persister, même après l'expiration de la session, on aura donc besoin de PHP.

En PHP, il existe une variable superglobale du nom de $_FILES. Il s'agit d'un tableau associatif à deux dimensions. Il contient donc deux crochets, la première clé est la valeur de l'attribut HTML name du champ de type file et la deuxième peut avoir l'une des 5 valeurs suivantes:
  • name: désigne le nom d'origine du fichier chargé. Il s'agit du nom qu'il a sur le disque dur du client.
  • tmp_name: désigne le nom temporaire donné par serveur au fichier chargé.
  • type: désigne le type et le MIME du fichier chargé (par exemple images/jpeg).
  • size: désigne la taille en octets du fichier chargé.
  • error: désigne le code d'erreur dans le cas où les choses ne se sont pas déroulées comme prévu.

Par exemple $_FILES["monfichier"]["name"] désigne le nom du fichier chargé depuis le formulaire précédent.

Certes, la variable $_FILES permet de faire des traitement important une fois le chargement du fichier effectué sur le serveur, comme par exemple, vérifier le type du fichier, sa taille... Or, pour faire persister le fichier sur le serveur il faut le copier de son emplacement temporaire vers un emplacement de notre choix. Pour ce faire, on peut recourir à la fonction copy() vu dans la partie qui traite les fichiers, ou mieux encore, on se servira de la fonction move_uploaded_file().

La fonction move_uploaded_file($tmp,$pers) permet de copier le fichier temporaire $tmp (qui correspond à la clé tmp_name) dans l’empalement $pers.

Exemple pratique

Supposons que l'on veut permettre aux visiteurs d'uploader des images JPEG ou PNG dont la taille ne dépasse pas 2Mo. Le dossier qui est sensé accueillir les images chargés s'appelle "uploads" et existe dans le même dossier contenant la page PHP à coder. Pour simplifier, on va enregistrer l'image avec son nom d'origine.
Pour simplifier, nous n'allons pas gérer la duplication des noms dans cet exercice. Donc si une image est chargée et qu'il existe déjà une image du même nom, alors celle ci sera remplacée par la nouvelle.
Voici ma version de code:
<?php
   $message="";
   if(isset($_POST["valider"])){
      if(!preg_match("#jpeg|png#",$_FILES["monfichier"]["type"]))
         $message='<span class="nook">Format invalide!</span>';
      elseif($_FILES["monfichier"]["size"]>2000000)
         $message='<span class="nook">Taille trop grande!</span>';
      else{
         $message='Nom du fichier :<b>'.
            $_FILES["monfichier"]["name"].
            '</b><br />';
         $message.='Nom temporaire du fichier :<b>'.
            $_FILES["monfichier"]["tmp_name"].
            '</b><br />';
         $message.='Type du fichier :<b>'.
            $_FILES["monfichier"]["type"].
            '</b><br />';
         $message.='Taille du fichier :<b>'.
            $_FILES["monfichier"]["size"].
            ' octets</b><br />';
         if(move_uploaded_file($_FILES["monfichier"]["tmp_name"],"uploads/".$_FILES["monfichier"]["name"]))
            $message.='<span class="ok">Image chargée avec succès</span>';
      }
   }
?>
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8" />
      <style>
         *{
            font-family:arial, sans-serif;
         }
         .nook{
            color:#DD0000;
         }
         .ok{
            color:#00DD00;
         }
      </style>
   </head>
   <body>
      <form method="post" action="" enctype="multipart/form-data">
         <input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
         <input type="file" name="monfichier" /><br />
         <input type="submit" name="valider" value="Uploader" />
      </form>
      <?php
         echo $message;
      ?>
   </body>
</html>
Bien qu'on a prévu une vérification de la taille maximale à l'aide du champ MAX_FILE_SIZE, on a également prévu une autre vérification à l'aide de PHP. En effet, la première vérification est faite sur le client dont le code peut être manipulé par le visiteur pour nous envoyer ensuite des fichiers plus gros que ce qui est permis.

Notez qu'il existe une directive dans le fichier php.ini qui permet de spécifier la taille maximale des fichiers que l'on peut uploader sur le serveur. Elle ressemble à ceci:
upload_max_filesize = 2M
Vous pouvez modifier sa valeur pour permettre l'upload de fichiers de plus grande taille.

Parfois, il est utile d'agir sur les droits attribués aux utilisateurs sur le fichier chargé. C'est grâce à la fonction chmod().

  • Fonction chmod():

  • La fonction chmod($fichier,$mode) applique le mode $mode au fichier $fichier. Le mode signifie les droits ou les privilèges que possèdent les utilisateurs sur un fichier ou dossier. La variable $mode est exprimée en octal et peut avoir des valeurs qui ressemblent à 0700 ou 0755 etc...

    Parmi les quatre chiffres qui constituent le mode, le premier à gauche est toujours mis à 0, par contre les trois autres peuvent avoir chacun une des valeurs suivantes: 0, 1, 2, 4 ou le résultat de leur addition comme: 3, 5, 6 ou 7
    • 0 signifie aucun privilège
    • 1 signifie droit d’exécution
    • 2 signifie droit d'écriture
    • 4 signifie droit de lecture

    En additionnant ces chiffres on combine les droits associés. Par exemple 6 signifie lecture et écriture (4 + 2), 5 signifie lecture et exécution (4 + 1)...

    Après le 0 de gauche le premier chiffre signifie les droits du propriétaire du fichier ou dossier, le deuxième chiffre les droits des utilisateurs du groupe du propriétaire et le dernier, les droits des autres utilisateurs.

    Exemple:
    chmod("image.jpg",0744);
    signifie que le propriétaire a tous les droits (7=4+2+1), les utilisateurs du groupe ont le droit de le lecture (4) et les autres aussi ont le droit de lecture (4).