59 votes

<script> Sctipt de téléchargement d'images sécurisé complet </script>

Je ne sais pas si cela va se produire, mais je vais essayer.

Pendant l'heure écoulée, j'ai fait des recherches sur la sécurité de téléchargement d'images. J'ai appris qu'il existe de nombreuses fonctions pour tester le téléchargement.

Dans mon projet, j'ai besoin d'être prudent avec les images téléchargées. Il pourrait aussi y avoir une très grande quantité et cela pourrait nécessiter beaucoup de bande passante, donc acheter une API n'est pas une option.

Alors j'ai décidé d'obtenir un script PHP complet pour un téléchargement d'images VRAIMENT sécurisé. Je pense aussi que cela aidera de nombreuses personnes, car il est impossible de trouver une solution vraiment sécurisée. Mais je ne suis pas un expert en php, donc c'est vraiment un casse-tête pour moi d'ajouter certaines fonctions, donc je vais demander de l'aide à cette communauté pour créer un script complet de téléchargement d'images VRAIMENT sécurisé.

De bons sujets sur cela sont ici (cependant, ils disent simplement ce qu'il faut faire, mais pas comment le faire, et comme je l'ai dit, je ne suis pas un maître en PHP, donc je ne suis pas capable de le faire tout seul) : Liste de vérification de sécurité du téléchargement d'images PHP https://security.stackexchange.com/questions/32852/risks-of-a-php-image-upload-form

En résumé, ils disent que c'est ce qui est nécessaire pour un téléchargement d'images sécurisé (je vais citer les pages ci-dessus) :

  • Désactiver l'exécution de PHP à l'intérieur du dossier de téléchargement en utilisant .httaccess.
  • Ne pas autoriser le téléchargement si le nom du fichier contient la chaîne "php".
  • Autoriser uniquement les extensions : jpg, jpeg, gif et png.
  • Ne permettre que le type de fichier image.
  • Interdire les images avec deux types de fichiers.
  • Changer le nom de l'image. Charger dans un sous-répertoire et non dans le répertoire racine.

Aussi :

  • Re-traiter l'image en utilisant GD (ou Imagick) et enregistrer l'image traitée. Tout le reste est juste ennuyeux pour les pirates
  • Comme l'a souligné rr, utilisez move_uploaded_file() pour tout téléchargement
  • Au fait, vous voulez être très restrictif concernant votre dossier de téléchargement. Ce sont l'un des coins sombres où de nombreuses failles se produisent. Cela est valable pour tout type de téléchargement et tout langage/serveur de programmation. Consultez https://www.owasp.org/index.php/Unrestricted_File_Upload
  • Niveau 1 : Vérifiez l'extension (le fichier d'extension se termine par)
  • Niveau 2 : Vérifiez le type MIME ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
  • Niveau 3 : Lisez les 100 premiers octets et vérifiez s'ils contiennent des octets dans la plage suivante : ASCII 0-8, 12-31 (décimal).
  • Niveau 4 : Vérifiez les nombres magiques dans l'en-tête (10 à 20 premiers octets du fichier). Vous pouvez trouver certains des octets d'en-tête des fichiers dans ce lien : http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples
  • Vous voudrez peut-être exécuter "is_uploaded_file" sur le $_FILES['my_files']['tmp_name'] également. Voir http://php.net/manual/en/function.is-uploaded-file.php

Voici une grande partie, mais ce n'est pas tout. (Si vous avez des informations supplémentaires qui pourraient aider à rendre le téléchargement encore plus sécurisé, veuillez les partager).

CE QUE NOUS AVONS MAINTENANT

  • Code PHP principal :

    function uploadFile ($file_field = null, $check_image = false, $random_name = false) {
    
    //Section de configuration    
    //Définir le chemin de téléchargement du fichier
    $path = 'uploads/'; //avec une barre oblique finale
    //Définir la taille maximale du fichier en octets
    $max_size = 1000000;
    //Définir la liste blanche par défaut des extensions de fichiers
    $whitelist_ext = array('jpeg','jpg','png','gif');
    //Définir la liste blanche par défaut des types de fichiers
    $whitelist_type = array('image/jpeg', 'image/jpg', 'image/png','image/gif');
    
    //La Validation
    // Créer un tableau pour contenir toute sortie
    $out = array('error'=>null);
    
    if (!$file_field) {
      $out['error'][] = "Veuillez spécifier un nom de champ de formulaire valide";           
    }
    
    if (!$path) {
      $out['error'][] = "Veuillez spécifier un chemin de téléchargement valide";               
    }
    
    if (count($out['error'])>0) {
      return $out;
    }
    
    //S'assurer qu'il y a un fichier
    if((!empty($_FILES[$file_field])) && ($_FILES[$file_field]['error'] == 0)) {
    
    // Obtenir le nom de fichier
    $file_info = pathinfo($_FILES[$file_field]['name']);
    $name = $file_info['filename'];
    $ext = $file_info['extension'];
    
    //Vérifier que le fichier a la bonne extension           
    if (!in_array($ext, $whitelist_ext)) {
      $out['error'][] = "Extension de fichier non valide";
    }
    
    //Vérifier que le fichier est du bon type
    if (!in_array($_FILES[$file_field]["type"], $whitelist_type)) {
      $out['error'][] = "Type de fichier non valide";
    }
    
    //Vérifier que le fichier n'est pas trop grand
    if ($_FILES[$file_field]["size"] > $max_size) {
      $out['error'][] = "Le fichier est trop gros";
    }
    
    //Si $check image est défini sur true
    if ($check_image) {
      if (!getimagesize($_FILES[$file_field]['tmp_name'])) {
        $out['error'][] = "Le fichier téléchargé n'est pas une image valide";
      }
    }
    
    //Créer un nom de fichier complet incluant le chemin
    if ($random_name) {
      // Générer un nom de fichier aléatoire
      $tmp = str_replace(array('.',' '), array('',''), microtime());
    
      if (!$tmp || $tmp == '') {
        $out['error'][] = "Le fichier doit avoir un nom";
      }     
      $newname = $tmp.'.'.$ext;                                
    } else {
        $newname = $name.'.'.$ext;
    }
    
    //Vérifier si le fichier existe déjà sur le serveur
    if (file_exists($path.$newname)) {
      $out['error'][] = "Un fichier portant ce nom existe déjà";
    }
    
    if (count($out['error'])>0) {
      //Le fichier n'a pas été correctement validé
      return $out;
    } 
    
    if (move_uploaded_file($_FILES[$file_field]['tmp_name'], $path.$newname)) {
      //Succès
      $out['filepath'] = $path;
      $out['filename'] = $newname;
      return $out;
    } else {
      $out['error'][] = "Erreur de serveur !";
    }
    
     } else {
      $out['error'][] = "Aucun fichier téléchargé";
      return $out;
     }      
    }
    
    if (isset($_POST['submit'])) {
     $file = uploadFile('file', true, true);
     if (is_array($file['error'])) {
      $message = '';
      foreach ($file['error'] as $msg) {
      $message .= ''.$msg.'';    
     }
    } else {
     $message = "Fichier téléchargé avec succès".$newname;
    }
     echo $message;
    }
  • Et le formulaire :

Donc, ce que je demande, c'est de l'aide en postant des extraits de code qui m'aideront (et aideront tout le monde) à rendre ce script de téléchargement d'images vraiment sécurisé. Ou en partageant/créant un script complet avec tous les extraits ajoutés.

1 votes

Depuis que je reçois des votes positifs sur ma réponse à celle-ci, permettez-moi d'expliquer les votes négatifs sur votre question : Stack Overflow est un endroit pour trouver de l'aide si vous avez des problèmes avec votre code. Ce n'est pas un endroit pour améliorer du code qui fonctionne (Code Review est le site Web pour cela), et ce n'est pas non plus un endroit pour trouver ou demander des tutoriels. Simplement parce que (comme vous le voyez), il faut écrire la moitié d'un livre pour donner une réponse correcte et complète. Le nombre de vues est simplement parce que vous avez offert une prime dessus. Pas parce que tout le monde en a besoin :)

3 votes

@icecub Je suis sûr qu'il y a encore des personnes qui cherchent cette réponse et qui sont contentes que vous l'ayez donnée.

0 votes

Oui, il semble que beaucoup de personnes y fassent référence dans d'autres questions car beaucoup de gens ne réalisent pas que leurs scripts de téléchargement ne sont pas sécurisés. Je ne m'attendais pas à obtenir autant de votes positifs cependant. C'est assez rare de nos jours.

105voto

icecub Points 5039

Lorsque vous commencez à travailler sur un script de téléchargement d'images sécurisé, il y a beaucoup de choses à considérer. Maintenant, je suis loin d'être un expert en la matière, mais on m'a demandé de développer cela une fois dans le passé. Je vais vous expliquer tout le processus que j'ai suivi pour que vous puissiez le suivre. Pour cela, je vais commencer avec un formulaire html très basique et un php script qui gère les fichiers.

Formulaire HTML :

<form name="upload" action="upload.php" method="POST" enctype="multipart/form-data">
    Select image to upload: <input type="file" name="image">
    <input type="submit" name="upload" value="upload">
</form>

Fichier PHP :

<?php
$uploaddir = 'uploads/';

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

if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
    echo "Image succesfully uploaded.";
} else {
    echo "Image uploading failed.";
}
?> 

Premier problème : les types de fichiers
Les attaquants n'ont pas besoin d'utiliser le formulaire de votre site web pour télécharger des fichiers sur votre serveur. Les requêtes POST peuvent être interceptées de plusieurs façons. Pensez aux modules complémentaires de navigateur, aux proxies, aux scripts Perl. Quels que soient nos efforts, nous ne pouvons pas empêcher un attaquant d'essayer de télécharger quelque chose qu'il n'est pas censé faire. Toute notre sécurité doit donc être assurée par les serveurs.

Le premier problème concerne les types de fichiers. Dans le script ci-dessus, un attaquant pourrait télécharger ce qu'il veut, comme un script php par exemple, et suivre un lien direct pour l'exécuter. Donc, pour empêcher cela, nous implémentons Vérification du type de contenu :

<?php
if($_FILES['image']['type'] != "image/png") {
    echo "Only PNG images are allowed!";
    exit;
}

$uploaddir = 'uploads/';

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

if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
    echo "Image succesfully uploaded.";
} else {
    echo "Image uploading failed.";
}
?>

Malheureusement, ce n'est pas suffisant. Comme je l'ai déjà mentionné, l'attaquant a un contrôle total sur la requête. Rien ne l'empêchera de modifier les en-têtes de la requête et de changer simplement le type de contenu en "image/png". Ainsi, au lieu de se fier uniquement à l'en-tête Content-type, il serait préférable de valider également le contenu du fichier téléchargé. C'est ici que la bibliothèque php GD s'avère utile. Utilisation de getimagesize() nous allons traiter l'image avec la bibliothèque GD. S'il ne s'agit pas d'une image, cette opération échouera et, par conséquent, le téléchargement entier échouera :

<?php
$verifyimg = getimagesize($_FILES['image']['tmp_name']);

if($verifyimg['mime'] != 'image/png') {
    echo "Only PNG images are allowed!";
    exit;
}

$uploaddir = 'uploads/';

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

if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {
    echo "Image succesfully uploaded.";
} else {
    echo "Image uploading failed.";
}
?>

Mais nous n'en sommes pas encore là. La plupart des types de fichiers image permettent d'y ajouter des commentaires textuels. Là encore, rien n'empêche l'attaquant d'ajouter un code php en guise de commentaire. La bibliothèque GD évaluera cela comme une image parfaitement valide. L'interpréteur PHP ignorera complètement l'image et exécutera le code php dans le commentaire. Il est vrai que la configuration de php détermine quelles extensions de fichiers sont traitées par l'interpréteur php et lesquelles ne le sont pas, mais comme de nombreux développeurs n'ont aucun contrôle sur cette configuration en raison de l'utilisation d'un VPS, nous ne pouvons pas supposer que l'interpréteur php ne traitera pas l'image. C'est pourquoi l'ajout d'une liste blanche d'extensions de fichiers n'est pas non plus assez sûr.

La solution consiste à stocker les images à un endroit où un attaquant ne peut pas accéder directement au fichier. Cela peut être en dehors du document Root ou dans un répertoire protégé par un fichier .htaccess :

order deny,allow
deny from all
allow from 127.0.0.1

Edit : Après avoir discuté avec d'autres programmeurs PHP, je suggère fortement d'utiliser un dossier en dehors du Root du document, car htaccess n'est pas toujours fiable.

Il faut néanmoins que l'utilisateur ou tout autre visiteur puisse visualiser l'image. Nous allons donc utiliser php pour récupérer l'image pour eux :

<?php
$uploaddir = 'uploads/';
$name = $_GET['name']; // Assuming the file name is in the URL for this example
readfile($uploaddir.$name);
?>

Deuxième problème : les attaques par inclusion de fichiers locaux
Bien que notre script soit maintenant raisonnablement sécurisé, nous ne pouvons pas supposer que le serveur ne souffre pas d'autres vulnérabilités. Une vulnérabilité de sécurité courante est connue sous le nom de Inclusion de fichiers locaux . Pour expliquer cela, je dois ajouter un exemple de code :

<?php
if(isset($_COOKIE['lang'])) {
   $lang = $_COOKIE['lang'];
} elseif (isset($_GET['lang'])) {
   $lang = $_GET['lang'];
} else {
   $lang = 'english';
}

include("language/$lang.php");
?>

Dans cet exemple, nous parlons d'un site web multilingue. La langue du site n'est pas considérée comme une information à "haut risque". Nous essayons d'obtenir la langue préférée des visiteurs par le biais d'un cookie ou d'une requête GET et d'inclure le fichier requis en fonction de celle-ci. Imaginez maintenant ce qui se passe lorsque l'attaquant entre dans l'url suivante :

www.example.com/index.php?lang=../uploads/my_evil_image.jpg

PHP va inclure le fichier téléchargé par l'attaquant en contournant le fait qu'il ne peut pas accéder directement au fichier et nous sommes de retour à la case départ.

La solution à ce problème est de s'assurer que l'utilisateur ne connaît pas le nom du fichier sur le serveur. Au lieu de cela, nous allons changer le nom du fichier et même l'extension en utilisant une base de données pour en garder la trace :

CREATE TABLE `uploads` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(64) NOT NULL,
    `original_name` VARCHAR(64) NOT NULL,
    `mime_type` VARCHAR(20) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

<?php

if(!empty($_POST['upload']) && !empty($_FILES['image']) && $_FILES['image']['error'] == 0)) {

    $uploaddir = 'uploads/';

    /* Generates random filename and extension */
    function tempnam_sfx($path, $suffix){
        do {
            $file = $path."/".mt_rand().$suffix;
            $fp = @fopen($file, 'x');
        }
        while(!$fp);

        fclose($fp);
        return $file;
    }

    /* Process image with GD library */
    $verifyimg = getimagesize($_FILES['image']['tmp_name']);

    /* Make sure the MIME type is an image */
    $pattern = "#^(image/)[^\s\n<]+$#i";

    if(!preg_match($pattern, $verifyimg['mime']){
        die("Only image files are allowed!");
    }

    /* Rename both the image and the extension */
    $uploadfile = tempnam_sfx($uploaddir, ".tmp");

    /* Upload the file to a secure directory with the new name and extension */
    if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile)) {

        /* Setup a database connection with PDO */
        $dbhost = "localhost";
        $dbuser = "";
        $dbpass = "";
        $dbname = "";

        // Set DSN
        $dsn = 'mysql:host='.$dbhost.';dbname='.$dbname;

        // Set options
        $options = array(
            PDO::ATTR_PERSISTENT    => true,
            PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
        );

        try {
            $db = new PDO($dsn, $dbuser, $dbpass, $options);
        }
        catch(PDOException $e){
            die("Error!: " . $e->getMessage());
        }

        /* Setup query */
        $query = 'INSERT INTO uploads (name, original_name, mime_type) VALUES (:name, :oriname, :mime)';

        /* Prepare query */
        $db->prepare($query);

        /* Bind parameters */
        $db->bindParam(':name', basename($uploadfile));
        $db->bindParam(':oriname', basename($_FILES['image']['name']));
        $db->bindParam(':mime', $_FILES['image']['type']);

        /* Execute query */
        try {
            $db->execute();
        }
        catch(PDOException $e){
            // Remove the uploaded file
            unlink($uploadfile);

            die("Error!: " . $e->getMessage());
        }
    } else {
        die("Image upload failed!");
    }
}
?>

Nous avons donc fait ce qui suit :

  • Nous avons créé un endroit sécurisé pour sauvegarder les images.
  • Nous avons traité l'image avec la bibliothèque GD.
  • Nous avons vérifié le type MIME de l'image
  • Nous avons renommé le nom du fichier et changé l'extension
  • Nous avons enregistré le nouveau et l'ancien nom de fichier dans notre base de données.
  • Nous avons également enregistré le type MIME dans notre base de données.

Nous devons encore être en mesure d'afficher l'image aux visiteurs. Nous utilisons simplement la colonne id de notre base de données pour ce faire :

<?php

$uploaddir = 'uploads/';
$id = 1;

/* Setup a database connection with PDO */
$dbhost = "localhost";
$dbuser = "";
$dbpass = "";
$dbname = "";

// Set DSN
$dsn = 'mysql:host='.$dbhost.';dbname='.$dbname;

// Set options
$options = array(
    PDO::ATTR_PERSISTENT    => true,
    PDO::ATTR_ERRMODE       => PDO::ERRMODE_EXCEPTION
);

try {
    $db = new PDO($dsn, $dbuser, $dbpass, $options);
}
catch(PDOException $e){
    die("Error!: " . $e->getMessage());
}

/* Setup query */
$query = 'SELECT name, original_name, mime_type FROM uploads WHERE id=:id';

/* Prepare query */
$db->prepare($query);

/* Bind parameters */
$db->bindParam(':id', $id);

/* Execute query */
try {
    $db->execute();
    $result = $db->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e){
    die("Error!: " . $e->getMessage());
}

/* Get the original filename */
$newfile = $result['original_name'];

/* Send headers and file to visitor */
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.basename($newfile));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($uploaddir.$result['name']));
header("Content-Type: " . $result['mime_type']);
readfile($uploaddir.$result['name']);
?>

Grâce à ce script, le visiteur pourra visualiser l'image ou la télécharger avec son nom de fichier original. Cependant, il ne pourra pas accéder directement au fichier sur votre serveur et ne pourra pas non plus tromper votre serveur pour qu'il accède au fichier pour lui, car il n'a aucun moyen de savoir de quel fichier il s'agit. Ils ne peuvent pas non plus forcer votre répertoire de téléchargement, car celui-ci ne permet à personne d'y accéder, sauf au serveur lui-même.

Et cela conclut mon script de téléchargement sécurisé d'images.

J'aimerais ajouter que je n'ai pas inclus de taille maximale de fichier dans ce script, mais vous devriez facilement pouvoir le faire vous-même.

Classe ImageUpload
En raison de la forte demande de ce script, j'ai écrit une classe ImageUpload qui devrait vous permettre à tous de gérer de manière sécurisée les images téléchargées par les visiteurs de votre site web. La classe peut gérer à la fois un et plusieurs fichiers à la fois, et vous fournit des fonctionnalités supplémentaires comme l'affichage, le téléchargement et la suppression des images.

Puisque le code est simplement trop grand pour être affiché ici, vous pouvez télécharger la classe de MEGA ici :

Télécharger la classe ImageUpload

Il suffit de lire le fichier README.txt et de suivre les instructions.

Le passage à l'Open Source
Le projet de classe Image Secure est maintenant également disponible sur mon site web. Github profil. Ceci afin que d'autres personnes (vous ?) puissent contribuer au projet et faire de cette bibliothèque une grande bibliothèque pour tous.

7 votes

La fonction getimagesize() indique clairement que vous ne devez pas utiliser cette fonction pour valider si une image est une image. N'utilisez pas getimagesize() pour vérifier qu'un fichier donné est une image valide. Utilisez plutôt une solution spécialement conçue comme l'extension Fileinfo à la place. php.net/manual/en/function.getimagesize.php

0 votes

Est-ce que cela fonctionnerait avec des téléchargements multiples ? Par exemple, est-ce que je peux télécharger 3 images en une seule soumission de formulaire ?

0 votes

@Lachie Eh bien, vous devriez adapter le code pour gérer plusieurs fichiers à la fois, mais à part ça je ne vois pas pourquoi pas :) Je prévois cependant de transformer cela en bibliothèque, afin que ce soit beaucoup plus facile à utiliser pour tout le monde. Cependant, en raison de ma vie bien remplie, je n'ai pas de date de livraison pour le moment :(

6voto

Olaf Erlandsen Points 800

Pour télécharger des fichiers en PHP est facile et sécurisé. Je recommanderais d'apprendre à propos de :

  • pathinfo - Renvoie des informations sur un chemin de fichier
  • move_uploaded_file - Déplace un fichier téléchargé vers un nouvel emplacement
  • copy - Copie un fichier
  • finfo_open - Crée une nouvelle ressource fileinfo

Pour télécharger un fichier en PHP vous avez deux méthodes : PUT et POST. Pour utiliser la méthode POST avec HTML vous devez activer enctype sur votre formulaire comme ceci :

Ensuite dans votre PHP vous devez récupérer votre fichier téléchargé avec $_FILES comme ceci :

$_FILES['file']

Ensuite vous devez déplacer le fichier depuis le dossier temporaire ("upload") avec move_uploaded_file :

if (move_uploaded_file($_FILES['file']['tmp_name'], VOTRE_CHEMIN)) {
   // ...
}

Et une fois que vous avez téléchargé le fichier, vous devez vérifier l'extension du fichier. La meilleure façon de le faire est d'utiliser pathinfo comme ceci :

$extension = pathinfo($_FILES['file']['tmp_name'], PATHINFO_EXTENSION);

Mais l'extension n'est pas sécurisée car vous pouvez télécharger un fichier avec l'extension .jpg mais avec un type MIME text/php et c'est une porte dérobée. Donc, je recommande de vérifier le vrai type MIME avec finfo_open comme ceci :

$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $_FILES['file']['tmp_name']);

Et n'utilisez pas $_FILES['file']['type'] car parfois, en fonction de votre navigateur et du système d'exploitation du client, vous pouvez recevoir application/octet-stream et ce type MIME n'est pas le vrai type MIME de votre fichier téléchargé.

Je pense que vous pouvez télécharger des fichiers de manière sécurisée avec ce scénario.

Désolé pour mon anglais, au revoir!

0 votes

Salut, merci pour votre réponse. Cependant, je ne pense pas que cela réponde pleinement à ma question. J'ai le script qui inclut toutes les fonctions que vous avez mentionnées. Cependant, cela ne rend pas le script totalement sûr comme nous pouvons le lire ici security.stackexchange.com/questions/32852/…. J'espérais que quelqu'un donnerait (pas besoin d'écrire le code, peut-être que quelqu'un l'a déjà) toutes les fonctions mentionnées dans la réponse précédente, ce qui rendrait le script de téléchargement d'images aussi sécurisé que possible. Merci encore pour vos efforts pour répondre à cette question.

0 votes

@Simon Dans la partie images, il y a beaucoup de choses que vous devez prendre en compte lors du stockage et de l'affichage. J'espère qu'il y aura beaucoup de personnes pour vous aider dans la partie stockage sur cette plateforme. Mais en ce qui concerne la partie affichage, je vous recommande de consulter ce php.net/manual/fr/book.imagick.php

0voto

dave Points 31

Voici un autre conseil. Ne vous fiez pas à l'élément ['type'], c'est trop peu fiable. Vérifiez plutôt l'en-tête du fichier pour voir quel est réellement le type de fichier. Quelque chose comme ceci :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X