Return to TechKnowMe.com

Warning: Geekiness Ahead

Rob Zazueta is the founder, project manager and lead programmer at TechKnowMe, which designs, develops, markets and maintains web sites for small businesses. Within these pages you'll find code samples, techno-rants and other things that cause the average non-programmer's eyes to glaze. Small business owners looking for ways to improve their reach online may find Rob's blog at the Small Business Community more enjoyable.

Follow Rob Z. on Twitter

Subscribe

Tracking and Protecting Web-Based Downloads (In PHP)

There’s a consistent need to either protect a file from being downloaded unless a user has been properly authorized/authenticated to access it or to track those files using a JavaScript tracking system like Google Analytics. I ran into this issue a few years ago and came up with what I thought was an elegant solution given the parameters – access those files using a PHP page.

The idea is simple: Send the filename as part of a request to a specified php page (in this case, download.php). That page will perform whatever authorization/authentication checks are necessary, ensure the file exists and – if everything passes muster – immediately begin sending the file to the user’s browser. You can use Google Analytics to track these downloads as well either by using the PHP CURL library or creating a redirect page.

Here’s some generic code to show this in action. Please Note: this code is an edited version from a full set of code. I’ve tried to make this standalone, but I haven’t actually tested it. You’ll want to fill in the blanks and give this a shot yourself – this is not a simple drop-and-go solution.

<?php
	//If you need to confirm that this user is logged in, etc.
	//you should handle the authentication/authorization stuff
	//here

	//Set this to wherever you will be storing the actual files
	define('DOWNLOAD_PATH', '/home/username/protected_files');

	//Format of URL: http://www.mysite.com/download.php?f=
	$filename = $_REQUEST["f"];
	$filePath = DOWNLOAD_PATH."/".$filename;

	//Handle this error however you want.
	if(file_exists($filePath)) {
		trigger_error("Could not find file: ".$filePath, E_USER_ERROR);
		exit();
	}

	$pathParts = pathinfo($filePath);

	header("Server: Apache/PHP", true);
	header("Cache-Control: no-store, no-cache, must-revalidate", true);
	header("Keep Alive: timeout=15; max=89", true);
	header("Connection: Keep-Alive", true);
	//NOTE: mime_type is a custom function - see below
	header("Content-Type: ".mime_type($filePath), true);
	header("Content-Disposition: attachment; filename=\"".$pathParts["basename"]."\"", true);

	//readfile() outputs the given file directly to the buffer which, in this case, goes to the browser.
	if(!@readfile($filePath)) {
		//Handle this error however you want
		trigger_error("Failed to open and read file ".$filePath, E_USER_ERROR);
		exit();
	}

	/**
	 Determines the MIME type of the given file. Requires a valid mime types file.

	 @param $file The file name/filepath fo the file being checked.
	 @returns string a mime-type string for a content header based on the file extension if found, otherwise returns false.
	*/
.
	function mime_type($file) {
		//Replace with the location of your mime.type file (I got mine from Apache)
		$mimeFile = "./mime.type";
		$mimeFound = false;
		$mime = -1;
		$fileInfo = pathinfo($file);
		if(is_file($mimeFile)) {
			if($fp = fopen($mimeFile, 'r')) {
				while ((!feof($fp)) && !$mimeFound) {
					$string = fgets($fp, 4096);
					$tempArray = preg_split("/\s+/", $string);
					//Eliminate comment lines
					if(!(strstr($tempArray[0], '#') == 1)) {
						for ($n = 1; $n < sizeof($tempArray); $n++) {
							if(strtolower($tempArray[$n]) == strtolower($fileInfo["extension"])) {
								//Found the mime type!
								$mime = $tempArray[0];
								$mimeFound = true;
								break;
							}
						}
					}
				}
				fclose($fp);
			} else {
				trigger_error("Cannot open ".$mimeFile, E_USER_WARNING);
			}
		} else {
			trigger_error("Cannot find ".$mimeFile, E_USER_WARNING);
		}
		return $mime;
	}

?>

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>