Reputation: 377
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:
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().
Upvotes: 7
Views: 10128
Reputation: 618
I update your JS code for JSZip 3+ version. It's more easy. I hope i'll be useful to someone.
$.ajax(
{
url : url,
type: "POST",
data: $('#form').serialize(),
cache: false,
dataType: 'text',
responseType :'blob',
mimeType: 'text/plain; charset=x-user-defined',
success: function(data) {
JSZip.loadAsync(data)
.then(function (zip){
return zip.generateAsync({type: "blob"})})
.then(function (blob){
var date = new Date();
saveAs(blob, date.getFullYear() + "" + (date.getMonth() + 1) + "" + date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds()+".zip");
});
},
error: function() {
alert('error');
}
);
Upvotes: 0
Reputation: 1
I was searching for a solution for following problem: "Sending a request on php url for creating a zip of a directory and downloading it by using ajax response."
Following code works:
PHP part for zip:
// Function for creating a zip of a directory
function zipFilesAndDownload($directory, $file_names) {
$zip = new ZipArchive();
if ($zip->open("../temp/$directory.zip", ZIPARCHIVE::CREATE) !== TRUE) {
exit("Error on creating '../temp/$directory.zip'");
}
foreach ($file_names as $file) {
$zip->addFile($file, substr($file, strrpos($file, "/") + 1));
}
$zip->close();
readfile("../temp/$directory.zip");
unlink("../temp/$directory.zip");
}
// Code for creating array of filenames
$directory = $_POST['directory']; // e.g. a directory with ID "123"
$dirToZip = "../uploaddir/$directory";
if ($handle = opendir($dirToZip)) {
$file_names = array();
while (($file = readdir($handle)) !== false) {
if ($file != "." && $file != "..") {
array_push($file_names, "$dirToZip/$file");
}
}
closedir($handle);
zipFilesAndDownload($directory, $file_names);
}
JS part:
$(document).on('click', '#downloadDirectory', function () {
var directory = '123';
$.ajax({
type: 'POST',
url: '../createZip.php',
data: {"directory": directory},
dataType: 'text',
mimeType: 'text/plain; charset=x-user-defined',
success: function (data) {
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, "pictures.zip"); // "saveAs" function is provided in FileSaver.js
}
});
});
Upvotes: 0
Reputation: 377
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
Upvotes: 12