[PHP] Zip-Archiv aus Input-Stream öffnen

Hi,

ich stehe mal wieder vor einem Problem, wo ich nicht weiter weiß.

Ich möchte mittels eines Scriptes ein zip-Archiv empfangen und die darin enthaltenen Dateien weiterverarbeiten (nicht nur einfach entpacken :wink:).
Das Problem ist nun, dass der Upload aus einem Spiel erfolgen soll.
[Anmerkung: Bei dem Spiel handelt es sich um TrackMania, wo man mit speziellen XML-Dateien InGame eine Website anzeigen lassen kann. Und genau über diese Ingame-Website soll es einem Admin der Seite möglich sein, ein zip-Archiv hochzuladen.]

Den Inhalt einer Datei zu empfangen, stellt dabei kein Problem dar, das konnte ich schon erfolgreich umsetzen:

Wenn ich dies allerdings als Zip laden möchte, so kommt es zu einem Fehler:

Der Fehler hat die Nummer 11, glaub das bedeutet “Cannot open file”, und ich denke es liegt an dem php-input. Lade ich das Zip manuell hoch und geb den Dateipfad an, so funktioniert es.

Lange Rede kurzer Sinn: Kann mir jemand sagen, wie ich aus dem Input das Zip-Archiv bekommen kann?

Kenne mich mit dieser Art der Datei-Übertragung auch nicht sonderlich aus (bisher gings immer über $_FILES ^^), kann sein dass ich da auch einfach etwas falsch verstanden habe. An der Art der Übertragung kann ich nichts ändern, da das vom Spiel so gesendet wird.

Würde mich über Hilfe freuen,
MfG FunTracker

Anders als bei file_get_contents wird im Handbuch nicht
behauptet, daß da bei zip_open was anderes als ein Dateiname
angegeben werden kann. Hast du überprüft, ob die Funktion mit
einer statischen Datei funktioniert?
Da ließe sich ja schon mal eingrenzen, wo das Problem ist und
wie man es umgehen kann.

Danke schonmal für deine Antwort.

Wenn ich das Zip temporär auf dem Webspace speicher, so kann ich es anschließend auch problemlos einlesen und verarbeiten:

$z = file_get_contents('php://input'); file_put_contents('./archiv.zip', $z); $zipFile = zip_open('./archiv.zip');

Nun möchte ich das temporäre Speichern möglichst vermeiden. Nur weiß ich nicht, ob es vielleicht einen anderen Weg gibt, den Input direkt als Zip verarbeiten zu können.

(Dass das “php://input” in zip-open funktionieren könnte, war blind ins blaue geraten, und offenbar ist es ja nicht so ^^)

Ich habe das noch nie benutzt, aber offenbar ist es ja so, daß
$zip = new zipfile();
ein neues ZIP-Archiv erzeugt und zwar im Speicher, nicht in
einer Datei.

Von daher könnte es sich lohnen auszuprobieren, was passiert,
wenn man die eingelesene Zeichenkette einfach als ZIP
behandelt, statt ein existierendes ZIP zu öffnen - funktioniert
das? Da könnte man mal herumprobieren …

Mit
$zip = file_get_contents(‘php://input’);
hat man das Archiv ja in der Zeichenkette stehen.
Falls das kompatibel zu
$zip = new zipfile();
ist oder
$zip = zip_open(’./archiv.zip’);
muß man es ja gar nicht mehr
öffnen, sondern kann in jedem Falle immer
das $zip verarbeiten …

Konnte ich im Handbuch jetzt nicht so eindeutig erkennen, ob
die das intern anders verwalten oder ob jeweils in $zip immer
solch ein Archiv steht.
Wenn hingegen in $zip nur ein Zeiger auf eine ZIP-Datei steht,
so bleibt einem kaum was anderes übrig, als eine anzulegen.
wobei dann darauf zu achten ist, daß bei zwei unabhängigen
Zugriffen nicht dieselbe Datei bearbeitet wird ;o)

Ich habe mal nun noch ein wenig rumprobiert, und auch mit ZipArchive() (zipFile() konnt ich gar nicht finden) scheint das nicht zu gehen. Zumindest ein

$zip = new ZipArchive(); $zip->open("php://input");
resultiert wieder im Fehler 11 (ER_OPEN).

Deine Idee mit der Kompatibilität glaube ich nicht, dass es funktionieren kann. Denn:

$zip = file_get_contents('php://input'); // $zip ist String mit Inhalt der Zip-Datei $zip = new ZipArchive(); // $zip ist Zeiger auf Instanz der Klasse ZipArchive $zip = zip_open(...); // $zip ist Ressourcen-ID
Somit kann ersteres nicht kompatibel zu den letzten beiden sein. Und einen String kann man weder mit den zip-Funktionen, noch mit ZipArchive als Zip interpretieren lassen…
(Oder hab ich dich falsch verstanden?)

Klar, als Notlösung muss ich die Datei dann temporär auf dem Server speichern. Die Kollision mehrerer gleichzeitiger Zugriffe sollte sich relativ leicht ausschließen lassen (es würde zB. ein Zeitstempel im Dateinamen reichen, denn beide Admins zur gleichen Sekunde ein Archiv hochladen ist wohl sehr unwahrscheinlich :smiley:)

Du kannst die PHP ZIP-Funktionen ja nicht nur zum lesen, sondern auch zum schreiben verwenden. Darum scheidet das Öffnen eines Streams ja schon grundlegend aus.

Mein Rat ist es das ZIP-Archiv mit copy auf das Dateisystem zu kopieren, und dann erst als ZIP öffnen.

$filename = "temp/" . uniqid() . ".tmp.zip";  //Einzigartiger Dateiname

copy("php://input", $filename);  //Datei schreiben

$zip = new ZipArchive;
$zip->open($filename);

//mach was mit $zip

unlink($filename); //Datei wieder löschen

Wenn das Skript nicht zuende läuft bleibt die Datei erhalten!

Allerdings ist hier zu prüfen, was du genau machst. Allgemein sind diese Trackmania-Sachen nicht gerne gesehen

Das aktuelle Projekt wird am Ende nicht auf bplaced gehostet werden, es ist nur während der Entwicklung hier hochgeladen, da ich einfach mein Foren-Webspace für dieses Projekt mit nutze :wink:

Ich möchte aus dem Zip die einzelnen Dateien extrahieren, einige Informationen aus diesen auslesen und diese dann in der DB speichern bzw. die Dateien auf dem Server. Das ganze soll ein Pack-Upload werden, um nicht jede Datei einzeln hochladen zu müssen (es handelt sich dabei um wenige KB große Streckendateien des Spiels, keine Mods oder ähnliches), da der “Auftraggeber” schon mehrere hundert Strecken beisammen hat. Und genau dafür suche ich eben einen Weg, das Zip ohne speichern direkt auszulesen.
Wenn es natürlich keine Möglichkeit gibt, werd ich das Zip temporär wohl oder übel speichern müssen. :wink:

Trotzdem Danke für deine Antwort, besonders das mit dem einzigartigen Dateinamen könnte mir nützlich sein :slight_smile:

Findest du es sinnvoll das ZIP in der vollen größe im Arbeitsspeicher abzulegen? Also ich persönlich zweifle wirklich daran :ps:

Du musst ja bedenken, dass es irgendwo gespeichert werden muss. ZIPs speichern ja mehrere Dateien an verschiedenen Stellen der Datei und können somit nicht direkt gestreamt dekomprimiert werden.
Du musst dir immer klar sein, welche Techniken du verwendest :wink:

Hmm gut, von diesem Standpunkt hab ich es noch gar nicht betrachtet.
Dann ist das temporäre Speichern wohl doch der bessere Weg als krampfhaft irgendwie zu versuchen, dass Zip im Speicher zu verarbeiten.

Ist das erste mal, dass ich mit Zip arbeite, man lernt eben doch immer wieder was neues :smiley:

Danke euch beiden für die Hilfe :wink:

[quote=“FunTracker”]Ich habe mal nun noch ein wenig rumprobiert, und auch mit ZipArchive() (zipFile() konnt ich gar nicht finden) scheint das nicht zu gehen. Zumindest ein

$zip = new ZipArchive(); $zip->open("php://input");
resultiert wieder im Fehler 11 (ER_OPEN).[/quote]
Natürlich - denn wenn ich dich richtig verstanden habe, dann willst du auf diese Weise gleich einen HTTP-Dateiupload verarbeiten?

Dann liegen die Daten in php://input aber noch gar nicht in der Form vor, die sie in einer Datei hätten - sondern sind noch als multipart/form-data kodiert, und das müsstest du dann erst mal auswerten.