Ever wonder how to create a download link in #PHP and then make it expire? Would you like to know how to expire a download link after a set number of times they download it? Do you want to know how to protect your files from people trying to steal your downloads? We are going to answer those questions and more on this tutorial.
Setting Up The Database For Expired Links
Set up your database first. Create a database and then use the following code to set up the table and rows. Let me tell you what each row is going to do. The link row is going to save an encrypted link you will use for your application. This will appear in the URL address bar. The file is going to be the name of the file you are uploading for a user to download. You can keep track of how many times you allow a file to be downloaded by using the counting row. The expire row is going to keep track of the time you set for the link to expire. The tstamp row is going to keep track of the time that you uploaded the file.CREATE TABLE `links` ( `id` int(11) NOT NULL, `link` char(40) NOT NULL, `file` text NOT NULL, `counting` int(11) NOT NULL DEFAULT 11, `expire` int(11) NOT NULL, `tstamp` int(10) UNSIGNED NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;;
For Future Projects
Keep in mind this tutorial is showing you how to do something like this. In the future, you can build on this further to create purchases or user activations on a website or app.File To Create Expired Download Link
Here are the complete files to create expired download links in PHP. Now let's talk about the files so you understand what they do.Index File To Start Process
The index.php file is there to start the process. You can name it anything you want. It looks like this when you open it to your editor. See the video for detailed explanations.<?php include('header.php'); if(isset($_POST['submit'])){ $errors= array(); $file_name = $_FILES['file']['name']; $file_size =$_FILES['file']['size']; $file_tmp =$_FILES['file']['tmp_name']; $file_type=$_FILES['file']['type']; $fileend=explode('.',$file_name); $file_ext=strtolower(end($fileend)); $extensions= array("jpeg","jpg","png","pdf", "zip"); if(in_array($file_ext,$extensions)=== false){ $errors[]="extension not allowed, please choose a JPEG, PNG, ZIP or PDF file."; } if($file_size > 2097152){ $errors[]='File size must be under 2 MB'; } if(empty($errors)==true){ move_uploaded_file($file_tmp,"files/".$file_name); //echo "Success"; }else{ print_r($errors); } $expire=$_POST['date']; $counting=$_POST['counting']; $date = date('M d, Y h:i:s A', strtotime($expire)); $dbdate = date('Y M d H:i:s', strtotime($expire)); $one= 'To Expire on '.$date.'<br/>'; $d = DateTime::createFromFormat( 'Y M d H:i:s', $dbdate, new DateTimeZone('EST') ); if ($d === false) { die("Incorrect date string"); } else { $expiredate=$d->getTimestamp(); } $link = sha1(uniqid($file_name, true)); $tstamp=$_SERVER["REQUEST_TIME"]; mysqli_query($db,"INSERT INTO links(`link`,`file`, `counting`, `expire`, `tstamp`) VALUES ('$link', '$file_name', '$counting','$expiredate','$tstamp')"); $two= '<a href="download.php?link='.$link.' " target="_NEW">Link</a>'; } ?> <div class="container"> <div class="jumbotron"><p class="text-xl-center"><?php if(isset($one)){echo $one.$two;};?></p></div> <h1 class="animated bounce"><span class="glyphicon glyphicon-link"></span>Generate A Link That Expires</h1> <div class="row"> <div class="col-sm-4"></div> <div class="col-sm-4"> <form method="post" role="form" enctype="multipart/form-data"> <div class="form-group"> <label for="file">Select File:</label> <input type="file" class="form-control" name="file" required> </div> <div class="form-group"> <label for="counting">How Many Times Can Link Be Accessed?:</label> <input type="tel" class="form-control" name="counting" required> </div> <div class="form-group"> <label for="date">Set Expiration Date and Time For Link:</label> <input type="datetime-local" class="form-control" name="date" required> </div> <input type="submit" name="submit" class="btn btn-success btn-lg" value="submit" /> </form> </div> <div class="col-sm-4"></div> </div> </div> <?php include('footer.php'); ?>Now lets go to the download file on the next page.
The Download File
Here is the download.php file, this file is the one that actually keeps tracks of the expired links, times the files is downloaded and provides the download if they meet all conditions. It also contains comments if you were to add future users, keep track of purchases and more.
<?php include('header.php'); ?> <div class="container"> <div class="jumbotron"><p class="text-xl-center"> <?php // retrieve link if (isset($_GET["link"]) && preg_match('/^[0-9A-F]{40}$/i', $_GET["link"])) { $link = $_GET["link"]; }else{ echo "<h1>Valid link not provided.</h1>"; exit(); } //starting verification with the $ct variable $ct=0; $currenttime= $_SERVER["REQUEST_TIME"]; $currentdate = date('M d, Y h:i:s A', $currenttime); echo 'Current Date '.$currentdate.'<br/>'; // verify link get necessary information we will need to preocess request $result = $db->query("SELECT * FROM links WHERE link='$link' ") ; while ($row = $result->fetch_assoc()) { $linkdb = $row['link']; $filedownload = $row['file']; $tstamp = $row['tstamp']; $expire = $row['expire']; $counting = $row['counting']; $newcount=$counting-1;</pre> //convert timestamp to readable date the show expiration date and time $date = date('M d, Y h:i:s A', $expire); echo 'To Expire on '.$date.'<br/>'; // Check to see if link has expired if ($currenttime > $expire) { echo "We are so sorry the link has expired."; exit(); // delete link so it can't be used again mysqli_query($db,"DELETE FROM links WHERE link='$link' "); exit(); } if ($linkdb==$link) { echo 'You have '.$newcount.' more times to access this link.'; mysqli_query($db,"UPDATE links SET counting='$newcount' WHERE link='$linkdb' "); $ct=1; } else { echo "Valid link not provided or link has expired."; exit(); } } // delete link so it can't be used again mysqli_query($db,"DELETE FROM links WHERE link='$link' AND counting < '1' "); //FILE DOWNLOAD //path to file if($ct==1){ $path = ''; $path = "files/$filedownload"; echo $path; $mime_type=mime_content_type($path); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$path.'"'); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header('Content-Length: ' . filesize($path)); //Absolute URL ob_clean(); flush(); readfile($path); //Absolute URL exit(); }else{ echo '<p>This file has already been dowloaded the maximum number of times.</p>'; } ?> </p> </div> <?php include_once('footer.php'); ?>
Header, Footer and Config Files
Here is the header, footer and config.php files to properly include scripts we need.header.php
<?php date_default_timezone_set('America/New_York'); include('config.php'); ?> <html> <head> <title>Create A Link That Expires</title> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css" > <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css"> <link href="style.css" rel="stylesheet" type="text/css" > </head> <body>
footer.php
</body> </html> <?php $db->close(); ?>
config.php
<?php $db = mysqli_connect("localhost","root","","test"); if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); }else{ echo ""; } ?>
Protect Your Files Folder
An important note is that you want to protect your files folder so that people cannot sneakily find out where you store your downloads, then just come and download all your files for free. You do this by including a htaccess file in the folder. I include it with the download files above. Here is what it looks like.Deny From All