PHP - Protected download
In this example, we are protecting a file from an unauthenticated download.
The script will ask for username and password, and if it is OK, it will send a file. Notice, that we do not give file URL. We are sending file through PHP script, so the real location of the file stays secret for the outside world. The downside is that a user cannot continue an interrupted download.
Depending on the server configuration, you may not have sufficient permissions to use mime_content_type (it is disabled by default). If this is a situation, just hardcode your MIME type.
<?php
if (isset($_POST["username"]) && ($_POST["username"] == "phpbee") &&
isset($_POST["password"]) && ($_POST["password"] == "phpbee"))
SendFile();
else
DisplayLoginPage();
function DisplayLoginPage()
{
?>
<html>
<head>
<title>Protected download</title>
</head>
<body>
<h2>Welcome to download area</h2>
<p> Type username and password to download a file </p>
<p> Type phpbee for both username and password </p>
<form action="download.php" method="post">
Username<br>
<input type="text" name="username"><br>
Password<br>
<input type="password" name="password"><br>
<input type="hidden" name="login"><br>
<input type="submit">
<input type="reset">
</form>
</body>
</html>
<?php
}
function SendFile()
{
$FileName = "filename.zip";
//header("Content-Type: " . mime_content_type($FileName));
// if you are not allowed to use mime_content_type, then hardcode MIME type
// use application/octet-stream for any binary file
// use application/x-executable-file for executables
// use application/x-zip-compressed for zip files
header("Content-Type: application/octet-stream");
header("Content-Length: " . filesize($FileName));
header("Content-Disposition: attachment; filename=\"$FileName\"");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
$fp = fopen($FileName,"rb");
fpassthru($fp);
fclose($fp);
}
?>
if (isset($_POST["username"]) && ($_POST["username"] == "phpbee") &&
isset($_POST["password"]) && ($_POST["password"] == "phpbee"))
SendFile();
else
DisplayLoginPage();
function DisplayLoginPage()
{
?>
<html>
<head>
<title>Protected download</title>
</head>
<body>
<h2>Welcome to download area</h2>
<p> Type username and password to download a file </p>
<p> Type phpbee for both username and password </p>
<form action="download.php" method="post">
Username<br>
<input type="text" name="username"><br>
Password<br>
<input type="password" name="password"><br>
<input type="hidden" name="login"><br>
<input type="submit">
<input type="reset">
</form>
</body>
</html>
<?php
}
function SendFile()
{
$FileName = "filename.zip";
//header("Content-Type: " . mime_content_type($FileName));
// if you are not allowed to use mime_content_type, then hardcode MIME type
// use application/octet-stream for any binary file
// use application/x-executable-file for executables
// use application/x-zip-compressed for zip files
header("Content-Type: application/octet-stream");
header("Content-Length: " . filesize($FileName));
header("Content-Disposition: attachment; filename=\"$FileName\"");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
$fp = fopen($FileName,"rb");
fpassthru($fp);
fclose($fp);
}
?>
Related Marakana Courses
- PHP and MySQL Bootcamp Training
November 7th, 2007 at 5:01 am
Parse error: syntax error, unexpected ':' in /home/cafe-galleri/web/cafe-galleri.no/download.php on line 39
i get that error, line 39 is header(Content-Type: application/octet-stream);
what's wrong?
January 18th, 2008 at 10:39 pm
yeah it gives me:
Warning: Cannot modify header information - headers already sent by (output started at /home/www/longpoke.us.to/lp/x.php:7)
wtf mate i was liking the code too :O
January 18th, 2008 at 10:43 pm
oh nvm now i see how it works
July 20th, 2008 at 8:05 am
h?mm it needs ob_start(); at the beginning and ob_flush(); for the " Cannot modify header information " problem
however when I run this code it downloads my page not the file? is there any problem with header or is it a configuration issue of the server?
November 12th, 2008 at 6:56 pm
jfw9y3b5ork1r41e
May 18th, 2009 at 10:19 am
thank you
May 23rd, 2009 at 9:29 pm
Вполне возможно. Иногда так действительно случается.
June 1st, 2009 at 2:13 am
Если это не большой секрет;), автор блога откуда родом?
September 10th, 2009 at 5:59 am
Hi! I was surfing and found your blog post… nice! I love your blog.
Cheers! Sandra. R.
September 10th, 2009 at 8:18 am
I love your site.
Love design!!! I just came across your blog and wanted to say that Ive really enjoyed browsing your blog posts. Sign: ndsam
September 21st, 2009 at 7:04 pm
Thanks, this has been very helpful code, especially when combined with ob_start, ob_flush as Kor suggested.
September 23rd, 2009 at 12:37 pm
Hey thanks a lot for this, really helpful. I just wish that there was a little more security.
January 25th, 2010 at 12:41 pm
Hi All,
This code seems to work perfectly as written when run on a uni*/linux machine. However, it appears that if it is run under Windows (I have XP Pro), the only way PHP sees the file to be downloaded is if the file is in the same folder as the PHP code resides. Relative or absolute URLs have no effect, apparently. If I place the download file in some other part of the document tree (i.e., ../tmp/somefile.zip), windows doesn't know what to do with it and downloads the download.php file instead. I tried using the reverse backslash (as sometimes required in Windows environments ..\tmp\somefile.zip) to no avail. If I have more time, I'll try to isolate this issue because it is quite unusual for PHP to be this inconsistent across platforms, except for OS specific restrictions, such as file naming conventions and so on. I don't ever remember running into something like this, and I've been working with PHP since version 3.0.
April 17th, 2010 at 9:42 pm
I was using this code happily until I discovered it didn't work for two of my larger files (48mb and 50mb), however it worked with a 31mb file. I would really love to know how to do a protected download with larger files. If anyone knows a way, please post it here. Thanks!