PHP Dateien in SQL DB speichern sinnvoll?

Domi83

Rear Admiral
Registriert
Feb. 2010
Beiträge
5.305
Hallo.. :)
Nachdem ich mich ja die Woche über mit dem ZendFramework befasst hatte und gestern eine kleine Diskussion dafür angestoßen hatte, möchte ich heute eigentlich nur noch eine Frage stellen :D

Ist es Sinnvoll, Dateien die über ein Input-Feld oder auch via Email ausgelesen werden, in eine MySQL Datenbank zu speichern.. oder macht es mehr Sinn, diese Dateien auf dem Server physikalisch abzuspeichern?

Für die, die Fragen was ich mache.. ich habe mir mit dem ZendFramework ein Skript gebaut, dass mir die Mails aus meinem Postfach holt und diese in eine SQL Datenbank nach meinen Wünschen speichert. Zur Verwendung von einem Ticketsystem :)

So, und da ist jetzt die Frage der Fragen :D
Meine Anhänge in den Emails, sollte man diese pysikalisch auf der Festplatte in einem Verzeichnis speichern, oder in der SQL Datenbank?

Die Forensysteme speichern das (meines Wissens) in einem Ordner, da wäre dann aber (denke ich) das Problem mit den doppelten Dateinamen.. gibt es da als Alternative die Möglichkeit, der physischen Datei einen random-Namen zu geben (z.B. 2012-02_hzt437.jpg) so dass das Datum + Random enthalten sind, und hinterher bei der Ausgabe kann man den Original-Namen wiedergeben!?

Ich meine das Ungefähr so, Datei "blabla.pdf" liegt in einem Ordner, wird aber virtuell über einen ganz anderen Namen dargestellt.. z.B. wenn man sagt Datei Öffnen oder Speichern, wird gesagt "anhang1.pdf" und nicht mehr "blabla.pdf" :D

Damit wäre ich dann schon mal ein wenig informiert.. glaube ich :)
Gruß, Domi
 
Hi,

wo siehst du den Unterschied von "physikalisch Speichern" und "in einer Datenbank speichern"? Abgesehen von der möglichen Indizierung und dem Performancegewinn durch eine Datenbank (Stichwort: "Suche Datei XYZ" oder "Suche alle Dateien der entsprechenden Mail raus")? Physikalisch sind die Daten da auch gespeichert.

Doppelte Dateinamen sind eine Zeile Code mehr um diesen dann anzupassen.

Es kommt einfach darauf an, wie du mit den Daten umgehen willst. Ich finde die Zuordnung über die DB recht einfach. Komplexer wird es aber auch nicht wenn du Sie im Dateisystem ablegst.

Wenn du eh schon eine DB verwendest dann bietet es sich meiner Meinung nach an auch die Anhänge da drin abzulegen. Ein Backup der DB und alles ist gesichert.

VG,
Mad
 
schadsoftware als blob weggespeichert sind sie keine gefahr, auf einem filesystem abgelegt schon
 
Gut gut, der Unterschied zwischen dem physikalischen Daten und der Datenbank bringt mich auch gerade zum schmunzeln :D Klar sind sie physikalisch vorhanden in beiden Formen.. ist mir zu spät eingefallen. Aber gut, das Beispiel "suche alle Dateien der entsprechenden Mail raus" finde ich persönlich ganz gut. Wenn ich in der Datenbank eine Tabelle für Anhänge erstelle, kann ich ja ein Spalte für die Zuordnung anhand der IDs machen, dann brauche ich in der Datenbank nur alle Anhänge mit der ID x raus suchen. X ist dann die ID der Mail und gut ist. Zusätzlich kann ich dann noch den Namen der Datei in einer Spalte speichern und gut ist.

Woran ich noch gar nicht dachte, "Schadsoftware als blob weggespeichert sind sie keine Gefahr"... das ist ein gutes Argument, hab ich so noch gar nicht gesehen / bedacht. Was ich auch noch gut finde ist die Backup-Geschichte. So brauche ich wirklich nur die eine Datenbank sichern und habe alles darin. Email Anfragen, die ganzen Antworten + Anhänge..

Aber was ich noch nicht gemacht habe, wir gebe ich mir denn die blob-Felder aus? Ich kann ja keinen "href=" zu einer Datei machen. Oder doch?

Gruß, Domi
 
Benutze doch Hashes zur Identifizierung, und weise ihnen separat ihre ursprünglichen Dateinamen zu...
 
Domi83 schrieb:
Aber was ich noch nicht gemacht habe, wir gebe ich mir denn die blob-Felder aus? Ich kann ja keinen "href=" zu einer Datei machen. Oder doch?

es muss eine PHP-Datei aufgerufen werden, die die Daten aus der Datenbank in den PHP-Speicher lädt und dann ausgibt, wer meint, dass sowas performant ist, soll es nutzen. Dateisysteme wurden nicht ohne Grund erschaffen und existieren heute auch noch aus guten Gründen und es wird nicht einfach alles in eine DB gespeichert...
 
Zuletzt bearbeitet:
Du speicherst in einer Datenbank zu jeder Datei, die als Anhang reinkommt den Dateinamen/Pfad und die Zeit. Diese kannst du konkatenieren, damit hättest du ja eigentlich schon einen eindeutigen Index. Zudem könntest du aus diesem String einen Hash erzeugen, das ist in Datenbanken etwas performanter wenn du beispielsweise etwas suchst. Diesen Hash benutzt du als Index. Zudem könntest du dazu eine Art ID einbauen, die eindeutig die Email identifiziert.
Wenn du den Weg über die Form "TitelDesDokuments_20120110.xxx" gehst, kannst du einfache reguläre Ausdrücke verwenden, um den Originaldateinamen wieder auseinanderzufriemeln.

Wenn du dich für nen Weg entschieden hast, sag einfach bescheid wenn du Hilfe brauchst, ich helf dir gern.

Edit: Hashtabellen sind nicht injektiv. Das heißt, dass ab einer bestimmten Menge an Elementen mehrere Elemente denselben Hashwert erhalten. Das kann später Probleme machen, je nachdem wie viele Files du indizieren willst.
 
Zuletzt bearbeitet: (HashNachteil)
the-bashelor schrieb:
Edit: Hashtabellen sind nicht injektiv. Das heißt, dass ab einer bestimmten Menge an Elementen mehrere Elemente denselben Hashwert erhalten. Das kann später Probleme machen, je nachdem wie viele Files du indizieren willst.

Also am effetivsten ist da folgendermaßen vorzugehen (nutze ich bei einer sehr großen Datenbank):
Aus dem String (hier: Dateiname) wird ein Integer-Hash gebildet (z.B. 32Bit) über FNV-1a oder andere Algorithmen.
Dann wird in der Datenbank nach diesem Integer-Hash gesucht (normaler Index, nicht unique) was nur noch ein Bruchteil der echten Datenmenge ist, und dann anhand des echten Dateinamens gefiltert.

Als Beispielcode:
PHP:
$hash = App_Hash::hash('fnv1a',$filename);
$res = mysql_fetch_query('SELECT ..... WHERE hash = ? AND filename = ?', $hash, $filename);

Warum kein Index auf eine String-Spalte? Der Speicherverbrauch für den Index ist viel höher (4 Byte Integer vs. strlen($filename) + 1 Byte) und der Vergleich ist viel viel komplexer.

Das Vorgehen kann man auch nochmal in dem Buch "High Performance MySQL, 2nd Edition" nachlesen, da habe ich die Idee her.
 
Zuletzt bearbeitet:
Domi83 schrieb:
Was ich auch noch gut finde ist die Backup-Geschichte. So brauche ich wirklich nur die eine Datenbank sichern und habe alles darin. Email Anfragen, die ganzen Antworten + Anhänge..
Das denkst du JETZT, aber SQL-Dumps sind immer volle Backups, es gibt keine inkrementellen Lösungen

Angenommen, du hast nach einer Weile so 2GB Anhänge, dann ist dein Datenbank-Dump eben etwas über 2GB groß. Kompression ist nicht drin, weil du blob-Felder (in denen auch wirklich blob steht) nicht ernsthaft komprimieren kannst (nicht im Vergleich zu reinen Text-Daten in Longtext- oder Varchar-Feldern). Jedes deiner Backups ist jetzt also >2GB groß, Tendenz steigend.

Angenommen, du speicherst nur reine Textdaten in der DB (inkl. Pfadangaben fürs Dateisystem, wo die Files liegen), und lässt den Rest im Dateisystem. Dann hast du pro Backup:
- einen einzigartigen Datenbank-Dump mit guten Kompressionsmöglichkeiten, der vielleicht 5-6MB groß ist
- einen Haufen Dateien, die zusammen 2GB Platz benötigen (und nicht gut komprimiert werden können).
Jetzt kombinierst du das mit nem rsync-basierten Backuptool (ich nutz auf Arbeit Dirvish. Sehr feines Ding auf rsync-Basis) und ziehst beim ERSTEN Backup die vollen 2GB+DB.sql, bei den nächsten Backups nur die aktuelle DB.sql sowie die Änderungen innerhalb der Files. Der Unterschied ist astronomisch. In meinem Falle: pro Backup-Zyklus 50-60MB SQL-Dump + 100MB Datei-Änderungen statt 50-60MB SQL + 3-4GB Dateien.

Aber was ich noch nicht gemacht habe, wir gebe ich mir denn die blob-Felder aus? Ich kann ja keinen "href=" zu einer Datei machen. Oder doch?
in einem separaten PHP-Script (oder was du halt für ne Sprache nutzt)
- Blob aus der DB fischen
- per PHP den passenden Datei-Header senden
- per PHP den Blob ausgeben (da tuts im Prinzip print_r)

Dein Href geht z.B. auf printfile.php?id=15...
 
Angenommen, du speicherst nur reine Textdaten in der DB (inkl. Pfadangaben fürs Dateisystem, wo die Files liegen), und lässt den Rest im Dateisystem. Dann hast du pro Backup:
- einen einzigartigen Datenbank-Dump mit guten Kompressionsmöglichkeiten, der vielleicht 5-6MB groß ist
- einen Haufen Dateien, die zusammen 2GB Platz benötigen (und nicht gut komprimiert werden können).

Richtig. Da stimme ich den Kollegen zu, ich glaube das solltest du so tun. Achja, noch zu deiner Malware-Befürchtung: Du kannst das Risiko einer Infektion natürlich drastisch verringern, indem du eine Unix-Basis nutzt :-) Außerdem gibts Unix-Filesysteme, die um einiges Mehr Funktionen beinhalten, vielleicht nützen die dir ja was bei der Umsetzung deines Projekts.
 
Neija das Malware-Argument ist einfach sinnlos, keine Malware kann irgendwas anrichten, wenn sie einfach nur auf dem Dateisystem gespeichert wird oder per Webserver an die Nutzer gesendet wird. Malware kann erst aktiv werden, wenn man in irgendeiner Form mit ihr arbeitet.
 
Eben, in dem Moment wo der BLOB ausgelesen und an einen User geschickt wird, hat man die Malware eh wieder am Laufen.
Noch schlimmer: einen BLOB kann das Antivirus-System nicht checken. Mit Files ist das hingegen kein Akt. Da baut man sich n Cronjob, der ClamAV regelmäßig über die Files schickt und unerwünschten Kram gleich entsorgt, schon ist alles in Butter.

Kann PHP eigentlich Dateien per inode ansprechen? Auf die schnelle find ich keine passende Funktion, aber das wäre absolut genial. Damit könnte man tolle Sachen machen.
 
Zuletzt bearbeitet:
@ ice breaker
@ daroon
gibt genügens stream scanner, die das bei upload können - es geht hier aber um serverseitig gespeicherte binaries, die als blobs harmlos sind, da gekapselt abgespeichert - es ist allerdings unbestritten, dass bei download diese pot. malware wieder clientseitig ausgeführt wird.

bzgl. ausführbarkeit auf dem server bei ablage im dateisystem: wenn man ne datei ablegt und über den pfad wieder aufruft, dann wird sie aktiv - backdoor als typ. bsp.
 
Zuletzt bearbeitet von einem Moderator:
@poly123: Das Argument bleibt trotzdem schwach. Wenn man einen solchen Upload-Dienst z.B. macht, dann speichert man die Dateien und sendet sie an Browser mehr macht man damit nicht. Du willst mir nicht ernsthaft erzählen, dass du auf hochgeladene Dateien Ausführungsrechte setzt und die Datei dann ausführst oder? Sebst bei Schwachstellen in PDFs oder Bildern ist es nötig, dass du diese in irgendeiner Form öffnest. Ein PDF wirst du auf dem Server nicht öffnen und bei Bildern ist dann wieder relevant mit welcher Software diese geöffnet werden und ob der Bug da auch enthalten ist. Würde man also Thumbnails von Bildern erzeugen ist sowohl eine DB-Lösung als auch eine File-Lösung "angreifbar", aber das ist wirklich alles rein theoretisch. Das Malware-Argument ist einfach sowas von an den Haaren herbeigezogen...
 
an den haaren herbeigezogen? file inclusion ist doch das typische einfallstor, am besten mal den unterschied zwischen blop und nativer speicherung im dateisystem mit dem EICAR test file testen - es reicht ja wenn die shell etc auf dem server liegt, sobald aufgerufen -> verloren, als weitere bsp. fallen mir hier c99 shell utc. ein
 
Tut mir leid, aber das Argument ist immernoch lächerlich.
Wenn du ne File-Inclusion-Lücke hast, dann hast du weit größere Probleme als Dateien die auf der Platte statt inner DB liegen, denn dann hat dein System massive Schwachstellen.
Wenn du mit solchen Argumenten kommst, kann man auch mit dem genauso lächerlichen Argument kommen das man mit SQL-Injections XYZ machen.

Die Entscheidung Filesystem vs. DB auf Grund einer Schwachstelle zu treffen, ist einfach nur unrealistisch. Hey er darf gar keine Datenbank verwenden, weil damit SQL-Injections möglich sind! Ach und kein PHP weil da in PHP 5.3.9 eine Schwere Lücke gefunden und und und.

Eine Designentscheidung einer Architektur trifft man nicht auf Basis potentieller Schwachstellen durch Dummheit beim Programmieren.
 
Ok ok ok... :)
Dann werde ich die Anhänge in ein Verzeichnis auf dem Server laden, dieses Verzeichnis werde ich dann mit einem Virenscanner + Cronjob in regelmäßigen Abständen prüfen. Irgend etwas kann ich mir da schon zurecht zaubern.. denke ich :D

Nur den Namen für das File muss ich dann noch anpassen. Auf der Festplatte muss das File ja einen eindeutigen Namen bekommen, und wenn man in der Weboberfläche auf die Datei klickt, sollte die Datei ja den Namen haben, wie sie auch versandt worden ist. Da muss ich mal schauen, dass habe ich so noch nie gebaut.

Beispiel, ich sende Datei "bla.xls", auf dem Server wird sie als "12345.xls" und wenn man den Anhang anklickt, sollte er sagen das ich "bla.xls" öffne oder speichere :D Aber das System wurde ja schon verstanden :)
 
Zurück
Oben