2011-07-12 26 views
29

Tengo un botón y onclick llamará a una función ajax.Descargar archivo a través de una llamada ajax php

Aquí es mi función ajax

function csv(){ 

    ajaxRequest = ajax();//ajax() is function that has all the XML HTTP Requests 

    postdata = "data=" + document.getElementById("id").value; 

    ajaxRequest.onreadystatechange = function(){ 
     var ajaxDisplay = document.getElementById('ajaxDiv'); 
     if(ajaxRequest.readyState == 4 && ajaxRequest.status==200){ 
      ajaxDisplay.innerHTML = ajaxRequest.responseText;   
     } 
    } 

    ajaxRequest.open("POST","csv.php",false); 
    ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
    ajaxRequest.send(postdata); 
} 

puedo crear el archivo csv en base a la entrada del usuario. Después de su creación, quiero que solicite descargar o forzar la descarga (preferiblemente fuerza). Estoy usando la siguiente secuencia de comandos al final del archivo php para descargar el archivo. Si ejecuto este script en un archivo separado, funciona bien.

$fileName = 'file.csv'; 
$downloadFileName = 'newfile.csv'; 

if (file_exists($fileName)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: text/csv'); 
    header('Content-Disposition: attachment; filename='.$downloadFileName); 
    ob_clean(); 
    flush(); 
    readfile($fileName); 
    exit; 
} 
echo "done"; 

Pero si lo ejecuto al final de csv.php da salida a los contenidos de la file.csv en la página (en el ajaxDiv) en lugar de la descarga.

¿Hay alguna manera de forzar la descarga del archivo al final de csv.php?

Respuesta

36

AJAX no es para descargar archivos. Abre una nueva ventana con el enlace de descarga como su dirección, o haz document.location = ....

+16

Creo que técnicamente es mejor establecer 'window.location'; vea esta discusión: http://stackoverflow.com/questions/7857878/window-location-vs-document-location – yitwail

8

Lo he logrado con un iframe oculto. Yo uso perl, no php, así que solo daré un concepto, no una solución de código.

El cliente envía la solicitud Ajax al servidor, lo que hace que se genere el contenido del archivo. Esto se guarda como un archivo temporal en el servidor y el nombre de archivo se devuelve al cliente.

cliente (javascript) recibe el nombre de archivo, y establece el src iframe en cierta URL que entregará el archivo, como:

$('iframe_dl').src="/app?download=1&filename=" + the_filename 

servidor sorbe el archivo, desvincula, y envía la corriente al cliente, con estos encabezados:

Content-Type:'application/force-download' 
Content-Disposition:'attachment; filename=the_filename' 

funciona como un encanto.

8

@joe: Muchas gracias, este fue un buen aviso!

que tenía un problema un poco más difícil: 1. el envío de una petición AJAX con datos POST, para el servidor para producir un archivo ZIP 2. conseguir una respuesta de vuelta 3. Descarga el archivo ZIP

Así que eso cómo lo hice (usando jQuery para manejar la petición AJAX):

  1. solicitud POST inicial:

    var parameters = { 
        pid  : "mypid", 
        "files[]": ["file1.jpg","file2.jpg","file3.jpg"] 
    }

    var options = { url: "request/url",//replace with your request url type: "POST",//replace with your request type data: parameters,//see above context: document.body,//replace with your contex success: function(data){ if (data) { if (data.path) { //Create an hidden iframe, with the 'src' attribute set to the created ZIP file. var dlif = $('<iframe/>',{'src':data.path}).hide(); //Append the iFrame to the context this.append(dlif); } else if (data.error) { alert(data.error); } else { alert('Something went wrong'); } } } }; $.ajax(options);

El "request/url" maneja la creación de zip (fuera del tema, por lo que no publicará el código completo) y devuelve el siguiente objeto JSON.Algo así como:

//Code to create the zip file 
//...... 
//Id of the file 
$zipid = "myzipfile.zip" 
//Download Link - it can be prettier 
$dlink = 'http://'.$_SERVER["SERVER_NAME"].'/request/download&file='.$zipid; 
//JSON response to be handled on the client side 
$result = '{"success":1,"path":"'.$dlink.'","error":null}'; 
header('Content-type: application/json;'); 
echo $result; 

La "petición/descarga" puede realizar algunas comprobaciones de seguridad, si es necesario, y generar la transferencia de archivos:

$fn = $_GET['file']; 
if ($fn) { 
    //Perform security checks 
    //.....check user session/role/whatever 
    $result = $_SERVER['DOCUMENT_ROOT'].'/path/to/file/'.$fn; 
    if (file_exists($result)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/force-download'); 
    header('Content-Disposition: attachment; filename='.basename($result)); 
    header('Content-Transfer-Encoding: binary'); 
    header('Expires: 0'); 
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
    header('Pragma: public'); 
    header('Content-Length: ' . filesize($result)); 
    ob_clean(); 
    flush(); 
    readfile($result); 
    @unlink($result); 
    } 

} 
+0

¿Solo el & necesario cambiar a? para la cadena de consulta. ¡Gracias por la increíble ayuda con esto! - Intenté hacer una edición pero era tan pequeña que no me dejaba !! $ dlink = 'http: //'.$_SERVER ["SERVER_NAME"].'/Request/download? File = '. $ Zipid; –

19

Una solución muy sencilla usando jQuery:

en el lado del cliente:

$('.act_download_statement').click(function(e){ 
    e.preventDefault(); 
    form = $('#my_form'); 
    form.submit(); 
}); 

y en el lado del servidor, asegúrese de devolver el correcto Content-Type encabezado, por lo que el navegador sabrá que es un archivo adjunto y la descarga comenzará.

+1

+1 Esto funcionó muy bien para mí al enviar datos al servidor y obtener una descarga de archivo ZIP como respuesta. Sin página recargar –

+0

+1 La publicación es más técnica y es un buen truco – bizzr3

+0

¿Puedes dar un poco más de detalle y proporcionar algún código sobre lo que sucede en ambos extremos? –

2

No puede descargar el archivo directamente a través de ajax.

Puede poner un enlace en la página con la URL de su archivo (devuelto desde la llamada ajax) u otra forma es usar iframe oculto y establecer la URL de la fuente de ese iframe dinámicamente. De esta manera puede descargar el archivo sin refrescar la página.

Este es el código

$.ajax({ 
    url : "yourURL.php", 
    type : "GET", 
    success : function(data) { 
     $("#iframeID").attr('src', 'downloadFileURL'); 
    } 
}); 
+0

Publicar el código relevante ayudaría a ilustrar lo que está tratando de decir aquí. – larsAnders

+0

en su respuesta exitosa ajax puede establecer el iframe oculto src –

Cuestiones relacionadas