Bilder in DB speichern und via PHP-GD ausgeben
Betriebssystem: Linux
Webserver: Apache
Datenbank: MySQL
Scriptsprache: PHP
Bilder hochladen, kodieren und in DB speichern.
Um Bilder in einer DB zu speichern, kann man in einer Abfrage ja nicht einfach den Dateinamen angeben, sondern das Bild wird
z.B. mittels eines Formulars hochgeladen. Natürlich war jetzt meine Überlegung, wenn ich ein Bild sowieso hochladen muß,
um es in einer DB zu speichern, dann kann ich doch beides miteinander kombinieren: Upload und/oder Speichern in einer DB
Herausgekommen ist ein Upload-Script mit folgenden Funktionen:
- Das Script speichert Bilder in einem Verzeichnis des Webservers
- Optional kann noch ein Unterverzeichnis angegeben werden
- Via Checkbox kann man entscheiden, ob Bilder nach dem Hochladen noch kodiert und in einer DB gespeichert werden
- Sollen Bilder nur im der DB gespeichert werden, können Bilder nach Upload und Kodierung wieder gelöscht werden
Ein eventuell angelegtes Unterverzeichnis wird nicht gelöscht, da es ja auch noch mehr Bilder und/oder Daten enthalten könnte.
Zusätzlich kann ein Copyright über das Bild gelegt werden, entweder in Form eines einfachen Text und/oder als transparentes Wasserzeichen.
Der Text kann hierbei ein- oder mehrzeilig sein. Soll der Text mehrzeilig sein, so muß ein Array erstellt werden.
Beispiele hierzu finden sich im Script weiter unten.
Verwendete Software auf dem Server
Betriebssystem: Linux
Webserver: Apache
Datenbank: MySQL
Scriptsprache: PHP
Zum Zugriff auf die Datenbank verwende ich PDO. Um aus den kodierten Bilddaten "wieder ein Bild zu machen", wird die GD-Bibliothek benötigt.
Um nachzusehen, ob beides zur Verfügung steht, einfach eine PHP-Seite erstellen, und dort die Funktion phpinfo() aufrufen.
Die Datenbank zum Speichern der Bilddaten
Meine Datenbank zur Aufnahme der kodierten Bilddaten besteht aus einer Tabelle mit lediglich zwei Spalten
- id vom Typ int mit auto_increment
- data vom Typ Text
Upload-Script
Im Upload-Script wird das Root-Verzeichnis des Webservers ermittelt: $pfad=$HTTP_SERVER_VARS['DOCUMENT_ROOT']. An dieses Verzeichnis wird
ein Unterverzeichnis angehangen, in das der Webserver hochgeladene Bilder speichert bzw. weitere Unterverzeichnisse erstellt. Dieses Verzeichnis
muss dem Webserver gehören und er muss Schreib-Leserechte besitzen.
Ein Bild aus der DB laden und im Browser ausgeben
In diesem Script habe ich eine kleine Klasse mit ein paar Methoden erstellt, um aus den Bilddaten wieder ein Bild im Browser auszugeben.
Diese Methoden verwenden Funktionen der GD-Bibliothek. Diese Funktionen haben teilweise eine "ellenlange" Parameterliste. Um nicht
immer alle Parameter angeben zu müssen, sind in den Methoden einige (oder alle) Parameter mit Werten vorbelegt. Will man die Werte ändern,
so müssen die Werte von links nach rechts lückenlos eingegeben werden. Beispiel Textfarbe setzen:
Die Standardfarbe für Text ist rot. Würde man nun die Textfarbe auf grün setzen wollen, so notiert man:
Die Ausgabe eines Bilds habe ich in zwei Dateien vorgenommen:
- Eine Datei für die Klasse
- Eine Datei, in der der Datenbankzugriff erfolgt und die Anwendung der Klasse
Die Klassendatei
Anwendung der Klasse in einer Datei
Diese Datei stellt unter Verwendung der eingebundenen Klasse das Bild dar. Diese Datei kann im Browser aufgerufen werden, oder man gibt sie
in einer PHP-Datei als Bildresource an: <img src = "mein_bild.php">
Damit wäre die Bildausgabe fertig. Um nun noch einen Text als Copyright/transparentes Wasserzeichen über das Bild zu definieren, gibt es zwei Möglichkeiten:
- Eine einzige Textzeile
- Einen mehrzeiligen Text (als Array)
Beide Variablen können der Methode übergeben werden
Das transparente Wasserzeichen
Dazu erstellen wir erstmal ein leeres Bild in der gewünschten Breite und Höhe
Dann werden die Textparameter für das Wasserzeichen gesetzt
Anschließend wird das transparente Wasserzeichen erstellt
Ein Bild mit Text und Wasserzeichen könnte dann so aussehen:
Abhängig von der Bildgröße muß man mit den Positionsparametern ein wenig ausprobieren, um den Text/das Wasserzeichen im Bild darzustellen.
Zum Schluß noch die Upload-Datei
Thats all Folks
Gruß
Güni
Webserver: Apache
Datenbank: MySQL
Scriptsprache: PHP
Bilder hochladen, kodieren und in DB speichern.
Um Bilder in einer DB zu speichern, kann man in einer Abfrage ja nicht einfach den Dateinamen angeben, sondern das Bild wird
z.B. mittels eines Formulars hochgeladen. Natürlich war jetzt meine Überlegung, wenn ich ein Bild sowieso hochladen muß,
um es in einer DB zu speichern, dann kann ich doch beides miteinander kombinieren: Upload und/oder Speichern in einer DB
Herausgekommen ist ein Upload-Script mit folgenden Funktionen:
- Das Script speichert Bilder in einem Verzeichnis des Webservers
- Optional kann noch ein Unterverzeichnis angegeben werden
- Via Checkbox kann man entscheiden, ob Bilder nach dem Hochladen noch kodiert und in einer DB gespeichert werden
- Sollen Bilder nur im der DB gespeichert werden, können Bilder nach Upload und Kodierung wieder gelöscht werden
Ein eventuell angelegtes Unterverzeichnis wird nicht gelöscht, da es ja auch noch mehr Bilder und/oder Daten enthalten könnte.
Zusätzlich kann ein Copyright über das Bild gelegt werden, entweder in Form eines einfachen Text und/oder als transparentes Wasserzeichen.
Der Text kann hierbei ein- oder mehrzeilig sein. Soll der Text mehrzeilig sein, so muß ein Array erstellt werden.
Beispiele hierzu finden sich im Script weiter unten.
Verwendete Software auf dem Server
Betriebssystem: Linux
Webserver: Apache
Datenbank: MySQL
Scriptsprache: PHP
Zum Zugriff auf die Datenbank verwende ich PDO. Um aus den kodierten Bilddaten "wieder ein Bild zu machen", wird die GD-Bibliothek benötigt.
Um nachzusehen, ob beides zur Verfügung steht, einfach eine PHP-Seite erstellen, und dort die Funktion phpinfo() aufrufen.
Die Datenbank zum Speichern der Bilddaten
Meine Datenbank zur Aufnahme der kodierten Bilddaten besteht aus einer Tabelle mit lediglich zwei Spalten
- id vom Typ int mit auto_increment
- data vom Typ Text
Upload-Script
Im Upload-Script wird das Root-Verzeichnis des Webservers ermittelt: $pfad=$HTTP_SERVER_VARS['DOCUMENT_ROOT']. An dieses Verzeichnis wird
ein Unterverzeichnis angehangen, in das der Webserver hochgeladene Bilder speichert bzw. weitere Unterverzeichnisse erstellt. Dieses Verzeichnis
muss dem Webserver gehören und er muss Schreib-Leserechte besitzen.
Ein Bild aus der DB laden und im Browser ausgeben
In diesem Script habe ich eine kleine Klasse mit ein paar Methoden erstellt, um aus den Bilddaten wieder ein Bild im Browser auszugeben.
Diese Methoden verwenden Funktionen der GD-Bibliothek. Diese Funktionen haben teilweise eine "ellenlange" Parameterliste. Um nicht
immer alle Parameter angeben zu müssen, sind in den Methoden einige (oder alle) Parameter mit Werten vorbelegt. Will man die Werte ändern,
so müssen die Werte von links nach rechts lückenlos eingegeben werden. Beispiel Textfarbe setzen:
/*
* Methode um Textfarbe zu setzen, einfacher Text
*/
public function set_text_color($r = 255, $g = 0, $b = 0){
$this->text_color = imagecolorallocate ($this->im, $r, $g, $b);
}
Die Standardfarbe für Text ist rot. Würde man nun die Textfarbe auf grün setzen wollen, so notiert man:
$image->set_text_color(0, 255);
Die Ausgabe eines Bilds habe ich in zwei Dateien vorgenommen:
- Eine Datei für die Klasse
- Eine Datei, in der der Datenbankzugriff erfolgt und die Anwendung der Klasse
Die Klassendatei
<?php
class MyImage{
/*
* Das Bild
*/
private $im;
/*
* Das Wasserzeichen
*/
private $copyright_stamp;
private $stamp_width;
private $stamp_heigth;
/*
* Textparameter für Wasserzeichen
*/
private $stamp_font_size;
private $stamp_font_color;
private $stamp_text;
private $text_pos_from_left;
private $text_pos_from_top;
/*
* Textfarbe, einfacher Text
*/
private $text_color;
/*
* Konstruktor für das Bild
*/
public function __construct($str){
$this->im = imagecreatefromstring(base64_decode($str));
}
/*
* Methode um Textfarbe zu setzen, einfacher Text
*/
public function set_text_color($r = 255, $g = 0, $b = 0){
$this->text_color = imagecolorallocate ($this->im, $r, $g, $b);
}
/*
* Methode um Text einzufügen, einfacher Text
*/
public function set_text($text, $from_left = 1, $from_top = 30, $font_size = 5){
if(is_array($text)){
foreach($text as $textline){
ImageString($this->im, $font_size, $from_left, $from_top, $textline, $this->text_color);
$from_top += 20;
}
}else{
ImageString($this->im, $font_size, $from_left, $from_top, $text, $this->text_color);
}
}
/*
* Methoden um ein transparentes Wasserzeichen einzufügen
*
* Ein leeres Bild für das Wasserzeichen erstellen
*/
public function create_copyright_stamp($width, $heigth){
$this->stamp_width = $width;
$this->stamp_heigth = $heigth;
$this->copyright_stamp = imagecreatetruecolor($width, $heigth);
}
/*
* Das Wasserzeichen erstellen, die Form des Wasserzeichens ist rechteckig
*/
public function set_stamp($border_width = 10, $pos_from_right = 10, $pos_from_bottom = 10, $transparenz = 50, $border_color = 0xff0000, $body_color = 0x000000){
$x = 0;
$y = 0;
imagefilledrectangle($this->copyright_stamp, $x, $y, $this->stamp_width - 1, $this->stamp_heigth - 1, $border_color);
imagefilledrectangle($this->copyright_stamp, $x + $border_width, $y + $border_width, $this->stamp_width - $border_width, $this->stamp_heigth - $border_width, $body_color);
if(is_array($this->stamp_text)){
foreach($this->stamp_text as $text){
imagestring($this->copyright_stamp, $this->stamp_font_size, $this->text_pos_from_left, $this->text_pos_from_top, $text, $this->stamp_font_color);
$this->text_pos_from_top += 20;
}
}else{
imagestring($this->copyright_stamp, $this->stamp_font_size, $this->text_pos_from_left, $this->text_pos_from_top, $this->stamp_text, $this->stamp_font_color);
}
/*
* Position des Wasserzeichens
*/
$marge_right = $pos_from_right;
$marge_bottom = $pos_from_bottom;
$sx = imagesx($this->copyright_stamp);
$sy = imagesy($this->copyright_stamp);
/*
* Das Wasserzeichen über das Bild legen
*/
imagecopymerge($this->im, $this->copyright_stamp, imagesx($this->im) - $sx - $marge_right, imagesy($this->im) - $sy - $marge_bottom, 0, 0, imagesx($this->copyright_stamp), imagesy($this->copyright_stamp),
$transparenz);
}
/*
* Textparameter für Wasserzeichen setzen
*/
public function set_stamp_text($text, $from_left = 20, $from_top = 30, $font_size = 5, $text_color = 0xff0000){
$this->stamp_font_size = $font_size;
$this->stamp_font_color = $text_color;
$this->stamp_text = $text;
$this->text_pos_from_left = $from_left;
$this->text_pos_from_top = $from_top;
}
/*
* Bild ausgeben und Speicher freigeben
*/
public function show(){
imagejpeg($this->im);
imagedestroy($this->im);
}
}
?>
Anwendung der Klasse in einer Datei
Diese Datei stellt unter Verwendung der eingebundenen Klasse das Bild dar. Diese Datei kann im Browser aufgerufen werden, oder man gibt sie
in einer PHP-Datei als Bildresource an: <img src = "mein_bild.php">
<?php
header ("Content-type: image/jpeg");
include("a_image.inc.php"); //Name der Klassendatei
error_reporting (E_ALL);
ini_set ("display_errors", true);
$conn = new PDO("mysql:host=localhost;dbname=test", "guenni", "guenni");
$query = "select data from bilder where id = 2";
$stm = $conn->prepare($query);
$stm->execute();
$result = $stm->fetch(PDO::FETCH_ASSOC);
$image_string = $result['data'];
/*
* Das Bildobjekt erstellen
*/
$image = new MyImage($image_string);
/*
* Das Bild ausgeben
*/
$image->show();
?>
Damit wäre die Bildausgabe fertig. Um nun noch einen Text als Copyright/transparentes Wasserzeichen über das Bild zu definieren, gibt es zwei Möglichkeiten:
- Eine einzige Textzeile
- Einen mehrzeiligen Text (als Array)
$copyright = "Copyright by ME!";
$copyright_array = array("Copyright by ME!","(c) 2013","Viersen, NRW, Germany");
Beide Variablen können der Methode übergeben werden
$image->set_text_color();
$image->set_text($copyright);
//oder mehrzeilig
//$image->set_text($copyright_array);
Das transparente Wasserzeichen
Dazu erstellen wir erstmal ein leeres Bild in der gewünschten Breite und Höhe
$image->create_copyright_stamp(230, 110);
Dann werden die Textparameter für das Wasserzeichen gesetzt
$image->set_stamp_text($copyright);
//oder mehrzeilig
//$image->set_stamp_text($copyright_array);
Anschließend wird das transparente Wasserzeichen erstellt
$image->set_stamp();
Ein Bild mit Text und Wasserzeichen könnte dann so aussehen:
Abhängig von der Bildgröße muß man mit den Positionsparametern ein wenig ausprobieren, um den Text/das Wasserzeichen im Bild darzustellen.
Zum Schluß noch die Upload-Datei
<?php
error_reporting ( E_ALL );
ini_set ( 'display_errors', true );
/*
* Datenbank Verbindungsparameter
*/
$conn = new PDO("mysql:host=localhost;dbname=test", "guenni", "guenni");
/*
* Mit $HTTP_SERVER_VARS['DOCUMENT_ROOT'] wird das Rootverzeichnis des Servers ermittelt,
* pub ist das Standardverzeichnis, in dem Bilder abgelegt werden.
*/
$pfad=$HTTP_SERVER_VARS['DOCUMENT_ROOT']."pub/";
if(isset($_POST["cmd"])){
/*
* verz wird mit dem Formular gesendet und bestimmt den Ordner,
* in dem die Datei gespeichert wird.
* Im Array not_allow können Zeichen(ketten) definiert werden, die im Verzeichnisnamen
* nicht vorkommen sollen(oder nicht dürfen). Liste der nicht erlaubten Zeichen(ketten (eventuell)) erweitern.
*/
$not_allow = array(' ','.',':','?',';','www','/','\\');
$verz=str_replace($not_allow, '', $_POST['verz']);
/*
* Es wird überprüft, ob $_POST['verz'] existiert. Wenn ja, wird
* es dem Pfad angehangen.
* Wenn nein, wird es erstellt und dem Pfad angehangen.
* Ist $_POST['verz'] leer, wird die Datei im oben angegeben Ordner gespeichert.
*/
if(empty($verz)){
//keine Aktion
}else{
if(is_dir($pfad.$verz)){
$pfad.=$verz."/";
}else{
mkdir($pfad.$verz,0777);
$pfad.=$verz."/";
}
}
/*
* Im folgenden werden die Variablen für die copy-Funktion
* deklariert und belegt.
*/
$quelle=$_FILES["myfile"]["tmp_name"]; // Name der temporären Datei
$quellenname=$_FILES["myfile"]["name"]; // Originalname der Datei
$ziel=$pfad.$quellenname; // Originalname wird an Pfad angehangen
/*
* Auf Bilddatei prüfen, Liste der Endungen (eventuell) erweitern.
*/
$bild_end = array(".bmp", ".gif", ".jpg", ".jpeg" , ".png");
$punkt_pos = strrpos($quellenname, '.');
if(!in_array(strtolower(substr($quellenname, $punkt_pos)), $bild_end)){
echo "Datei $quellenname ist keine Bilddatei. <a href=\"a_11.php\"> Zurück </a>";
exit;
}
/*
* Wird kopiert ?
*/
if(move_uploaded_file($quelle,$ziel)){
echo "Datei $quellenname wurde hochgeladen.<br>";
echo "-------------------------------------<br>";
echo "Quelle: ".$quelle."<br>";
echo "Quellenname: ".$quellenname."<br>";
echo "Ziel: ".$ziel."<br>";
}else{ /*
* if-else copy - Kopieren fehlgeschlagen
* Häufiger Grund einer Fehlermeldung ist, dass die hochgeladene Datei größer ist,
* als in der php.ini erlaubt ist.
*/
echo "Fehler beim Hochladen der Datei ".$quellenname."<a href=\"a_11.php\"> Zurück </a>";
exit;
}
}
/*
* Ist die Checkbox conv angewählt, wird die hochgeladene Datei kodiert und in der DB gespeichert.
*/
if(isset($_POST["conv"])){
$bild = '';
$file = $ziel;
if (!$handle = fopen($file, "r")) die("Konnte Datei $file nicht oeffnen!");
while ($str = fread($handle, filesize($file))) {
$bild.=base64_encode($str);
}
fclose($handle);
/*
* Bild in DB speichern
*/
$query = $conn->prepare("insert into bilder(data) values(:bild)");
$query->bindParam(":bild", $bild, PDO::PARAM_STR);
$result = $query->execute();
if($result !== false){
$id = $conn->lastInsertId();
echo "<br>Die ID des eingefügten Datensatzes ist ".$id;
}else{
echo "<pre>";
print_r($query->errorInfo());
echo "</pre>";
}
/*
* Ist die Checkbox delete angewählt, wird die hochgeladene Datei wieder gelöscht
*/
if(isset($_POST["delete"])){
unlink($file);
}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Upload and Encode</title>
</head>
<body>
<p>Bild hochladen, kodieren und in DB speichern</p>
<form enctype="multipart/form-data" method="post" action="a_11.php">
<p>Ordner(optional): <input type="text" name="verz"> Bild: <input type="file" name="myfile"></p>
<input type="submit" name="cmd" value="Hochladen"> Bild kodieren und in DB speichern <input type="checkbox" name="conv">
Bild nach Upload löschen <input type="checkbox" name="delete">
</form>
</body>
</html>
Thats all Folks
Gruß
Güni
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 219873
Url: https://administrator.de/contentid/219873
Ausgedruckt am: 21.11.2024 um 22:11 Uhr
2 Kommentare
Neuester Kommentar
Hi,
prinzipiell keine schlechte Anleitung, allerdings drei-vier Anmerkungen von mir dazu:
Du benutzt noch $HTTP_SERVER_VARS, was seit Version 4.1 veraltet ist und daher nicht mehr verwendet werden sollte (ich glaube sogar, spätestens unter 5.4 funktioniert es auch tatsächlich nicht mehr). Stattdessen sollte man $_SERVER verwenden: http://php.net/manual/en/reserved.variables.server.php
Dann sollte man bei der Arbeit mit benutzerdefinierten Verzeichnis- und Dateinamen nach Möglichkeit "realpath()" bzw. "basename()" verwenden, um das zu filtern.
Oder direkt einfach eine Whitelist mit den normalen lateinischen Zeichen machen und entsprechend alles, was nicht in der Liste steht zu ersetzen.
Denn dein Filter holt mir z.B. keine Unicode-Zeichen aus dem angegebenen Verzeichnisnamen heraus. Kannst du ja gerne mal mit U+0338 versuchen - sieht aus wie ein Schrägstrich, ist aber keiner: ̸
Oder U+043C, das kyrillische kleine "Em": м
Kann zumindest zu interessanten Konfusionen führen
Und zum Schluss:
Beim Entwickeln ganz hilfreich, im Produktivsystem aber aus verschiedenen Gründen nicht zu empfehlen:
PHP-Fehler ausgeben, gerade dann wenn man kurz vorher den Content-Type auf "image/jpeg" setzt.
Du erfährst alle PHP-Fehler und Warnungen auch aus dem Error-Log deines Webservers. Wobei... Mit E~ALL hättest du auch eigentlich Deprecated-Warnungen sehen müssen?
prinzipiell keine schlechte Anleitung, allerdings drei-vier Anmerkungen von mir dazu:
Du benutzt noch $HTTP_SERVER_VARS, was seit Version 4.1 veraltet ist und daher nicht mehr verwendet werden sollte (ich glaube sogar, spätestens unter 5.4 funktioniert es auch tatsächlich nicht mehr). Stattdessen sollte man $_SERVER verwenden: http://php.net/manual/en/reserved.variables.server.php
Dann sollte man bei der Arbeit mit benutzerdefinierten Verzeichnis- und Dateinamen nach Möglichkeit "realpath()" bzw. "basename()" verwenden, um das zu filtern.
Oder direkt einfach eine Whitelist mit den normalen lateinischen Zeichen machen und entsprechend alles, was nicht in der Liste steht zu ersetzen.
Denn dein Filter holt mir z.B. keine Unicode-Zeichen aus dem angegebenen Verzeichnisnamen heraus. Kannst du ja gerne mal mit U+0338 versuchen - sieht aus wie ein Schrägstrich, ist aber keiner: ̸
Oder U+043C, das kyrillische kleine "Em": м
Kann zumindest zu interessanten Konfusionen führen
Und zum Schluss:
Beim Entwickeln ganz hilfreich, im Produktivsystem aber aus verschiedenen Gründen nicht zu empfehlen:
PHP-Fehler ausgeben, gerade dann wenn man kurz vorher den Content-Type auf "image/jpeg" setzt.
Du erfährst alle PHP-Fehler und Warnungen auch aus dem Error-Log deines Webservers. Wobei... Mit E~ALL hättest du auch eigentlich Deprecated-Warnungen sehen müssen?