Home arrow PHP arrow Page 2 - Generating One-Time URLs with PHP
PHP

Generating One-Time URLs with PHP


Daniel explains in this article that there is a way of generating a unique URL that can be used to market a digital product.

Author Info:
By: Daniel Solin
Rating: 5 stars5 stars5 stars5 stars5 stars / 8
March 20, 2003
TABLE OF CONTENTS:
  1. · Generating One-Time URLs with PHP
  2. · The Article
  3. · Summary

print this article
SEARCH DEVARTICLES

Generating One-Time URLs with PHP - The Article
(Page 2 of 3 )

Creating the URL

The script generate_url.php will generate our URLs. It uses PHP's md5() and uniqid() functions to create a unique, long and complicated token which will act as the key to the file to protect. Tokens are 32 random characters long, so to figure this out by mental arithmetic would be impossible. The listing below shows you the implementation of generate_url.php.

<?
/*
* generate_url.php
*
* Script for generating URLs that can be accessed one single time.
*
*/
/* Generate a unique token: */
$token = md5(uniqid(rand(),1));
/* This file is used for storing tokens. One token per line. */
$file = "/tmp/urls.txt";
if( !($fd = fopen($file,"a")) )
        die("Could not open $file!");
if( !(flock($fd,LOCK_EX)) )
        die("Could not aquire exclusive lock on $file!");
if( !(fwrite($fd,$token."\n")) )
        die("Could not write to $file!");
if( !(flock($fd,LOCK_UN)) )
        die("Could not release lock on $file!");
if( !(fclose($fd)) )
        die("Could not close file pointer for $file!");
/* Parse out the current working directory for this script. */
$cwd = substr($_SERVER['PHP_SELF'],0,strrpos($_SERVER['PHP_SELF'],"/"));
/* Report the one-time URL to the user: */
print "Use this URL to download the secret file:<br><br>\n";
print "<a href='http://".$_SERVER['HTTP_HOST'].
      "$cwd/get_file.php?q=$token'>\n";
print "
http://".$_SERVER['HTTP_HOST']."/get_file.php?q=$token</a>\n
";
?>

In short terms, md5() calculates a 32-character long hexadecimal number by using the RSA Data Security, Inc. MD5 Message-Digest Algorithm out of the unique string generated by uniqid(). Note that we also feed uniqid() with a random value.

You see, uniqid() generates a unique id based on the current time in microseconds. Although small, there's always a possibility that the script is executed two or more times simultaneously, which could result in the same id being generated more than once.

By feeding uniqid() with a random value generated by rand(), we push the risk of not getting a really unique id closer to zero. Or, as stated in the PHP reference documentation, this generates a token "that is extremely difficult to predict".

If you need more documentation on md5() and uniqid(), please consult the PHP reference documentation at http://www.php.net/manual/en/function.md5.php and http://www.php.net/manual/en/function.uniqid.php .

After generating the unique id, we open the file /tmp/urls.txt for writing. This file is used to store the unique tokens, one per line. When writing to this file, it's very important the we do real file-locking to prevent two processes writing the file at the same time. We do this by using PHP's flock() function. See http://www.php.net/manual/en/function.flock.php for more information about file-locking with PHP.

Finally, on the last three lines, the newly generated URL is presented to the client. It should show something like Figure 1.

Figure 1 -- A new and unique id is generated.

Sending Out the Secret File

As you saw in the previous section, there's reference to a file called get_file.php. This script takes care of the verification of a generated token, and, if the token is valid, sends out the secret file to the user. This file also deletes a token from /tmp/urls.txt after it has been used. See the listing below.

<?
/*
* get_file.php
*
* Script for validating a request through a secret token, passing a file
* to the user, and ensuring the token can not be used again.
*
*/
/* Retrive the given token: */
$token = $_GET['q'];
if( strlen($token)<32 )
{
        die("Invalid token!");
}
/* Define the secret file: */
$secretfile = "/tmp/secret_file.txt";
/* This variable is used to determine if the token is valid or not: */
$valid = 0;
/* Define what file holds the ids. */
$file = "/tmp/urls.txt";
/* Read the whole token-file into the variable $lines: */
$lines = file($file);
/* Truncate the token-file, and open it for writing: */
if( !($fd = fopen("/tmp/urls.txt","w")) )
        die("Could not open $file for writing!");
/* Aquire exclusive lock on $file. */
if( !(flock($fd,LOCK_EX)) )
        die("Could not equire exclusive lock on $file!");
/* Loop through all tokens in the token-file: */
for( $i = 0; $lines[$i]; $i++ )
{
        /* Is the current token the same as the one defined in $token? */
        if( $token == rtrim($lines[$i]) )
        {
                $valid = 1;
        }
        /* The code below will only get executed if $token does NOT match the
           current token in the token file. The result of this will be that
           a valid token will not be written to the token file, and will
           therefore only be valid once. */
        else
        {
                fwrite($fd,$lines[$i]);
        }
}
/* We're done writing to $file, so it's safe release the lock. */
if( !(flock($fd,LOCK_UN)) )
        die("Could not release lock on $file!");
/* Save and close the token file: */
if( !(fclose($fd)) )
        die("Could not close file pointer for $file!");
/* If there was a valid token in $token, output the secret file: */
if( $valid )
{
        readfile($secretfile);
}
else
{
        print "Invalid URL!";
}
?>

This script requires a token to be passed to it via the GET method. If a valid token is not provided, execution is terminated directly. This is a very important security issue. What would happen if an empty token was sent to the script and /tmp/urls.txt had an empty line on the end? Again, note the use of flock() to accomplish file-locking. This is, as in generate_url.php, an important feature for securing the file-handling.

Every line in urls.txt is then compared to the token that was sent to the script. If the token is actually present in urls.txt, the script marks the request as valid by setting $valid to 1. If the request is not valid, $valid will keep the value 0, and the secret file will not get passed to the user. Also note that all tokens that do not match the request are written to urls.txt again, but tokens that do match the request are skipped and, by that, removed from urls.txt .

Place get_file.php and generate_url.php on your Web server and click on the link shown in Figure 2. Depending on what is in your /tmp/secret_file.txt, you should now see something like Figure 2.

Figure 2 -- the super-secret contents of the super-secret file

As you see, get_file.php approved the request and presented us with the contents of /tmp/secret_file.txt. However, if you now try to reload the page, get_file.php will block the request. See Figure 3.

Figure 3 -- secret files without secret keys

Viola. Mission accomplished.


blog comments powered by Disqus
PHP ARTICLES

- Removing Singletons in PHP
- Singletons in PHP
- Implement Facebook Javascript SDK with PHP
- Making Usage Statistics in PHP
- Installing PHP under Windows: Further Config...
- File Version Management in PHP
- Statistical View of Data in a Clustered Bar ...
- Creating a Multi-File Upload Script in PHP
- Executing Microsoft SQL Server Stored Proced...
- Code 10x More Efficiently Using Data Access ...
- A Few Tips for Speeding Up PHP Code
- The Modular Web Page
- Quick E-Commerce with PHP and PayPal
- Regression Testing With JMeter
- Building an Iterator with PHP

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2014 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials