En matière de téléchargement la langue française n'est pas assez versatile : seul le mot téléchargement existe, quel que soit le sens. En anglais, upload (vers le serveur) dont il est question ici s'oppose à download (vers le client). Ci-après rien de bien nouveau sous le soleil, si ce n'est la gestion de multiples fichiers qui, à mon grand étonnement, n'a pas beaucoup de succès sur le net.
D'abord le principe de base du formulaire. La balise form reçoit la méthode d'encodage des fichiers enctype='multipart/form-data' qui indique l'utilisation d'un champ de type file. Ce dernier accepte la forme simple name='fichier' mais aussi la forme tableau name='fichier[]' comme l'ensemble des éléments de formulaire, d'ailleurs. Les index du tableau s'incrémentent d'eux même. Un menu ou un champ permet de choisir, au préalable, le nombre de fichiers à télécharger (une fonction javascript pourrait être implémentée afin de rajouter des champs à la volée).
NB : la directive MAX_FILE_SIZE permet d'éviter l'upload de trop gros fichiers, ce qui pourrait mettre le script en danger (timeout). En cas d'erreur, le script l'interprète comme un type incorrect (puisque le fichier a été ignoré par le serveur) sauf si l'on traite l'erreur avec $_FILES['lefichier']['error'].
Tout se fait à travers la lecture du tableau multi-dimensionnel $_FILES. En effet, $_FILES['lefichier'] contient l'index de chaque fichier, lui-même doté des informations propres à ce dernier. Le script traite successivement name, error, size, type et tmp_name. Rendu à sa plus simple expression, il permet juste de renommer le nom de fichier à travers $_POST['lenom'], s'il ce dernier est conforme à $nametype (traitement simplifié là aussi).
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Upload</title>
<meta name="author" content="Pierre Pesty">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<?
/* variables à modifier */
$taillemax = 512000; // taille max d'un fichier (multiple de 1024)
$filetype = "/jpeg|gif/i"; // types de fichiers acceptés, séparés par |
$nametype = "/\.jpeg|\.jpg|\.gif/i"; // extensions correspondantes
$rep = "upload/"; // répertoire de destination
$maxfichier = 10; // nombre maximal de fichiers
/* fin des modifications */
// fichier courant (URI absolue) : formulaire récursif
$PHP_SELF = basename($_SERVER['PHP_SELF']);
if($_POST) {
$msg = array(); // message
$fichier = $_FILES['lefichier']; // simplication du tableau $_FILES
for($i=0; $i<count($fichier['name']); $i++) {
// nom du fichier original = nom par défaut
$nom = $fichier['name'][$i];
// test existence fichier
if(!strlen($nom)) {
$msg[] = "Aucun fichier !";
continue;
}
// si un nouveau nom est renseigné (avec extension correcte)
if(preg_match($nametype, $_POST['lenom'][$i]))
$nom = $_POST['lenom'][$i];
// répertoire de destination
$destination = $rep.$nom;
// test erreur (PHP 4.3)
if($fichier['error'][$i]) {
switch($fichier['error'][$i]) {
// dépassement de upload_max_filesize dans php.ini
case UPLOAD_ERR_INI_SIZE:
$msg[] = "Fichier trop volumineux !"; break;
// dépassement de MAX_FILE_SIZE dans le formulaire
case UPLOAD_ERR_FORM_SIZE:
$msg[] = "Fichier trop volumineux (supérieur à ".(INT)($taillemax/1024)." Mo)"; break;
// autres erreurs
default:
$msg[] = "Impossible d'uploader le fichier !";
}
}
// test taille fichier
elseif($fichier['size'][$i] > $taillemax)
$msg[] = "Fichier $nom trop volumineux : ".$fichier['size'][$i];
// test type fichier
elseif(!preg_match($filetype, $fichier['type'][$i]))
$msg[] = "Fichier $nom de type incorrect : ".$fichier['type'][$i];
// test upload sur serveur (rep. temporaire)
elseif(!@is_uploaded_file($fichier['tmp_name'][$i]))
$msg[] = "Impossible d'uploader $nom";
// test transfert du serveur au répertoire
elseif(!@move_uploaded_file($fichier['tmp_name'][$i], $destination))
$msg[] = "Problème de transfert avec $nom";
else
$msg[] = "Fichier <b>$nom</b> téléchargé avec succès !";
}
// affichage confirmation
for($i=0; $i<=count($msg); $i++)
echo "<p>$msg[$i]</p>";
}
// 1 fichier par défaut (ou supérieur à $maxfichier)
$upload = (isset($_REQUEST['upload']) && $_REQUEST['upload'] <= $maxfichier) ? $_REQUEST['upload'] : 1;
// choix du nombre $upload de fichier(s)
echo "<form action='$PHP_SELF' method='post'>\n";
echo "Quantité <select name='upload' onChange=\"window.open(this.options[this.selectedIndex].value,'_self')\">\n";
for($i=1; $i<=$maxfichier; $i++) {
echo "<option value='$PHP_SELF?upload=$i'";
if($i == $upload) echo " selected";
echo ">$i\n";
}
echo "</select>\n";
echo "<input name='upload' value='$upload' size='3'>\n";
echo "<input type='submit' value='Modifier'></form>\n";
// le formulaire
echo "<form action='$PHP_SELF' enctype='multipart/form-data' method='post'>\n";
// boucle selon nombre de fichiers $upload
for($i=1; $i<=$upload; $i++) {
echo "<p>Nom $i <input name='lenom[]'>\n";
echo "<input type='hidden' name='MAX_FILE_SIZE' value='$taillemax'>";
echo "Fichier <input type='file' name='lefichier[]'></p>\n";
}
?>
<input type='submit' value='Envoyer'>
</form>
</body>
</html>
Dans le cas d'un traitement via une base de données, il s'agira d'affecter un nom automatisé aux fichiers (ex. img_1.jpg, img_2.jpg, etc.) en reportant dans la bdd le nom entré via $_POST['lenom'] ; ce qui autorise alors une totale liberté en terme de syntaxe (donc aucune vérification syntaxique de $nom). Le nom correspondra simplement à l'id de la table, lui même associé à l'id de l'image. Afin de gérer cette automatisation, on récupère l'id après un INSERT par la fonction mysql_insert_id(). Le nom sera composé de $prefixe.$id.$extension. Si l'on veut traiter plusieurs types de fichiers, la variable $extension sera récupérée via $fichier['name'] grâce à l'index 1 de getimagesize().
Et oui, en dehors de ne pas avoir le droit à l'erreur pour le nombre de fichiers, de ne rien savoir du traitement de l'upload (aucun message de la part du serveur), le fait de ne pas pouvoir choisir plusieurs fichiers à la fois - en un clic - est des plus pénibles. En HTML point de salut ! Il faut se tourner vers l'Active-X ou, surtout, vers Java. A ce titre, l'applet JUpload est absolument remarquable. Je l'utilise avec bonheur dans plusieurs sites et son implémentation est très simple. Il s'interface avec divers langages dont, bien sûr, notre ami PHP. Le script ci-dessus peut lui être associé.
Très très bien... Et pour l'insertion dans un base de données, ben suffit de se mettre au boulot les gars... On peut pas toujours tout avoir. C'est déjà super d'avoir une base sur laquelle démarrer...
Euh .. Dites vous demandez tous un exemple d'insertion en BDD ...
Vous savez pas faire un insert sql juste avant le message de confirmation d'upload avec en paramètre le titre du fichier?
Déjà qu'ils vous mache le boulot, lui demandez pas de tout vous faire non plus ;)
Salut,
merci pour cet article, le principe m'a servi à réaliser mon script d'upload multiple en flash et php, NAS Uploader
Pour ceux que ça intéresse ça se trouve ici http://www.nasuploader.com
et c'est gratos et opensource
@+
Très bon script mais un exemple avec une base de données pour min 2 images serait TOP ! Merci d'avance !
Félicitations pour cet article. Il m'a aidé à comprendre le fonctionnement d'un formulaire, surtout avec l'option de télécharger un fichier. Il m'a aussi permis de configurer le mien.
Merci.
tres bon scripte et en attendant la partie d'ansertion au bdd
Ce script est parfait. Seulement, il me laisse sur ma faim car je m'attendais à voir la partie sur le traitement via base de données.
Si tu pouvais la faire (cette partie) là. Merci d'avance.
il existe un mot pour upload = téléversement!;)
Le code insert pour des debutants recherchent cette solutions et pour comprendre le script cela serais sympa merci d'avance
Bonjour et la versions insertion dans une base de donnée dommage quelle ne soit pas de la partie.
salut
http://dev.ppan.net [Document mis à jour le 11.06.2010]