One Time Temporary Download Link with Expiration in PHP

Temporary download link is very useful to sell digital goods on the website. It provides a secure way to share the download link of the digital products. The user allows downloading the file only one time, after the download the link is expired or removed. The one-time download link is ideal to give a digital product (code, music, video, etc) to a single person and expire the link once the product is downloaded.

With the single-use download link, you don’t need to manually monitor the download activity in order to change the download link. Instead, the download link will be expired immediately after the first download. In this tutorial, we will show you how to generate one-time download link in PHP and implement the temporary download URL functionality on the web application using PHP.

The example code allows you to generate a unique link to download the file from the server. This link will allow the user to download one time. Also, the link will have an expiration time and it will be expired after the specified expiry date.

For example, you want to sell an eBook on your website. The eBook is sold on your website for $5, you could use our script to allow that user to download the respective eBook only one-time. The download link will give them a limited number of seconds/minutes/hours/days/week/years to claim their download.

The following process will be followed to implement the temporary download link functionality in PHP.

  • Generate a download link with a unique key.
  • Create a protected directory to store keys.
  • Create a file and write a unique key to it.
  • On download request, token key and expiration time is validated.
  • Force the browser to download the file.

Configurations (config.php)

The configuration variables are defined in this file.

  • $files – An array of the files with the unique ID.
    • You can specify the different name of the file being downloaded. It helps to protect the original file.
    • You can specify the local or remote file path.
  • BASE_URL – Define the URL of the application.
  • DOWNLOAD_PATH – Define the path of the file downloading script.
  • TOKEN_DIR – Set the token directory path where the keys will be stored.
  • OAUTH_PASSWORD – Set the authentication password to generate a download link.
  • EXPIRATION_TIME – Set a time when the file will expire.
<?php
// Array of the files with an unique ID
$files = array(
    
'UID12345' => array(
        
'content_type' => 'application/zip'
        
'suggested_name' => 'codex-file.zip'
        
'file_path' => 'files/test.zip',
        
'type' => 'local_file'
    
),
    
'UID67890' => array(
        
'content_type' => 'audio/mpeg'
        
'suggested_name' => 'music-codex.mp3'
        
'file_path' => 'https://www.dropbox.com/XXXXXXX/song.mp3?dl=1',
        
'type' => 'remote_file'
    
),
);

// Base URL of the application
define('BASE_URL','http://'$_SERVER['HTTP_HOST'].'/');

// Path of the download.php file
define('DOWNLOAD_PATH'BASE_URL.'download.php');

// Path of the token directory to store keys
define('TOKEN_DIR''tokens');

// Authentication password to generate download links
define('OAUTH_PASSWORD','CODEXWORLD');

// Expiration time of the link (examples: +1 year, +1 month, +5 days, +10 hours)
define('EXPIRATION_TIME''+5 minutes');

index.php

In this file, a link will be displayed to navigate to the download link creation file. The authentication password needs to be specified in the query string of the link.

<a href="generate.php?CODEXWORLD">Generate download link</a>

Create Temporary Download Link (generate.php)

This file creates a temporary download link and lists the links on the web page. The query string must have the authentication password and need to be matched with the specified in the config.php file, otherwise, 404 error is rendered.

  • Get the authentication password from the query string.
  • Validate the authentication password.
  • Encode the file ID with base64_encode() in PHP.
  • Generate a new unique key with a timestamp using uniqid() in PHP.
  • Generate download link with file ID and key.
  • Create a protected directory to store keys.
  • Write the key in a file and put it in the token directory.
  • List all the download links in the web page.
<?php
// Include the configuration file
require_once 'config.php';
    
// Grab the password from the query string
$oauthPass trim($_SERVER['QUERY_STRING']);

// Verify the oauth password
if($oauthPass != OAUTH_PASSWORD){
    
// Return 404 error, if not a correct path
    
header("HTTP/1.0 404 Not Found");
    exit;
}else{    
    
// Create a list of links to display the download files
    
$download_links = array();
    
    
// If the files exist
    
if(is_array($files)){
        foreach(
$files as $fid => $file){
            
// Encode the file ID
            
$fid base64_encode($fid);
            
            
// Generate new unique key
            
$key uniqid(time().'-key',TRUE);
            
            
// Generate download link
            
$download_link DOWNLOAD_PATH."?fid=$fid&key=".$key
            
            
// Add download link to the list
            
$download_links[] = array(
                
'link' => $download_link
            
);
            
            
// Create a protected directory to store keys
            
if(!is_dir(TOKEN_DIR)) {
                
mkdir(TOKEN_DIR);
                
$file fopen(TOKEN_DIR.'/.htaccess','w');
                
fwrite($file,"Order allow,deny\nDeny from all");
                
fclose($file);
            }
            
            
// Write the key to the keys list
            
$file fopen(TOKEN_DIR.'/keys','a');
            
fwrite($file"{$key}\n");
            
fclose($file);
        }
    }
}    
?> <!-- List all the download links --> <?php if(!empty($download_links)){ ?>
    <ul>
    <?php foreach($download_links as $download){ ?>            
        <li><a href="<?php echo $download['link']; ?>"><?php echo  $download['link']; ?></a></li>
    <?php ?>
    </ul>
<?php }else{ ?>
    <p>Links are not found...</p>
<?php ?>

Download File by Temporary Link (download.php)

This file downloads the file by the temporary download link.

  • Get the file ID & key from the query string of the URL.
  • Get the time from the key and calculate link expiration time.
  • Retrieve the keys from the tokens file.
  • Loop through the keys to find a match, when the match is found, remove it.
  • Put the remaining keys back into the tokens file.
  • If match found and the link is not expired, force the browser to download the file.
<?php
// Include the configuration file
require_once 'config.php';

// Get the file ID & key from the URL
$fid base64_decode(trim($_GET['fid']));
$key trim($_GET['key']);

// Calculate link expiration time
$currentTime time();
$keyTime explode('-',$key);
$expTime strtotime(EXPIRATION_TIME$keyTime[0]);

// Retrieve the keys from the tokens file
$keys file(TOKEN_DIR.'/keys');
$match false;

// Loop through the keys to find a match
// When the match is found, remove it
foreach($keys as &$one){
    if(
rtrim($one)==$key){
        
$match true;
        
$one '';
    }
}

// Put the remaining keys back into the tokens file
file_put_contents(TOKEN_DIR.'/keys',$keys);

// If match found and the link is not expired
if($match !== false && $currentTime <= $expTime){
    
// If the file is found in the file's array
    
if(!empty($files[$fid])){
        
// Get the file data
        
$contentType $files[$fid]['content_type'];
        
$fileName $files[$fid]['suggested_name'];
        
$filePath $files[$fid]['file_path'];
        
        
// Force the browser to download the file
        
if($files[$fid]['type'] == 'remote_file'){
            
$file fopen($filePath'r');
            
header("Content-Type:text/plain");
            
header("Content-Disposition: attachment; filename=\"{$fileName}\"");
            
fpassthru($file);
        }else{
            
header("Content-Description: File Transfer");
            
header("Content-type: {$contentType}");
            
header("Content-Disposition: attachment; filename=\"{$fileName}\"");
            
header("Content-Length: " filesize($filePath));
            
header('Pragma: public');
            
header("Expires: 0");
            
readfile($filePath);
        }
        exit;
    }else{
        
$response 'Download link is not valid.';
    }
}else{
    
// If the file has been downloaded already or time expired
    
$response 'Download link is expired.';
}
?> <html> <head> <title><?php echo $response?></title> </head> <body> <h1><?php echo $response?></h1> </body> </html>

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

5 Comments

  1. MKDan Said...
  2. JAMES C REINSCH Said...
  3. Saravana Said...
  4. Aaron Said...
  5. Daryl Snowden Said...

Leave a reply

keyboard_double_arrow_up