Dateien mit PHP in mySQL DB speichern

Hier schreibe ich, wie man eine Datei in einer mySQL Datenbank speichert. Dafür sollte man sich etwas mit PHP und mySQL auskennen. Ich schreibe hier nicht, wie man Dateien auf den Webspace hochlädt. Zudem gehe ich davon aus, dass die Datei schon auf dem Webspace liegt.

Vorbereitungen

Also los. Zuerst zur Datenbank. Prädestiniert für Binärdateien sind die Blobs (Binary Large Objects). Zudem sollte man den Mimetype in der Datenbank speichern, falls der schon, zum Beispiel durch einen Upload bekannt ist. Also sieht die Tabelle zum Beispiel so aus:
mysql> describe files;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| fileID   | int(11)      |      | PRI | NULL    | auto_increment |
| fileType | varchar(200) |      |     |         |                |
| fileData | blob         |      |     |         |                |
+----------+--------------+------+-----+---------+----------------+

Daten schreiben

Um die Daten in die DB zu schreiben, muss zuerst den Inhalt der Datei auslesen. Die macht man so:
<?
// die datei, die in die db geschrieben wird
$file="bild.jpg";

// datei oeffnen
// das r steht fuer read und das b fuer binary
$fp=@fOpen($file,"rb")or die("konnte die datei nicht oeffnen");

// daten auslesen
$content=fRead($fp,fileSize($file));

// datei schliessen
fClose($fp);
?>
Nun ist der Inhalt der Datei in der Variable $content gespeichert.
Jetzt muss der Inhalt der Datei noch in die Datenbank geschrieben werden. Da die Datei in diesem Beispiel ein JPG ist nehme ich ich den Mimetype image/jpeg. Sollte dieser Typ nicht bekannt sein, muss auf die Datei mime.types zurückgegriffen werden. Dieser Mimetype ist wichtig, da er nachher als Content-type an den Browser gesendet wird.
Nun zur mySQL Query:
<?
mysql_query
("
    INSERT INTO
        files
        (
            `fileType`,
            `fileData`
        )
    VALUES
        (
            'image/jpeg',
            '"
.addSlashes($content)."'
        )"
);
?>
Die Funktion addSlashes() ist wichtig, da es sonst zu mySQL Fehler kommt, da das Zeichen ' im Dateiinhalt sein könnte.

Daten auslesen


<?
// id setzen. kann auch per $_GET bzw. $_POST geschehen
$id=1;

// daten auslesen
$result=$db->query("
                SELECT
                    fileType,
                    fileData
                FROM
                    files
                WHERE
                    fileID="
.$id);

$type=mysql_result($result,0,"fileType");
$data=mysql_result($result,0,"fileData");

// headers
// den content-type (mimetype) senden. aus der db
header("Content-type: ".$type);

// die groesse des inhalts anzeigen. damit der browser die verbleibende zeit berechnen kann.
header("Content-Length: ".strLen($data));

// die anzeige und der filename der datei.
// content-disposition: attachment oeffnet einen speichern unter dialog
// content-disposition: inline oeffnet das file im browser falls moeglich (pdf)
header("Content-Disposition: attachment; filename=bild.jpg");

echo 
$data;
?>


Keine grosse Kunst, allerdings gibt es doch einige Dinge, die man beachten sollte.

Kommentare

Michel 27.03.07 09:47
Gravatar von Michel Find ich interessant, gibts spezifische Anwendungsgebiete wo man Dateien am besten in eine Datenkbank schreibt?
david 27.03.07 10:11
Gravatar von david Es ist sehr umstritten, ob das Speichern von Binärdaten in Datenbanken sinnvoll ist. Viele Leute sind der Meinung, dass das nonsense ist.
Ich verwende diese Funktionalität momentan, um PDF Dateien zu speicheren. Es hat den Vorteil, dass ich nur die DB und keine sonstigen Datern von der Festplatte speichern muss. Zudem muss ich, beim löschen eines Datensatztes nicht noch die Datei auf der Festplatte entfernen.
Wo es in meiner Meienung auch noch sinn machen würde, ist bei geschützen Bereichen. Manchmal möchte man Dateien nicht allen Benutzern zugänglich machen. Wenn die Datei in einer mySQL DB gespeichert ist, kann man das ganz klar regeln.

Schlussendlich muss man sagen, dass mySQL halt nicht so schnell ist wie das Filesystem und dass dafür auch immer ein zusätzliches Script gestartet werden muss. Allerdings muss man nur die DB sichern.

Ein spezifisches Anwenungsgebiet kann ich dir nicht nennen, am besten Entscheidet man von Fall zu Fall ob sowas sinnvoll ist. Eine Downloadpage würde ich auf jeden Fall nicht so realisieren.
Michel 28.03.07 13:53
Gravatar von Michel Danke für die Ausführung! Ja, eben gerade wegen der Performance habe ich es bisher noch nicht mal gewagt daran zu denken Files in die Datenkbank zu schreiben, gerade wenn eine Applikation skalierbar sein muss.

Aber werde deine Anleitung trotzdem mal testen. Danke!
Tony 31.03.07 20:56
Gravatar von Tony Eine weitere Anwendung ist die Ergänzung der Dokumente mit Metadaten wie Autor, Datum der Veröffentlichung, Sprache in welcher das Dokument geschrieben ist (muss ja nicht mit der Webseitensprache übereinstimmen...) etc. Mit diesen Metadaten kann eine sehr aussagekräftige Dokumentenliste auf der Webseite angezeigt werden. Zudem ist die Filterung nach Metadaten möglich - mach das mal auf dem Filesystem...
dominik kessler 15.06.07 16:34
Gravatar von dominik kessler ihr habt doch alle keine ahnung so macht mann dass: =>

for($i = 0, $Export = ""; $i < mysql_num_rows($ResultPointer); $i++)
{
$Daten = mysql_fetch_object($ResultPointer);


$Spalte[] = str_replace("\"", "\"\"", $Daten->usr_id);
$Spalte[] = str_replace("\"", "\"\"", $Daten->username);
$Spalte[] = str_replace("\"", "\"\"", $Daten->first_name);
$Spalte[] = str_replace("\"", "\"\"", $Daten->last_name);
dominik kessler 15.06.07 16:35
Gravatar von dominik kessler $Spalte[] = str_replace("\"", "\"\"", $Daten->usr_id);
$Spalte[] = str_replace("\"", "\"\"", $Daten->username);
$Spalte[] = str_replace("\"", "\"\"", $Daten->first_name);
david 20.06.07 15:15
Gravatar von david Und was hat das genau mit dem Thema zu tun?
Gravatar von der echte Dominik Kessler ...ich war das nicht! Nicht dass mich da jemand verunglimpfen will, im weltweiten webnetz ;-)
ChrisPHL 09.03.09 10:59
Gravatar von ChrisPHL Die Anleitung funktioniert hervorragend, eine 3kb große Datei kann ich in die Db schreiben, Teste ich mit einer 8kb-Datei, bekomme ich immer "Lost connection to MySQL server during query".
Kann man da zur Laufzeit(!) irgend was mit php "drehen"?
david 09.03.09 21:07
Gravatar von david Hmm komisch... Ich habe mit dieser Methode schon über 10 MB grosse Files ohne Probleme in die DB geschrieben.
Über Google habe ich einige Links zu Themen gefunden, wo das Problem war, dass die mySQL-Verbindung nicht zum Localhost hergestellt wurde. Wie sieht das bei dir aus? Ist das ein Server beim Hoster oder eins bei dir, wo du die mySQL-Konfiguration anpassen kannst?
Wieland Peter 10.04.09 19:06
Gravatar von Wieland Peter Finde das dargestellte Beispiel zwar recht nice um zu verstehen, wie man grundsätzlich ne Datenbank-Verbindung aufbaut, jedoch rate ich jedem davon ab, auf diese Weiße Daten in die Datenbank zu schreiben.

Ich nenne diese Art "Stringgefutzel". Verwendet besser mysqli als PHP-Schnittstelle mit prepaired-satements.

Das hier ist TOTAL unsicher.
Macht mal auf diese Weise ne Passwortabfrage und Ihr werdet feststellen, dass man sich einloggen kann, indem man als Passwort 1' or true eingibt.
Mit dem ' schließt man die query und or true liefert der Webseite immer true zurück, so als ob das Passwort richtig wäre.

Kommentieren

Name:
Mail:
Homepage:
4+2=? (Spamschutz)