Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get a zip with $.ajax from php server

I'm trying to send a zip generated by a php server when requested by jquery's $.ajax.

This is my code:

php:

        $file = tempnam($a_folder_path, "zip");

        $zip = new ZipArchive();
        $zip->open($file, ZipArchive::OVERWRITE);
        $zip->addFile($path_to_json, 'data.json');
        $zip->close();

        rename($file, $file . '.zip');

        $filename = basename($file . '.zip');
        $filepath = $file . '.zip';
        while (ob_get_level()) {
            ob_end_clean();
        }
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
        header("Content-Description: File Transfer");
        header("Content-type: application/octet-stream");
        header("Content-Disposition: attachment; filename=\"".$filename."\"");
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: ".filesize($filepath));
        ob_end_flush();
        echo file_get_contents($filepath);
        //@readfile($filepath);

javascript:

$.ajax(
        {
            url:    myUrl,                
            type:   'POST',                
            data:   {
                "leData"     : "some_data"
            },
            context: document.body,
            cache:  false,
            success: function(data) {
                console.log(data);
                console.log(data.length);
                var bytes = new Uint8Array(data.length);
                for (var i=0; i<data.length; i++) {
                    bytes[i] = data.charCodeAt(i);
                }
                blob = new Blob([bytes], {type: "application/zip"})
                saveAs(blob, "test.zip");//trying to access data with FileSave.js
                zip.load(data);//trying to access data with JSZip.js
                jsonData = JSON.parse(zip.file('shouldBeThere.json').asText());
            },
            error: function() {
                alert('error');
            }
        }
    );

What happens:

  1. The server creates the zip file I ask it to, and this file isn't corrupted. It contains, among others, shouldBeThere.json.
  2. The server sends data to the frontend.
  3. The console.log(data); line in javascript prints a string almost identical from what I get by opening the zip file created on the server with a text editor.
  4. The console.log(data.length); line in javascript prints a number smaller than the content length of the response header according to chrome's devtools. Maybe a hint to a data corruption.
  5. saveAs creates a zip containing the file it's meant to, with the right name, but when I try to unzip it 7zip shows an error: "an attempt was made to move the file pointer before the beginning of the file". 6.JSZip seems to load the data but then zip.file('shouldBeThere.json') is null.

The problem is I have no idea if the problem comes from php or from javascript. I don't know if php is sending a corrupted zip or if javascript isn't reading it right.

I have tried all the php headers combinations and methods i've found on the internet. I have also tried to do things differently in javascript: using an ArrayBuffer instead of Uint8Array, passing bytes instead of data to zip.load(), using {type: "application/octet-stream"} in Blob().

like image 544
Teo M Avatar asked Apr 08 '15 13:04

Teo M


People also ask

Can you use AJAX with PHP?

Start Using AJAX Today In our PHP tutorial, we will demonstrate how AJAX can update parts of a web page, without reloading the whole page. The server script will be written in PHP. If you want to learn more about AJAX, visit our AJAX tutorial.

How send data from PHP to HTML in AJAX?

ajax({ type: 'POST', url: 'process. php', data: { text1: val1, text2: val2 }, success: function(response) { $('#result'). html(response); } }); });


1 Answers

I finally found a solution: It has to be specified to ajax the received data type, and then convert this unicode data into characters. Here is my new javascript code:

$.ajax(
    {
        url:    myUrl,                
        type:   'POST',                
        data:   {
            "leData"     : "some_data"
        },
        context: document.body,
        cache:  false,
        dataType: 'text',                                   //solution code
        mimeType: 'text/plain; charset=x-user-defined',     //solution code
        success: function(data) {
            console.log(data);
            console.log(data.length);
            newContent = "";                                //solution code
            for (var i = 0; i < data.length; i++) {         //solution code
                newContent += String.fromCharCode(data.charCodeAt(i) & 0xFF); //solution code
            } 
            var bytes = new Uint8Array(newContent.length);                     //modified
            for (var i=0; i<newContent.length; i++) {                          //modified
                bytes[i] = newContent.charCodeAt(i);                           //modified
            }
            blob = new Blob([bytes], {type: "application/zip"})
            saveAs(blob, "test.zip");
            zip.load(newContent);                                              //modified
            jsonData = JSON.parse(zip.file('shouldBeThere.json').asText());
        },
        error: function() {
            alert('error');
        }
    }
);

My php code was fine, it even worked without headers. Here is the minimal php code I need:

 $file = tempnam($a_folder_path, "zip");

    $zip = new ZipArchive();
    $zip->open($file, ZipArchive::OVERWRITE);
    $zip->addFile($path_to_json, 'data.json');
    $zip->close();

    rename($file, $file . '.zip');

    echo file_get_contents($file . '.zip');

Solution inspired by this

like image 159
Teo M Avatar answered Sep 23 '22 03:09

Teo M