Téléversement de fichiers
Dernière mise à jour le 4 novembre 2025
Le formulaire
Pour téléverser un fichier, vous avez besoin d'un formulaire utilisant la méthode POST, ce qui signifie que les données (contenu du fichier) seront transmises dans le corps de la requête HTTP et non dans l'URL comme ce serait le cas avec une requête GET.
<form action="traiter_fichier.php" method="post"> ... </form>
Champ de type file
Ce formulaire doit contenir un champ d'entrée de type file, ce qui fait apparaître une boîte de sélection de fichier :
<form action="traiter_fichier.php" method="post"> Fichier : <input name="fichier" size="35" type="file"> </form>
Sortie (essayez pour voir!) :
Encodage multipart/form-data
Pour que le fichier sélectionné soit téléchargé vers le serveur (téléversé), vous devez absolument spécifier le type de codage des données (enctype) suivant : multipart/form-data.
<form action="traiter_fichier.php" method="post" enctype="multipart/form-data"> Fichier : <input name="fichier" size="35" type="file"> </form>
L'attribut enctype de la balise form spécifie le type de codage utilisé par le navigateur pour envoyer les données au serveur (quand la valeur de l'attribut method est post).
Le tableau suivant indique les types de codage courants :
| Type de codage | Description |
|---|---|
| application/x-www-form-urlencoded |
Les données de formulaire organisées sous la forme de paires nom-valeur. Tous les caractères spéciaux sont encodés. Par exemple, les espaces deviennent des Exemple : Nom: Jean Narrache Age: 33 devient : Nom=Jean+Narrache&Age=33 Il s'agit là du format de codage standard (valeur par défaut avec la méthode POST). |
| multipart/form-data |
Les données de formulaire sont codées sous la forme d'un message comportant une partie distincte pour chacun des champs. Nécessaire en présence de champs d'entrée de type Exemple de formulaire : <form action="http://patoche.org/televerser.php" method="post" enctype="multipart/form-data"> <input type="text" name="texte" value="Le texte"> <input type="file" name="fichier1"> <input type="file" name="fichier2"> <button type="submit">Submit</button> </form> Requête générée :
POST /televerser.php HTTP/1.1
Host: patoche.org
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686;
rv:29.0) Gecko/20100101 Firefox/29.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--ceci-est-le-separateur--
Content-Length: 5540
--ceci-est-le-separateur--
|
| text/plain |
Les données de formulaire sont codées en texte brut, sans aucun contrôle ni caractères de mise en forme Rarement utilisé, sauf pour des fins de test et de débogage. |
Maintenant rassurez-vous : vous n'avez pas besoin de maîtriser ces différents types d'encodages! Retenez seulement que pour le téléversement de fichiers vous devez utiliser multipart/form-data.
MAX_FILE_SIZE
Un champ caché nommé MAX_FILE_SIZE doit précéder le champ input de type file.
Il spécifie la taille maximale en octets d'un fichier pouvant être téléchargé vers le script.
Attention : cette valeur peut être contournée et il est nécessaire de vérifier la taille du fichier transmis une fois celui-ci rendu sur le serveur.
<form action="traiter_fichier.php" method="post" enctype="multipart/form-data"> <input type="hidden" name="MAX_FILE_SIZE" value="50000"> Fichier : <input name="fichier" size="35" type="file"> </form>
Nom du fichier
Enfin, faites attention au nom de l'élément input de type text qui sert à saisir le nom, car c'est lui qui déterminera la clé (indice) dans le tableau associatif $_FILES qui sera utilisé par le script sur le serveur (voir plus loin).
Version complète du formulaire :
<form action="traiter_fichier.php" method="post" enctype="multipart/form-data"> <input type="hidden" name="MAX_FILE_SIZE" value="50000"> Fichier : <input name="fichier" size="35" type="file"> <input type="submit" value="Envoyer le fichier"> </form>
Traitement des fichiers téléversés
À sa réception sur le serveur, un fichier téléversé est stocké sous un nom temporaire dans un répertoire spécifique (ex : "/tmp/phprEXcl3").
Si aucun répertoire de téléversement n'est spécifié dans le fichier de configuration (php.ini), c'est le répertoire des fichiers temporaires du système (/tmp) qui est utilisé.
Les informations qui se rattachent aux fichiers téléversés sont stockées côté serveur dans un tableau à deux dimensions appelé $_FILES.
Exemple :
// informations sur le fichier envoyé via le champ d'entrée "fichier" $_FILES['fichier']['name'] $_FILES['fichier']['type'] ... // informations sur le fichier envoyé via le champ d'entrée "foobar" $_FILES['foobar']['name'] ...
En supposant que le fichier est envoyé via un champ d'entrée appelé "fichier", l'élément $_FILES['fichier']['name'] contiendra par exemple le "vrai" nom du fichier.
L'ensemble des informations disponibles est représenté dans le tableau suivant :
Le bout de code suivant affiche le contenu du fichier reçu :
// si le fichier contient du HTML ou du texte if (($_FILES['fichier']['type'] == "text/html") || ($_FILES['fichier']['type'] == "text/plain")) { // on envoie le contenu dans la sortie standard (le navigateur) readfile($_FILES['fichier']['tmp_name']); } else { echo "Le fichier ne peut être affiché"; }
Pour stocker le fichier dans un répertoire de l'application, il faut utiliser la fonction move_uploaded_file().
Le bout de code suivant déplace le fichier téléchargé dans le répertoire "fichiers" de l'application :
// répertoire où l'application conserve les fichiers téléversés $rep = 'mes_fichiers/'; // nouveau chemin du fichier à conserver $fich = $rep . $_FILES['fichier']['name']; if (move_uploaded_file($_FILES['fichier']['tmp_name'], $fich)) { echo "Le fichier a été déplacé dans " . $fich; } else { echo "Problème lors du déplacement"; }
Pour débogage
Le code suivant affiche toutes les données disponibles sur le fichier téléversé. N'hésitez pas à l'utiliser pour déboguer.
<?php $nom = $_FILES['fichier']['name']; $taille = $_FILES['fichier']['size']; $temp = $_FILES['fichier']['tmp_name']; $type = $_FILES['fichier']['type']; $erreur = $_FILES['fichier']['error']; echo "<pre>"; echo "Nom d'origine : $nom\n"; echo "Taille : $taille octets\n"; echo "Emplacement temporaire : $temp\n"; echo "Type MIME : $type\n"; echo "Code d'erreur : $erreur\n"; echo "</pre>"; ?>
Remarque : le code d'erreur retourné n'est malheureusement pas toujours fiable.
Le code suivant affiche l'état du téléchargement :
<?php
if ($erreur = $_FILES['fichier']['error']) {
echo "Une erreur s'est produite : ";
switch ($erreur) {
case UPLOAD_ERR_INI_SIZE:
echo "le fichier est plus gros que le maximum autorisé";
break;
case UPLOAD_ERR_FORM_SIZE:
echo "le fichier est plus gros qu'indiqué dans le formulaire";
break;
case UPLOAD_ERR_PARTIAL:
echo "le fichier n'a été que partiellement téléversé";
break;
case UPLOAD_ERR_NO_FILE:
echo "aucun fichier n'a été téléversé";
}
} else {
echo "Fichier correctement téléversé";
}
?>
Problèmes courants
Configuration de PHP
Parmi les problèmes rencontrés souvent avec le téléversement, il y a d'abord les valeurs limites imposées par la configuration PHP.
Les valeurs qui peuvent affecter le téléversement, telles que définies dans le fichier php.ini sont :
upload_max_filesizepost_max_sizememory_limitmax_file_uploadsmax_execution_timemax_input_time
On peut vérifier ces valeurs à l'aide de la fonction phpinfo().
Les valeurs typiques de ces constantes sont :
upload_max_filesize = 2M post_max_size = 8M memory_limit = 128M max_file_uploads = 20 max_execution_time = 30 max_input_time = 60
Note personnelle : par le passé j'ai dû jouer avec la valeur des trois premières constantes pour autoriser le téléversement de gros fichiers.
Consultez la documentation pour en savoir plus!
Droits d'écriture
Un autre problème fréquent consiste à oublier d'ouvrir à tous les internautes le répertoire cible de la fonction move_uploaded_file().
La façon la plus facile de régler ce problème est de donner à tous la permission d'écrire (donc de créer des fichiers) dans notre répertoire de téléversement :
$ chmod 777 nom_du_répertoire
Mais cette approche n'est pas sécuritaire puisqu'elle permet à tous les usagers du serveur d'ajouter, modifier ou supprimer des fichiers dans ce répertoire!
La meilleure façon consiste à donner au groupe www-data la propriété de ce répertoire. Le groupe appelé www-data est attribué automatiquement par le serveur à tous les clients.
Si vous êtes un "sudoer" (administrateur du serveur Linux), vous n'avez qu'à effectuer la commande suivante :
$ sudo chgrp www-data nom_du_répertoire
Si ce n'est pas le cas, vous devez procéder indirectement en suivant les étapes suivantes :
-
Donnez temporairement à tous le droit d'écriture dans le répertoire de votre application (on suppose ici que ce répertoire est "/home/usagerXX/public_html/projet/") :
$ chmod 777 projet
Remarque : vous pouvez aussi effectuer cette opération à l'aide du logiciel FileZilla. -
Écrivez un script comme celui-ci pour créer un répertoire de téléchargement et exécutez-le à partir de votre navigateur :
<?php mkdir("/home/usagerXX/public_html/projet/mes_fichiers", 0755); ?>Ce répertoire appartiendra à l'usager et au groupe www-data et pourra donc accueillir sans problème tous les fichiers téléversés.$ cd projet $ ls -l drwxr-xr-x 2 www-data www-data 4096 Nov 2 17:58 mes_fichiers
-
Rétablissez ensuite les permissions sur votre répertoire de projet :
$ cd .. $ chmod 775 projet
Enfin, si notre distribution Linux utilise le module de sécurité SELinux, il faudra changer le contexte de ce répertoire :
sudo chcon -R -t httpd_sys_rw_content_t répertoire
Et voilà! Bon téléversement!
Exercice
Le script suivant permet le téléversement, puis l'affichage d'un fichier texte. Il sera commenté en classe.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Téléversement d'un fichier texte</title>
<style>
.succes { color: green; }
.echec { color: red; }
</style>
</head>
<body>
<h1>Téléversement d'un fichier texte</h1>
<?php
if ($_SERVER['REQUEST_METHOD'] == "POST") {
// s'il s'agit d'un fichier de texte
if ($_FILES['fichier']['type'] == "text/plain") {
// récupération et affichage des informations sur le fichier
echo "<h2>Détails</h2>";
$nom = $_FILES['fichier']['name'];
$taille = $_FILES['fichier']['size'];
$temp = $_FILES['fichier']['tmp_name'];
$type = $_FILES['fichier']['type'];
$erreur = $_FILES['fichier']['error'];
echo "<pre>";
echo "Nom d'origine : $nom\n";
echo "Taille : $taille octets\n";
echo "Emplacement temporaire : $temp\n";
echo "Type MIME : $type\n";
echo "Code d'erreur : $erreur\n";
echo "</pre>";
// on envoie le contenu dans la sortie standard (le navigateur)
echo "<h2>Contenu</h2>";
readfile($_FILES['fichier']['tmp_name']);
// répertoire où l'application conserve les fichiers téléversés
$rep = 'projet/mes_fichiers/';
// nouveau chemin du fichier à conserver
$fich = $rep . $_FILES['fichier']['name'];
if (move_uploaded_file($_FILES['fichier']['tmp_name'], $fich)) {
echo '<p class="succes">Le fichier a été déplacé dans <strong>' . $fich . '</strong></p>';
} else {
echo '<p class="echec">Problème lors du déplacement</p>';
}
} else {
echo '<p class="echec">Le fichier ne peut être affiché</p>';
}
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="50000">
<label id="fich">Fichier texte</label>
<input name="fichier" id="fich" size="35" type="file">
<input type="submit" value="Envoyer le fichier">
</form>
</body>
</html>
Adaptez maintenant ce script pour le téléversement d'images JPG ou PNG.
Points à surveiller :
-
Le type MIME d'un fichier au suffixe "jpg" ou "jpeg" est image/jpeg. Celui d'un fichier au suffixe "png" est image/png.
-
N'oubliez pas l'attribut
altde la baliseimg. Il est obligatoire. -
Utilisez les propriétés CSS
max-widthetmax-heightpour limiter la surface occupée par l'image. Nous verrons bientôt comment réduire la taille réelle de l'image.
Solution :
<?php $titre = "Téléversement d'une image"; ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <title><?= $titre ?>s</title> </head> <body> <h1><?= $titre ?></h1> <?php if ($_SERVER['REQUEST_METHOD'] == "POST") { // s'il s'agit d'un fichier d'une image JPEG ou PNG if ( $_FILES['fichier']['type'] == "image/jpeg" || $_FILES['fichier']['type'] == "image/png") { // répertoire où l'application conserve les fichiers téléversés $repertoire = 'images/'; // nouveau chemin du fichier à conserver $chemin = $repertoire . $_FILES['fichier']['name']; // on déplace le fichier if ( move_uploaded_file($_FILES['fichier']['tmp_name'], $chemin) ) { // affichage de l'image echo '<img src="' . $chemin . '" alt="Une image" style="max-width: 640px; ' . 'max-height: 480px;">'; } else { "<p>Le fichier ne peut être déplacé</p>'"; } } else { echo "<p>L'image ne peut être affichée</p>'"; } } ?> <form action="" method="post" enctype="multipart/form-data"> <input type="hidden" name="MAX_FILE_SIZE" value="1000000"> <label id="fich">Fichier image</label> <input name="fichier" id="fich" size="35" type="file"> <input type="submit" value="Envoyer le fichier"> </form> </body> </html>
Traitement d'image en PHP
Les fichiers téléversés sont souvent des images. Le problème est que ces images, fournies par les utilisateurs, ont souvent des dimensions inappropriées à notre application (trop grandes ou trop petites).
Des images trop petites peuvent nuire à l'esthétique ou rendre le site moins agréable à consulter.
Des images trop grandes, même si leurs dimensions apparentes peuvent être gérées par du code CSS, entraînent des problèmes plus importants :
-
puisque pour une mème résolution (pixels par pouce) une grande image représente un plus grand nombre d'octets, de grandes images nécessitent un plus grand espace de stockage côté serveur;
-
une grande image (gros fichier) prend plus de temps de téléchargement qu'une petite image (petit fichier), rendant ainsi plus important le temps de chargement de la page pour le client.
Le défi est donc de réduire pysiquement (et non seulement en apparence) la taille des images inutilement grandes.
On peut s'attaquer à la résolution de l'image (sa netteté, sa précision) ou à ses dimensions (largeur et hauteur). Nous nous attaquerons ici aux dimensions de l'image.
La bibliothèque GD
GD est une bibliothèque libre servant à manipuler des images dynamiquement, son nom vient de l'anglais gif draw (dessiner un GIF). Cette bibliothèque peut manipuler dynamiquement plusieurs types d'images, tels que les formats AVIF, BMP, GIF, HEIF, JPEG, PNG, TIFF, TGA, WBMP, WebP, XBM et XPM.
Écrite en langage C, GD supporte de nombreux langages dont PHP (elle est disponible sous forme d'extension depuis la version 3.0).
Réduire les dimensions d'une image
Notre objectif ici n'est pas de montrer toutes les possibilités de cette bibliothèque, mais simplement d'expliquer comment redimensionner une images téléversée.
Nous procéderons en trois étapes. La première consiste à créer une image, plus précisément une instance de la classe GdImage :
$chemin = "temporaire/grenouille.jpg"; // création d'un objet GdImage $image = imagecreatefromjpeg($chemin); if (!$image) { // traitement de l'erreur ... }
Bien entendu il existe plusieurs variantes de cette fonction :
- imagecreatefrombmp
- imagecreatefromgif
- imagecreatefrompng
- ...
La deuxième étape consiste à changer l'échelle de l'image (la redimensionner) :
$largeur = 640; // 640 pixels $hauteur = 480; // en spécifiant uniquement la largeur, les proportions seront respectées $image = imagescale($image, $largeur); if (!$image) { // traitement de l'erreur ... } // ici l'image sera possiblement déformée $image = imagescale($image, $largeur, $hauteur); ...
La troisième et dernière étape, en ce qui nous concerne, est de sauvegarder la nouvelle image dans un fichier :
$chemin = "images/9372387780.jpg";
if ( imagejpeg($image, $chemin) ) {
// succès
...
} else {
// échec
...
}
Et voilà! C'est tout ce qu'il faut savoir pour l'instant!
Questions et exercices
Question 1
Donnez intégralement le code d'un formulaire HTML pour le téléversement d'un fichier d'un maximum de 10000 octets vers le script "analyse.php". Assurez-vous de bien comprendre à quoi servent chacun des éléments du formulaire.
Question 2
Le téléversement utilise la méthode...
a) GET
b) POST
c) a ou b
Question 3
Après son téléversement sur le serveur, où se trouve exactement le fichier?
Question 4
Expliquez ce que contient le tableau $_FILES.
Question 5
Donnez le nom de la fonction utilisée par le script (côté serveur) pour récupérer le fichier qui vient d'être téléversé.
Question 6
Donnez le nom du principal fichier de configuration de l'environnement PHP côté serveur.
Question 7
Donnez le nom de la fonction qui permet d'afficher dans une page Web le contenu du fichier de la question précédente.