简体   繁体   English

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

[英]How to check if an uploaded file is an image without mime type?

I'd like to check if an uploaded file is an image file (eg png, jpg, jpeg, gif, bmp) or another file. 我想检查上传的文件是图像文件(例如png,jpg,jpeg,gif,bmp)还是其他文件。 The problem is that I'm using Uploadify to upload the files, which changes the mime type and gives a 'text/octal' or something as the mime type, no matter which file type you upload. 问题是我正在使用Uploadify来上传文件,无论你上传哪种文件类型,都会更改mime类型并提供“text / octal”或类似mime类型的内容。

Is there a way to check if the uploaded file is an image apart from checking the file extension using PHP? 除了使用PHP检查文件扩展名之外,有没有办法检查上传的文件是否是图像?

My thought about the subject is simple: all uploaded images are evil. 我对这个主题的想法很简单:所有上传的图像都是邪恶的。

And not only because they can contain malicious codes, but particularly because of meta-tags. 而且不仅因为它们可能包含恶意代码,而且特别是因为元标记。 I'm aware about crawlers that browse the web to find some protected images using their hidden meta-tags, and then play with their copyright. 我知道浏览网页的抓取工具使用隐藏的元标记找到一些受保护的图像,然后播放他们的版权。 Perhaps a bit paranoid, but as user-uploaded images are out of control over copyright issues, I take it seriousely into account. 也许有点偏执,但由于用户上传的图像不受版权问题的控制,我将其考虑在内。

To get rid of those issues, I systematically convert all uploaded images to png using gd. 为了摆脱这些问题,我使用gd系统地将所有上传的图像转换为png。 This have a lot of advantages: image is clean from eventual malicious codes and meta tags, I only have one format for all uploaded images, I can adjust the image size to fit with my standard, and... I immediately know if the image is valid or not! 这有很多优点:图像是最终的恶意代码和元标记,我只有一种格式的所有上传的图像,我可以调整图像大小以符合我的标准,并... 我立即知道图像是否有效! If the image can't be opened for conversion (using imagecreatefromstring which doesn't care about image format), then I consider the image as invalid. 如果无法打开图像进行转换(使用不关心图像格式的imagecreatefromstring ),则认为图像无效。

A simple implementation could look like this: 一个简单的实现可能如下所示:

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

To test it: 测试它:

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

This does not exactly answer your question as this is the same kind of hack than the accepted answer, but I give you my reasons to use it, at least :-) 这并没有完全回答你的问题,因为这是与被接受的答案相同的黑客攻击,但我告诉你我使用它的理由,至少:-)

您可以使用getimagesize()在非图像上返回零大小。

If Uploadify really changes the mime type - i would consider it a bug. 如果Uploadify真的改变了mime类型 - 我认为它是一个bug。 It doesn't make sense at all, because that blocks developers from working with mime-type based functions in PHP: 它根本没有意义,因为它阻止开发人员在PHP中使用基于mime类型的函数:

This is a little helper function which returns the mime-type based on the first 6 bytes of a file. 这是一个小辅助函数,它根据文件的前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;
}

You can verify the image type by checking for magic numbers at the beginning of the file. 您可以通过检查文件开头的幻数来验证图像类型。

For example: Every JPEG file begins with a "FF D8 FF E0" block. 例如:每个JPEG文件都以“FF D8 FF E0”块开头。

Here is more info on magic numbers 这里有关于魔术数字的更多信息

Try using exif_imagetype to retrieve the actual type of the image. 尝试使用exif_imagetype检索图像的实际类型。 If the file is too small it will throw an error and if it can't find it it will return false 如果文件太小,则会抛出错误,如果找不到,则返回false

您可以检查文件的前几个字节是否有幻数,以确定图像格式。

Is it not possible to interrogate the file with finfo_file ? 是不是可以使用finfo_file查询文件?

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

This answer is untested but based on this forum discussion on the Uploadify forums. 这个答案是未经测试,但基于这个论坛讨论的Uploadify论坛。

I would also point out that finfo should "try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file" so in my mind this should still work even though Uploadify has specified the wrong mime type. 我还要指出,finfo应该“通过在文件中的特定位置查找某些魔术字节序列来尝试猜测文件的内容类型和编码”,所以在我看来,即使上传指定了错误的mime,这仍然可以工作类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM