Apakah ada cara untuk menghitung hash MD5 file sebelum diunggah ke server menggunakan Javascript?
Apakah ada cara untuk menghitung hash MD5 file sebelum diunggah ke server menggunakan Javascript?
Jawaban:
Meskipun ada implementasi JS dari algoritme MD5, browser lama biasanya tidak dapat membaca file dari sistem file lokal .
Saya menulisnya di tahun 2009. Lalu bagaimana dengan browser baru?
Dengan browser yang mendukung FileAPI , Anda * dapat * membaca konten file - pengguna harus memilihnya, baik dengan <input>
elemen atau drag-and-drop. Mulai Jan 2013, berikut ini susunan browser utama:
Saya telah membuat perpustakaan yang mengimplementasikan incremental md5 untuk melakukan hash file besar secara efisien. Pada dasarnya Anda membaca file dalam potongan (untuk menjaga memori rendah) dan melakukan hash secara bertahap. Anda mendapatkan penggunaan dasar dan contoh di readme.
Ketahuilah bahwa Anda memerlukan FileAPI HTML5, jadi pastikan untuk memeriksanya. Ada contoh lengkap di folder tes.
.end()
metode tersebut. Jika Anda memanggil metode ini lagi maka itu memberikan hasil yang salah di lain waktu. Karena .end()
panggilan .reset()
internal. Ini adalah bencana pengkodean dan tidak baik untuk penulisan perpustakaan.
sangat mudah untuk menghitung hash MD5 menggunakan fungsi MD5 dari CryptoJS dan API FileReader HTML5 . Potongan kode berikut menunjukkan bagaimana Anda dapat membaca data biner dan menghitung hash MD5 dari gambar yang telah diseret ke Browser Anda:
var holder = document.getElementById('holder');
holder.ondragover = function() {
return false;
};
holder.ondragend = function() {
return false;
};
holder.ondrop = function(event) {
event.preventDefault();
var file = event.dataTransfer.files[0];
var reader = new FileReader();
reader.onload = function(event) {
var binary = event.target.result;
var md5 = CryptoJS.MD5(binary).toString();
console.log(md5);
};
reader.readAsBinaryString(file);
};
Saya merekomendasikan untuk menambahkan beberapa CSS untuk melihat area Drag & Drop:
#holder {
border: 10px dashed #ccc;
width: 300px;
height: 300px;
}
#holder.hover {
border: 10px dashed #333;
}
Lebih lanjut tentang fungsionalitas Seret & Jatuhkan dapat ditemukan di sini: API File & FileReader
Saya menguji sampel di Google Chrome Versi 32.
readAsBinaryString()
belum distandarisasi dan tidak didukung oleh Internet Explorer. Saya tidak mengujinya di Edge, tetapi bahkan IE11 tidak mendukungnya.
readAsBinaryString()
: caniuse.com/#feat=filereader - Microsoft Edge mendukungnya.
readAsBinaryString()
karena tidak didukung oleh browser lama. Alternatif yang saya temukan adalah SparkMD5. Ia menggunakan API FileReader juga tetapi metode readAsArrayBuffer
, yang didukung oleh IE. Dan itu bisa menangani file besar dengan membacanya dalam potongan.
CryptoJS.lib.WordArray.create(arrayBuffer);
spark-md5
danQ
Dengan asumsi Anda menggunakan browser modern (yang mendukung API File HTML5), berikut ini cara Anda menghitung Hash MD5 dari file besar (ini akan menghitung hash pada potongan variabel)
function calculateMD5Hash(file, bufferSize) {
var def = Q.defer();
var fileReader = new FileReader();
var fileSlicer = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
var hashAlgorithm = new SparkMD5();
var totalParts = Math.ceil(file.size / bufferSize);
var currentPart = 0;
var startTime = new Date().getTime();
fileReader.onload = function(e) {
currentPart += 1;
def.notify({
currentPart: currentPart,
totalParts: totalParts
});
var buffer = e.target.result;
hashAlgorithm.appendBinary(buffer);
if (currentPart < totalParts) {
processNextPart();
return;
}
def.resolve({
hashResult: hashAlgorithm.end(),
duration: new Date().getTime() - startTime
});
};
fileReader.onerror = function(e) {
def.reject(e);
};
function processNextPart() {
var start = currentPart * bufferSize;
var end = Math.min(start + bufferSize, file.size);
fileReader.readAsBinaryString(fileSlicer.call(file, start, end));
}
processNextPart();
return def.promise;
}
function calculate() {
var input = document.getElementById('file');
if (!input.files.length) {
return;
}
var file = input.files[0];
var bufferSize = Math.pow(1024, 2) * 10; // 10MB
calculateMD5Hash(file, bufferSize).then(
function(result) {
// Success
console.log(result);
},
function(err) {
// There was an error,
},
function(progress) {
// We get notified of the progress as it is executed
console.log(progress.currentPart, 'of', progress.totalParts, 'Total bytes:', progress.currentPart * bufferSize, 'of', progress.totalParts * bufferSize);
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/q.js/1.4.1/q.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/2.0.2/spark-md5.min.js"></script>
<div>
<input type="file" id="file"/>
<input type="button" onclick="calculate();" value="Calculate" class="btn primary" />
</div>
Anda perlu menggunakan FileAPI. Ini tersedia di FF & Chrome terbaru, tetapi tidak di IE9. Ambil implementasi JS md5 yang disarankan di atas. Saya sudah mencoba ini dan meninggalkannya karena JS terlalu lambat (menit pada file gambar besar). Dapat mengunjungi kembali jika seseorang menulis ulang MD5 menggunakan array yang diketik.
Kode akan terlihat seperti ini:
HTML:
<input type="file" id="file-dialog" multiple="true" accept="image/*">
JS (w JQuery)
$("#file-dialog").change(function() {
handleFiles(this.files);
});
function handleFiles(files) {
for (var i=0; i<files.length; i++) {
var reader = new FileReader();
reader.onload = function() {
var md5 = binl_md5(reader.result, reader.result.length);
console.log("MD5 is " + md5);
};
reader.onerror = function() {
console.error("Could not read the file");
};
reader.readAsBinaryString(files.item(i));
}
}
reader
variabel akan menjadi file terakhir pada saat fungsi onload dijalankan.
CryptoJS.lib.WordArray.create(arrayBuffer);
Terlepas dari ketidakmungkinan untuk mendapatkan akses sistem file di JS, saya tidak akan menaruh kepercayaan sama sekali pada checksum yang dibuat klien. Jadi, membuat checksum di server adalah wajib dalam hal apa pun. - Tomalak 20 April '09 pukul 14:05
Yang tidak berguna dalam banyak kasus. Anda ingin MD5 dihitung di sisi klien, sehingga Anda dapat membandingkannya dengan kode yang dihitung ulang di sisi server dan menyimpulkan bahwa unggahan salah jika berbeda. Saya perlu melakukan itu dalam aplikasi yang bekerja dengan file besar data ilmiah, di mana menerima file yang tidak rusak adalah kuncinya. Kasus saya sederhana, karena MD5 pengguna sudah dihitung dari alat analisis data mereka, jadi saya hanya perlu menanyakannya kepada mereka dengan bidang teks.
Untuk mendapatkan file hash, ada banyak pilihan. Biasanya masalahnya adalah sangat lambat untuk mendapatkan hash file besar.
Saya membuat perpustakaan kecil yang mendapatkan hash file, dengan 64kb di awal file dan 64kb di akhir file.
Contoh langsung: http://marcu87.github.com/hashme/ dan perpustakaan: https://github.com/marcu87/hashme
Ada beberapa skrip di luar sana di internet untuk membuat Hash MD5.
Yang dari webtoolkit bagus, http://www.webtoolkit.info/javascript-md5.html
Meskipun, saya tidak percaya itu akan memiliki akses ke sistem file lokal karena akses itu terbatas.
harap Anda telah menemukan solusi yang baik sekarang. Jika tidak, solusi di bawah ini adalah implementasi janji ES6 berdasarkan js-spark-md5
import SparkMD5 from 'spark-md5';
// Read in chunks of 2MB
const CHUCK_SIZE = 2097152;
/**
* Incrementally calculate checksum of a given file based on MD5 algorithm
*/
export const checksum = (file) =>
new Promise((resolve, reject) => {
let currentChunk = 0;
const chunks = Math.ceil(file.size / CHUCK_SIZE);
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
const loadNext = () => {
const start = currentChunk * CHUCK_SIZE;
const end =
start + CHUCK_SIZE >= file.size ? file.size : start + CHUCK_SIZE;
// Selectively read the file and only store part of it in memory.
// This allows client-side applications to process huge files without the need for huge memory
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
};
fileReader.onload = e => {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) loadNext();
else resolve(spark.end());
};
fileReader.onerror = () => {
return reject('Calculating file checksum failed');
};
loadNext();
});
Cuplikan berikut menunjukkan contoh, yang dapat mengarsipkan throughput 400 MB / dtk saat membaca dan mencirikan file.
Ini menggunakan pustaka yang disebut hash-wasm , yang didasarkan pada WebAssembly dan menghitung hash lebih cepat daripada pustaka js-only. Mulai tahun 2020, semua browser modern mendukung WebAssembly.
const chunkSize = 64 * 1024 * 1024;
const fileReader = new FileReader();
let hasher = null;
function hashChunk(chunk) {
return new Promise((resolve, reject) => {
fileReader.onload = async(e) => {
const view = new Uint8Array(e.target.result);
hasher.update(view);
resolve();
};
fileReader.readAsArrayBuffer(chunk);
});
}
const readFile = async(file) => {
if (hasher) {
hasher.init();
} else {
hasher = await hashwasm.createMD5();
}
const chunkNumber = Math.floor(file.size / chunkSize);
for (let i = 0; i <= chunkNumber; i++) {
const chunk = file.slice(
chunkSize * i,
Math.min(chunkSize * (i + 1), file.size)
);
await hashChunk(chunk);
}
const hash = hasher.digest();
return Promise.resolve(hash);
};
const fileSelector = document.getElementById("file-input");
const resultElement = document.getElementById("result");
fileSelector.addEventListener("change", async(event) => {
const file = event.target.files[0];
resultElement.innerHTML = "Loading...";
const start = Date.now();
const hash = await readFile(file);
const end = Date.now();
const duration = end - start;
const fileSizeMB = file.size / 1024 / 1024;
const throughput = fileSizeMB / (duration / 1000);
resultElement.innerHTML = `
Hash: ${hash}<br>
Duration: ${duration} ms<br>
Throughput: ${throughput.toFixed(2)} MB/s
`;
});
<script src="https://cdn.jsdelivr.net/npm/hash-wasm"></script>
<!-- defines the global `hashwasm` variable -->
<input type="file" id="file-input">
<div id="result"></div>
Dengan HTML5 saat ini seharusnya mungkin untuk menghitung hash md5 dari file biner, Tapi saya pikir langkah sebelumnya adalah untuk mengubah data banary BlobBuilder menjadi String, saya mencoba melakukan langkah ini: tetapi belum berhasil.
Berikut adalah kode yang saya coba: Mengonversi BlobBuilder menjadi string, dalam HTML5 Javascript
Saya tidak yakin ada cara di javascript untuk mengakses konten unggahan file. Jadi, Anda tidak dapat melihat konten file untuk menghasilkan jumlah MD5.
Namun Anda dapat mengirim file ke server, yang kemudian dapat mengirim kembali jumlah MD5 atau mengirim kembali konten file .. tetapi itu banyak pekerjaan dan mungkin tidak bermanfaat untuk tujuan Anda.