TL; DR: Ich habe ein CMS-System, das Anhänge (undurchsichtige Dateien) unter Verwendung von SHA-1 des Dateiinhalts als Dateiname speichert. Wie kann ich überprüfen, ob die hochgeladene Datei wirklich mit einer im Speicher übereinstimmt, da ich bereits weiß, dass der SHA-1-Hash für beide Dateien übereinstimmt? Ich hätte gerne eine hohe Leistung.
Lange Version:
Wenn ein Benutzer eine neue Datei auf das System hochlädt, berechne ich den SHA-1-Hash des hochgeladenen Dateiinhalts und überprüfe dann, ob eine Datei mit identischem Hash bereits im Speicher-Backend existiert. PHP stellt die hochgeladene Datei in /tmp
, bevor mein Code ausgeführt wird, und dann führe ich sha1sum
gegen die hochgeladene Datei aus, um SHA-1-Hash des Dateiinhalts zu erhalten. Ich berechne dann Fanout aus dem berechneten SHA-1-Hash und entscheide das Speicherverzeichnis unter der NFS-Verzeichnishierarchie. (Wenn beispielsweise der SHA-1-Hash für einen Dateiinhalt 37aefc1e145992f2cc16fabadcfe23eede5fb094
ist, lautet der permanente Dateiname /nfs/data/files/37/ae/fc1e145992f2cc16fabadcfe23eede5fb094
.) Zusätzlich zum Speichern des eigentlichen Dateiinhalts, habe ich INSERT
eine neue Zeile in eine SQL-Datenbank für die Benutzer übermittelte Metadaten (zB Content-Type
, Originaldateiname, Datumsstempel, usw.).
Der Eckfall, den ich gerade herausfinde, ist der Fall, in dem eine neu hochgeladene Datei SHA-1-Hash hat, der mit dem vorhandenen Hash im Speicher-Backend übereinstimmt. Ich weiß, dass die Veränderungen durch Zufall zufällig astronomisch niedrig sind, aber ich möchte sicher sein. (Für den Fall der Fälle siehe Ссылка )
Wie können Sie bei zwei Dateinamen $file_a
und $file_b
schnell prüfen, ob beide Dateien den gleichen Inhalt haben? Nehmen Sie an, dass Dateien zu groß sind, um in den Speicher geladen zu werden. Mit Python würde ich filecmp.cmp()
verwenden, aber PHP scheint nichts Ähnliches zu haben. Ich weiß, dass dies mit fread()
gemacht werden kann und abgebrochen wird, wenn ein nicht übereinstimmendes Byte gefunden wird, aber ich möchte diesen Code lieber nicht schreiben.
Wenn Sie bereits eine SHA1-Summe haben, können Sie einfach Folgendes tun:
%Vor%sonst
%Vor%Überprüfen Sie auch die Dateigröße, um eine Hash-Kollision etwas zu verhindern (was bereits sehr unwahrscheinlich ist). Auch mit MD5, weil es deutlich schneller ist als die SHA-Algorithmen (aber ein bisschen weniger einzigartig).
Aktualisierung:
So können Sie zwei Dateien genau vergleichen.
%Vor%Aktualisieren
Wenn Sie sicherstellen wollen, dass die Dateien gleich sind, sollten Sie zuerst die Dateigrößen überprüfen und wenn sie übereinstimmen, dann differentieren Sie den Dateiinhalt. Dies ist viel schneller als eine Hash-Funktion und wird definitiv das richtige Ergebnis geben.
Es ist nicht erforderlich, den gesamten Dateiinhalt in den Speicher zu laden, wenn Sie den Inhalt mit md5_file()
oder sha1_file()
oder einer anderen hash_function überprüfen. Hier kommt ein Beispiel mit md5
:
Ausgabe:
%Vor%In Ihrem Beispiel wäre es:
%Vor%Wenn Sie eine Hash-Funktion verwenden, haben Sie immer eine Situation, in der Sie sich einerseits zwischen der Komplexität einerseits und der Wahrscheinlichkeit von Kollisionen andererseits entscheiden müssen (was bedeutet, dass zwei verschiedene Nachrichten den gleichen Hash erzeugen) .
Wenn Ihre Dateien groß und binär sind, können Sie einige Bytes davon mit ein paar Offsets testen. Es sollte viel schneller als jede Hashing-Funktion sein, insbesondere, dass die Funktion das Ergebnis durch das erste andere Zeichen zurückgibt.
Diese Methode funktioniert jedoch nicht für Dateien mit nur wenigen unterschiedlichen Zeichen. Es ist das beste für große Archive, Videos und so weiter.
Tags und Links php file-io performance file-upload