4
votes

I'm using the following script to initiate file downloads:

if (file_exists($newfilename)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.basename($newfilename));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($newfilename));
    ob_clean();
    flush();
    readfile($newfilename);
    exit;
}

It works fine when I open the page directly, but the thing is, I need this script to be called through Ajax from another page. When I do that, then the download doesn't start. The rest of the script does what it's supposed to.

I assume the problem is not being able to use the header function this way, but surely there's a way to make this work?

This is the Ajax function if it's of any help:

<script type="text/javascript">
    // function create GetXmlHttpObject
    function GetXmlHttpObject()
    {
    if (window.XMLHttpRequest)
    {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    return new XMLHttpRequest();
    }
    if (window.ActiveXObject)
    {
    // code for IE6, IE5
    return new ActiveXObject("Microsoft.XMLHTTP");
    }
    return null;
    }

    function submitVideoAjax(){
    var myAjaxPostrequest=new GetXmlHttpObject();

    var t2_title=document.video_form.title.value;

    var parameters="title="+t2_title;

    myAjaxPostrequest.open("POST", "newdownloadmanager.php", true);
    myAjaxPostrequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    myAjaxPostrequest.send(parameters);
    myAjaxPostrequest.onreadystatechange=function(){
    if(myAjaxPostrequest.readyState==4){
    if(myAjaxPostrequest.status==200){
    document.getElementById("result").innerHTML=myAjaxPostrequest.responseText;
    document.getElementById("video_form").style.display = "none";

    }
    else    {
    document.getElementById("video_form").innerHTML="An error has occured making the request";
    }
    }
    }
    }
    </script>

And this is the form:

<form name='video_form' id='video_form' method="post">
<input type="hidden" name="title" id="title" value="Madelyn2-01.mp4"/>
<button type="button" name="submit_video" id="submit_video" onclick="submitVideoAjax();">Download</button>
</form>
5
What makes you believe that it could work? Because you want it?hakre

5 Answers

10
votes

You cannot use AJAX to download files. It doesn't make sense. You can send the AJAX request and fetch the file contents inside the success handler on the client, but for obvious security reasons you can't do much with it. You cannot save it on the client computer and there's no javascript API allowing you to prompt the user where to save it.

So to download files, don't use AJAX. Create an anchor pointing to your server side script that serves the file to be downloaded.

1
votes

javascript cannot download files as its a security issue.

1
votes

AJAX requests does not served the same that other browser HTTP request do. You need only to put a link to your script with desired parameters, using about="_blank" or something like this. Modern browsers serve that well.

1
votes

It is possible to download a file using AJAX.

javascript:

function exportToCsv(){

    var xmlhttp;

    if(window.XMLHttpRequest){ xmlhttp = new XMLHttpRequest; }else{ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
    xmlhttp.onreadystatechange = function(){
        if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
                window.location="download.php?filename=export.csv";
            }

        }
    }
    request = "exportToCsv.php";
    xmlhttp.open("GET", request, true);
    xmlhttp.send();

}

The code above, exports a mysql database of contacts to a .csv file. After that, if everything is Ok (xmlhttp.readyState == 4) automatically starts the download. window.location="download.php?filename=export.csv";

download.php file:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

After this, the browser just presents the "Save file as" dialog, and no page refresh happens whatsoever. I have the application up and running, and never had problems. Runs on the following browsers:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
1
votes

When I need to download a file using ajax, I have one of the following two situations:

  • The extension of the file to download is interpretable by the webserver (html, txt, pl, php), depending on how the server is configured
  • The extension of the file is another, and it exists the physical (or logical) file mapped in the URL.

In this second case, it is enough to write a meta tag in the ajax answer, writing it into any element's innerHTML:

<meta http-equiv = "refresh" content="0;URL='somedir/worksheet.xls'" />

Since the xls extension points to an existing file it will be immediately offered to the user for download.

In the first case, however, it is not possible to use the meta tag, since the extension is html or any other interpretable by the webserver and will be served redirecting our website.

As it is usual practice to offer an anchor with the URL of the file to be downloaded for the case that does not start the download automatically, I apply this solution: first, I write the hiperlink

<p> If the download does not start, 
  <a id="link_id" href='somedir/some.html'> click here</a> 
</p>

into some element of the page and then make the callback function click on the anchor element

document.getElementById ("link_id").click();