Bilder in MySQL-Datenbank speichern

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 abgefragt 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 kann 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;
?>
Empfehlen

6 Kommentare

simonnickel schrieb am 15. Februar 2011

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.

Patrick schrieb 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”.

simonnickel schrieb 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.

digilist schrieb am 19. 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.

xy schrieb am 17. April 2011

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

Patrick schrieb am 3. Juni 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?

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>