Bilder ohne "speichern unter" downloaden
Wer Gafiken, Wallpapers oder einfache Fotos einfach per Klick als Download anbieten möchte wird merken, dass es gar nicht so einfach ist. Ja, der Weg mit "rechte Maustaste" - "speichern unter" funktioniert zwar, wirkt aber nicht sehr professionell. Ein möglicher Weg wäre natürlich auch die Grafik in ein ZIP-Archiv zu packen. Nur wegen einer Grafikdatei gleich ein Zip File zu machen ist auch nicht sehr professionell.
Mit ein paar PHP-Codezeilen schaffen wir den besseren Weg mit der man eine Grafik direkt Downloaden kann. Wie das geht zeige ich hier.
Beispiel 1 - einzelne JPG Datei downloaden
Wir haben eine Grafik mit dem Namen "testbild.jpg
", die wir mit einem einfachen Textlink zum Downloaden anbieten möchten.
Im gleichen Verzeichnis (Ordner) in der diese Grafik gespeichet ist, erstellen wir eine PHP Datei mit dem Namen "download.php
mit folgendem Inhalt:
<?php header('Content-type: image/jpg'); header('Content-Disposition: attachment; filename="testbild.jpg"'); readfile('testbild.jpg'); ?>
Nun müssen wir nur noch den Link zur "download.php"
" auf der Webseite einbauen, wo der Downloadlink stehen soll. Hier schreiben wir einfach:
<a href="/download.php" title="Download" />Download</a>
Natürlich muss je nach Verzeichnisstruktur die URL angepasst werden.
Resultat würde dann so aussehen: Download
Beispiel 2 - mehrere GIF Dateien einzeln downloaden
Wir haben mehrere GIF Dateien im Unterordner "images
" liegen, die wir alle mit separaten Links zum Download anbieten möchten. Dazu erstellen wir zunächst eine PHP Datei, geben ihr den Namen "download.php
" und speichern diese im gleichen Unterverzeichnis. Der Inhalt dieser "download.php
" schaut folgendermaßen aus:
<?php $img=$_GET['img']; header('Content-type: image/gif'); header('Content-Disposition: attachment; filename="'.$img.'.gif"'); readfile($img.'.gif'); ?>
Die Downloadlinks müssen die Namen der Grafikdateien als GET-Variable übergeben.
<a href="/images/download.php?img=testbild1" title="Download 1" />Download Bild 1</a><br /> <a href="/images/download.php?img=testbild2" title="Download 2" />Download Bild 2</a><br /> <a href="/images/download.php?img=testbild3" title="Download 3" />Download Bild 3</a>
Natürlich muss je nach Verzeichnisstruktur die URL angepasst werden.
Resultat würde dann so aussehen:
Download Bild 1
Download Bild 2
Download Bild 3
Beispiel 3 - unterschiedliche Grafiktypen downloaden
Wir haben unterschiedliche Grafik Dateien im Unterordner "images
" liegen. Eine "testbild.gif
", eine "testbild.jpg
" und eine "testbild.png
" Datei.
Wir erstellen wieder eine PHP Datei, geben ihr den Namen "download.php
" und speichern diese im gleichen Unterverzeichnis. Der Inhalt dieser "download.php
" schaut jetzt folgendermaßen aus:
<?php $img=$_GET['img']; $type = mime_content_type($img); switch ($type) { case "image/gif": header('Content-type: image/gif'); header('Content-Disposition: attachment; filename="'.$img.'"'); readfile($img); break; case "image/jpeg": header('Content-type: image/jpeg'); header('Content-Disposition: attachment; filename="'.$img.'"'); readfile($img); break; case "image/png": header('Content-type: image/png'); header('Content-Disposition: attachment; filename="'.$img.'"'); readfile($img); break; } ?>
Die Downloadlinks müssen die Namen der Grafikdateien als GET-Variable übergeben. Dieses mal aber auch mit der Extension.
<a href="/images/download.php?img=testbild.gif" title="Download GIF" />Download GIF-Bild</a><br /> <a href="/images/download.php?img=testbild.jpg" title="Download JPG" />Download JPG-Bild</a><br /> <a href="/images/download.php?img=testbild.png" title="Download PNG" />Download PNG-Bild</a>
Natürlich muss je nach Verzeichnisstruktur die URL angepasst werden.
Resultat würde dann so aussehen:
Kommentare (2)
David Losse
Beispiel 1 ist okay, ich würde jedoch noch den Content -Lenght rein coden, vorteilhaft wenn es sich um MB Große Bilder > 3 MB
header("Content-Length: ".filesize('testbild.jpg'));
handelt, Mehr Pixel desto größer denn an einer UMTS Leidung bzw DSL Nutzer mit einer langsamen Download Geschwindigkeit würden raten wie groß die datei ist, da für keinen Internetznutzer eine Dateigröße angezeigt werden, ich finde es vorteilhafter wenn jeder weiss wie viel er noch zu laden hat.
Beispiel 2 würde ich ehr meiden wollen, ich bin jetzt kein Hacker oder so nur ich weiss nicht ob Hacker über die Webadresse sich PHP Dateien beschaffen können oder ob .gif am ende es absichert.
auch hier fehlt die Content-Length, $_GET Parameter sind nicht sauber im Quellcode das kann an anderen stellen zu Scriptproblemen u.a. Cookies führen, wenn durch ein Fehler bereits eine ausgabe z.B. einer Notice oder Error Apache-PHP Meldungen erfolgte.
//Frei gecoded möglicherweise Tipp- oder Klammerfehler! kein if vergessen
$img = (isset($_GET['img'])?$_GET['img']:false);
if($img === false || ($img !== false && file_exists($img) === false)) die("Bild nicht ladbar");
Was ich im 2. Beispiel unsicherer einstufe ist kann ich hier im 3. Beispiel als sicherer einstufen, da der Mime Typ (Datentyp) vom Server ermittelt wird und somit im case Zweig einen php Code nicht ladbar macht, da php nicht als Content Type image/.... gewertet wird. Auch hier fehlt der Prüf zweig für img.
z.B. fürde die funktion mime_content_type() einen Fehler aufrufen, wenn dem System die Datei nicht bekannt ist, auch wenn die Fehlermeldungen durch display_error oder abgeschalteter error_reports auf 0 ist. is_readable() wäre auch noch eine gute Funktion um die Premission zu prüfen.
z.B. eine Bild von Beispiel 2 was nicht exitiert
Warning: readfile(******** [function.readfile]: failed to open stream: No such file or directory in /www/htdocs/w****154/demos/php-schnipsel/images_download_2/download.php on line 5
Für den Fall das es wie hier eine Usereingabe ist preg benutzen!!!
a-zA-Z0-9 oder selbst anderweitig prüfen..
Beispiel 3 könnte kürzer gehen. :D
switch ($type) {
case "image/gif":
case "image/jpeg":
case "image/png":
header('Content-type: '.$type);
header('Content-Disposition: attachment; filename="'.$img.'"');
header('Content-Length: '.filesize($img));
readfile($img);
break;
}
ich schreib mir doch nicht die Fingerwund, wenn der type eh schon vorhanden ist und doch nur auf den geprüft wird ^^ Die length hab ich auch schon reingemacht.. 50% weniger Zeilen ;-) er springt erst mit dem break aus dem case..
Würde hier zwei arten sein, müsste man nen break vor setzen, mal ein Beispiel an monate
checkDate($d,$m,$y) {
switch($m) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:$maxd = 31; break;
case 2: // hier code zur berechnung für schaltjahre da februar
break;
case 4: case 6: case 9: case 11: $maxd = 30; break;
}
}
hoffe es ist klar was ich meine?
Günther Hörandl
Vielen Dank für deine guten Überlegungen und Tipps!