如何在PHP中检查上传文件的类型

44

我使用了这段代码来检查图片的类型:

$f_type=$_FILES['fupload']['type'];

if ($f_type== "image/gif" OR $f_type== "image/png" OR $f_type== "image/jpeg" OR $f_type== "image/JPEG" OR $f_type== "image/PNG" OR $f_type== "image/GIF")
{
    $error=False;
}
else
{
    $error=True;
}

但有些用户抱怨在上传任何类型的图像时出现错误,而其他一些用户则没有出现任何错误!

我想知道这是否可以解决问题:

if (mime_content_type($_FILES ['fupload'] ['type']) == "image/gif"){...

有什么评论吗?

9个回答

96

永远不要使用$_FILES..['type']。它包含的信息没有经过任何验证,是由用户定义的值。请自行测试类型。对于图像,通常可以使用exif_imagetype

$allowedTypes = array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
$detectedType = exif_imagetype($_FILES['fupload']['tmp_name']);
$error = !in_array($detectedType, $allowedTypes);

如果您的服务器支持,那么另外一个很好的选择是finfo函数


1
我认为这些扩展在我的共享主机上没有启用:extension=php_mbstring.dll extension=php_exif.dll - John
2
exif_imagetype是否无法欺骗? - A F
@assensi 你可能想要了解一下$_FILES中不同字段的含义:https://www.php.net/manual/en/features.file-upload.post-method.php。`tmp_name`是正确的。 - deceze
@decese - 有没有一种好的方法来获取存储在内存字符串变量中的图像类型?从MSGraph加载用户个人资料图片或从SQL服务器检索它们作为varbinary,我得到的图像是一个"string",但需要能够设置MIME类型并为浏览器发送HTTP头。$photoData = MSGraph::getUserProfilePic($username); $photoType = SomeMagicMaetadataFunction($photoData);如果有任何指引,将不胜感激,否则我将需要进行二进制十六进制编码,并学习一些文件格式并编写一个尝试手动解析我的关键情况的函数。 - TampaCraig

9

除了@deceze之外,您还可以使用finfo()检查非图片文件的MIME类型:

$finfo = new finfo();
$fileMimeType = $finfo->file($path . $filename, FILEINFO_MIME_TYPE);

4

在我看来,最好的方法是先使用 getimagesize() 函数,然后再使用 imagecreatefromstring() 函数。

    $size = getimagesize($filename);
    if ($size === false) {
        throw new Exception("{$filename}: Invalid image.");
    }
    if ($size[0] > 2500 || $size[1] > 2500) {
        throw new Exception("{$filename}: Image too large.");
    }

    if (!$img = @imagecreatefromstring(file_get_contents($filename))) {
        throw new Exception("{$filename}: Invalid image content.");
    }

使用getimagesize()进行检查可以防止一些DoS攻击,因为我们不必尝试从用户提供的每个文件中创建图像,包括非图像文件或文件过大。不幸的是,根据PHP文档,不能依赖于检查图像类型内容。

imagecreatefromstring()最终尝试将文件作为图像打开-如果成功-我们就有了一个图像。


4

确实,您可以使用 exif 来检查是否为图像,但我认为更好的方法是使用 finfo,如下所示:

$allowed_types = array ( 'application/pdf', 'image/jpeg', 'image/png' );
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$detected_type = finfo_file( $fileInfo, $_FILES['datei']['tmp_name'] );
if ( !in_array($detected_type, $allowed_types) ) {
    die ( 'Please upload a pdf or an image ' );
}
finfo_close( $fileInfo );

2

这是一个简单的、一行的脚本,我经常使用它。

$image = "/var/www/Core/temp/image.jpg";
$isImage = explode("/", mime_content_type())[0] == "image";

我基本上使用mime_content_type()来获取像“image / jpg”之类的东西,然后通过“/”进行分解,并检查数组的第一个元素是否说“image”。

我希望它有效!


建议使用dirname($x)代替explode("/", $x)[0] - miken32

0
在PHP 5.5中,我使用此函数获取文件类型并检查是否为图片:
function getFileType( $file ) {
    return image_type_to_mime_type( exif_imagetype( $file ) );
}

// Get file type
$file_type = getFileType( 'path/to/images/test.png' );
echo $file_type;
// Prints image/png
// 1. All images have mime type starting with "image"
// 2. No other non-image mime types contain string "image" in it 

然后你可以这样做:

if ( strpos( $filetype, 'image' ) !== false ) {
    // This is an image 
}

完整的MIME类型列表:http://www.sitepoint.com/web-foundations/mime-types-complete-list/


0

最后一行很接近了。您可以使用以下代码:

if (mime_content_type($_FILES['fupload']['tmp_name']) == "image/gif"){...

在我目前正在处理的情况下,我的$_FILES..['type']报告自己为"text/csv",而mime_content_type()finfo()(由其他人建议)报告为"text/plain." 正如@deceze所指出的那样,$_FILES..['type']仅有用于知道客户端认为文件类型是什么。


-2

你可以试试这个

$file_extension = explode('.',$file['name']);
$file_extension = strtolower(end($file_extension));
$accepted_formate = array('jpeg','jpg','png');
if(in_array($file_extension,$accepted_formate)) {           
  echo "This is jpeg/jpg/png file";
} else {
  echo $file_extension.' This is file not allowed !!';
}

3
这是检查文件扩展名,而不是MIME内容类型。 - NicholasM

-6

警告:以下回答实际上并没有检查文件类型,只是检查了文件名。它不能用于实际安全目的。

编辑:不要使用这种方法,因为它没有进行任何安全检查。我保留此回答,以免其他人像我一样犯同样的错误。


我尝试了以下内容,对我来说有效:
$allowed =  array('gif','png' ,'jpg', 'pdf');
$filename = $_FILES['input_tag_name']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if(!in_array($ext,$allowed) ) {
    echo 'error';
}

源链接


17
警告!这仅仅是检查扩展名是否在您允许的数组中,而不会做任何其他检查。如果您将 myVirus.exe 重命名为 myVirus.jpg,它可以轻松地通过您的函数。显然,这并不是您想要的... - Byson
4
这非常危险...避免并且永远不要将其用于重要文件的检查。 - ErickBest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接