cómo obtener un zip con $ .ajax del servidor php

Estoy intentando enviar un zip generado por un servidor php cuando lo solicite el $ .ajax de jquery.

Este es mi código:

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'); } } ); 

Lo que pasa:

  1. El servidor crea el archivo zip que le pido, y este archivo no está dañado. Contiene, entre otros, debería estar allí.
  2. El servidor envía datos a la interfaz.
  3. La consola.log (datos); line in javascript imprime una cadena casi idéntica a la que obtengo al abrir el archivo zip creado en el servidor con un editor de texto.
  4. La consola.log (data.length); line in javascript imprime un número más pequeño que la longitud del contenido del encabezado de respuesta de acuerdo con los devtools de Chrome Tal vez una pista para una corrupción de datos.
  5. saveAs crea un archivo zip que contiene el archivo al que está destinado, con el nombre correcto, pero cuando bash descomprimirlo, 7zip muestra un error: “se hizo un bash de mover el puntero del archivo antes del comienzo del archivo”. 6.JSZip parece cargar los datos pero luego zip.file (‘shouldBeThere.json’) es nulo.

El problema es que no tengo idea si el problema viene de PHP o de JavaScript. No sé si PHP está enviando un archivo zip dañado o si JavaScript no lo está leyendo correctamente.

He probado todas las combinaciones de encabezados de php y los métodos que he encontrado en internet. También he intentado hacer cosas de manera diferente en javascript: usando un ArrayBuffer en lugar de Uint8Array, pasando bytes en lugar de datos a zip.load (), usando {type: “application / octet-stream”} en Blob ().

Finalmente encontré una solución: se debe especificar para ajax el tipo de datos recibidos y luego convertir estos datos Unicode en caracteres. Aquí está mi nuevo código javascript:

 $.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 

Mi código php estaba bien, incluso funcionaba sin encabezados. Aquí está el código php mínimo que necesito:

  $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'); 

Solución inspirada en este

Estaba buscando una solución para el siguiente problema: “Enviar una solicitud en phl url para crear un archivo zip de un directorio y descargarlo utilizando la respuesta ajax”.

El siguiente código funciona:

PHP parte para 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']; // eg 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 parte:

  $(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 } }); });