L'envoi de fichiers


Vous saviez qu'on pouvait aussi envoyer des fichiers grâce aux formulaires ? Vous aurez besoin de lire cette section si vous voulez que vos visiteurs puissent envoyer (on dit aussi uploader) des images, des programmes ou tout autre type de fichier sur votre site.

Cette section est un peu plus complexe que le reste du chapitre. Sa lecture n'est d'ailleurs pas obligatoire pour la bonne compréhension de la suite du cours.
Par conséquent, n'hésitez pas à revenir la lire plus tard, lorsque vous en aurez besoin, si vous ne voulez pas vous attaquer de suite à une partie un peu « difficile ».



Là encore, ça se passe en deux temps.

  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.

Attention : l'envoi du fichier peut être un peu long si celui-ci est gros. Il faudra dire au visiteur de ne pas s'impatienter pendant l'envoi.



On va commencer par créer le formulaire permettant d'envoyer un fichier (une simple page HTML).
Nous verrons ensuite comment traiter l'envoi du fichier côté serveur avec PHP.


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>.

Code : PHP

1

2

3

<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.

Code : PHP 

1

2

3

4

5

6

7

<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>



Voilà, c'est suffisant.

Vous pouvez ajouter d'autres champs plus classiques au formulaire (champ de texte, cases à cocher). Vous pouvez aussi proposer d'envoyer plusieurs fichiers en même temps.
Là, on va se contenter d'un seul champ (envoi de fichier) pour faire simple.


Le traitement de l'envoi en PHP



Comme vous avez dû le remarquer, 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 :

Variable

Signification

$_FILES['monfichier']['name']

Contient le nom du fichier envoyé par le visiteur.

$_FILES['monfichier']['type']

Indique le type du fichier envoyé. Si c'est une image gif par exemple, le type sera image/gif.

$_FILES['monfichier']['size']

Indique la taille du fichier envoyé. Attention : cette taille est en octets. Il faut environ 1 000 octets pour faire 1 Ko, et 1 000 000 d'octets pour faire 1 Mo.
Attention : la taille de l'envoi est limitée par PHP. Par défaut, impossible d'uploader des fichiers de plus de 8 Mo.

$_FILES['monfichier']['tmp_name']

Juste après l'envoi, le fichier est placé dans un répertoire temporaire sur le
serveur en attendant que votre script
PHP décide si oui ou non il accepte de
le stocker pour de bon. Cette variable
contient l'emplacement temporaire du
fichier (c'est PHP qui gère ça).

$_FILES['monfichier']['error']

Contient un code d'erreur permettant de savoir si l'envoi s'est bien effectué ou s'il
y a eu un problème et si oui, lequel. La
variable vaut 0 s'il n'y a pas eu d'erreur.


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.

Code : PHP 

1

2

3

4

5

6

7

<?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'] :

Code : PHP 

 1

 2

 3

 4

 5

 6

 7

 8

 9

10

11

<?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 :

Code : PHP

1

2

3

4

<?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 :

Code : PHP 

 1

 2

 3

 4

 5

 6

 7

 8

 9

10

11

12

13

14

15

16

17

18

<?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']) ;
  • le 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 fonctionbasename qui renverra juste « fichier.png ».

Code : PHP 

 1

 2

 3

 4

 5

 6

 7

 8

 9

10

11

12

13

14

15

16

17

18

19

20

21

<?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.



Pour aller plus loin, je vous recommande de lire le tutoriel de DHKold sur l'upload de fichiers par formulaire qui traite le sujet plus en détail.

Bonne lecture !

Créé avec HelpNDoc Personal Edition: Ne laissez pas les utilisateurs non autorisés consulter vos PDF : découvrez comment définir des mots de passe