Bạn có thể dễ dàng xác định loại MIME tệp bằng JavaScript FileReader
trước khi tải nó lên máy chủ. Tôi đồng ý rằng chúng ta nên thích kiểm tra phía máy chủ hơn phía máy khách, nhưng vẫn có thể kiểm tra phía máy khách. Tôi sẽ chỉ cho bạn cách và cung cấp một bản demo hoạt động ở phía dưới.
Kiểm tra xem trình duyệt của bạn hỗ trợ cả File
và Blob
. Tất cả những người quan trọng nên.
if (window.FileReader && window.Blob) {
// All the File APIs are supported.
} else {
// File and Blob are not supported
}
Bước 1:
Bạn có thể truy xuất File
thông tin từ một <input>
yếu tố như thế này ( ref ):
<input type="file" id="your-files" multiple>
<script>
var control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
// When the control has changed, there are new files
var files = control.files,
for (var i = 0; i < files.length; i++) {
console.log("Filename: " + files[i].name);
console.log("Type: " + files[i].type);
console.log("Size: " + files[i].size + " bytes");
}
}, false);
</script>
Đây là phiên bản kéo và thả của phần trên ( ref ):
<div id="your-files"></div>
<script>
var target = document.getElementById("your-files");
target.addEventListener("dragover", function(event) {
event.preventDefault();
}, false);
target.addEventListener("drop", function(event) {
// Cancel default actions
event.preventDefault();
var files = event.dataTransfer.files,
for (var i = 0; i < files.length; i++) {
console.log("Filename: " + files[i].name);
console.log("Type: " + files[i].type);
console.log("Size: " + files[i].size + " bytes");
}
}, false);
</script>
Bước 2:
Bây giờ chúng ta có thể kiểm tra các tệp và trêu chọc các tiêu đề và các loại MIME.
Phương pháp nhanh
Bạn có thể yêu cầu Blob một cách ngây thơ về loại MIME của bất kỳ tệp nào mà nó đại diện bằng cách sử dụng mẫu này:
var blob = files[i]; // See step 1 above
console.log(blob.type);
Đối với hình ảnh, các loại MIME quay lại như sau:
hình ảnh / hình ảnh jpeg
/ png
...
Hãy cẩn thận: Loại MIME được phát hiện từ phần mở rộng tệp và có thể bị đánh lừa hoặc giả mạo. Người ta có thể đổi tên .jpg
thành a .png
và loại MIME sẽ được báo cáo là image/png
.
✓ Phương pháp kiểm tra tiêu đề phù hợp
Để có được loại MIME bonafide của tệp phía máy khách, chúng ta có thể tiến thêm một bước và kiểm tra một vài byte đầu tiên của tệp đã cho để so sánh với các số được gọi là ma thuật . Được cảnh báo rằng nó không hoàn toàn đơn giản bởi vì, ví dụ, JPEG có một vài "số ma thuật". Điều này là do định dạng đã phát triển từ năm 1991. Bạn có thể thoát khỏi việc chỉ kiểm tra hai byte đầu tiên, nhưng tôi thích kiểm tra ít nhất 4 byte để giảm dương tính giả.
Chữ ký tệp ví dụ của JPEG (4 byte đầu tiên):
FF D8 FF E0 (SOI + ADD0)
FF D8 FF E1 (SOI + ADD1)
FF D8 FF E2 (SOI + ADD2)
Đây là mã cần thiết để lấy tiêu đề tệp:
var blob = files[i]; // See step 1 above
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
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);
}
console.log(header);
// Check the file signature against known types
};
fileReader.readAsArrayBuffer(blob);
Sau đó, bạn có thể xác định loại MIME thực như vậy (thêm chữ ký tệp ở đây và đây ):
switch (header) {
case "89504e47":
type = "image/png";
break;
case "47494638":
type = "image/gif";
break;
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
case "ffd8ffe3":
case "ffd8ffe8":
type = "image/jpeg";
break;
default:
type = "unknown"; // Or you can use the blob.type as fallback
break;
}
Chấp nhận hoặc từ chối tải lên tệp theo ý muốn dựa trên các loại MIME dự kiến.
Bản giới thiệu
Đây là một bản demo hoạt động cho các tệp cục bộ và các tệp từ xa (tôi đã phải bỏ qua CORS chỉ cho bản demo này). Mở đoạn mã, chạy nó và bạn sẽ thấy ba hình ảnh từ xa thuộc các loại khác nhau được hiển thị. Ở đầu bạn có thể chọn tệp hình ảnh hoặc dữ liệu cục bộ và chữ ký tệp và / hoặc loại MIME sẽ được hiển thị.
Lưu ý rằng ngay cả khi một hình ảnh được đổi tên, loại MIME thực sự của nó có thể được xác định. Xem bên dưới.
Ảnh chụp màn hình
// Return the first few bytes of the file as a hex string
function getBLOBFileHeader(url, blob, callback) {
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
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);
}
callback(url, header);
};
fileReader.readAsArrayBuffer(blob);
}
function getRemoteFileHeader(url, callback) {
var xhr = new XMLHttpRequest();
// Bypass CORS for this demo - naughty, Drakes
xhr.open('GET', '//cors-anywhere.herokuapp.com/' + url);
xhr.responseType = "blob";
xhr.onload = function() {
callback(url, xhr.response);
};
xhr.onerror = function() {
alert('A network error occurred!');
};
xhr.send();
}
function headerCallback(url, headerString) {
printHeaderInfo(url, headerString);
}
function remoteCallback(url, blob) {
printImage(blob);
getBLOBFileHeader(url, blob, headerCallback);
}
function printImage(blob) {
// Add this image to the document body for proof of GET success
var fr = new FileReader();
fr.onloadend = function() {
$("hr").after($("<img>").attr("src", fr.result))
.after($("<div>").text("Blob MIME type: " + blob.type));
};
fr.readAsDataURL(blob);
}
// Add more from http://en.wikipedia.org/wiki/List_of_file_signatures
function mimeType(headerString) {
switch (headerString) {
case "89504e47":
type = "image/png";
break;
case "47494638":
type = "image/gif";
break;
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
type = "image/jpeg";
break;
default:
type = "unknown";
break;
}
return type;
}
function printHeaderInfo(url, headerString) {
$("hr").after($("<div>").text("Real MIME type: " + mimeType(headerString)))
.after($("<div>").text("File header: 0x" + headerString))
.after($("<div>").text(url));
}
/* Demo driver code */
var imageURLsArray = ["http://media2.giphy.com/media/8KrhxtEsrdhD2/giphy.gif", "http://upload.wikimedia.org/wikipedia/commons/e/e9/Felis_silvestris_silvestris_small_gradual_decrease_of_quality.png", "http://static.giantbomb.com/uploads/scale_small/0/316/520157-apple_logo_dec07.jpg"];
// Check for FileReader support
if (window.FileReader && window.Blob) {
// Load all the remote images from the urls array
for (var i = 0; i < imageURLsArray.length; i++) {
getRemoteFileHeader(imageURLsArray[i], remoteCallback);
}
/* Handle local files */
$("input").on('change', function(event) {
var file = event.target.files[0];
if (file.size >= 2 * 1024 * 1024) {
alert("File size must be at most 2MB");
return;
}
remoteCallback(escape(file.name), file);
});
} else {
// File and Blob are not supported
$("hr").after( $("<div>").text("It seems your browser doesn't support FileReader") );
} /* Drakes, 2015 */
img {
max-height: 200px
}
div {
height: 26px;
font: Arial;
font-size: 12pt
}
form {
height: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form>
<input type="file" />
<div>Choose an image to see its file signature.</div>
</form>
<hr/>
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Tôi không hiểu tại sao bạn nói rằng việc xác thực phải được thực hiện ở phía máy chủ, nhưng sau đó nói rằng bạn muốn giảm tài nguyên máy chủ. Nguyên tắc vàng: Không bao giờ tin tưởng đầu vào của người dùng . Điểm kiểm tra loại MIME ở phía máy khách là gì nếu bạn chỉ thực hiện nó ở phía máy chủ. Chắc chắn đó là một sự "lãng phí không cần thiết của tài nguyên khách hàng "?