Offer a generated file for download from jQuery post

17,205

Solution 1

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.

Solution 2

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;
?>

Solution 3

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);
});
Share:
17,205

Related videos on Youtube

lightstrike
Author by

lightstrike

I'm a web developer with experience in PHP, Python, MySQL, Postgres, JavaScript/jQuery, CSS, (X)HTML

Updated on June 04, 2022

Comments

  • lightstrike
    lightstrike almost 2 years

    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.

    • Lightness Races in Orbit
      Lightness Races in Orbit about 12 years
      What took you to the conclusion that this is a task for AJAX? Just make a POST request. It's like everybody's forgotten about normal requests nowadays :(
  • Yevgeniy
    Yevgeniy over 11 years
    I just now encountered a similar task. I did find a workaround allow an Ajax POST to prompt to download file w/o leaving page.Edit whoops--can't press return or use code. see reply to topic