简体   繁体   English

确定上传的文件是否是MVC上的图像(任何格式)

[英]Determine if uploaded file is image (any format) on MVC

So I'm using this code for view:所以我使用这个代码来查看:

<form action="" method="post" enctype="multipart/form-data">

  <label for="file">Filename:</label>
  <input type="file" name="file" id="file" />

  <input type="submit" />
</form>

This for model:这对于模型:

[HttpPost]
public ActionResult Index(HttpPostedFileBase file) {

  if (file.ContentLength > 0) {
    var fileName = Path.GetFileName(file.FileName);
    var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
    file.SaveAs(path);
  }

  return RedirectToAction("Index");
}

Works great unless the user add a file which isn't an image.除非用户添加不是图像的文件,否则效果很好。 How can I assure the file uploaded is an image.我如何确保上传的文件是图像。 Thanks谢谢

In case it can helps anyone, Here is a static method for HttpPostedFileBase that checks if a given uploaded file is an image:如果它可以帮助任何人,这是HttpPostedFileBase的静态方法,用于检查给定的上传文件是否为图像:

public static class HttpPostedFileBaseExtensions
{
    public const int ImageMinimumBytes = 512;

    public static bool IsImage(this HttpPostedFileBase postedFile)
    {
        //-------------------------------------------
        //  Check the image mime types
        //-------------------------------------------
        if (!string.Equals(postedFile.ContentType, "image/jpg", StringComparison.OrdinalIgnoreCase) &&
            !string.Equals(postedFile.ContentType, "image/jpeg", StringComparison.OrdinalIgnoreCase) &&
            !string.Equals(postedFile.ContentType, "image/pjpeg", StringComparison.OrdinalIgnoreCase) &&
            !string.Equals(postedFile.ContentType, "image/gif", StringComparison.OrdinalIgnoreCase) &&
            !string.Equals(postedFile.ContentType, "image/x-png", StringComparison.OrdinalIgnoreCase) &&
            !string.Equals(postedFile.ContentType, "image/png", StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }

        //-------------------------------------------
        //  Check the image extension
        //-------------------------------------------
        var postedFileExtension = Path.GetExtension(postedFile.FileName);
        if (!string.Equals(postedFileExtension , ".jpg", StringComparison.OrdinalIgnoreCase)
            && !string.Equals(postedFileExtension , ".png", StringComparison.OrdinalIgnoreCase)
            && !string.Equals(postedFileExtension , ".gif", StringComparison.OrdinalIgnoreCase)
            && !string.Equals(postedFileExtension , ".jpeg", StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }

        //-------------------------------------------
        //  Attempt to read the file and check the first bytes
        //-------------------------------------------
        try
        {
            if (!postedFile.InputStream.CanRead)
            {
                return false;
            }
            //------------------------------------------
            //   Check whether the image size exceeding the limit or not
            //------------------------------------------ 
            if (postedFile.ContentLength < ImageMinimumBytes)
            {
                return false;
            }

            byte[] buffer = new byte[ImageMinimumBytes];
            postedFile.InputStream.Read(buffer, 0, ImageMinimumBytes);
            string content = System.Text.Encoding.UTF8.GetString(buffer);
            if (Regex.IsMatch(content, @"<script|<html|<head|<title|<body|<pre|<table|<a\s+href|<img|<plaintext|<cross\-domain\-policy",
                RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline))
            {
                return false;
            }
        }
        catch (Exception)
        {
            return false;
        }

        //-------------------------------------------
        //  Try to instantiate new Bitmap, if .NET will throw exception
        //  we can assume that it's not a valid image
        //-------------------------------------------

        try
        {
            using (var bitmap = new System.Drawing.Bitmap(postedFile.InputStream))
            {
            }
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
             postedFile.InputStream.Position = 0;
        }

        return true;
    }
}

Edit 2/10/2017: According to a suggested edit, added a finally statement to reset the stream, so we can use it later. 2017 年 2 月 10 日编辑:根据建议的编辑,添加了 finally 语句来重置流,以便我们稍后使用。

It's 2018 and the accepted answer does not work with .NET CORE 2.1 because we now have IFormFile instead of HttpPostedFileBase .现在是 2018 年,接受的答案不适用于 .NET CORE 2.1,因为我们现在拥有IFormFile而不是HttpPostedFileBase

Here comes the adaption of the accepted answer to .NET CORE 2.1 (I also fixed the bug/typo mentioned by TomSelleck in his comment to the accepted answer):这是对 .NET CORE 2.1 接受的答案的改编(我还修复了 TomSelleck 在他对接受的答案的评论中提到的错误/错字):

public static class FormFileExtensions
{
    public const int ImageMinimumBytes = 512;

    public static bool IsImage(this IFormFile postedFile)
    {
        //-------------------------------------------
        //  Check the image mime types
        //-------------------------------------------
        if (postedFile.ContentType.ToLower() != "image/jpg" &&
                    postedFile.ContentType.ToLower() != "image/jpeg" &&
                    postedFile.ContentType.ToLower() != "image/pjpeg" &&
                    postedFile.ContentType.ToLower() != "image/gif" &&
                    postedFile.ContentType.ToLower() != "image/x-png" &&
                    postedFile.ContentType.ToLower() != "image/png")
        {
            return false;
        }

        //-------------------------------------------
        //  Check the image extension
        //-------------------------------------------
        if (Path.GetExtension(postedFile.FileName).ToLower() != ".jpg"
            && Path.GetExtension(postedFile.FileName).ToLower() != ".png"
            && Path.GetExtension(postedFile.FileName).ToLower() != ".gif"
            && Path.GetExtension(postedFile.FileName).ToLower() != ".jpeg")
        {
            return false;
        }

        //-------------------------------------------
        //  Attempt to read the file and check the first bytes
        //-------------------------------------------
        try
        {
            if (!postedFile.OpenReadStream().CanRead)
            {
                return false;
            }
            //------------------------------------------
            //check whether the image size exceeding the limit or not
            //------------------------------------------ 
            if (postedFile.Length < ImageMinimumBytes)
            {
                return false;
            }

            byte[] buffer = new byte[ImageMinimumBytes];
            postedFile.OpenReadStream().Read(buffer, 0, ImageMinimumBytes);
            string content = System.Text.Encoding.UTF8.GetString(buffer);
            if (Regex.IsMatch(content, @"<script|<html|<head|<title|<body|<pre|<table|<a\s+href|<img|<plaintext|<cross\-domain\-policy",
                RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline))
            {
                return false;
            }
        }
        catch (Exception)
        {
            return false;
        }

        //-------------------------------------------
        //  Try to instantiate new Bitmap, if .NET will throw exception
        //  we can assume that it's not a valid image
        //-------------------------------------------

        try
        {
            using (var bitmap = new System.Drawing.Bitmap(postedFile.OpenReadStream()))
            {
            }
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            postedFile.OpenReadStream().Position = 0;
        }

        return true;
    }
}

For anyone that runs into this.对于遇到此问题的任何人。

You could also use a file.ContentType.Contains("image") to check if the content type is of image/*.您还可以使用file.ContentType.Contains("image")来检查内容类型是否为 image/*。

if(file.ContentLength > 0 && file.ContentType.Contains("image"))
{
    //valid image
}
else
{
    //not a valid image
}

Not sure if this is best practice, but it works for me.不确定这是否是最佳实践,但它对我有用。

Don't have the compiler at hand but something like this should do:手头没有编译器,但应该这样做:

try
{
   var bitmap = Bitmap.FromStream( file.InputStream );
   // valid image stream
}
catch 
{
    // not an image
}

Use in static helper class:在静态助手类中使用:

public static bool IsImage(HttpPostedFileBase postedFile)
    {
        try  {
              using (var bitmap = new System.Drawing.Bitmap(postedFile.InputStream))
                    {                        
                            return !bitmap.Size.IsEmpty;
                    }
                }
                catch (Exception)
                {
                    return false;
                }
            }
    }

Use in ASP.NET MVC viewmodel:在 ASP.NET MVC 视图模型中使用:

public class UploadFileViewModel
    {
        public HttpPostedFileBase postedFile { get; set; }

        public  bool IsImage()
        {
            try  {
                  using (var bitmap = new System.Drawing.Bitmap(this.postedFile.InputStream))
                        {                        
                                return !bitmap.Size.IsEmpty;
                        }
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
        }
    }

This example checks to see whether the image is a real image, and you can modify and convert it.本示例检查图像是否为真实图像,您可以对其进行修改和转换。

It eats memory as an example of six-liter V8, so it should be used when you really want to know what this image.它以六升V8的吃内存为例,所以当你真的想知道这个图像是什么时应该使用它。

Implementation in much more cleaner way,以更清洁的方式实施,

public static class FileExtensions
{
    private static readonly IDictionary<string, string> ImageMimeDictionary = new Dictionary<string, string>
    {
        { ".bmp", "image/bmp" },
        { ".dib", "image/bmp" },
        { ".gif", "image/gif" },
        { ".svg", "image/svg+xml" },
        { ".jpe", "image/jpeg" },
        { ".jpeg", "image/jpeg" },
        { ".jpg", "image/jpeg" },
        { ".png", "image/png" },
        { ".pnz", "image/png" }
    };

    public static bool IsImage(this string file)
    {
        if (string.IsNullOrEmpty(file))
        {
            throw new ArgumentNullException(nameof(file));
        }

        var extension = Path.GetExtension(file);
        return ImageMimeDictionary.ContainsKey(extension.ToLower());
    }
}

It doesn't answer the question how to check if an uploaded file is an image on the server.它没有回答如何检查上传的文件是否是服务器上的图像的问题。

However, the original problem statement appears more to be that users are accidentally uploading the wrong file.然而,最初的问题陈述似乎更多是用户不小心上传了错误的文件。

In which case, a very easy solution is to set the accept attribute on the input element instead.在这种情况下,一个非常简单的解决方案是在 input 元素上设置accept 属性

<input type="file" id="file" accept="image/*">

The usual caveats about trusting user input applies.关于信任用户输入的常见警告适用。

作为第一步,您应该针对ContentType属性围绕可接受的 MIME 类型形成一个白名单。

public static ImageFormat GetRawImageFormat(byte[] fileBytes)
{
    using (var ms = new MemoryStream(fileBytes))
    {
        var fileImage = Image.FromStream(ms);
        return fileImage.RawFormat;
    }
}

Usage:用法:

if (GetRawImageFormat(fileBytes).IsIn(ImageFormat.Jpeg, ImageFormat.Png, ImageFormat.Gif))
    {
        //do somthing
    }

For IFormFile : It is based on a logic that if .NET can treat the file as a valid image and can be processed further, then it is a valid image.对于IFormFile :它基于一个逻辑,如果 .NET 可以将文件视为有效图像并可以进一步处理,那么它就是有效图像。

using System.Drawing;

    private bool IsValidImageFile(IFormFile file) {
    
      try {
        var isValidImage = Image.FromStream(file.OpenReadStream());
      } catch {
        return false;
      }
    
      return true;
    }

在服务器端与内容类型进行比较,如果它与您所需的上传格式匹配,则继续,否则返回错误消息

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

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