- comprendre le fonctionnement de l'upload par HTTP,
- mettre en oeuvre une méthode de traitement du fichier uploadé.
Références:
Avant toute chose, ce tutorial n'est peut-être pas exhaustif, et vous devez IMPERATIVEMENT vous réferer à la documentation officielle de PHP sur l'upload de fichiers, disponible à http://www.php.net/manual/fr/features.file-upload.php
Environnement minimal:
PHP 4.1.0 (pour pouvoir utiliser la variable superglobale $_FILES)
Bases de l'upload par HTTP:
Avant toute chose, il faut un formulaire html classique doté d'au moins une balise <input type="file">.
A la soumission de ce formulaire (le mieux par la méthode POST), les différents champs sont envoyés par HTTP au script récepteur et les fichiers sélectionnés à partir de balises <input type="file"> sont uploadés dans un répertoire temporaire du serveur web (voir plus bas).
Il faut alors faire quelques manipulations pour tester que le fichier uploadé répond à certaines conditions ET pour le déplacer du répertoire temporaire vers un répertoire plus adéquat.
Notes préliminaires:
- - Le fichier qui a été uploadé dans le répertoire temporaire sera AUTOMATIQUEMENT détruit à la fin du script de réception du formulaire, s'il n'a pas été renommé ou déplacé!
- Pour effectuer le déplacement du fichier uploadé du répertoire temporaire vers le vrai répertoire destination, il faut s'assurer que le répertoire destination en question EXISTE et EST ACCESSIBLE EN ECRITURE!
Certaines variables du fichier de configuration de PHP (php.ini) permettent une gestion avancée des fichiers uploadés:
- - file_uploads. Autorise (On) ou non (Off) l'upload de fichiers.
- upload_tmp_dir Définit un répertoire temporaire par défaut spécifique à PHP pour l'upload de fichiers. Si cette variable n'est pas définie, le répertoire par défaut du serveur web est utilisé.
- upload_max_filesize Définit la taille maximale autorisée pour fichier à uploader. Au delà de cette limite, il y a génération d'une erreur (voir plus bas). La valeur par défaut est souvent 2M (2 Méga-octets)
- post_max_size Définit la taille maximale autorisée des données envoyées par un formulaire. Influe indirectement sur upload_max_filesize; donc on a toujours post_max_size > upload_max_filesize
Pour vérifier la configuration proposée par votre hébergeur, écrivez un script contenant uniquement:
<?php
phpinfo();
?>
exécutez-le, et recherchez les valeurs des paramètres indiqués plus haut.Note de pjl: A noter qu'il semble y avoir des problèmes avec l'upload chez Free... Sans doute car file_uploads est à Off... Le vérifier par vous-même...
Si vous n'avez pas accès au php.ini, il faut trouver d'autres solutions de supervision de l'upload. C'est ce que nous allons voir dans les prochains sections.
Ecriture des scripts
Définition d'un formulaire destiné à l'upload d'un fichier :
Code : Tout sélectionner
<form name="form" method="post" action="page_receptrice.php" enctype="multipart/form-data">
<!-- Taille maximale en octets. Non sécurisé car facilement contournable !! -->
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Veuillez sélectionner un fichier à uploader:
<input type="file" name="aFile" />
<input type="submit" name="submitFile" value="Envoyer le fichier" />
</form>- - L'attribut enctype définit simplement le type MIME du formulaire; en gros le type de données envoyées par le formulaire. Il est indispensable dans le cas de l'upload de fichiers.
- La balise <input type="hidden" name="MAX_FILE_SIZE"> est facultative; elle définit la taille maximum acceptée d'un fichier à uploader. Mais elle n'assure de rien; elle est facilement countournable et ne constitue donc qu'une maigre mesure de sécurité en soi.
- La balise <input type="file" name="aFile" /> correspond à un champ "Sélectionner le fichier à uploader"
Définition du script en réception (page_receptrice.php) :
Erreurs possibles
Plusieurs types d'erreurs peuvent arriver à la réception ou au traitement du fichier uploadé.
- Première chose, il peut y avoir eu une erreur lors de l'upload.
- Ensuite, le fichier uploadé n'a peut-être pas la bonne taille, ni le bon type, ni la bonne extension.
- Le déplacement du fichier du répertoire temporaire vers le répertoire réel peut engendrer une erreur (répertoire destination non existant ou non accessible en écriture par exemple).
- Le nom réel du fichier original peut contenir des caractères que le système de fichiers du serveur web ne reconnait pas (par exemple, espaces, caractères accentués, etc.)
- Un fichier portant le même nom que le fichier qui va être déplacé vers le bon répertoire existe déjà dans ce même répertoire. Si c'est le cas, la fonction de déplacement utilisée (move_uploaded_files) va écrire par dessus le fichier existant. Afin de conserver des fichiers existants, il vaut donc mieux renommer de manière unique le fichier lors du déplacement.
Il va nous falloir traiter tous ces cas d'erreurs possibles.
La variable superglobale $_FILES
Les champs classiques d'un formulaire sont accessibles à la réception du formulaire en manipulant la variable superglobale $_POST. Les champs de type file sont quand à eux accessibles à partir de la variable superglobale $_FILES.
En d'autres termes, si dans un formulaire, il y a <input type="text" name="unChamp" />, alors $_POST['unChamp'] contiendra la valeur qui aura été saisie.
Si dans ce formulaire, il y a aussi une balise <input type="file" name="unFichier" />, alors c'est $_FILES['unFichier'] qui contiendra des informations sur le fichier uploadé.
Un petit script tout simple comme
<?php
print '<pre>';
print_r($_FILES);
print '</pre>';
?>
vous donnera le contenu d'une telle variable.A l'exécution, vous obtiendrez quelque chose ressemblant à:
Code : Tout sélectionner
Array
(
[aFile] => Array
(
[name] => chiffrir.exe
[type] => application/octet-stream
[tmp_name] => C:\WINDOWS\TEMP\php362.tmp
[error] => 0
[size] => 6304
)
)- - name - Nom du fichier source
- type - Type MIME du fichier source (par exemple: image/png). N'est pas toujours disponible (selon le navigateur)
- tmp_name - Chemin et nom du fichier qui a été uploadé dans un répertoire temporaire du serveur web
- error - Code d'erreur possible lors de l'upload du fichier (voir plus bas)
- size - Taille en octets du fichier uploadé
Code
Une fois que toutes ces informations ont été comprises, il suffit maintenant d'écrire un petit script de gestion d'upload de fichiers par HTTP.
La fonction principale permettant de déplacer le fichier uploadé du répertoire temporaire vers le répertoire final s'appelle move_uploaded_file.
Elle recoit le chemin et le nom du fichier temporaire comme 1er argument, et le répertoire et nom du fichier final après déplacement.
Le transfert s'effectue donc en appelant simplement:
$nouveau_chemin = '/var/www/html/upload/';
move_uploaded_file($_FILES['aFile']['tmp_name'], $nouveau_chemin.$_FILES['aFile']['name']);
A noter que si vous souhaitez renommer le fichier uploadé en "monFichier.png", le code correspondant est
$nouveau_chemin = '/var/www/html/upload/';
move_uploaded_file($_FILES['aFile']['tmp_name'], $nouveau_chemin.'monFichier.png');
Ce script suffit en soi...
Mais comme précisé plus haut, move_uploaded_file peut retourner un code d'erreur (false) et il vaut donc mieux la traiter (ne serait-ce que pour que l'utilisateur ait un message lui disant que l'opération s'est bien passée ou non).
Par ailleurs, si un fichier portant le nom spécifié comme 2ème paramètre existe déjà, php va écrire par dessus... Donc à éviter à tout prix !
Maintenant, voilà un exemple plus complexe mais à peu près complet et sécurisé, prenant en compte toutes les erreurs possibles (listées plus haut) :
<?php
/**
* function formatFileName
* @access public
* @param string - nom de fichier à formater
* @param int - longueur maximale autorisée pour le nom de fichier
* @return string - nom de fichier formaté
* @desc Tronque éventuellement le nom de fichier, le convertit en minuscules et
* y élimine les caractères potentiellement dangereux.
*/
function formatFileName($aFileName, $aMaxLength = 50) {
$aFileName = strToLower(subStr($aFileName, 0, $aMaxLength));
$aFileName = ereg_replace('[^a-zA-Z0-9,._\+\()\-]', '_', $aFileName);
return $aFileName;
} // end of function formatFileName() /2
/* PARAMETRES DE CONFIGURATION DU SCRIPT
*/
// chemin d'accès au répertoire d'upload (vers où le fichier uploadé temporaire sera transféré)
// ce répertoire doit EXISTER et être ACCESSIBLE EN ECRITURE !!
$destination_dir = '/var/www/html/upload';
// taille maximale en octets du fichier à uploader
$file_max_size = 100;
// extensions de fichiers autorisées
$authorized_extensions = array('jpg', 'gif');
/* TRAITEMENT PRINCIPAL
*/
// vérifie l'existence du répertoire de destination
if (!is_dir($destination_dir)) {
echo 'Veuillez indiquer un répertoire destination correct !';
die();
}
// vérifie que répertoire de destination a des droits en écriture
if (!is_writeable($destination_dir)) {
echo 'Veuillez spécifier des droits en écriture pour le répertoire destination !';
die();
}
// réception du formulaire
if (isSet($_POST['submitFile'])) {
// vérifie qu'un fichier a bien été soumis
if (isSet($_FILES) && is_array($_FILES)) {
// pas d'erreur lors de l'upload
if ($_FILES['aFile']['error'] == UPLOAD_ERR_OK) {
// vérifie la taille en octets
if ($_FILES['aFile']['size'] <= $file_max_size) {
// vérifie l'extension du fichier recu
// il est aussi possible (et sans doute mieux) de se baser sur $_FILES['aFile']['type']
// qui retourne le type MIME correspondant (par exemple: image/pjpeg)
$lastPos = strRChr($_FILES['aFile']['name'], ".");
if ($lastPos !== false && in_array(strToLower(subStr($lastPos, 1)), $authorized_extensions)) {
// définit un nom de fichier destination unique à partir du nom du fichier original formaté
$destination_file = time().formatFileName($_FILES['aFile']['name']);
// déplace le fichier uploadé du répertoire temporaire
// vers les répertoire/fichier destination spécifiés
if (move_uploaded_file($_FILES['aFile']['tmp_name'],
$destination_dir.DIRECTORY_SEPARATOR.$destination_file)) {
echo 'Fichier valide et uploadé correctement.';
} else { // error sur move_uploaded_file
echo 'Le fichier n\'a pas été uploadé correctement !';
}
} else { // pas d'extension ou mauvaise extension
echo 'Mauvaise extension !';
}
} else { // Taille maximale dépassée
echo 'Fichier trop volumineux !';
}
} else { // Erreur lors de l'upload
switch ($_FILES['aFile']['error']){
case UPLOAD_ERR_INI_SIZE:
echo 'Le fichier uploadé dépasse la valeur spécifiée
pour upload_max_filesize dans php.ini.';
break;
case UPLOAD_ERR_FORM_SIZE:
echo 'Le fichier uploadé dépasse la valeur spécifiée
pour MAX_FILE_SIZE dans le formulaire d\'upload.';
break;
case UPLOAD_ERR_PARTIAL:
echo 'Le fichier n\'a été que partiellement uploadé.';
break;
default:
echo 'Aucun fichier n\'a été uploadé.';
} // switch
}
} else { // aucun fichier reçu
echo 'Pas de fichier recu';
}
} // fin de réception de formulaire
?>
Hope this helps.
/Flood