0

I have a gallery of files shown in a table with checkboxes for each file. The goal is to check the files you want to download, then click a button to download a zip file containing those individual files.

Everything seems to work okay... the array, the ajax, the "success" response... but the file won't download. Is it possible to download files in this way? If not, what do I need to do differently for this to work properly?

jQuery

// searchIDs returns an array of file names. ie:
// 'file1.zip', 'file2.png', 'file3.pdf'

$('#toolkit-bin input[type=submit]').on('click', function(e) {
    e.preventDefault();

    $.ajax({
        type : 'POST',
        url : './functions.php',
        data : { searchIDs: searchIDs },
        success : function(data) {
            alert(data);
        },
        error : function(request,error) {
            alert("Request: "+JSON.stringify(request));
        }
    });

});

functions.php

// ROOT is defined as the root directory of the server.

$zipname = 'LiveLOUD-Toolkit.zip';
$zip = new ZipArchive();
$zip -> open($zipname, ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Get the array of the selected files. 
$files = $_POST['searchIDs'];

// Loop through the files.
foreach ($files as $file)
{
    // Get the path to the file.
    $path = ROOT.'/_assets/toolkit/'.$file;

    // Add the file to the zip.
    $zip -> addFromString(basename($path), file_get_contents($path));  
}

// Zip archive will be created only after closing object.
$zip -> close();

// If the file was created successfully...
if (file_exists($zipname))
{   
    // Download the zip file.
    // THIS STUFF DOES NOT SEEM TO WORK
    header('Content-Type: application/zip');
    header('Content-disposition: attachment; filename='.$zipname);
    header('Content-Length: '.filesize($zipname));

    // Delete the zip after download.
    unlink($zipname);

    // This is successfully returned.
    echo 'Success!';
}
else
{
    echo 'Error!';
}
Paul Ruocco
  • 462
  • 3
  • 18
  • you are not sending the actual data: `readfile($zipname);` – msg Jun 14 '19 at 20:02
  • I added the `readfile($zipname);` right before the `unlink($zipname);` and I get the following as a response. https://ibb.co/Px9CNQ0 – Paul Ruocco Jun 17 '19 at 15:59
  • I gave that a shot just now but no change. I did notice, however, the `error` of the ajax is firing, not the `success`. Any idea what could be causing ajax to trigger that? – Paul Ruocco Jun 17 '19 at 16:26
  • The error callback fires depending on the HTTP status code, but other than that, no idea what could be causing it. It's still sending the content, right ? – msg Jun 17 '19 at 16:51
  • The binary content, yeah. And the HTTP status code is 200. – Paul Ruocco Jun 17 '19 at 17:04
  • Turns out [you can't](https://stackoverflow.com/questions/6668776#answer-13322848) – msg Jun 17 '19 at 17:28

1 Answers1

0

Many thanks to msg and the people in this thread. I got my downloads to work by creating the zip file in the functions.php and passing the file name back to ajax. Then, using window.location to open the zip. My final code is below:

jQuery / Ajax:

// searchIDs returns an array of file names. ie:
// 'file1.zip', 'file2.png', 'file3.pdf'

// If submmit download button is clicked...
$('#toolkit-bin input[type=submit]').on('click', function(e) {
    e.preventDefault();

    var searchIDs = [];

    $('#croud-toolkit').find(':checkbox:checked').map(function(){
        searchIDs.push($(this).val());
    });

    $.ajax({
        type : 'POST',
        url : './functions.php',
        data : { searchIDs: searchIDs },
        success : function(data) {
            window.location = './'+data;
        },
        error : function(data) {
            alert('error');
        }
    });

});

functions.php

// ROOT is defined as the root directory of the server.

// Name and create the Zip archive.
$zipname = 'LiveLOUD-Toolkit.zip';
$zip = new ZipArchive();
$zip -> open($zipname, ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Get the array of the selected files. 
$files = $_POST['searchIDs'];

// Loop through the files.
foreach ($files as $file)
{
    // Get the path to the file.
    $path = ROOT.'/_assets/toolkit/'.$file;

    // Add the file to the zip.
    $zip -> addFromString(basename($path), file_get_contents($path));  
}

// Zip archive will be created only after closing object.
$zip -> close();

// Return data to Ajax
echo $zipname;
Paul Ruocco
  • 462
  • 3
  • 18
  • Wouldn't `$('#croud-toolkit').submit()` be enough based on the linked answer? Could you show your html? Maybe js isn't even necessary – msg Jun 17 '19 at 20:13