125 Stimmen

Wie man md5-Hash einer Datei mit Javascript berechnen

Gibt es eine Möglichkeit, den MD5-Hash einer Datei vor dem Upload auf den Server mit Javascript zu berechnen?

3 Stimmen

Stark verwandt: [Wie generiert man eine Prüfsumme und konvertiert in 64 Bit in Javascript für sehr große Dateien, ohne dass der RAM überläuft? ]( stackoverflow.com/q/51987434/514235 )

107voto

Paul Dixon Punkte 286600

Es gibt zwar JS-Implementierungen des MD5-Algorithmus, ältere Browser können im Allgemeinen keine Dateien aus dem lokalen Dateisystem lesen .

Das habe ich 2009 geschrieben. Und was ist mit neuen Browsern?

Mit einem Browser, der die FileAPI Sie puede den Inhalt einer Datei lesen - muss der Nutzer sie ausgewählt haben, entweder mit einem <input> Element oder durch Ziehen und Ablegen. Stand Januar 2013: So sehen die wichtigsten Browser aus:

Wie?

Siehe die Antwort unten von Benny Neugebauer die die MD5-Funktion von CryptoJS

34 Stimmen

Abgesehen davon, dass es unmöglich ist, in JS Zugriff auf das Dateisystem zu erhalten, würde ich einer vom Client generierten Prüfsumme überhaupt nicht vertrauen. Die Generierung der Prüfsumme auf dem Server ist also auf jeden Fall erforderlich.

7 Stimmen

@Tomalak Sie müssen es auch auf dem Client tun, wenn Sie es nur hochladen wollen, wenn es sich von dem unterscheidet, was Sie bereits haben.

4 Stimmen

@John Nun, meine Aussage schließt dies nicht aus. Client-seitige Prüfungen dienen ausschließlich der Bequemlichkeit des Benutzers (und sind daher mehr oder weniger optional, je nachdem, wie bequem man es machen möchte). Serverseitige Prüfungen hingegen sind obligatorisch.

35voto

Benny Neugebauer Punkte 45468

Ist es ziemlich einfach, den MD5-Hash zu berechnen, indem man die MD5-Funktion von CryptoJS et le HTML5 FileReader API . Der folgende Codeausschnitt zeigt, wie Sie die Binärdaten lesen und den MD5-Hash aus einem Bild berechnen können, das in Ihren Browser gezogen wurde:

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);
};

Ich empfehle, etwas CSS hinzuzufügen, um den Drag & Drop-Bereich zu sehen:

#holder {
  border: 10px dashed #ccc;
  width: 300px;
  height: 300px;
}

#holder.hover {
  border: 10px dashed #333;
}

Mehr über die Drag & Drop-Funktionalität finden Sie hier: Datei-API & FileReader

Ich habe das Beispiel in Google Chrome Version 32 getestet.

2 Stimmen

Das Problem ist, dass readAsBinaryString() wurde nicht standardisiert und wird vom Internet Explorer nicht unterstützt. Ich habe es nicht in Edge getestet, aber auch IE11 unterstützt es nicht.

0 Stimmen

@user25163 Internet Explorer (und Opera Mini) scheinen die einzigen modernen Browser zu sein, die readAsBinaryString() : caniuse.com/#feat=filereader - Microsoft Edge unterstützt dies.

0 Stimmen

Vielen Dank für die Informationen zu MS Edge! Ich arbeite für ein Unternehmen. Und Sie wissen, dass Kunden oft alte Software verwenden und wie schwer es ist, sie zu überzeugen, ihre Software zu aktualisieren. Ich wollte nur darauf hinweisen, dass man vorsichtig sein muss, wenn man readAsBinaryString() da sie von älteren Browsern nicht unterstützt wird. Eine Alternative, die ich gefunden habe, ist SparkMD5. Es verwendet ebenfalls die FileReader-API, aber die Methode readAsArrayBuffer die vom IE unterstützt wird. Und er kann große Dateien verarbeiten, indem er sie in Stücken liest.

34voto

satazor Punkte 611

Ich habe eine Bibliothek erstellt, die inkrementelles md5 implementiert, um große Dateien effizient zu hashen. Im Grunde lesen Sie eine Datei in Chunks (um den Speicherplatz gering zu halten) und Hash es inkrementell. In der Readme-Datei finden Sie die grundlegende Verwendung und Beispiele.

Seien Sie sich bewusst, dass Sie HTML5 FileAPI benötigen, also stellen Sie sicher, dass Sie es haben. Ein vollständiges Beispiel befindet sich im Testordner.

https://github.com/satazor/SparkMD5

0 Stimmen

@Biswa hier ist meine Umsetzung. gist.github.com/marlocorridor/3e6484ae5a646bd7c625

1 Stimmen

Hey, das funktioniert super! Ich habe versucht, CryptoJS und konnte nie eine genaue MD5 aus ihm aus irgendeinem Grund zu bekommen, dies funktioniert wie ein Charme! Irgendwelche Pläne für sha256? @satazor

0 Stimmen

@cameck, die Bibliothek ist gut. Allerdings habe ich sie heute ausprobiert und es scheint, dass es ein Problem mit dem .end() Methode. Wenn Sie diese Methode erneut aufrufen, erhalten Sie beim nächsten Mal ein falsches Ergebnis. Denn .end() ruft auf. .reset() im Inneren. Das ist eine Katastrophe für die Codierung und nicht gut für die Erstellung von Bibliotheken.

27voto

Biró Dani Punkte 344

Das folgende Snippet zeigt ein Beispiel, das einen Durchsatz von 400 MB/s beim Lesen und Hashing der Datei archivieren kann.

Es verwendet eine Bibliothek namens Hash-Wasm die auf WebAssembly basiert und den Hash schneller berechnet als reine js- Bibliotheken. Ab 2020 unterstützen alle modernen Browser 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>

15voto

HTML5 + spark-md5 y Q

Unter der Annahme, dass Sie einen modernen Browser verwenden (der HTML5 File API unterstützt), können Sie die MD5-Hash einer großen Datei (es wird der Hash auf variablen Chunks berechnet)

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>

1 Stimmen

Prüfen Sie das Repo( github.com/satazor/js-spark-md5 ), die einen Beispielcode zur Berechnung von md5-Dateien enthält.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X