Building a Force Download Script with PHP and JavaScript
I’ve had the recent challenge of writing a script to forcing a file to be automatically downloaded from a webpage. If you’ve ever gone to sites such as Download.com, or Tucows.com and downloaded a file then you’ve seen this technique in action.
The idea is rather than you clicking a direct link on a file to be downloaded, a script is used as a sort of redirect to the file itself. This gives the developer a chance to determine who you are, if you have access to the file and anything else he wants to dynamically generate.
The Problem
I had to present a page, which a user would read over then click to load a form. They would then fill out the form and submit this to the server which would result in a file being downloaded and the form disappearing (or being removed from the page).
The Solution
I used a mix of PHP and JavaScript with the help of Prototype/Scriptaculous libraries. Here is the page being examined:
Divvies Stores
At the bottom of the page is a large button which upon clicking would load an overlay with the form. This is done with some AJAX magic where the form is actually a separate PHP file being echoed into a div using the AJAX.Request method.
$('store_localButton').observe('click', fadeArea);
$('store_localButton').observe('click', loadHTMLPage);
function fadeArea() {
var bodyOb=document.getElementsByTagName('body')[0];
var newOb='<div id="fadearea"></div>';
$(bodyOb).insert({
'top':newOb
});
}
function loadHTMLPage(url) {
if($('top')) {
location.href="#top";
}
var url=url;
new Ajax.Request(url, {
onSuccess: function(transport) {
displayPage(transport.responseText);
}
});
}
The first part of the script defines a few click event handlers which will handle user clicking the large button on the page. Both handlers work off the same click, and call two different function in order.
The first function, fadeArea, simply inserts an empty div with an id of “fadearea”. This is styled with CSS to fill the entire page with 50% black.
In the next function, loadHTMLPage, I first check if there is an element on the page with an id of ‘top’, and go there. The reason here is because the anchor for the button is null which doesn’t go anywhere. Often times pages will use href=”#” but this sends you back to the top of the page which is a very jarring experience and can usually confuse users. In cases where I am attaching events to anchors, I tend to make the href attribute null like: href=”javascript:void(null);”, which basically returns nothing. The second part of the function makes a request for the specified url, which in this case is a PHP file.
Once the file is successfully retrieved the displayPage is called.
function displayPage(htmlSnippet) {
$('fadearea').insert({
'top':htmlSnippet
})
}
Here, knowing its being inserted into the fadearea div, we use Prototype to easily insert the contents of the requested file.
In my form I used an inline onsubmit event to kickoff the whole submitting process (Probably could have/should have used the DOM3 method).
Heres where it gets sticky, the form now gets submitted using Prototype’s Form .Request method, which is an http request with your serialized data. The Form.Request method sends its data to the file in your forms action attribute, which if all is ok, will simply echo the string literal “download.php”.
The HTML form tag