6

I have my controller

[HttpPost]
public ActionResult ChangeAvatar(HttpPostedFileBase file)
{
    AvatarHelper.AvatarUpdate(file, User.Identity.Name);
    return RedirectToAction("Index", "Profile");
}

And I already check if file is in jpeg/png format:

private static bool IsImage(string contentType)
{   
  return AllowedFormats.Any(format => contentType.EndsWith(format,   
             StringComparison.OrdinalIgnoreCase));
}

public static List<string> AllowedFormats
{
    get { return new List<string>() {".jpg", ".png", ".jpeg"}; }
}

What I need - it ensure that uploaded file is real image file and not txt file with image extension.

I convert my uploaded file like this:

using (var image = System.Drawing.Image.FromStream(postedFile.InputStream))
{
          ///image stuff
}

I am thinking about try/catch block on creating image from input stream but I wonder if there is good way to do it? Thanks)

P.S.

I wonder if there is another (more efficient way that try/catch block) way to check whether file is real image?

makambi
  • 769
  • 1
  • 13
  • 22
  • try/catching should work just fine. Are you asking if that's a bad idea or if there's a better way? Not sure what your question is. Have you tried the try/catch method and it didn't work as expected or what? – Eli Gassert Mar 11 '13 at 11:27
  • try/catch works just fine. I just wonder it there is more efficient way to do it. – makambi Mar 11 '13 at 11:29
  • check the mimetype of it if it is image/octet-stream – K D Mar 11 '13 at 12:16

2 Answers2

5

You could use the RawFormat property:

private static ImageFormat[] ValidFormats = new[] { ImageFormat.Jpeg, ImageFormat.Png };
public bool IsValid(Stream image)
{
    try
    {
        using (var img = Image.FromStream(file.InputStream))
        {
            return ValidFormats.Contains(img.RawFormat);
        }
    }
    catch
    {
        return false;
    }
}

Also you could put this validation logic into a reusable validation attribute as I have shown in this post.

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • yep, as I wrote above I already do it. the question is: is there another way than try/catch block to figure out where incoming file is image and not just random file with image extension? – makambi Mar 11 '13 at 11:30
  • Yes, there is. You could start reading the stream and use heuristics to determine whether the format is one of the supported image formats. You will have to read each image format specification you want to support and be able to recognize the headers. It will be a lot of work though. – Darin Dimitrov Mar 11 '13 at 11:33
2

My solution as an extension, actually checking if a base64 string is an image or not:

public static bool IsImage(this string base64String)
    {
        byte[] imageBytes = Convert.FromBase64String(base64String);

        var stream = new MemoryStream(imageBytes, 0, imageBytes.Length);
        try
        {
            stream.Write(imageBytes, 0, imageBytes.Length);
            System.Drawing.Image image = System.Drawing.Image.FromStream(stream, true);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

Usage:

if(!"base64string".IsImage())
     throw new Exception("Not an image");
Sam Jones
  • 4,443
  • 2
  • 40
  • 45