web-dev-qa-db-fra.com

Comment vérifier si un fichier téléchargé est une image sans type mime?

J'aimerais vérifier si un fichier téléchargé est un fichier image (E.G PNG, JPG, JPEG, GIF, BMP) ou un autre fichier. Le problème est que j'utilise ultérieurement pour télécharger les fichiers, ce qui modifie le type MIME et donne un "texte/octal" ou quelque chose en tant que type MIME, quel que soit le type de fichier que vous avez téléchargé.

Existe-t-il un moyen de vérifier si le fichier téléchargé est une image en dehors de la vérification de l'extension de fichier à l'aide de PHP?

27
Click Upvote

Vous pouvez utiliser getimagesize() qui retourne des zéros pour la taille sur les non-images.

33
Scott C Wilson

Ma pensée sur le sujet est simple: toutes les images téléchargées sont diaboliques.

Et non seulement parce qu'ils peuvent contenir des codes malveillants, mais en particulier à cause des méta-tags. Je suis conscient des agresseurs qui parcourent le Web pour trouver des images protégées à l'aide de leurs méta-tags cachés, puis jouez avec leur droit d'auteur. Peut-être un peu paranoïaque, mais comme des images téléchargées par l'utilisateur sont incontrôlables sur des problèmes de droit d'auteur, je le prends sérieusement en compte.

Pour vous débarrasser de ces problèmes, je convertis systématiquement toutes les images téléchargées en PNG en utilisant GD. Cela présente de nombreux avantages: l'image est propre des codes malveillants éventuels et des balises méta, je n'ai qu'un seul format pour toutes les images téléchargées, je peux régler la taille de l'image pour s'adapter à ma norme et ... Je sais immédiatement si l'image est valide ou non! Si l'image ne peut pas être ouverte pour la conversion (utilisation imagecreatefromstring qui ne se soucie pas de l'image format), puis je considère que l'image est value non valide.

Une implémentation simple pourrait ressembler à ceci:

function imageUploaded($source, $target)
{
   // check for image size (see @DaveRandom's comment)
   $size = getimagesize($source);
   if ($size === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   if ($size[0] > 2000 || $size[1] > 2000) {
      throw new Exception("{$source}: Too large.");
   }

   // loads it and convert it to png
   $sourceImg = @imagecreatefromstring(@file_get_contents($source));
   if ($sourceImg === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   $width = imagesx($sourceImg);
   $height = imagesy($sourceImg);
   $targetImg = imagecreatetruecolor($width, $height);
   imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height);
   imagedestroy($sourceImg);
   imagepng($targetImg, $target);
   imagedestroy($targetImg);
}

Pour le tester:

header('Content-type: image/png');
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output');

Cela ne répond pas exactement à votre question car c'est le même type de piratage que la réponse acceptée, mais je vous donne mes raisons de l'utiliser, au moins :-)

38
Alain Tiemblo

Si Uploadify change vraiment le type MIME - je considérerais cela un bug. Il n'a pas de sens du tout, car cela bloque les développeurs de travailler avec des fonctions basées sur MIME à PHP:

Ceci est une petite fonction d'assistance qui renvoie le type MIME basé sur les 6 premiers octets d'un fichier.

/**
 * Returns the image mime-type based on the first 6 bytes of a file
 * It defaults to "application/octet-stream".
 * It returns false, if problem with file or empty file.
 *
 * @param string $file 
 * @return string Mime-Type
 */
function isImage($file)
{
    $fh = fopen($file,'rb');
    if ($fh) { 
        $bytes = fread($fh, 6); // read 6 bytes
        fclose($fh);            // close file

        if ($bytes === false) { // bytes there?
            return false;
        }

        // ok, bytes there, lets compare....

        if (substr($bytes,0,3) == "\xff\xd8\xff") { 
            return 'image/jpeg';
        }
        if ($bytes == "\x89PNG\x0d\x0a") { 
            return 'image/png';
        }
        if ($bytes == "GIF87a" or $bytes == "GIF89a") { 
            return 'image/gif';
        }

        return 'application/octet-stream';
    }
    return false;
}
5
Jens A. Koch

Vous pouvez vérifier le type d'image en vérifiant les numéros magiques au début du fichier.

Par exemple: chaque fichier JPEG commence par un "FF D8 FF E0" bloc.

Voici plus d'informations sur numéros magiques

5
rcode

Essayez d'utiliser exif_imagetype pour récupérer le type réel de l'image. Si le fichier est trop petit, il lancera une erreur et s'il ne le trouve pas, il retournera false

3
kaore

Vous pouvez vérifier les premiers octets du fichier pour le numéro magique pour comprendre le format d'image.

3
Kibbee

N'est-il pas possible d'interroger le fichier avec Finfo_file ?

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $filename); //should contain mime-type
finfo_close($finfo);

Cette réponse est non testée mais basée sur cette discussion sur le forum sur les forums de téléchargement.

Je voudrais également souligner que Finfo devrait "Essayez de deviner le type de contenu et le codage d'un fichier en recherchant certaines séquences d'octets magiques à des positions spécifiques dans le fichier" dans mon esprit que cela devrait toujours fonctionner même Bien que Uploadify ait spécifié le mauvais type MIME.

2
Jeffrey Jenkinson