ZIP Datei Download erzwingen


Sprint

Erfahrenes Mitglied
#1
Hallo zusammen,

in dem aktuellen Projekt sollen einige PDF Dateien zu einem ZIP File zusammengefaßt und automatisch runtergeladen werden. Über ein Ajax Script werden die PDF erzeugt und anschließend wird über einen weiteren Ajax Aufruf das ZIP Archiv erzeugt. Es funktioniert soweit auch alles, nur beim Download versagt das Script. Es passiert nichts. Nicht einmal in der Logdatei ist ein Fehler drin.

Natürlich könnte ich nach der Erstellung einen Link anbieten, es soll aber anschließend das Verzeichnis wieder leergeräumt werden. Darum wäre es mir am liebsten, die Datei würde nach Erstellung automatisch an den Browser geschickt.
PHP:
$verzeichnis = "zip/";
$zip_name = substr($_SESSION['usernr'],0,5).'.zip';

$dummy = glob('zip/'.substr($_SESSION['usernr'],0,5).'*.pdf');
foreach ($dummy as $dum)
    $dateien[] = end(explode('/', $dum));

$zip = new ZipArchive;

$status = $zip->open($verzeichnis.$zip_name, ZipArchive::CREATE);

if ($status) {
    foreach ($dateien as $datei) {
        $zip->addFile($verzeichnis.$datei);
    }

    $zip->close();

    if (file_exists($verzeichnis.$zip_name)) {
        $size = filesize($verzeichnis.$zip_name);
        $dateiname = basename($verzeichnis.$zip_name);
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename='.$dateiname);
        header("Content-Length: $size");
        readfile($verzeichnis.$zip_name);
    }
}
Hat da jemand eine Idee, warum der Download nicht gestartet wird?

Danke schon mal im Voraus,
Sprint
 

Sempervivum

Erfahrenes Mitglied
#2
Als ich mit deinem Code eine Testdatei gemacht habe, habe ich hier einen Laufzeitfehler bekommen:
Code:
foreach ($dummy as $dum)
    $dateien[] = end(explode('/', $dum));
dass der Parameter von end() eine echte Variable sein muss. Ergebnis eines Funktionsaufrufes ist nicht zulässig lt. Doku.
Nachdem ich dies korrigiert hatte, funktioniert der Download einwandfrei:
Code:
<?php
ini_set('display_errors', '1');
error_reporting(E_ALL);

$verzeichnis = "zip/";
$zip_name = 'test.zip';

$dummy = glob('zip/*.pdf');
$dateien = [];
foreach ($dummy as $dum) {
    $namarr = explode('/', $dum);
    $dateien[] = end($namarr);
}

$zip = new ZipArchive;

$status = $zip->open($verzeichnis . $zip_name, ZipArchive::CREATE);

if ($status) {
    foreach ($dateien as $datei) {
        $zip->addFile($verzeichnis . $datei);
    }

    $zip->close();

    if (file_exists($verzeichnis . $zip_name)) {
        $size = filesize($verzeichnis . $zip_name);
        $dateiname = basename($verzeichnis . $zip_name);
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename=' . $dateiname);
        header("Content-Length: $size");
        readfile($verzeichnis . $zip_name);
    }
}
?>
 

Sprint

Erfahrenes Mitglied
#3
Den Laufzeitfehler, den du in der foreach bekommen hattest, kam bei mir nicht. Aber das war ja auch bei der Erstellung der ZIP Datei selbst, und das hat immer funktioniert.

Aber auch nach der Umstellung hat es bei mir nicht geklappt. Dabei kam mir aber die Idee, daß du das Testscript ja vom Browser aus gestartet hattest und siehe da, das klappt auch bei mir. Bei diesem Script habe ich aber das Problem, daß es per Ajax aufgerufen wird. Gibt es dafür auch eine Lösung, oder muß ich die ZIP Erstellung im Browser aufrufen und von da aus dann die eigentliche Hauptseite neu laden?
 

Sempervivum

Erfahrenes Mitglied
#4
Ja, dafür gibt es eine Lösung. Hier wird beschrieben, wie man ein Binärfile mit Ajax herunter laden kann:
https://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
Dann muss man das Blob noch speichern. Dafür habe ich schon häufig dieses Skript eingesetzt:
http://danml.com/download.html
Mit diesem Javascript funktioniert es dann bei mir:
Javascript:
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'thread82-download-zip.php', true);
        xhr.responseType = 'blob';

        xhr.onload = function (e) {
            if (this.status == 200) {
                // get binary data as a response
                var blob = this.response;
                download(blob, "test.zip", "application/zip");
            }
        };
        xhr.send();
 

Sprint

Erfahrenes Mitglied
#5
Ui, für auf die Schnelle überfordert das ganze dann doch meine Kenntnisse. Da muß ich mich erst einmal in einer ruhigen Minute drin vertiefen.

Mein aber viel größeres Problem ist aber, daß das Script erst ab IE10 funktioniert. Da die Seite aber bei Autohändlern läuft und viele Herstellerseiten noch für IE6 gebaut wurden, sind da moderne Browser bei weitem noch nicht Standard. Da werde ich mir was anderes überlegen.
 

Sempervivum

Erfahrenes Mitglied
#6
OMG, ich dachte, alles vor IE11 sei Geschichte. Bin selber schon auf Unverständnis gestoßen, wenn ich darauf hingewiesen habe, dass Dinge wie Pfeiloperator, forEach für Nodelist etc. durch IE11 nicht unterstützt werden. Dann wünsche ich viel Erfolg bei der Suche nach eine Alternative.
 

Sprint

Erfahrenes Mitglied
#7
Tja, die müssen sich ja darauf konzentrieren, ihre Diesel sauber zu rechnen. Da bleibt nicht mehr viel Zeit für ihre Händlerportale ;)
Ich habe es jetzt so gelöst, daß nach Erstellung der ZIP Datei die Ausgangsseite mit einem GET Wert neu gestartet wird und so dann wie ursprünglich gedacht über header() und readfile() die Datei geladen wird. Ich weiß bloß noch nicht, wie ich es abfangen soll, wenn der automatische Download nicht gestartet wird. readfile() wird das ja wohl nicht merken, wenn der Browser da nicht mitspielt.