lundi 1 avril 2013

Upload PHP

L'upload en PHP est utilisé au travers du web en générale d'une façon très peux sécurisé (la plupart du temps, pas du tout sécurisé).
L'un des problèmes est le manque de mises en garde et d'exemples sécurisé d'upload PHP.
L'upload PHP n'est pas à prendre à la légère; On doit vraiment prendre en compte les risques de sécurités qu'il engendre.

Pour commencer, voici un exemple d'upload PHP très simple qui ne fais aucune vérification de sécurité.
Ne pas utiliser sur un site en production !


<form method="post" enctype="multipart/form-data" action="">
<input type="file" name="fichier" size="30">
<input type="submit" name="upload" value="Uploader">
</form>
<?php
// 1
if( isset($_POST['upload']) )
{
    $content_dir = $_SERVER['DOCUMENT_ROOT'].'/upload_dir/';

    // 2
    if( !is_uploaded_file($_FILES['fichier']['tmp_name']) )
    {
        exit("Le fichier est introuvable");
    }

    // 3
    if( !move_uploaded_file($_FILES['fichier']['tmp_name'], $content_dir . $_FILES['fichier']['name']) )
    {
        exit("Impossible de copier le fichier dans $content_dir");
    }

    echo "Le fichier a bien été uploadé";
}
?>


Explications :
1) On vérifie que le formulaire a bien été validé
2) Upload du fichier
3) déplacement du ficher de sen répertoire temporaire vers le répertoire d'upload de destination



Voyons maintenant un exemple d'upload PHP sécurisé (du moins, beaucoup plus sécurisé)

On vérifie quoi en faite ?
Ceci dépend de vous et de ce que vous voulez en faire, qui va avoir accès aux fichier, etc... Mais en règle générale :

- Extension
- Poids
- Caractères spéciales

Le code PHP d'upload sécurisé :
<form method="post" enctype="multipart/form-data" action="">
    <input type="file" name="fichier" size="30">
    <input type="submit" name="upload" value="Uploader">
</form>
<?php
if($_POST['upload'])
{
    // repertoire où vont être placé les fichiers
    $content_dir = $_SERVER['DOCUMENT_ROOT'].'/upload_dir/';
   
    // ajouter ici les autres extensions autorisé
    $extensions_OK = array('jpg', 'jpeg', 'gif', 'png', 'pdf', 'doc', 'docx', 'etc...');

    // Le nom du fichier ne peux pas être vide
    if(empty($_FILES['fichier']['name'])){
        exit("Aucun fichier sélectionné.");
    }

    // on test si le fichier est uploadé
    if( !is_uploaded_file($_FILES['fichier']['tmp_name']) ){
        exit("Le fichier n'a pas pu être uploadé.");
    }
   
    // récupération de l'extension du fichier
    $ext = strtolower( pathinfo($_FILES['fichier']['name'],  PATHINFO_EXTENSION) );
   
    // est ce que l'extension est valide ?
    if(!in_array($ext, $extensions_OK)) {
        exit("Le format de votre fichier n'est pas autorisé.");
    }

    // renommons le fichier pour plus de sécurité
    // ceci donne un nom de fichier très dur à trouver
    $name_file = md5( uniqid('H', 5) ).'.'.$ext;

    // upload
    if(!move_uploaded_file($tmp_file,$content_dir.$name_file)){
        exit("Impossible de copier le fichier !");
    }else{
        echo "Le fichier a bien été uploadé";
    }

}
?>


Dans cette exemple, on vérifie que le nom du fichier n'est pas vide, que l'extension est bien valide.
Puis, on le renomme pour avoir un nom de fichier très dur à trouver.


Et maintenant, une fonction PHP d'upload avec une utilisation très simple !
<?php
function upload($_files, $destination_rep)
{
    if(!empty($_files['fichier']['tmp_name']) && !empty($_files['fichier']['name']))
    {
        $tmp_file = $_files['fichier']['tmp_name'];

        //on test si l'upload a reussi
        if(!is_uploaded_file($tmp_file))
            exit('Erreur lors de l\'upload.');

        // on va ajouter une chaine pour rendre le nom du fichier unique et pratiquement introuvable.
        $unikifier = md5( uniqid('H', 5) );
       
        // extension du fichier
        $ext = pathinfo($_FILES['fichier']['name'],  PATHINFO_EXTENSION);

        // nettoyage du nom du fichier (on peux pas d'accents ou d'espace)
        $file_name = $unikifier.'.'.$ext;

        //on déplace le fichier vers notre répertoire de destination
        if(!move_uploaded_file($tmp_file, $destination_rep.$file_name))
            exit("Impossible de déplacer le fichier. Upload annulé.");
        else
            return $file_name;
    }
}


$file_dir = './upload_dir/';

if($_POST || $_FILES)
{
    $file = upload($_FILES, $file_dir);
    echo 'Upload terminé : '.$file;
}
else
{
    echo '
    <form method="post" enctype="multipart/form-data" action="">
        <input type="file" name="fichier" size="30">
        <input type="submit" name="upload" value="Uploader">
    </form>'
;
}
?>



On pourrait allez plus loin ? OUI !
Il faudrait définir le répertoire d'upload dans un endroit NON accessible depuis un navigateur web,
renommer complètement le fichier, vérifié que le fichier ne contient pas (DANS le fichier) du code PHP ou autre, vérifié le type MIME et faire une contre vérification avec l'extension.


Bon upload php !

Aucun commentaire:

Enregistrer un commentaire