Reputation: 15557
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
Upvotes: 71
Views: 95775
Reputation: 1
Correct answer is:
public bool CheckTrueImageType()
{
// DICTIONARY OF ALL IMAGE FILE HEADER
Dictionary<string, byte[][]> imageHeader = new Dictionary<string, byte[][]>();
imageHeader.Add("JPG", new byte[][] { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xDB } });
imageHeader.Add("JPEG", new byte[][] { new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 },
new byte[] { 0xFF, 0xD8, 0xFF, 0xDB } });
imageHeader.Add("PNG", new byte[][] { new byte[] { 0x89, 0x50, 0x4E, 0x47 } });
imageHeader.Add("TIF", new byte[][] { new byte[] { 0x49, 0x49, 0x2A, 0x00 },
new byte[] { 0x49, 0x20, 0x49 },
new byte[] { 0x4D, 0x4D, 0x00, 0x2A },
new byte[] { 0x4D, 0x4D, 0x00, 0x2B } });
imageHeader.Add("TIFF", new byte[][] { new byte[] { 0x49, 0x49, 0x2A, 0x00 },
new byte[] { 0x49, 0x20, 0x49 },
new byte[] { 0x4D, 0x4D, 0x00, 0x2A },
new byte[] { 0x4D, 0x4D, 0x00, 0x2B } });
imageHeader.Add("GIF", new byte[][] { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 },
new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 } });
imageHeader.Add("BMP", new byte[][] { new byte[] { 0x42, 0x4D } });
imageHeader.Add("ICO", new byte[][] { new byte[] { 0x00, 0x00, 0x01, 0x00 } });
bool isTrueImage = false;
if (FileUpload1.HasFile)
{
// GET FILE EXTENSION
string fileExt = FileUpload1.FileName.Substring(FileUpload1.FileName.LastIndexOf('.') + 1).ToUpper();
// CUSTOM VALIDATION GOES HERE BASED ON FILE EXTENSION IF ANY
byte[][] tmp = imageHeader[fileExt];
foreach (byte[] validHeader in tmp)
{
byte[] header = new byte[validHeader.Length];
// GET HEADER INFORMATION OF UPLOADED FILE
FileUpload1.FileContent.Seek(0, System.IO.SeekOrigin.Begin);
FileUpload1.FileContent.Read(header, 0, header.Length);
if (CompareArray(validHeader, header))
{
// VALID HEADER INFORMATION
isTrueImage = true;
break;
}
}
}
if (!isTrueImage)
{
lblStatus.ForeColor = System.Drawing.Color.Red;
lblStatus.Text += "<br />Invalid file header! ";
}
return isTrueImage;
}
private bool CompareArray(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
for (int i = 0; i < a1.Length; i++)
{
if (a1[i] != a2[i])
return false;
}
return true;
}
Upvotes: 0
Reputation: 181
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.
using System.Drawing;
private bool IsValidImageFile(IFormFile file) {
try {
var isValidImage = Image.FromStream(file.OpenReadStream());
} catch {
return false;
}
return true;
}
Upvotes: 1
Reputation: 2221
In case it can helps anyone, Here is a static method for HttpPostedFileBase
that checks if a given uploaded file is an image:
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.
Upvotes: 128
Reputation: 4253
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 type="file" id="file" accept="image/*">
The usual caveats about trusting user input applies.
Upvotes: 2
Reputation: 726
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
}
Upvotes: 0
Reputation: 3711
It's 2018 and the accepted answer does not work with .NET CORE 2.1 because we now have IFormFile
instead of 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):
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;
}
}
Upvotes: 50
Reputation: 2732
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());
}
}
Upvotes: 2
Reputation: 468
For anyone that runs into this.
You could also use a file.ContentType.Contains("image")
to check if the content type is of 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.
Upvotes: 20
Reputation: 1630
in the server side compare with content type if its matching with your required uploaded format then proceed or else return error message
Upvotes: -2
Reputation: 136
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:
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.
Upvotes: 11
Reputation: 190941
As a first step, you should form a white list around the acceptable MIME types against the ContentType
property.
Upvotes: 0
Reputation: 48250
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
}
Upvotes: 15