It is not a good idea to avoid using model when developing in MVC(Model View Controller). As the meaning of MVC says, most of the time you ought to validate your Model before save data in database with IsValid method. The advice that i can give you is to forgotten about how you are working because it is not secure. Ought can you protect your web site from XSS scripting and others type of attack if not using a isvalid method of a Model. The main advantage with model is that you can easily validate it before saving these data and that you can easily solve this type of issues by creating your own validation attribute which will check these data both in server side and client side. Forget about the way that you are doing and just try to know about custom validation. I can however share this code which will check the file type in server if you are using a model.
public class FileTypeAttribute : ValidationAttribute
{
public string thefile{ get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo[] propriétés = validationContext.ObjectType.GetProperties();
PropertyInfo lafichies = propriétés.FirstOrDefault(p => p.Name == lefichier);
HttpPostedFileBase valFichierChoisi = thefile.GetValue(validationContext.ObjectInstance, null) as HttpPostedFileBase;
byte[] chkBytejpg = { 255, 216, 255, 224 };
byte[] chkBytejpg2 = { 255, 216, 255, 225 };
if (value != null && value.Equals(valFichierChoisi))
{//we check the type for jpeg file
//-------------------------------------------
if (valFichierChoisi.ContentType.ToLower() != "image/jpg" &&
valFichierChoisi.ContentType.ToLower() != "image/jpeg" &&
valFichierChoisi.ContentType.ToLower() != "image/pjpeg")
{
return new ValidationResult(ErrorMessage);
}
// Attempt to read the file and check the first bytes
//-------------------------------------------
try
{
if (!valFichierChoisi.InputStream.CanRead)
{
return new ValidationResult(ErrorMessage);
}
if (valFichierChoisi.ContentLength < ImageMinimumBytes)
{
return new ValidationResult(ErrorMessage);
}
byte[] buffer = new byte[valFichierChoisi.ContentLength];
valFichierChoisi.InputStream.Read(buffer, 0, valFichierChoisi.ContentLength);
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 new ValidationResult(ErrorMessage);
}
//you compare buffer sequence of file and known byte of jpeg in .net
if (chkBytejpg.SequenceEqual(buffer.Take(chkBytejpg.Length)))
{
return ValidationResult.Success;
}
else if (chkBytejpg2.SequenceEqual(buffer.Take(chkBytejpg2.Length)))
{
return ValidationResult.Success;
}
}
catch (Exception)
{
return new ValidationResult(ErrorMessage);
}
//-------------------------------------------
// 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(valFichierChoisi.InputStream))
{
}
}
catch (Exception)
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
}
I did it for server side. For client side validation, it is more difficult to use jquery unobstrusive validation for only one reason: It OUGHT TO RETURN a value. Let me explain. Suppose this validation result.
$.validator.unobtrusive.adapters.add('fichimage', ['thefile'],
function (options) {
options.rules['fichimage'] = options.params;
if (options.message) {
options.messages['fichimage'] = options.message;
}
}
);
$.validator.addMethod('fichimage', function (value, element, params) {
var lechoifait = $('input[name="' + params.thefile+ '"]').val();
if (value != null && value == lechoifait) {
//suppose that your browser allow the use of filereader
//know that you can obtain the selected file by using element.files[0]
var fr = new FileReader();
fr.onloadend = function (e) {
//Because this is done asynchronously
// the return will always be true for this validation no matter the kind of file
//apart of this, if you want to use any callback function, you will use it in this function which don't allows any return
};
fr.readAsDataURL(element.files[0]);
}
//this will always be true because of the asynchronously behaviour of onloadend function
return true;
}, '');
This is why i recommand you to implement your own way to solve this
based of the answer give by @Drakes(How to check file MIME type with javascript before upload?), i propose this answer.
Suppose that in the case of success, you want to load your image in this image
<img id="imagetoshow" alt="" src="" style=" width :80%; height :300px; display:none; "/>
Because you are working with mvc, your html helper could be something like that
@Html.TextBoxFor(m => m.selectedimage, new { type = "file", @class = "someclass", onchange = "checkandshow(this)" })
//this validation message is for checking for server side
//try another way if you are not using a model as claimed
@Html.ValidationMessageFor(m => m.selectedimage)
//you could use this label in the case of incorrect file
@Html.Label("", new { id = "badfile", @class = "badimageselected"})
in the case that you select an image(i check just for jpeg), the checkandshow(this) function will be executed. for signature of others kinds of files, please refer to this(https://en.wikipedia.org/wiki/List_of_file_signatures) and/or this (https://mimesniff.spec.whatwg.org/#matching-an-image-type-pattern)
function checkandshow(input) {
//imagetoshow is the id of the image tag where you want to load your image in the case of success
$('#imagetoshow').attr('src', '');
//you first check if the element contains any file
if (input.files && input.files[0]) {
// you check if the browser support filereader
if (window.FileReader && window.Blob) {
//because the browser support this, you create an object of this class
var filerdr = new FileReader();
filerdr.onload = function (e) {
//this subarray will allows you to check the first 4 bytes of the image
var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
var header = "";
for (var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
//typeFichier function will allows you obtaining the real mime of the file
var letype = typeFichier(header);
if (letype != 'image/jpeg') {
//in the case that it is not you type of file, just do whatever you want
//set the text in the label to prevent the user of this bad file
$("#badfile").text('The selected file is not a jpeg or jpg file.');
}
else {
//in the case of the good real MIME, you remove the text in the label and then load your image to the corresponding place
$("#badfile").text('');
//you just load the correct image
var loaderfr = new FileReader();
loaderfr.onload = function (c) {
//because the image is just show when you select the file, you change display: none and allow it be seen
$("#imagetoshow").show()
$('#imagetoshow').attr('src', c.target.result);
}
//this is for loading the image
loaderfr.readAsDataURL(input.files[0]);
}
}
//this is for loading the array buffer which will allows the bytes of the file to be checked
filerdr.readAsArrayBuffer(input.files[0]);
} else {
//in the case that File and Blob are not supported
$("#imagetoshow").show()
//you change the height because you want to reduce the space
$('#imagetoshow').height(15);
$('#imagetoshow').attr('alt', 'Sorry, your browser do not allows a preview of the selected image, migrate to another version of the browser or to other browser which allows this preview.');
}
}
};
the nonimage class of the label could be something like this
.nonimage { color: Red;font-weight:bold ; font-size:24px; }
here is the function which allows the get the real MIME of the file
function typeFichier(entete) {
switch (entete) {
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
type = "image/jpeg";
break;
default:
type = "unknown";
break;
}
return type;
};
Don't forget to add the required attribute if you want to use model ,in order to check the file in server side, something like this
[Required(FileType="selectedimage", ErrorMessage = "It seems that your file is incorrect, please try another one.")]
public HttpPostedFileBase selectedimage{ get; set; }
I strongly recommend you to use model for this kind of validation
jquery.validate. Refer this article for an example. - user3559349