首页 文章

如何检查上传的文件是否是没有mime类型的图像?

提问于
浏览
24

我想检查上传的文件是图像文件(例如png,jpg,jpeg,gif,bmp)还是其他文件 . 问题是我正在使用Uploadify上传文件,这些文件会更改mime类型并提供“text / octal”或类似mime类型的内容,无论您上传哪种文件类型 .

除了使用PHP检查文件扩展名之外,有没有办法检查上传的文件是否是图像?

7 回答

  • 5

    你可以使用getimagesize(),它在非图像上返回大小的零 .

  • 32

    我对这个主题的想法很简单:所有上传的图像都是邪恶的 .

    而且不仅因为它们可能包含恶意代码,而且特别是因为元标记 . 我知道浏览网页的抓取工具使用隐藏的元标记找到一些受保护的图像,然后播放他们的版权 . 也许有点偏执,但由于用户上传的图像不受版权问题的控制,我将其考虑在内 .

    为了摆脱这些问题,我使用gd系统地将所有上传的图像转换为png . 这有很多优点:图像从最终的恶意代码和元标记中清除,我只有一种格式用于所有上传的图像,我可以调整图像大小以符合我的标准,并且... I immediately know if the image is valid or not! 如果图像可以' t打开转换(使用imagecreatefromstring,它不关心图像格式),然后我认为图像无效 .

    一个简单的实现可能如下所示:

    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);
    }
    

    测试它:

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

    这并没有完全回答你的问题,因为这是与被接受的答案相同的黑客攻击,但我告诉你我使用它的理由,至少:-)

  • 2

    您可以通过检查文件开头的幻数来验证图像类型 .

    例如:每个JPEG文件都以 "FF D8 FF E0" 块开头 .

    以下是magic numbers的更多信息

  • 3

    如果Uploadify真的改变了mime类型 - 我认为它是一个bug . 它根本没有意义,因为它阻止开发人员在PHP中使用基于mime类型的函数:

    这是一个小辅助函数,它根据文件的前6个字节返回mime类型 .

    /**
     * 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;
    }
    
  • 6

    您可以检查magic number文件的前几个字节,以确定图像格式 .

  • 3

    尝试使用exif_imagetype检索图像的实际类型 . 如果文件太小,则会抛出错误,如果找不到,则返回false

  • 37

    是否无法使用finfo_file查询文件?

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

    此答案未经测试,但基于Uploadify论坛上的this forum discussion .

    我还要指出finfo应该"try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file"所以在我看来这应该仍然有效,即使Uploadify指定了错误的mime类型 .

相关问题