Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Offer a generated file for download from jQuery post

Tags:

jquery

post

php

I've got a large form where the user is allowed to input many different fields, and when they're done I need to send the contents of the form to the server, process it, and then spit out a .txt file containing the results of the processing for them to download. Now, I'm all set except for the download part. Setting the headers on the response to the jQuery .post() doesn't seem to work. Is there any other way than doing some sort of iframe trick to make this work (a la JavaScript/jQuery to download file via POST with JSON data)?

Again, I'm sending data to the server, processing it, and then would like to just echo out the result with headers to prompt a download dialog. I don't want to write the result to disk, offer that for download, and then delete the file from the server.

like image 781
lightstrike Avatar asked Feb 01 '12 19:02

lightstrike


3 Answers

Don't use AJAX. There is no cross-browser way to force the browser to show a save-as dialog in JavaScript for some arbitrary blob of data received from the server via AJAX. If you want the browser to interpret the results of a HTTP POST request (in this case, offering a download dialog) then don't issue the request via AJAX.

If you need to perform some kind of validation via AJAX, you'll have to do a two step process where your validation occurs via AJAX, and then the download is started by redirecting the browser to the URL where the .txt file can be found.

like image 188
meagar Avatar answered Nov 07 '22 06:11

meagar


Found this thread while struggling with similar issue. Here's the workaround I ended up using:

$.post('genFile.php', {data : data}, function(url) {
    $("body").append("<iframe src='download.php?url="+url+"' style='display: none;'></iframe>");
    }); 

genFile.php creates the file in staging location using a randomly generated string for filename. download.php reads the generated file, sets the MIME type and disposition (allowing to prompt using a predefined name instead of the random string in the actual filename), returns the file content and cleans up by deleting the source file.

[edit] might as well share the PHP code...

download.php:

<?php
$fname = "/tmp/".$_GET['url'];
header('Content-Type: text/xml');
header('Content-Disposition: attachment; filename="plan.xml"');
echo file_get_contents($fname);
unlink ($fname);
?>

genFile.php:

<?php
$length = 12;
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = substr( str_shuffle( $chars ), 0, $length ).'.xml';
$fh = fopen(('tmp/'.$str), 'w') or die("can't open file");
fwrite($fh,$_POST["data"]);
fclose($fh);
echo $str;
?>
like image 40
Yevgeniy Avatar answered Nov 07 '22 06:11

Yevgeniy


Rather than using jQuery's .post(), you should just do a normal POST by submitting the form, and have the server respond with appropriate Content-Encoding and MIME-type headers. You can't trigger a download through post() because jQuery encapsulates the returned data.

One thing I see in use rather frequently, though, is this:

$.post('generateFile.php', function(data) {
  // generateFile builds data and stores it in a
  // temporary location on the server, and returns
  // the URL to the requester.
  // For example, http://mysite.com/getFile.php?id=12345

  // Open a new window to the returned URL which
  // should prompt a download, assuming the server
  // is sending the correct headers:
  window.open(data);
});
like image 7
Justin ᚅᚔᚈᚄᚒᚔ Avatar answered Nov 07 '22 06:11

Justin ᚅᚔᚈᚄᚒᚔ