Hi Leute,
ist im weitesten Sinne Multimedia - deshalb hier
Ich habe seit mehreren Jahren eine Bilddatenbank laufen, bei denen sich die (angemeldeten) User Fotos in hoher Auflösung herunterladen können.
Der Download erfolgt via
[PHP]
header("Content-Type: image/jpeg");
header("Content-Disposition:attachment; filename=\"testbild.jpg\"");
readfile("testbild.jpg");
?>
[/PHP]mit aus der Datenbank generieten Namen.
Nun häufen sich in der letzten Zeit die Anfragen von Nutzern, die die heruntergeladenen Bilder nicht öffenen können.
Betroffen waren z.B. Nutzer, die die Bilder mit dem IE 8 unter Vista heruntergeladen hatten und sie dann mit dem Windows-Photoviewer betrachten wollten. Betrachtet man das Bild mit irfanview, ist alles in ORdnung
Ein wenig hin- und herprobieren ergab, dass sich die auf diese Weise heruntergeladenen Bilder von denen unterscheiden, die man im Browser angezeigt bekommt
[HTML]
[/HTML]wenn man im Browser auf "Bild speichern unter" klicke und das Bild herunterlädt.
Beide Male wird auf die IDENTISCHE Bilddatei verwiesen.
Betrachte ich nun die JPG-Header in z.B. Photoshop so fällt auf, dass die meisten der im Original vorhandenen Informationen aus dem Bild-Header verschwunden sind.
So sind ALLE EXIF-,und Photoshop-Anmerkungen weg, genauso wie die das eingebettete Thumbnail und die Informationen zur Bildgröße.
Dabei ist der Browser und das Betriebssystem egal. Die Ursache muss also auf dem Server liegen.
Ich hatte erst die Befürchtung, das hinge mit einem kürzlich erfolgen Umzug auf einen anderen Server zusammen - aber auch auf dem alten Server (auf dem ich noch Zugriff habe) verhält es sich genauso...
Eine Änderung des MIME-Typs nach x-application/octet-stream (wie in manchen Beispielen verwendet) bringt keine Änderung des Verhaltens...
Any Ideas?
Dirk
Klingt vielleicht absurd, aber könnte das mit irgendwelcher Filter-Software oder Security-Einstellungen zu tun haben?
Das Problem der fehlenden Informationen tritt hier bei mir beim Download unter Win2K, Vista und OS X 10.4 auf.
Bei anderen Usern unter XP (hab ich bei mir noch nicht ausprobiert)...
Ich hab es serverseitig sowohl auf einem IIS (unter PHP) als auch auf einem Apache nachvollziehen können.
Ich fürchte, ein Filter ist nicht die Ursache...
ciao
dirk
Vielleicht ein PHP-Problem - mit welcher Version?
V4.2 und 5.3...
Ciao
drk
Dann ist es wohl kein Bug in einer neuen PHP-Version, sondern ein generelles Problem im Coding. Ich habe daher mal Google angeworfen und in dieser Richtung gesucht - und tatsächlich, das Problem scheint nicht völlig unbekannt zu sein, wie in diesem Forum-Thread beschrieben.
Zunächst einmal scheint der Content-Typ "octetstream" sinnvoll zu sein, damit keine Konvertierung von Daten vorgenommen wird. Dazu wird dann auch noch (an anderer Stelle) empfohlen, mit "force-download" zu verhindern, dass der Browser das Bild versucht, das Bild anzuzeigen. Als Ergebnis kommt dann so etwas wie folgender Code heraus:
[HTML]header("Content-type: image/jpg");
header("Content-type: application/force-download");
header("Content-type: application/octetstream");
header("Content-Disposition: attachment; filename=$file");[/HTML]
Vielleicht probierst Du das einmal aus - ist leider kein klassisches PHP-Problem, also weniger mein Fachgebiet - mit den HTML-Headern habe ich in meinen Projekten nicht soo viel zu tun und müsste mich da selbst erstmal wieder einlesen...
Als ich mir heute Mittag den Code angeschaut habe, wunderte ich mich über den content-type application/octetstream, der dort angegeben war
Aber auch damit hat es nicht funktioniert - bzw. damit funktionierte es die ganze Zeit über nicht.
Ich hatte das dann in image/jpeg geändert - aber das klappte auch nicht.
Werde mir das morgen noch mal vornehmen...
ciao
dirk
Ich glaube, man kann davon ausgehen, dass es an den Headern liegt. Da steckt der Teufel im Detail (ich bin neugierig geworden und suche mir gerade ein paar weitere Informationen dazu zusammen).
Je nach PHP-Version werden z.B. mehrfache Header desselben Typs aus Sicherheitsgründen ignoriert (dann neuen Parameter "replace" verwenden; vermutlich sind sie aber ohnehin ein Denkfehler und in meinem oben verwendeten Beispiel auch verkehrt...).
Manche (ältere?) Browser enthalten an dieser Stelle Bugs und kümmern sich nicht um den Content-Type, sondern verwenden stattdessen immer die Extension im Filenamen, um den Typ zu ermitteln.
Dazu werden in den Quellen weitere Header-Angaben empfohlen, damit käme insgesamt so etwas wie dieser Code dabei heraus:
[PHP]
header("Content-Type: application/octetstream");
header("Content-Disposition: attachment; filename=$file");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Transfer-Encoding: binary");
header("Content-Length:" . filesize($file));
[/PHP]
Damit soll zusätzlich der Cache abgeschaltet, die Übertragung auf binär gestellt und die Länge der Datei übergeben werden. Die Wirkung des Cache ist mir unklar (sollte eigentlich nicht stören), die binäre Übertragung leuchtet mir schon eher ein und Dateilänge führt u.a. zur Anzeige des Fortschritt-Balkens im Browser (ach ja, der Filename macht so natürlich Probleme, wenn er Leerzeichen enthalten sollte, das habe ich hier mal nicht berücksichtigt...).
Ich habe das nicht ausprobiert, kann also nicht sagen ob das funktioniert - mich würde aber interessieren, ob das weiterhilft und wie am Ende die Lösung aussieht...
So,
ich habe nun ein wenig gespielt.
mit folgendem Code kann ich ein komplettes Bild herunterladen:
[PHP]
$file="258986055Uhlemann und Harksen.jpg";
$save_as_name=Substr($file,10,StrLen($file)-10);
header("Content-Type: image/jpeg");
header("Content-Disposition: attachment; filename=\"$save_as_name\"");
readfile("originale/$file");
?>
[/PHP]
Dies lädt die Datei [FONT=Courier New]3835891258986055Uhlemann und Harksen.jpg[/FONT] aus dem Verzeichnis [FONT=Courier New]originale[/FONT] und speichert sie unter dem Namen [FONT=Courier New]Uhlemann und Harksen.jpg[/FONT] auf meiner lokalen Platte.
Soweit, so gut.
Das Verzeichnis ist dabei das Originalverzeichnis, in dem die Bilder aus der Datenbank liegen...
Im Original Download-Skript sieht das wie folgt aus:
[PHP]
$row=mysql_fetch_object($result); // Datenbankzeile wird ausgelesen
$save_as_name=Substr($row->FILE_FileName,10,StrLen($row->FILE_FileName)-10); // Name zum Speichern wird erzeugt.
header("Content-Type: image/jpeg");
header("Content-Disposition: attachment; filename=\"$save_as_name\"");
readfile("originale/$row->FILE_FileName");
[/PHP]
Einen Unterschied kann es höchstens im Inhalt des Datenbankfeldes [FONT=Courier New]FILE_FileName[/FONT] geben. Aber wenn dort etwas anderes als der Dateiname stünde, dürfte GAR NICHTS heruntergeladen werden...
Die von Florian genannten anderen Header-Angaben ändern übrigens nichts am Ergebnis.
Ciao
Dirk
Ich habe nun im Original Download-Skript die 3 Zeilen, die den Download bestimmen nicht als Header, sondern als Text an den Browser ausgeben lassen:
[PHP]
header("Content-Type: image/jpeg");
header("Content-Disposition: attachment; filename=\"Uhlemann und Harksen.jpg\"");
readfile("originale/258986055Uhlemann und Harksen.jpg");
[/PHP]
Die Zeilen habe ich dann in eine separate PHP-Datei kopiert und:
Der Download funktioniert vollständig
Wuuaahhhh! :S
IRGENDWAS muss aber doch anders sein...
Ciao
dirk
Heureka!
Da irgendwo ja ein Unterschied sein musste, habe ich mir die Skripte noch mal vorgenommen.
Meine erste Vermutung war, dass da irgendwo Text ausgegeben wurde.
Also alle [FONT=Courier New]echo[/FONT] Zeilen kontrolliert, alle Leerzeilen gelöscht.
Das war es aber noch nicht.
Dann habe ich mich nach einem Tool umgesehen, mit dem man sich die Header anzeigen lassen kann.
Ich bin bei http://web-sniffer.net/ fündig geworden. Dort kann mach auch Datenübergabe per POST simulieren - das brauchte ich.
Und siehe da, es wurde tatsächlich Text zurückgeliefert, der da nicht hingehört:
Ich lese die übergebenen Parameter mit hilfe einer kleinen Funktion aus - und in dieser Funktion kann der Parameter zu Kontrollzwecken ins HTML-Dokument geschrieben werden.
Und genau das tat er hier...
Ich hab' trotzdem was gelernt
Ciao
dirk
...es handelt sich bei der Datenbank um
http://www.hajo.com
Diese ist so konzeptioniert, dass der Fotograf seine Bilder im Vorfeld verschlagwortet (z.B. in Photoshop oder Adobe Bridge) und dann NUR die Bilder per Skript hochlädt.
Das Upload-Skript ließt die Informationen aus den Bildheadern aus und schreibt sie in die Datenbank.
Gleichzeitig wird per PHP eine Thumbnail-Bild für die Übersicht und ein kleineres Vorschaubild erzeugt.
Basierend auf dieser Technik habe ich auch Fotogallerien für meine Kinder und mein Patenkind eingerichtet. Dort spare ich mir allerings die Verschlagwortung für's Web - es ja da primär ums betrachten, nicht ums weiterverwerten...
Ciao
dirk
D.h. die Header-Befehle waren unwirksam, weil vorher schon anderer Text ausgegeben wurde? Da hätte doch eine Fehlermeldung kommen müssen?
Eigentlich schon - kam aber nie.
Wenn ich das in der Testumgebung nachstelle, bekomme ich auch eine Fehlermeldung.
Komisch
dirk
Vielleicht steht da irgendwo so etwas wie:
[PHP]error_reporting(0);[/PHP]Das wäre natürlich keine so gute Idee, wird aber für im Echteinsatz befindliche Systeme manchmal gemacht. Intelligenter ist:
[PHP]error_reporting($_SERVER["SERVER_NAME"] == "localhost" ? E_ALL : 0);[/PHP]Damit werden die Fehlermeldungen beim Test auf dem Entwicklungssystem (eben meist der "localhost") angezeigt - aber sonst nicht.