Uploader des images sur un serveur web
- Par Emacs
- 16 commentaires
- 4 380 lectures
- Format PDF
- RSS - Atom
Beaucoup d'applications web ont recours à des modules d'upload d'images. Parmi elles nous pouvons citer les galleries d'images ou bien encore les systèmes d'avatars de forums type PHPBB, VBulletin ou IPB (pour ne citer que les plus connus). Les programmes permettant ce genre de fonctionnalités peuvent-être parfois très évolués car ils se chargent de contrôler l'intégrité du fichier ou bien même de le redimensionner à la volée.
Le script qui suit montre le fonctionnement d'un système d'upload d'images sur le serveur Web. Ses principales caractéristiques sont les suivantes :
- Il est entièrement configurable grâce aux constantes situées en tête du script.
- Il dispose d'un tableau d'extensions d'image autorisées. Les extensions possibles sont celles acceptées par la fonction getimagesize() de PHP.
- Il crée le répertoire cible s'il n'existe pas.
- Il contrôle l'extension du fichier envoyé.
- Il contrôle le type de l'image.
- Il contrôle les dimensions de l'image (largeur et hauteur).
- Il contrôle le poids de l'image.
- Il upload l'image sur le serveur avec un nouveau nom.
- Il retourne un message de réussite ou d'erreur à l'utilisateur.
- Il est sécurisé.
Le script complet
Script PHP de l'upload d'image<?php/************************************************************* Script realise par Emacs* Crée le 19/12/2004* Maj : 23/06/2008* Licence GNU / GPL* webmaster@apprendre-php.com* http://www.apprendre-php.com* http://www.hugohamon.com** Changelog:** 2008-06-24 : suppression d'une boucle foreach() inutile* qui posait problème. Merci à Clément Robert pour ce bug.**************************************************************//************************************************************* Definition des constantes / tableaux et variables*************************************************************/// Constantes// Tableaux de donnees// Variables$extension = '';$message = '';$nomImage = '';/************************************************************* Creation du repertoire cible si inexistant*************************************************************/exit('Erreur : le répertoire cible ne peut-être créé ! Vérifiez que vous diposiez des droits suffisants pour le faire ou créez le manuellement !');}}/************************************************************* Script d'upload*************************************************************/{// On verifie si le champ est rempli{// Recuperation de l'extension du fichier// On verifie l'extension du fichier{// On recupere les dimensions du fichier// On verifie le type de l'imageif($infosImg[2] >= 1 && $infosImg[2] <= 14){// On verifie les dimensions et taille de l'imageif(($infosImg[0] <= WIDTH_MAX) && ($infosImg[1] <= HEIGHT_MAX) && (filesize($_FILES['fichier']['tmp_name']) <= MAX_SIZE)){// Parcours du tableau d'erreurs&& UPLOAD_ERR_OK === $_FILES['fichier']['error']){// On renomme le fichier// Si c'est OK, on teste l'upload{$message = 'Upload réussi !';}else{// Sinon on affiche une erreur systeme$message = 'Problème lors de l\'upload !';}}else{$message = 'Une erreur interne a empêché l\'uplaod de l\'image';}}else{// Sinon erreur sur les dimensions et taille de l'image$message = 'Erreur dans les dimensions de l\'image !';}}else{// Sinon erreur sur le type de l'image$message = 'Le fichier à uploader n\'est pas une image !';}}else{// Sinon on affiche une erreur pour l'extension$message = 'L\'extension du fichier est incorrecte !';}}else{// Sinon on affiche une erreur pour le champ vide$message = 'Veuillez remplir le formulaire svp !';}}?>
Le formulaire HTML<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr"><head><title>Upload d'une image sur le serveur !</title></head><body><?phpif( !empty($message) ){echo '<p>',"\n";echo "\t\t<strong>", htmlspecialchars($message) ,"</strong>\n";echo "\t</p>\n\n";}?><!-- Debut du formulaire --><form enctype="multipart/form-data" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="post"><fieldset><legend>Formulaire</legend><p><label for="fichier_a_uploader" title="Recherchez le fichier à uploader !">Envoyer le fichier :</label><input type="hidden" name="MAX_FILE_SIZE" value="<?php echo MAX_SIZE; ?>" /><input name="fichier" type="file" id="fichier_a_uploader" /><input type="submit" name="submit" value="Uploader" /></p></fieldset></form><!-- Fin du formulaire --></body></html>
Les commentaires
2. Par Emacs le mercredi 05 décembre 2007 à 13:01
Bonjour,
Qu'appellez-vous "extensions fausses" ? La fonction pathinfo() renvoie la véritable extension du fichier envoyé.
Cordialement.
3. Par Bruno le mercredi 16 janvier 2008 à 00:12
Bonjour .
Bravo pour votre site très soigné .
Bon tuto , mais il manque la protection contre les insertions de code dans la source mème de l'image , seul readfile peut contrer cette ultime attaque .
Bruno
4. Par Emacs le mercredi 16 janvier 2008 à 09:09
Effectivement Bruno ! Je corrige ça dans l'après midi
![]()
5. Par Emacs le mercredi 16 janvier 2008 à 20:08
Correction apportée. L'image est renommée à la volée avec une chaine MD5 aléatoire générée par un uniqid().
6. Par Bruno le jeudi 17 janvier 2008 à 08:08
Oui , en fait , mon post n'a pas un rapport direct avec ton tutoriel .
Il intervient seulement si l'on doit afficher des images du client et dont on ignore l'origine .
http://www.nexen.net/actualites/securite/17226-attaque_par_image_gif.php
Bruno
7. Par Emacs le jeudi 17 janvier 2008 à 09:09
Oui je suis d'accord avec toi. Sachant qu'en plus j'ai lu récemment le livre de Damien Séguy. Il parle de la sécurité des noms de fichiers. On peut effectivement avoir des attaques XSS avec un nom de fichier malsaint.
8. Par bruno le jeudi 17 janvier 2008 à 22:10
Tu pourras effacer ces messages , soit dir en passant .
Je crois qu'on ne s'est pas compris , je parlais de php dans le code mème de l'image , le format gif supporte du code php en son sein . Contre ça , on ne peut rien faire , sauf le lire en désactivant le moindre code .
http://www.phpclasses.org/blog/post/67-PHP-security-exploit-with-GIF-images.html
9. Par Emacs le vendredi 18 janvier 2008 à 00:12
Oui c'est exact avec IE 6. Il faut ouvrir le fichier gif et contrôler qu'il n'y ait pas de code PHP à l'intérieur.
10. Par Mazzu le dimanche 20 janvier 2008 à 02:02
J'ai fait très récemment un script d'upload qui ressemble beaucoup à ça. C'est marrant
Je vais me permettre quelques petites remarques.
- En rapport avec la remarque de Bruno, il faut ou bien faire comme phpclasses.org l'explique ou bien s'assurer que le fichier n'a pas une extension de fichier qui soit interprété par PHP (comme c'est fait ici) ou bien placer les images dans un répertoire à part qui contient un .htaccess avec la ligne : "php_flag engine Off" et s'assurer de ne pas écraser le .htaccess
- Ensuite, juste pour avoir quelque chose de plus propre, j'aurais changé les lignes suivantes,
ligne 49 : if(!empty($_FILES['fichier']['name']) && $_FILES['fichier']['error'] === UPLOAD_ERR_OK)
ligne 58 : $infosImg = @getimagesize($_FILES['fichier']['tmp_name']);
ligne 61 : if($infosImg !== FALSE && $infosImg[2] >= 1 && $infosImg[2] <= 14)
11. Par Emacs le dimanche 20 janvier 2008 à 10:10
Bonjour Mazzu,
Ta solution du .htaccess est pas mal mais ce n'est pas la meilleure. Pour sécuriser encore un peu mieux, il faudrait placer les fichiers uploadés dans un répertoire "hors web". Néanmoins la création de répertoires au dessus de la racine web est très rarement autorisée sur des serveurs mutualisés.
Quant à la constante UPLOAD_ERR_OK, tu viens de me l'apprendreJe vais l'intégrer au script je pense.
Pour la ligne 58, le @ ne sert strictement rien si le serveur est bien configuré pour masquer les erreurs en production.
A la ligne 61, effectivement je n'ai pas vérifié la valeur de retour de la variable $infosImg.
Je te remercie pour ton commentaire constructif Mazzu
Hugo.
12. Par Mazzu le dimanche 20 janvier 2008 à 18:06
You're Welcome !
Pour la constante UPLOAD_ERR_OK, je n'ai rien inventé, tout est là
http://fr3.php.net/manual/fr/features.file-upload.php
13. Par bruno le mardi 22 janvier 2008 à 15:03
Bonjour a vous .
Finalement , la meilleure solution serait d'utiliser le format png a l'instar du gif . Avec le patch png pour IE .
Ce n'est qu'une idée .
Bruno
14. Par rocawear le mardi 29 janvier 2008 à 03:03
Bonjour a vous tous,
j'ai deja subit une attaque dans le passé car les fichier de type .php.ext fonctionais et php les executais.
pour resoudre ce probleme j'ai du faire une cimple condition toute bête !
Voila:
if(preg_match('#php#isU',$fichier)){ // Si le fichier comporte .php.jext, ont renome le php en 484 ( a vous de choisir )
$fichier = str_replace('php','484',$fichier);
}
15. Par Raherivo le vendredi 14 mars 2008 à 13:01
Bonjour à tous,
Je demanderai à vous, donnez moi le code du modification d'upload image s'il vous plaît! je n'en trouvais plus.
Merci beaucoup à bientôt!
16. Par Jeux le mercredi 02 juillet 2008 à 09:09
Merci ce script me sera bien utile, surtout avec toutes les modifications apportées petit à petit


1. Par prout le mardi 04 décembre 2007 à 22:10