Un Script d'upload securisé et complet Par JarodxXx
le mardi 1 juillet 2008, 09:50
Ce billet vous présente une fonction d'upload d'image totalement sécurisé ...
Je n'ai aucun mérite puisque le script ne vient pas de moi, quoi que mon ancien tuto sur le sujet s'en approchait énormément ...
L'auteur original est Emacs
Allons dans le vif du sujet, ici je n'ai rien retouché il s'agit du 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>
<?php
if( !empty($message) )
{
echo '<p>',"
";
echo "\t\t<strong>", htmlspecialchars($message) ,"</strong>
";
echo "\t</p>
";
}
?>
<!-- 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>
Passons aux choses sérieuses, en appelant la fonction QuickUpload() Le fichier posté ira se loger dans le répertoire Upload, en ayant pris soin de vérifier qu'il n'excède pas les 800x800 pour 10Mo, et il sera renommé avec un Uniqid pour ne pas écraser d'éventuelles images déjà uploadées .. Libre à vous de passer en paramètre :
- Le chemin vers le répertoire
- La hauteur maximum
- La largeur maximum
- Le nom de l'image récupérée d'une requête SQL (Mysql_insert_id) pourquoi pas
- La taille limite
[php]<?php
/************************************************************
* Script Original réalise par Emacs
* http://www.apprendre-php.com
* Bidouillé par jarodxxx.com
*************************************************************/
/************************************************************
* Définition des constantes / tableaux et variables
*************************************************************/
function QuickUpload($target = '/upload/' , $width_max='800', $height_max='800' , $max_size = '100000', $new_name = md5( uniqid() ) ) {
// Variables
/*
$target = '/upload/'; // Répertoire cible
$max_size = 100000; // Taille max en octets du fichier
$width_max = 800; // Largeur max de l'image en pixels
$height_max = 800; // Hauteur max de l'image en pixels
$new_name = md5( uniqid() ) ; // Nom de l'image une fois uploadée
*/
// Tableaux de données
$tabExt = array('jpg','gif','png','jpeg'); // Extensions autorisées
$infosImg = array();
// Variables
$extension = '';
$message = '';
$nomImage = '';
/************************************************************
* Création du répertoire cible si inexistant
*************************************************************/
if( !is_dir($target) ) {
if( !mkdir($target, 0755) ) {
exit('Erreur : le répertoire cible ne peut-être créé ! Vérifiez que vous disposiez des droits suffisants pour le faire ou créez-le manuellement !');
}
}
/************************************************************
* Script d'upload
*************************************************************/
if(!empty($_POST)){
// On verifie si le champ est rempli
if( !empty($_FILES['fichier']['name']) ){
// Recuperation de l'extension du fichier
$extension = pathinfo($_FILES['fichier']['name'], PATHINFO_EXTENSION);
// On verifie l'extension du fichier
if(in_array(strtolower($extension),$tabExt)){
// On récupère les dimensions du fichier
$infosImg = getimagesize($_FILES['fichier']['tmp_name']);
// On vérifie le type de l'image
if($infosImg[2] >= 1 && $infosImg[2] <= 14){
// On verifie les dimensions et taille de l'image
if(($infosImg[0] <= $width_max) && ($infosImg[1] <= $height_max) && (filesize($_FILES['fichier']['tmp_name']) <= $max_size)){
// Parcours du tableau d'erreurs
if(isset($_FILES['fichier']['error']) && UPLOAD_ERR_OK === $_FILES['fichier']['error']){
// On renomme le fichier
$nomImage = $new_name .'.'. $extension;
// Si c'est OK, on teste l'upload
if(move_uploaded_file($_FILES['fichier']['tmp_name'], $target.$nomImage)) {
$message = 'Upload réussi !';
}else{
// Sinon on affiche une erreur système
$message = 'Problème lors de l\'upload !';
}
}else{
$message = 'Une erreur interne a empêché l\'upload 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 !';
}
}
} // fin de fonction
?>













Ziki
Dailymotion
Flickr
Technorati
Twitter
1. Le mardi 1 juillet 2008, 20:25 par Rykian
Il me fallait bien une nouvelle tête de turc
Ton script n'est réutilisable que dans un nombre de cas très réduit. Tu l'appelle "Script d'upload sécurisé et complet".
- Upload : ok. Mais c'est juste de l'upload d'image.
- Sécurisé : je ne vois pas en quoi.
- Complet : Bah non, il n'upload que les images.
Alors développeur Web 2.0 toussa toussa... On est pas à l'heure des URL sémantiques ? Pourquoi faire un nom au hasard ? Juste histoire d'utiliser uniqid ?
Qui dit Web 2.0, dit POO aussi (ou plutôt, j'aimerais bien que ce soit le cas). Pourquoi ne pas avoir fait une classe permettant plus de souplesse et avec éventuellement, gestion du cas particulier des images (et pourquoi pas des filigranes).
Et entre nous, ce genre de script, on l'a vu combien de fois au cours de nos pérégrinations sur le web ? Tu crois que c'est réellement intéressant ? -_-
2. Le mardi 1 juillet 2008, 22:30 par jarodxxx
Je vais etre court et precis :
* t'es pas content ne reviens plus .. J'ai deja donné ma dose pour les troll
3. Le mercredi 2 juillet 2008, 12:37 par Shunny
ben Rykian tu a qu'a nous présenté ton script au lieu de critiquer
4. Le mercredi 2 juillet 2008, 14:26 par Front
Bonjour,
Je parcours ce blog depuis maintenant quelques semaines car certains billets sont très intéressants.
En voyant ce billet et le mot sécurisé, j'ai voulu voir les méthodes pour sécuriser l'upload...
Mais à ce que je vois y a pas grand chose... Il faudrait au moins rajouter un endroit pour vérifier le type/mime... Bref j'aurais bien voulu trouvé un nouveau moyen pour sécuriser mon script...
Bonne continuation.
5. Le mercredi 2 juillet 2008, 20:24 par Emacs
@front : il n'y a aucun moyen d'avoir le type mime d'un fichier avec fiabilité. Le meilleur moyen est d'avoir recours à une extension PECL de PHP.
++
6. Le jeudi 3 juillet 2008, 11:18 par Palleas
Dans le cas de l'upload d'image on peut se contenter de faire un getimagesize() :
Si l'accès à filename est impossible ou bien si filename n'est pas une image valide, getimagesize() générera une erreur de niveau E_WARNING. Si une erreur survient lors de la lecture, getimagesize() générera une erreur de niveau E_NOTICE.
7. Le jeudi 3 juillet 2008, 19:56 par Rykian
Une critique constructive est perçue comme un troll ? Intéressant
@Shunny: Que je t'explique 2 secondes. Je suis en train de réaliser une classe de ce type pour les besoins d'une application. Mais moi, je n'ai mis à aucun endroit que j'était développeur Web 2.0. Et quitte a faire quelquechose, voire même reprendre un ancien script, je préfèrerais y ajouter une valeur ajoutée certaine. Et donner mes sources ? Bah oui, bien sur. Ca se saurait si jamais l'OpenSource était une valeur sûre pour les entreprises.
Cela fait plusieurs années que je mine le moral parce que je trouve mon travail trop perfectible, vis à vis de ce que je pensais obtenir. Or, je ne peux vous le cacher, ce blog me donne de l'espoir. De voir des gens travailler tout en ayant un niveau si faible, c'est extrêment salvateur pour un égo en perdition.
Mille mercis et à bientôt
8. Le vendredi 4 juillet 2008, 00:14 par jarodxxx
Cher monsieur de Laval qui dit , et je cite : "je suis inculte" a la case culture ...
Je te prierais de retourner faire joujou avec les RPG et de ne plus revenir.
Qant a ton 1e commentaire (debile) si on pouvais faire une seule et meme fonction qui gererais TOUT les cas de figures , le nombres de paramaetres et/ou traitements serais trop lourd a faire tourner , il faut savoir relativiser .
Je le redit , ne viens plus tes commentaires n'apporte rien , ne donnent aucune solutions ce n'est donc aucunement constructif ... retourne a ton apli elle doit encore avoire des trou ...
9. Le samedi 5 juillet 2008, 07:11 par Olivier
Bon, ben je viens mettre mon grain de sel.
@Rykian : oui, tu as raison dans tes propos, j'ai eu peu ou prou la même réaction en tombant sur ce billet. Mais la manière de présenter les choses est par bien des manières trop agressive. Avec un zeste d'amabilité, les critiques constructives (car tes propos sont censés) seraient certainement mieux perçus. Lorsqu'un bloggeur met une ressource sur le net, il partage une expérience et un vécu propre, et prend du temps pour faire partager ses découvertes aux autres. Je pense que le principe même mérite une forme de respect, que l'on soit d'accord ou non avec les propos tenus.
@jarodxxx : Je suis ravi qu'il y ait un blog francophone de plus sur les technologies web, PHP, Ajax tout ça... J'ai beaucoup de respect pour ceux qui prennent le temps de partager leurs ressources et leurs expérience. En revanche, il faut garder une certaine humilité et du recul dans les propos que l'on tient, car sur le web on s'expose rapidement aux foudres des internautes. La conversation entamée dans les commentaires de ce billet confère hélas à un certain manque de maturité. En même temps, je peux comprendre la frustration à la lecture de certains commentaires, mais il faut arriver à prendre du recul, quitte à supprimer les commentaires injurieux plutôt qu'y répondre en étant encore en colère...
Enfin, pour répondre concrètement aux questions posées dans ce billet :
« Upload : ok. Mais c'est juste de l'upload d'image. » : comment ne pas être d'accord? Le filtre sur les extensions devrait être déplacé en paramètre optionnel à la fonction pour être réutilisable. On est bien sur la même longueur d'onde : on ne va pas créer une seconde fonction d'upload pour permettre d'uploader uniquement des documents word ou excel sous prétexte qu'il y ait trop d'arguments à passer...
« Sécurisé : je ne vois pas en quoi. » : la encore Rykian a raison. Le filtre sur les extensions ne peut être fiable. Il faut au minimum une vérification sur le type mime du fichier.
- « si on pouvais faire une seule et meme fonction qui gererais TOUT les cas de figures , le nombres de paramaetres et/ou traitements serais trop lourd a faire tourner » : c'est justement pour la première raison que Rikian propose une programmation orienté objet. Quant au second argument (trop lourd à faire tourner), je te promets, sans aller plus loin dans les détails, que tu fais erreur...
« ben Rykian tu a qu'a nous présenté ton script au lieu de critiquer » : ben alors justement, j'y vais de ma ressource: http://www.miasmatech.net/scripts/a...
Allez, je conclus en vous souhaitant bonne continuation
10. Le lundi 7 juillet 2008, 17:10 par keo
>Rykian dit : "Et donner mes sources ? Bah oui, bien sur. Ca se saurait si jamais l'OpenSource était une valeur sûre pour les entreprises."
Et symfony alors ?
11. Le lundi 7 juillet 2008, 20:04 par Laura
Merci pour ce script, je vais le tester pour que mes visiteurs puissent proposer des images mais est il vraiment sécurisé ? Les commentaires me font douter. En tout cas merci.
12. Le lundi 7 juillet 2008, 23:46 par Rykian
Bah oui, symfony gagne énormément d'argent...
J'suis pas sur que le support client suffise pour dire que c'est un projet économiquement perein. Ca suffit p'tet pour faire vivre une petite équipe, mais on est pas chez Yahoo (qui les exploitent d'ailleurs).
Et les grosses boîtes qui produisent de l'OpenSource, c'est pas par pure charitée, c'est juste le petit geste pour plaire aux actionnaires comme le don annuel à Green Peace ou aux petits africains alors qu'on utilise des millions de watts par jours avec des clim dans le DataCenter pour tout refroidir
13. Le mardi 8 juillet 2008, 17:10 par Gorgo
Olaaaa c'est la guerre ici ?
Moi je voulais juste dire que j'aime beaucoup ce blog, certains articles sont très sympa d'autre m'interessent moin mais je reviens toujours, donc c'est que le truc est bon à la base non ? :D
Aller, Peace & Love :p
14. Le mardi 8 juillet 2008, 19:05 par Eddy
Ah! Enfin un script que je trouve plus ou moins intéressant pour mon "futur" site.
Donc je confirme, il est bien un minimum sécurisé (htmlspecialchars) il me semble, qui évite de poster des code html (contre le sql mysql_real_escape_string(htmlspecialchars)).
Bon, je suis débutant dans le domaine du code source et j'ai vu cela il y a peu, je peux me tromper et ça ne m'étonnerai pas.
Merci pour ce script sinon.
Eddy.
15. Le mardi 8 juillet 2008, 22:10 par Cyril
Cela fait toujours plaisir de voir des gens travailler pour aider les autres en fournissant des extraits de codes.
Malheureusement tu parles de sécurité sans vraiment y attacher une importance et tu pourrais ainsi tromper des personnes (parfois paranoïac) souhaitant en maximum de sécurité. Même si ton script utilise la fonction getimagesize() qui risque bien de retourner false si le fichier n'est pas une image, tu n'es pas entièrement à l'abri.
Tu pourrais déjà l'améliorer un peu en ajoutant un test de type :
if ($_FILES['fichier']['error'] == UPLOAD_ERR_OK) {
continuer l'exécution
} else {
arrêter l'exécution
}
Bonne continuation,
Cyril
16. Le dimanche 27 juillet 2008, 18:27 par Dopaweb
@Rykian :
Tu as du courage de dire ce que tu penses, et tu m'as évité de dire ce que je pensais sur ce script.
Je critique beaucoup et, généralement, les gens réagissent mal (bah ouais, ils se cassent le cul et on les enfonce).
@Jarodxxx :
Je viens sur ton site régulièrement (je suis abonné au flux rss). Le titre ne correspond pas trop à son contenu. Néanmoins, le reste de ton site est très complet et je l'ai déjà recommandé à plusieurs personnes.
Sur ce, bonne fin de journée à tous bande de geeks.
17. Le lundi 4 août 2008, 18:08 par Reg
Rykian ferme ta gueulle un peu pour voir
"Il me fallait bien une nouvelle tête de turc :)" C'est quoi cette attitude de merde, de compétition, de "je veux impressionner"
Garçon, le PHP au cas ou si tu ne sais pas c'est un langage libre, ou la communauté est la pour s'aider, pas pour se tirer dans les pattes.
Si tu comprend pas ça, retourne coder pour ta petite boite de merde avec ton attitude pourri a souhaiter et rigole de ce qui apprenne à coder, mais rappel toi que tu es passé par la et dis toi que c'est cette attitude même qui fait que même sans te connaitre je suis sur que tu n'as pas d'ami
18. Le mardi 23 septembre 2008, 09:22 par Julien BREUX
[citation]Garçon, le PHP au cas ou si tu ne sais pas c'est un langage libre, ou la communauté est la pour s'aider, pas pour se tirer dans les pattes.[/citation]
+1
19. Le vendredi 29 janvier 2010, 00:49 par Nico
Le terme "sécurisé" sur un script qui ne l'est pas fait un peu titre trompeur.