Optimize File Downloading in PHP

Using PHP to serve downloadable content is more efficient, secure, and flexible than the traditional direct link method (using a hyperlink). In this programming tutorial you will learn some tips to optimize the file downloading process on your website.

The most common problems webmasters encounter with direct links are:

  • The true path to the downloadable content can be revealed easily and is not protected, allowing users to bypass web forms and download the content directly using a browser.
  • Direct links won’t effectively block bots that automatically download content.
  • They don’t minimize abusive use. For example, users can repetitively download the content an unlimited amount of times, slowding down your site.
  • For very large files (>10MB or even >40MB), the script will timeout, resulting in an incomplete file download. For those websites serving an .exe file or any installer file to their customer, this will cause the file to become corrupted.

This tutorial is an updated version of the previous download script mentioned here: http://www.devshed.com/c/a/PHP/Simple-and-Secure-PHP-Download-Script-with-Limits-Tutorial/ which has a lot of limitations.

The Solution: A Secure and Efficient PHP Download Script

Suppose you want to give free audio samples to your website visitors. There are two audio types that you want to provide: WAV and MP3. You want users to be authenticated before they download, asking them to provide an email address and their name. You also want to ensure they are human by letting them answer a captcha challenge.

Once they successfully enter the information in the web form, they will go to a confirmation page which then streams the audio file download. At the same time, you want to receive notifications of the download and log the successful downloads in the database.

To prevent system abuse, you can limit each user download to 3 times, using their IP address as identification. This is exactly how the project web form will look: http://www.php-developer.org/phpdownloadsystem/

There are actually 3 very important PHP files in this project:

  • index.php – the web form where user enters the details.
  • downloadfile.php – the actual download script that will read the file, streams it to the user, sends you the email and logs the transaction in the MySQL database.
  • confirmationpage.php – this is the download page after successful validation.

Meanwhile there are two auxiliaries:

  • is_email.php -used in validating email address.
  • recaptchalib.php – recaptcha library.

Let’s discuss the important scripts. A complete script can be downloaded at the end of this tutorial.

The Web Form (index.php)

Below is the complete source code of the web form (with comments):

<?php //Start PHP session session_start();
$key= 'This is your key'; //Add the key to session variable $_SESSION['key'] = md5($key); //Pre-defined validation variables $emailvalidation=TRUE;
$namevalidation=TRUE;
$audiotypevalidation=TRUE;
$captchavalidation=TRUE; //Check if the form is submitted if (isset($_POST["formchecker"]) && $_POST["formchecker"] == "submittedform") { //Form is submitted; start validation of submitted info
//Require email validator: RFC Compliant email validator: //http://www.dominicsayers.com/isemail/results.php require_once 'is_email.php'; //Define the sanitizing function, ensure that inputs are clean and secure. function sanitize($data){ //remove spaces from the input $data=trim($data); //convert special characters to html entities
//most hacking inputs in XSS are HTML in nature, so converting them to special //characters so that they are not harmful $data=htmlspecialchars($data);
return $data;
} //Now to use the sanitizing function, simple use it to sanitize the POST.
//Received posted values from form. $name=sanitize($_POST["name"]);
$email=sanitize($_POST["email"]);
$audiotype= sanitize($_POST["audiotype"]); //Validate email if (!(is_email($email))) { //Email invalid, return false $emailvalidation=FALSE;
} else {
$emailvalidation=TRUE;
} //Validate name if (empty($name)) { //Name is empty, return false $namevalidation=FALSE;
} else {
$namevalidation=TRUE; 
} //Validate audiotype if ((empty($audiotype)) || ($audiotype!="wav" && $audiotype!="mp3")) {//Not a valid audiotype $audiotypevalidation=FALSE;
} else {
$audiotypevalidation=TRUE; 
} //Validate recaptcha require_once('recaptchalib.php');
$privatekey = "Your_recaptcha_private_key_here";
$resp = recaptcha_check_answer ($privatekey,
 $_SERVER["REMOTE_ADDR"], POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); if (!$resp->is_valid) { //captcha validation fails $captchavalidation=FALSE;
} else {
$captchavalidation=TRUE; 
}
if (($emailvalidation==TRUE) && ($namevalidation==TRUE) && ($audiotypevalidation==TRUE) && ($captchavalidation==TRUE)) { //All validation succeeded, redirect user to confirmation page and start downloading $redirect = "http://www.example.org/phpdownloadsystem/confirmationpage.php"; //Assigned variables to session $_SESSION['name'] = $name;
$_SESSION['email'] = $email;
$_SESSION['audiotype'] = $audiotype; //redirect to confirmation page for downloading header(sprintf("Location: %s", $redirect)); 
exit;
}
}
?>
<!DOCTYPE HTML>
<html>
<head>
<title>PHP Download System Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
.invalid {
border: 1px solid #000000;
background: #FF00FF;
}
</style>
</head>
<body >
<h2>PHP Download Script Demo</h2>
<br />
Please enter your name and email address to download the music. Select either WAV or MP3 version.
<br /><br />
<form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">
<input type="hidden" name="formchecker" value="submittedform">
Name:  <input type="text" class="<?php if ($namevalidation==FALSE) echo "invalid"; ?>" id="name" name="name"><?php if ($namevalidation==FALSE) echo '<font color="red">Please enter valid name</font>'; ?><br /><br />
Email: <input name="email" type="text" class="<?php if ($emailvalidation==FALSE) echo "invalid"; ?>" id="email" ><?php if ($emailvalidation==FALSE) echo '<font color="red">Please enter valid email</font>'; ?><br /><br />
Audio file type:<br /><br />
<select class="<?php if ($audiotypevalidation==FALSE) echo "invalid"; ?>" name="audiotype">
<option value=""></option>
<option value="wav">WAV Audio File</option>
<option value="mp3">MP3 Audio File</option>
</select><?php if ($audiotypevalidation==FALSE) echo '<font color="red">Please enter valid audiotype</font>'; ?>
<br /><br />
Type the captcha below:
<br /> <br />
<?php
require_once('recaptchalib.php');
$publickey = "Your_recaptcha_public_key";
echo recaptcha_get_html($publickey);
?>
<?php if ($captchavalidation==FALSE) echo '<font color="red">Please enter correct captcha</font>'; ?>
<br /><br />
<input type="submit" value="Download">                  
</form>
</body>
</html>//Not a valid audiotype $audiotypevalidation=FALSE;} else {$audiotypevalidation=TRUE; } //Validate recaptcha require_once('recaptchalib.php');$privatekey = "Your_recaptcha_private_key_here";$resp = recaptcha_check_answer ($privatekey, $_SERVER["REMOTE_ADDR"], POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); if (!$resp->is_valid) { //captcha validation fails $captchavalidation=FALSE;} else {$captchavalidation=TRUE; }if (($emailvalidation==TRUE) && ($namevalidation==TRUE) && ($audiotypevalidation==TRUE) && ($captchavalidation==TRUE)) { //All validation succeeded, redirect user to confirmation page and start downloading $redirect = ""; //Assigned variables to session $_SESSION['name'] = $name;$_SESSION['email'] = $email;$_SESSION['audiotype'] = $audiotype; //redirect to confirmation page for downloading header(sprintf("Location: %s", $redirect)); exit;}}?><!DOCTYPE HTML><html><head><title>PHP Download System Demo</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><style type="text/css">.invalid {border: 1px solid #000000;background: #FF00FF;}</style></head><body ><h2>PHP Download Script Demo</h2><br />Please enter your name and email address to download the music. Select either WAV or MP3 version.<br /><br /><form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post"><input type="hidden" name="formchecker" value="submittedform">Name:  <input type="text" class="<?php if ($namevalidation==FALSE) echo "invalid"; ?>" id="name" name="name"><?php if ($namevalidation==FALSE) echo '<font color="red">Please enter valid name</font>'; ?><br /><br />Email: <input name="email" type="text" class="<?php if ($emailvalidation==FALSE) echo "invalid"; ?>" id="email" ><?php if ($emailvalidation==FALSE) echo '<font color="red">Please enter valid email</font>'; ?><br /><br />Audio file type:<br /><br /><select class="<?php if ($audiotypevalidation==FALSE) echo "invalid"; ?>" name="audiotype"><option value=""></option><option value="wav">WAV Audio File</option><option value="mp3">MP3 Audio File</option></select><?php if ($audiotypevalidation==FALSE) echo '<font color="red">Please enter valid audiotype</font>'; ?><br /><br />Type the captcha below:<br /> <br /><?phprequire_once('recaptchalib.php');$publickey = "Your_recaptcha_public_key";echo recaptcha_get_html($publickey);?><?php if ($captchavalidation==FALSE) echo '<font color="red">Please enter correct captcha</font>'; ?><br /><br /><input type="submit" value="Download">                   </form></body></html>

Confirmationpage.php (Download page)

<?php //Start PHP Session session_start(); //Define the PHP download script $downloadscript = "http://www.example.org/phpdownloadsystem/downloadfile.php"; // Get the URL of the page
// Javascript delay redirect does not pass referer value using PHP so this is the //alternative. function page_url(){
$url_page   = 'http';     if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){
$url_page .= 's';
}
return $url_page.'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
} //save referring page URL to sessions $_SESSION['referrer']   = page_url();
?>
<!DOCTYPE HTML>
<html>
<head>
<title>Thank you for Downloading</title>
<script type="text/javascript">
<!--
function wait(){
window.location = "<?php echo $downloadscript; ?>"
}
//-->
</script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body onLoad="setTimeout('wait()', 3000)">
Thank you for downloading.<br />
Your downloading starts in 3 seconds...<br />
If it does not download, make sure you have JavaScript enabled<br />
<a href="http://www.example.org/phpdownloadsystem/">Go back to the Form</a>
</body>
</html>

Downloadfile.php (The streaming script)

<?php//Start PHP Session session_start(); //Prevent early PHP script timeout which can interrupt downloading of big files. set_time_limit(0); //Set memory limit to allow substantial memory for this script ini_set("memory_limit","512M"); //Set maximum time to high to prevent an early timeout of large file downloading ini_set("max_input_time","20000"); //Set high execution time to prevent an early timeout that can disrupt ongoing script //execution. ini_set("max_execution_time","20000"); //Retrieve the referring page. $referer = $_SESSION['referrer']; //Retrieve the key passed from the originating page (form page) to authenticate //downloading.
//If the key does not match, then most likely it is an illegal download that bypass //web forms. $keymatch = $_SESSION['key']; //Retrieved user variables passed in a PHP session from the originating web form. $name = $_SESSION['name'];
$email = $_SESSION['email'];
$audiotype = $_SESSION['audiotype']; //Define correct pass key $pass='This is your key'; //MD5 the passkey $md5value= md5($pass); //Assigned appropriate filename and content type based on audiotype if ($audiotype=="wav") {
$filename="test.wav";
$contenttype="Content-type: audio/x-wav";
}
if ($audiotype=="mp3") {
$filename="test.mp3";
$contenttype="Content-type: audio/mpeg";
} //Define the download path,do not use http:// path but rather the absolute $downloadpath = "/home/replacewithyourpath/public_html/testsound/".$filename;
$confirmationpage = "http://www.example.org/phpdownloadsystem/confirmationpage.php";
$origin = "http://www.example.org/phpdownloadsystem/"; //Validate user by checking if the user has correct session set and referring page if (($referer==$confirmationpage)&& ($keymatch==$md5value)) //downloading is authorized { //MySQL connection parameters $username = "Your_MySQL_username";
$password = "Your_MySQL_password";
$hostname = "Your_MySQL_hostname";
$database = "Your_MySQL_database";
$dbhandle = mysql_connect($hostname, $username, $password)
or die("Unable to connect to MySQL");
$selected = mysql_select_db($database,$dbhandle)
or die("Could not select $database"); //Get the IP address of the user  $useripaddress= $_SERVER['REMOTE_ADDR'];
$useripaddress = mysql_real_escape_string($useripaddress); //Check if the user already downloaded before if (!($fetch = mysql_fetch_array( mysql_query("SELECT `ipaddress` FROM `filedownload` WHERE `ipaddress`='$useripaddress'"))))
{ //user has no downloading records, stream file for downloading header("$contenttype");
header("Content-disposition: attachment; filename=$filename");
$streamfordownload = file_get_contents($downloadpath);
echo $streamfordownload; //Assign as first download $firstdownload=1; //Sanitize before inserting to database $email = mysql_real_escape_string($email);
$name = mysql_real_escape_string($name);
$audiotype = mysql_real_escape_string($audiotype);
$firstdownload=intval($firstdownload);
mysql_query("INSERT INTO `filedownload` (`email`, `name`, `audiotype`, `ipaddress`, `downloadtimes`) VALUES ('$email', '$name', '$audiotype', '$useripaddress','$firstdownload')") or die(mysql_error());  //Send email to the website owner about the downloading $message =
"User Name: $namen" .
"User Email: $emailn" .
"Audiotype: $audiotype";
mail("youremail@example.org", "Download Notification", $message, "From: Example.orgn" );
exit();
}
else
{ //The user has some downloading records based on IP address. $result = mysql_query("SELECT `downloadtimes` FROM `filedownload` WHERE `ipaddress`='$useripaddress'")
or die(mysql_error());
$row = mysql_fetch_array($result)
or die("Invalid query: " . mysql_error());
$downloadtimes = $row['downloadtimes'];
if ($downloadtimes < 3) //still valid  {
header("$contenttype");
header("Content-disposition: attachment; filename=$filename");
$streamfordownload = file_get_contents($downloadpath);
echo $streamfordownload;
$updateddownloadtime = $downloadtimes + 1;
mysql_query("UPDATE `filedownload` SET `downloadtimes` = '$updateddownloadtime' WHERE `ipaddress` = '$useripaddress'")
or die(mysql_error()); //Send email to the website owner about the downloading $message =
"User Name: $namen" .
"User Email: $emailn" .
"Audiotype: $audiotype";
mail("youremail@example.org", "Download Notification", $message, "From: Example.orgn" );
exit();
}
else
{ //exceeded download limit, redirect back to download page session_destroy();
echo "<meta http-equiv='refresh' content='0;url=$origin'>";
}
} //Close the MySQL database connections mysql_close($dbhandle);
}
else
{ //This downloading is not authorized. 
//Destroy any session. session_destroy(); //Redirect the user back to the form echo "<meta http-equiv='refresh' content='0;url=$origin'>";
}
?>//Send email to the website owner about the downloading $message ="User Name: $namen" ."User Email: $emailn" . "Audiotype: $audiotype";mail("", "Download Notification", $message, "From: Example.orgn" );exit();}else { //The user has some downloading records based on IP address. $result = mysql_query("SELECT `downloadtimes` FROM `filedownload` WHERE `ipaddress`='$useripaddress'")or die(mysql_error());$row = mysql_fetch_array($result)or die("Invalid query: " . mysql_error());$downloadtimes = $row['downloadtimes'];if ($downloadtimes < 3) //still valid {header("$contenttype");header("Content-disposition: attachment; filename=$filename");$streamfordownload = file_get_contents($downloadpath);echo $streamfordownload;$updateddownloadtime = $downloadtimes + 1;mysql_query("UPDATE `filedownload` SET `downloadtimes` = '$updateddownloadtime' WHERE `ipaddress` = '$useripaddress'")or die(mysql_error()); //Send email to the website owner about the downloading $message ="User Name: $namen" ."User Email: $emailn" . "Audiotype: $audiotype";mail("", "Download Notification", $message, "From: Example.orgn" );exit();}else { //exceeded download limit, redirect back to download page session_destroy();echo "<meta http-equiv='refresh' content='0;url=$origin'>";}} //Close the MySQL database connections mysql_close($dbhandle);}else { //This downloading is not authorized. //Destroy any session. session_destroy(); //Redirect the user back to the form echo "<meta http-equiv='refresh' content='0;url=$origin'>";}?>//Send email to the website owner about the downloading $message ="User Name: $namen" ."User Email: $emailn" . "Audiotype: $audiotype";mail("", "Download Notification", $message, "From: Example.orgn" );exit();}else { //The user has some downloading records based on IP address. $result = mysql_query("SELECT `downloadtimes` FROM `filedownload` WHERE `ipaddress`='$useripaddress'")or die(mysql_error());$row = mysql_fetch_array($result)or die("Invalid query: " . mysql_error());$downloadtimes = $row['downloadtimes'];if ($downloadtimes < 3) //still valid {header("$contenttype");header("Content-disposition: attachment; filename=$filename");$streamfordownload = file_get_contents($downloadpath);echo $streamfordownload;$updateddownloadtime = $downloadtimes + 1;mysql_query("UPDATE `filedownload` SET `downloadtimes` = '$updateddownloadtime' WHERE `ipaddress` = '$useripaddress'")or die(mysql_error()); //Send email to the website owner about the downloading $message ="User Name: $namen" ."User Email: $emailn" . "Audiotype: $audiotype";mail("", "Download Notification", $message, "From: Example.orgn" );exit();}else { //exceeded download limit, redirect back to download page session_destroy();echo "<meta http-equiv='refresh' content='0;url=$origin'>";}} //Close the MySQL database connections mysql_close($dbhandle);}else { //This downloading is not authorized. //Destroy any session. session_destroy(); //Redirect the user back to the form echo "<meta http-equiv='refresh' content='0;url=$origin'>";}?>  

{mospagebreak title=Implementing PHP Download Optimization Script}

Implementation Steps

If you would like to run the project like what is shown in this demo page: http://www.php-developer.org/phpdownloadsystem :

1.) Download the script here and extract: http://www.php-developer.org/wp-content/uploads/scripts/phpdownloadsystem.zip

2.) Download testsound.zip here and extract: http://bit.ly/oWzsmL
3.) Upload testsound folder to the root directory of your website. Files are not publicly accessible since it is protected with “Deny from all” .htaccess.
4.) Create a MySQL database table like what is shown here: http://www.php-developer.org/screenshot/phpmyadminscreenshottable.jpg , using phpMyAdmin. Name the table: filedownload
5.) Open index.php and do the following changes:

a.) Change $key to something unique.
b.) Assign your own private and public key for recaptcha
c.) Change “example.org” domain in $redirect variable to your own domain
d.) Save index.php with the above changes.

6.) Open confirmationpage.php and do the following changes:

a.) Change “example.org” domain in $downloadscript variable to your own domain
b.)  Change “example.org” domain in the hyperlink value at the bottom of the code.
c.) Save confirmationpage.php with the changes.

7.) Open downloadfile.php and do the following changes:

a.)  Change $pass to be the same value with $key in index.php.
b.)  Change the value of $downloadpath with the absolute path to the testsound folder (with respect to your root).
c.)  For $confirmationpage and $origin variable, change the domain from example.org to your own domain name.
d.) Assign correct MySQL database credentials ($username, $password, etc)
e.) In the mail, change youremail@example.org to your actual email address. Change also the “From”.
f.) Save downloadfile.php

8.) Upload phpdownloadsystem with the edited scripts to your website root directory. The phpdownloadsystem folder should contain all the 5 PHP script files on it.

9.) Execute in the browser and test, just like in this page: http://www.php-developer.org/phpdownloadsystem.

You can test the demo and see how it works. You can use this project in any content types as long as the server is Apache and using PHP 5 and MySQL 5 in Linux/Unix OS.

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye