Bilder in MySQL-Datenbank speichern

veröffentlicht am 07. Februar 2011

Ich habe mich heute damit beschäftigt, wie man Bilder in einer relationalen Datenbank wie MySQL ablegen kann. Diese Methode hat viele Vorteile aber auch schlagkräftige Nachteile. Mit diesem Artikel beleuchte ich zunächst einmal die Vor- und Nachteile und zeige euch dann ein passendes PHP-Script, um Bilder in eine MySQL-Datenbank zu speichern und wieder auszulesen.

Vorteile

Viele Vorteile ergeben sich aus dem Fakt, dass Informationen (Artikel, Texte etc) zusammen in einer Datenbank abgespeichert werden. Dadurch können Bilder nicht ohne weiteres einfach verwaisen und es wird die Integrität der Daten vereinfacht. Metadaten können ebenfalls problemlos mit den Bildern verknüpft werden.

Die Speicherung in einer Datenbanken bringt aber auch noch andere Vorteile mit sich. So können sehr schnell und einfach Load-Balancing-Systeme auf Datenbank-Ebene eingeführt werden. Eine Portierung von einem System auf ein anderes ist ebenfalls sehr einfach, da einfach ein Backup der Datenbank erstellt und auf einen anderen Server übertragen werden kann – die Anwendung ist dann sofort wieder einsatzbereit.

Auch ist die Rechteverwaltung innerhalb einer Datenbank leichter umzusetzen, als auf Dateisystem-Ebene.

Es ergeben sich sicherlich noch weitere Vorteile, die mir auf die schnelle nicht eingefallen sind :)

Nachteile

Das Auslesen von Bildern aus einer Datenbank ist im Gegensatz zu einem direkten Zugriff auf das Dateisystem deutlich langsamer, da zunächst immer die Datenbankabfrage durchgeführt werden muss. Zudem kann ein Browser die Bilder nicht ohne weiteres zwischenspeichern, da der Webserver nicht erkennen kann, ob das Bild seit dem letzten Besuch verändert wurde. Die Backup-Strategie muss auch angepasst werden, da Bilder in Datenbanken als BLOBs (Binary Large Objects) abgelegt werden. Dadurch ist es nicht mehr so einfach möglich, textbasierte, inkrementelle Sicherungen zu erstellen.

Diese Nachteile können jedoch durch intelligente Lösungen drastisch reduziert werden. So kann man z.B. per PHP-Script überprüfen, ob sich das Bild in der Datenbank verändert hat und entsprechende Header zurückgeben. Für die Datenbank-Sicherung kann z.B. ein Point-in-Time Recovery verwendet werden.

PHP-Beispiel

Nachdem ich nun die Vor- und Nachteile erläutert habe, stelle ich ein simple Lösung vor, um Bilder per PHP in eine Datenbank zu bringen und wieder auszulesen. Diese Lösung ist wirklich minimalistisch und sollte um Überprüfungen und weitere Funktionalitäten erweitert werden.

Zunächst einmal muss eine entsprechende Datenbank angelegt werden:

CREATE DATABASE imagedb;
CREATE TABLE imagedb.images (
	id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	image BLOB NOT NULL,
	mimetype VARCHAR(32) NOT NULL
);

Nachdem die Datenbank angelegt wurde, erstellst du eine Datei namens connect.php, in der die MySQL-Verbindungsdaten hinterlegt werden und auch gleich die Verbindung zur Datenbank aufgebaut wird:

<?php
	// MySQL-Verbindungsdaten
	$hostname = 'localhost';
	$database = 'imagedb';
	$username = 'Dein DB-Benutzer';
	$password = 'Dein DB-Password';

	// MYSQL-Verbindung herstellen
	mysql_connect($hostname, $username, $password) or die(mysql_error());
	mysql_select_db($database) or die(mysql_error());
?>

Danach legst du die Datei index.php an, die für das Hochladen und Anzeigen der Bilder verantwortlich ist:

<?php
	// MySQL-Verbindung herstellen
	require 'connect.php';

	// Formular abgeschickt
	if(isset($_FILES['image'])) {

		// Datei hochgeladen
		if(is_uploaded_file($_FILES['image']['tmp_name'])) {

			// Verweis auf Bild
			$image = $_FILES['image']['tmp_name'];

			// Vorbereiten für den Upload in DB
			$data = addslashes(file_get_contents($image));

			// Metadaten auslesen
			$meta = getimagesize($image);
			$mime = $meta['mime'];

			// Bild in DB speichern
			mysql_query("INSERT INTO images VALUES('', '$data', '$mime')");
		}
	}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
		<title>MySQL-Bilder-Datenbank</title>
	</head>
	<body>
		<h1>Bild hochladen</h1>
		<form action="" method="post" enctype="multipart/form-data">
			<input name="image" type="file" />
			<input type="submit" value="hochladen" />
		</form>
		<h1>Bilderliste</h1>
		<?php
			$result = mysql_query("SELECT id FROM images");
			while($row = mysql_fetch_object($result)) {
				echo '<img alt="" src="image.php?id='.$row->id.'" /><br />';
			}
		?>
	</body>
</html>

Zuletzt wird die Datei image.php benötigt, die sich um das Auslesen der Bilder aus der Datenbank kümmert:

<?php
	// MySQL-Verbindung herstellen
	require 'connect.php';

	// Bild ausgeben
	$id = addslashed($_GET['id']);
	$result = mysql_query("SELECT image, mimetype FROM images WHERE id='$id'");
	$row = mysql_fetch_object($result);
	header("Content-type: $row->mimetype");
	echo $row->image;
?>

Quellen und weiterführende Links

Kommentare

Interessanter Ansatz.

Hast du testen können ob die Google Suche dabei mitspielt?

Und wie sieht es mit externen Aufrufen des Bildes aus, das geht ja wohl nicht, weil ja das image.php aufgerufen werden müsste.

Kommentar #1 von simonnickel am 15. Februar 2011


@simonnickel: Man kann natürlich auch die PHP-Datei von anderen Webseiten aus als Bildquelle angeben. Ich wüsste jetzt nicht, was dagegen sprechen könnte. Mit Google verhält es sich genauso: die PHP-Datei wird letztendlich „als Bild erkannt“.

Kommentar #2 von Patrick am 15. Februar 2011


Das stimmt natürlich, nicht lange genug nachgedacht. Hätte erst gedacht, dass das Probleme mit der Datenbank geben könnte. Aber da das Script das ja alles intern erledigt ist das ja kein Problem. Ist halt nur noch die Frage ob es wirklich Vorteile gegenüber einer Verwaltung des Bildarchivs mit Pfaden zur Datei im Dateisystem gibt.

Kommentar #3 von simonnickel am 15. Februar 2011


Um das Problem mit den BLOBs und den Backups zu umgehen, könnte man die Datei auch einfach per base64 encodieren und als (BIG)TEXT in die Datenbank speichern. Wie sich das hinsichtlich Performance und so auswirkt, kann ich grade nicht beurteilen, war auch nur ne spontane Idee. Die Backup-Files würden dadurch ja auch zu einer riesigen Datei anwachsen.

Kommentar #4 von digilist am 19. Februar 2011


mysql_select_db ist veraltet und in der image.php gibt es eine SQL Injection Lücke.

Kommentar #5 von xy am 17. April 2011


@xy: Ich hoffe mal, dass die SQL Injection Lücke nun durch Verwendung von addslashes bei der id in der Datei image.php geschlossen ist?

Und was verwendet man denn inzwischen statt mysql_select_db? Etwa folgendes?

mysql_query("USE DATABASE <Datenbank>");

Oder willst du darauf hinaus, dass ich die Angabe der Datenbank in den jeweiligen Queries machen sollte?

Kommentar #6 von Patrick am 03. Juni 2011


Super Lösung meiner Meinung nach.

Kommentar #7 von legatus am 12. Mai 2012


Vielen Dank für den Artikel. Ich bin auch eher für das speichern von Dateien im Filesystem. Deine Lösung macht es mir somit noch einfacher, dieses umzusetzen… Danke!

Kommentar #8 von magnus am 23. August 2012


Im Studium lernt man aber doch, dass man das geistige Eigentum anderer nicht als sein eigenes ausgeben soll?

Originaltext: http://www.php-faq.de/q-db-blob.html

Kommentar #9 von Thomas am 18. April 2013


Wenn Schavan und Guttenberg das können, kann ich das schon lange ;)

Nein im Ernst, ich glaube, damals vor dem Schreiben wirklich den Artikel gelesen zu haben. Habe mir auch irgendwann angewöhnt, verwendete Quellen unter dem Artikel anzugeben. Ich pflege den Link mal nach :)

Kommentar #10 von Patrick am 18. April 2013


Im image.php Skript ist ein Tippfehler:

$id = addslashed($_GET[‚id‘]);

müsste

$id = addslashes($_GET[‚id‘]);

heißen. Dann klappts auch mit den Bildern ;-)

Kommentar #11 von Carsten am 02. September 2014


kleiner fehler in image.php
// Bild ausgeben
$id = addslashed($_GET[‚id‘]);

addslasheS

Kommentar #12 von herbert am 03. November 2015


hei das ist ja super für mich als anfänger, leider stellte ich fest bei hochladen von paar testdateien, das es in der höhe das bild abschneidet.
Könnte mir da jemand einen Tipp geben woher das kommen könnte?
gruss
Steeve

Kommentar #13 von Steeve am 17. November 2015


@Steeve: Das Problem hatte ich auch. Ich konnte es lösen, indem ich bei der Definition der Tabelle für image den Typ LONGBLOB statt BLOB verwendet habe.

Kommentar #14 von Pascal am 21. November 2015


Habe es ausprobiert, leider werden die Bilder nicht angezeigt.

$id = addslashes($_GET[‚id‘]); habe ich korrigiert.

Was kann man noch machen?

Kommentar #15 von banto am 01. Dezember 2015


ich bastle noch gerade selbst an meiner seite und das hat mir sehr geholfen.
ich hattte nur ein problem ich musste bei image.php das addslashed rausnehmen jetzt klapts super!
grosses lob

MLG Elia

Kommentar #16 von Elia am 05. Januar 2016


Hinterlasse einen Kommentar