Scroll page back to the top

Download file with PHP

In this tutorial I will show you how to create a link to a file which prompts the user for a download.

To start with create two new files and call them download.php and index.php.
Open the download.php and remove the entire content which your editor added to it, then start typing the following:

<?php
// block any attempt to the filesystem
if (isset($_GET['file']) && basename($_GET['file']) == $_GET['file']) {
	$filename = $_GET['file'];
} else {
	$filename = NULL;
}

First we are checking if the the url contains the parameter file and whether basename($_GET['file']) and $_GET['file'] have the same value – this is to prevent any attackers from downloading files we don´t want them to download.

If the condition is true then we are assigning the value of the file to the variable called $filename, however if the condition is false then we are assigning NULL to the variable.

On the next line type:

// define error message
$err = '<p style="color:#990000">Sorry, the file you are requesting is unavailable.</p>';

This line of code creates a new variable called $err and assigns the default message which will be displayed to the user when the file is unavailable or any other problem occur.

	if (!$filename) {
		// if variable $filename is NULL or false display the message
		echo $err;
	} else {
		// define the path to your download folder plus assign the file name
		$path = 'downloads/'.$filename;
		// check that file exists and is readable
		if (file_exists($path) && is_readable($path)) {
			// get the file size and send the http headers
			$size = filesize($path);
			header('Content-Type: application/octet-stream');
			header('Content-Length: '.$size);
			header('Content-Disposition: attachment; filename='.$filename);
			header('Content-Transfer-Encoding: binary');
			// open the file in binary read-only mode
			// display the error messages if the file can´t be opened
			$file = @ fopen($path, 'rb');
			if ($file) {
				// stream the file and exit the script when complete
				fpassthru($file);
				exit;
			} else {
				echo $err;
			}
		} else {
			echo $err;
		}
	}
?>

What´s happening here is - first we check whether the $filename is NULL and if so we are displaying our message $err message. If it isn´t NULL then we are creating the variable called $path which stores the path to the file and assigns the populated name of the file to the end of it.

Next we are checking whether the file exists and is readable, if so then we are sending the appropriate http headers with file size and opening the file in binary read-only mode (rb). Then, if the file has been opened successfully, we are using the fpassthru() function to write the result to the output buffer.
If any of the condition was unsuccessfull we are displaying our $err message.

Now open index.php and type the following:

<a href="download.php?file=picture.jpg">Download file</a>

And that´s all there is to it.

 
 
 

Discussion (37 comments)

  • Simske

    Simske on Monday, 26th September 2011

    Thanks!!!!
    It works excellent!

    Reply

  • bazzaah

    bazzaah on Wednesday, 12th October 2011

    Thanks for this! The script works well for me.

    Reply

  • popking

    popking on Sunday, 20th November 2011

    Working 'out of the box'!
    Great, thanks!

    Reply

  • Peter M

    Peter M on Friday, 25th November 2011

    Hi. This seems like a nice piece of code but I can't get it to work. Exactly where do I wright my filename?

    Reply

  • Sebastian Sulinski

    Sebastian Sulinski : @designtutorials on Friday, 25th November 2011

    Hi Peter,
    The file name needs to be included in the url you're pointing to - when creating your link, where picture.jpg is the name of your file:

    <a href="download.php?file=picture.jpg">Download file</a>
    

    Reply

  • Peter M

    Peter M on Friday, 25th November 2011

    Thanks for the quick answer but it still doesn't work. Is it the only place I should write the file name in. Shouldn't I write the file name in the actual script somewhere?

    Reply

  • Sebastian Sulinski

    Sebastian Sulinski : @designtutorials on Sunday, 27th November 2011

    In the link you should only provide the file name, but in the code you will hard code the path to the folder where all these files are located - check the following line in the code above:

    // define the path to your download folder plus assign the file name
    $path = 'downloads/'.$filename;
    

    Reply

  • Jon Schreyers

    Jon Schreyers on Friday, 27th January 2012

    Thanks for this, works amazingly!

    Reply

  • Gordon

    Gordon on Friday, 27th January 2012

    Hi, is there a simple way to allow the end user to select where to save the file instead of a direct download to a predefined location?

    Reply

  • Sebastian Sulinski

    Sebastian Sulinski : @designtutorials on Sunday, 5th February 2012

    Hi Gordon,
    The way download behaves after button is clicked is pretty much the browser behavior / settings. If you check your browser preferences you should have an option to specify whether you wish to always download to the same folder or to prompt for the location.

    Reply

  • Theresa

    Theresa on Tuesday, 7th February 2012

    Hi I am using a newsletter signup that uses ajax url: 'index.php' is there a way to add the link to ajax success:
    Hope it makes sense not very good with ajax or javascript.

    Reply

  • Sebastian Sulinski

    Sebastian Sulinski : @designtutorials on Tuesday, 7th February 2012

    Hi Theresa,
    You can try one of our tutorials which explains how to display message after submission: Web Form with jQuery $.ajax() and PHP - I hope this is what you're looking for.

    Reply

  • Dany

    Dany on Wednesday, 14th March 2012

    Thanks Sebastian,for sharing this code with us.
    your code is simple yet powerful.
    thank you very much.

    Reply

  • minh

    minh on Wednesday, 21st March 2012

    this worked great! thanks Sebastian.

    Reply

 
Page 1 of 3
 
 
Add a comment
Add Comment