PHPFrance

Discuter de tout ce qui touche au PHP, en français.

Vers le contenu

» Masquer les résultats de la recherche

Recherche dynamique PHPfrance

  1. Effectuez une recherche, les résultats s'afficheront dynamiquement ici.

Upload de fichiers (par HTTP)

Trouvez ici tous les messages de FAQ et les tutoriels de PHPFrance.

Modérateur: ViPHP

Upload de fichiers (par HTTP)

Messagede Flood le 27 Fév 2005, 17:59

Objectifs du tutorial:
- 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!

Configuration du php.ini :
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

Cependant, à moins d'être votre propre hébergeur, vous ne pouvez *a priori* pas modifier le php.ini.

Pour vérifier la configuration proposée par votre hébergeur, écrivez un script contenant uniquement:
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
<?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 :
<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&eacute;lectionner un fichier &agrave; 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
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
<?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 à:
Array
(
    [aFile] => Array
        (
            [name] => chiffrir.exe
            [type] => application/octet-stream
            [tmp_name] => C:\WINDOWS\TEMP\php362.tmp
            [error] => 0
            [size] => 6304
        )

)


Pour chaque champ "file" reçu (ci-dessus, un seul: aFile), vous avez donc 5 propriétés accessibles par $_FILES['aFile']['nom_de_la_propriété']
    - 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:
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
$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
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
$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) :
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
<?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&eacute;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&eacute;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&eacute; correctement.';  

             } else { // error sur move_uploaded_file

               echo 'Le fichier n\'a pas &eacute;t&eacute; upload&eacute; 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&eacute; d&eacute;passe la valeur sp&eacute;cifi&eacute;e

                       pour upload_max_filesize dans php.ini.'
;

              break;

           case UPLOAD_ERR_FORM_SIZE:

              echo 'Le fichier upload&eacute; d&eacute;passe la valeur sp&eacute;cifi&eacute;e

                       pour MAX_FILE_SIZE dans le formulaire d\'upload.'
;

              break;

           case UPLOAD_ERR_PARTIAL:

              echo 'Le fichier n\'a &eacute;t&eacute que partiellement upload&eacute;.';

              break;                            

           default:

              echo 'Aucun fichier n\'a &eacute;t&eacute upload&eacute;.';

         } // switch

       }  

     } else { // aucun fichier reçu

       echo 'Pas de fichier recu';

     }

   } // fin de réception de formulaire

?>



Hope this helps.

/Flood
Flood
ViPHP
ViPHP
 
Messages: 59
Inscription: 07 Fév 2005, 14:37
Localisation: Paris

Publicité

Messagede haugure le 25 Mar 2005, 15:01

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é


C'est exacte mais précisez la toujours tout de meme car si un internaute met un fichier de 20Mo alors que vous etes limité par votre serveur a 2Mo par exemple ca evitera de faire "tomber" votre visiteur sur une page 500.
haugure
Maitre du phpinfo()
 
Messages: 43
Inscription: 08 Fév 2005, 14:23

Messagede Vianney le 11 Avr 2005, 15:37

salut,
bien sympa ton tuto merci :)

par contre je suis en train de me pencher sur la vérification des types de fichiers et je pense que faut changer ton systeme. Par exemple si je renomme mon fichier avec une autre extension ou quoi que ce soit ta vérif passe a coté.

La fonction getimagesize() est interessante (si qq1 a d'autres idées je suis preneur a fond !)
Par exemple si on veut limiter au jpeg et au gif :
Syntaxe: [ Télécharger ] [ Masquer ]
Code php

$infoImg = getimagesize($tempName);

if($infoImg[2] == '1' || $infoImg[2] == '2') {

    //...upload

}

else {

echo 'erreur mauvais fichier uploadé!!'

}

 


des suggestions ?
Vianney
J'ai codé une fonction !
 
Messages: 161
Inscription: 22 Fév 2005, 18:20
Localisation: Lille

Messagede ermelir le 12 Avr 2005, 03:27

salut

la fonction mime_content_typerepondra a tes besoins
http://www.phplibrairies.com: classes, modphp, tutoriaux...
Avatar de l’utilisateur
ermelir
Administrateur PHPfrance
Administrateur PHPfrance
 
Messages: 247
Inscription: 07 Fév 2005, 15:42

Messagede Vianney le 14 Avr 2005, 13:26

oki jvais essayer merci :)
Vianney
J'ai codé une fonction !
 
Messages: 161
Inscription: 22 Fév 2005, 18:20
Localisation: Lille

Messagede flitox le 29 Avr 2005, 10:36

Je suis complètement perdu au niveau de cette ligne là :

$destination_dir = '/var/www/html/upload';


J'ai Wamp5, le dossier de stockage de tous les sites est www, le répertoire d'upload est upload et je n'arrive pas à trouver le bon chemin pour ajouter mes fichiers :shock:

I need some help guys ;)
flitox
Eléphant
 
Messages: 828
Inscription: 09 Fév 2005, 10:55
Localisation: Paris

Messagede cerber le 29 Avr 2005, 11:01

où est le probleme : le $destination_dir c'est toi qui le parametre !
tu peux le faire pointer n'importe où sur l'ordi à condition que apache ait les droits d'écriture.
tu peux mettre $destination_dir = 'C:\\Program Files\\wamp\\upload';
ca marchera nikel
cerber
Administrateur PHPfrance
Administrateur PHPfrance
 
Messages: 408
Inscription: 11 Fév 2005, 01:38

Messagede flitox le 29 Avr 2005, 11:14

J'ai bêtement appliqué le tutorial du manuel PHP mais rien n'y fait :

Syntaxe: [ Télécharger ] [ Masquer ]
Code php
<!-- Le type d'encodage des données, enctype, DOIT être spécifié comme ce qui suit -->

<form enctype="multipart/form-data" action="<?php echo $PHP_SELF; ?>" method="post">

  <!-- MAX_FILE_SIZE doit précéder le champs input de type file -->

  <input type="hidden" name="MAX_FILE_SIZE" value="30000" />

  <!-- Le nom de l'élément input détermine le nom dans le tableau $_FILES -->  

  Envoyez ce fichier : <input name="userfile" type="file" />

  <input type="submit" value="Envoyer le fichier" />

</form>



<?php

// En PHP < 4.1.0, $HTTP_POST_FILES doit être utilisé

//    à la place de $_FILES.



$uploaddir = "D:\\Logiciels\\Wamp\\www\\upload";

$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);



echo '<pre>';

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {

   echo "Le fichier est valide, et a été téléchargé

           avec succès. Voici plus d'informations :\n"
;

} else {

   echo "Attaque potentielle par téléchargement de fichiers.

         Voici plus d'informations :\n"
;

}



echo 'Voici quelques informations de déboguage :';

print_r($_FILES);



echo '</pre>';



?>


J'obtiens cette réponse :

Le fichier est valide, et a été téléchargé
avec succès. Voici plus d'informations :
Voici quelques informations de déboguage :Array
(
[userfile] => Array
(
[name] => README.txt
[type] => text/plain
[tmp_name] => D:/Logiciels/Wamp/tmp\php2AF.tmp
[error] => 0
[size] => 239
)

)
flitox
Eléphant
 
Messages: 828
Inscription: 09 Fév 2005, 10:55
Localisation: Paris

Messagede Damien le 29 Avr 2005, 11:20

Utilises plutôt :

Syntaxe: [ Télécharger ] [ Masquer ]
Code php
$uploaddir = "D:/Logiciels/Wamp/www/upload";
Damien
Administrateur PHPfrance
Administrateur PHPfrance
 
Messages: 1215
Inscription: 07 Fév 2005, 10:57
Localisation: Mougins, ou parfois Gap

Messagede flitox le 29 Avr 2005, 11:25

Bon j'ai trouvé la solution ;)

Il manquait un slash à la fin de D:/Logiciels/Wamp/www/upload

Merci pour l'aide ;)
flitox
Eléphant
 
Messages: 828
Inscription: 09 Fév 2005, 10:55
Localisation: Paris


Retourner vers FAQ et tutoriels

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité

  • Publicité