zip Datei zum Client streamen

Saugkraft

Saugkraft

Aktives Mitglied
Thread Starter
Dabei seit
20.02.2005
Beiträge
9.022
Reaktionspunkte
3.189
Hallöchen,

ich will eine .zip Datei, die ich am Server dynamisch zusammen stelle, zum Client streamen.

Da ich in ASP programmiere, übersetze ich es für die nicht-ASPler mal in PHP. :D

Code:
<? 
$size = @filesize("datei.zip"); 
header("Content-Type: application/zip"); 
header("Content-disposition: attachment; filename=datei.zip"); 
header("Pragma: no-cache"); 
header("Expires: 0"); 
header("Content-length: ".$size); 
readfile("datei.zip"); 
?>

Der vollständigkeit halber hier mein ASP-Code (vielleicht kann ich ja jemanden für ASP begeistern und MS kann endlich die Weltherrschaft übernehmen :D) :
Code:
strFileName = "datei.zip"

Set fsize = fs.GetFile(strFileName)
StrFileSize = fsize.Size

Response.AddHeader "Content-Disposition", "attachment; filename=datei.zip" '& strFileName
Response.AddHeader "Content-Length", strFileSize
Response.ContentType = "application/zip"

Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = 1 'Binary
Response.CharSet = "UTF-8"
objStream.LoadFromFile(strFileName)
Response.BinaryWrite(objStream.Read)
response.Flush()
objStream.Close

Die Datei wird zum Browser gestreamt und auch gespeichert.

Aber es tritt folgendes Problem auf: Die Datei lässt sich nicht entpacken.
Nach einem Doppelklick erstellt OS X eine .cpgz Datei.

Auf dem Server wird die .zip Datei in einem temp Verzeichnis zwischengespeichert. Dort lässt sie sich entpacken. Das Problem muss also am Streamen liegen.

Hat jemand eine Idee, was es außer dem Content-Type und der Content-length noch zu beachten gibt?

Bin für jeden Hinweis dankbar. :)
 
Also Content-Length ist eigentlich egal, ist nur nett für den Benutzer. Aber geht auch ohne.

Bei meinen JNLP (Java Webstart, XML Datei) mache ich das in PHP so:

PHP:
header('Content-type: application/x-java-jnlp-file');
header('Content-Disposition: inline; filename="' . $jar . '.jnlp"');

echo …

Das klappt problemlos …

Dieses .cpgz entsteht wohl immer dann, wenn ein ZIP fehlerhaft entpackt worden ist. Also wenn du einfach mal
Code:
$ echo "xyz" > Desktop/test.zip
machst, und das test.zip dann doppelklickst, bekommst du ein test.zip.cpgz, welches dann einen merkwürdigen Inhalt hat:
Code:
$ cat test.zip.cpgz 
307Ad`四??(#ih
              ?44466056505?4?1??fhh``fb?n??!?i&?Ȗ?]??_?Z\?W?Y?PQYŅa4?????(??!A??>?A???
      #?e?

Also ich könnte mir vorstellen, dass vielleicht mit dem ZIP was verkehrt ist, oder bei der Übertragung Binär/Text oder eben die Zeichenkodierung kaputt geht.

Schau dir doch mal beide Dateien (Server-Temp und Heruntergeladen) mit einem Text- oder Hexeditor an.

Passiert das auch mit einem Windowsrechner?
 
Unter Windows passiert das Gleiche. Nicht exakt, aber der Explorer meldet, dass die .zip Datei ungültig ist.

An der Übertragung kann es eigentlich nicht liegen, mit objStream.Type = 1 setze ich die Übertragung auf Binär.

Die Datei hat heruntergeladen 826.898 bytes, auf dem Server 826.458 bytes. Mit dem Hex-Editor wird auch klar, warum.

Die heruntergeladene Datei hat die HTML Header der Downloadseite vorneweg drin:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head></head>
<body>
PK

Bei PK beginnt dann die eigentliche .zip Datei.

Da brat mir doch einer einen Storch. Warum wird der HTML Code vorne angehängt?
 
Vielleicht benutzt du irgendwo include() in einer HTML Seite um das Teil zu streamen? Oder du hast irgendwelche anderen Ausgaben vor dem ersten header() Befehl?
 
Ja, da wird noch eine Datei mit Einstellungen per HTML included (<!--include file..)

Macht das einen Unterschied? Ich kann das zwar rausnehmen, aber das Prinzip dahinter interessiert mich.

Edit: Ich werd bekloppt. Wenn ich den include rausnehme, geht es.
 
Wenn du einen header() Befehl sendest, darfst du vorher kein HTML oder sonstigen Text per echo gesendet haben. Bei ASP ist das sicher ähnlich.

Der SGML Kommentar "<!--" ist dann also schon eine Ausgabe an den Webbrowser, aber da du ihm sagst, es soll in das ZIP kann er entweder die Seite anzeigen oder aber alles in das ZIP stecken.

Von daher darf deine Ausgabeseite sonst nichts machen, nur das ZIP übertragen.
 
Ah. Verstehe.

Die Lösung hab ich daraufhin auch gleich gefunden. Bevor man die .zip Datei streamt kann man das Response Objekt (bei ASP die Ausgabe, die der Server zum Senden vorbereitet) mit Response.Clear() leeren. Standardmäßig wird die Response gepuffert bevor sie gesendet wird und da steckt dann wohl noch die HTML Ausgabe drin. Die wird dann offenbar zusammen mit der .zip Datei verschickt.

Google spuckt mir zu PHP da als Entsprechung ob_clean ( void ) aus. Ist das das selbe? PHP ist zwar nicht mein Ding, aber man muss ja auf dem Laufenden bleiben.

Ja Geilomat. Jetzt klappt es. Vielen Dank. Das nenne ich mal eine steile Lernkurve. :)
 
Also ich habe das nie gebraucht, da ich eben eine extra PHP Datei zum Streamen hatte, und die eben keine Ausgaben per echo macht, sondern erst die entsprechenden Header sendet und dann per echo den Dateiinhalt.

Ich verwende eh nur PHP4, ich müsste mich mal in PHP5 einarbeiten …

Freut mich, dass ich dir helfen konnte :)
 
Streng genommen ist die Datei ja extra zum Streamen. Allerdings binde ich per include noch die DB-Verbindung ein, weil ich vor dem Streamen noch ein paar Abfragen mache, ob der User die Datei überhaupt runterladen darf. Das ist mit meiner Einstellungsdatei deutlich einfacher.

Prima. Jetzt kann ich mich endlich wieder um die wesentlichen Dinge kümmern. :)
 
Datenbankverbindungen sind ja alles kein Problem, solange nichts an den Browser gesendet wird. Nur wenn man da dann so eine Debug-Ausgabe wie "Datenbank erfolgreich verbunden" drin hat, zerschießt es einem sowas auch. Das gleiche Problem hat man in PHP auch mit Sessions und Cookies, die müssen auch immer ganz am Anfang ausgelesen werden.

Ich kenne das mit den unwesentlichen Dingen nur zu gut, aber das macht dann kein Problem, wenn man nach Stunden bezahlt wird :hehehe:
 
Bist Du sicher, dass Du das zip auch mit UTF-8 erzeugt hast?
 
Jup, hab ich: Response.CharSet = "UTF-8"

Das Problem lag tatsächlich daran, dass in der Response vor der zip Datei noch HTML Code vorhanden war. Wenn die Response gelöscht wird, bevor die Datei erzeugt wird, klappt es.
 
Zurück
Oben Unten