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

时间:2011-06-26 13:41:37

标签: php image-processing file-upload upload mime-types

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

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

7 个答案:

答案 0 :(得分:38)

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

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

为了摆脱这些问题,我使用gd系统地将所有上传的图像转换为png。这有很多优点:图像从最终的恶意代码和元标记中清除,我只有一种格式用于所有上传的图像,我可以调整图像大小以符合我的标准,并且...... 我立即知道如果图像有效!如果无法打开图像进行转换(使用不关心图像格式的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');

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

答案 1 :(得分:33)

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

答案 2 :(得分:5)

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

例如:每个JPEG文件都以“FF D8 FF E0”块开头。

以下是magic numbers

的更多信息

答案 3 :(得分:5)

如果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;
}

答案 4 :(得分:3)

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

答案 5 :(得分:3)

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

答案 6 :(得分:2)

是否无法使用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类型。