Track downloads with PHP?

Miscellaneous Forums/General Discussion/Track downloads with PHP?

Hi, is there a simple way to track downloads with PHP code? Basically when people make a download on my site I want to record it, perhaps with date/time too (big text file would be fine). Can anyone recommend some simple code to do this (or isn't it easy)? Thanks.

Also worth considering, is there a way to track *completed* downloads as well. Because it may be that 20% are aborted or something so actual complete downloads is lower than it appears. Cheerz.

Get them to register when they finish downloading the game, e.g. Ask them a couple of questions then when they click 'ok', get the app to send the info to you.

The questions in question doesnt have to mean anything, there name, where they heard about the product, and even if they enter a load of bull, it doesnt matter, you still found out that the whole thing is downloaded! :)

Dabz

Can anyone recommend some simple code to do this (or isn't it easy)? Thanks.


Te easiest way to track downloads is using whatever webstatistics package that most webhosts provide...

You can do it through PHP as well and store the results in a database of your own, but I don't have any readily available code to do so. Basically you can use a redirector link that forwards you to a page that has the code to log the info you want to a database, and also automatically initiates the download for you.

Ok, I can't post the entire thing, but here's a download script that I wrote for a project a few months ago.

<?php
require_once("resources/includes/init.php");

if (isset($_GET['id'])){
	if ($_GET['id'] != ""){
		$id = HZ_Taint($_GET['id']);
		$file = HZ_SelectFromTable("HZ_FileList", "WHERE file_id = '".$id."'");
		
		if (!PEAR::isError($file)){
			if (count($file) > 0){
				if (count($file) > 1){//if we have more than one file with exactly the same name (should never happen)
					header('Content-Type: text/plain');
					echo "Error, file naming conflict, please contact admin with this error message and the file name you requested (".$name.")";
					exit;
				} else {
					$file = $file[0];//reassign the first object in the returned array to $file since there is only one file
					//if it really is a regular file
					if (is_file($file->path)){
						//if the requested file's path is not outside the base directory we set in config
						if (substr(realpath($file->path), 0, strlen(BASE_FILE_UPLOAD_DIR)) == BASE_FILE_UPLOAD_DIR){
							$file_data = file_get_contents($file->path);
							$finfo = finfo_open(FILEINFO_MIME);
							$finfo_mime = finfo_file($finfo, $file->path);
							//the following headers ensure that the browser is forced to download the file, it should work on all major bowsers
							header('Pragma: public');
							header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
							header('Cache-Control: no-store, no-cache, must-revalidate');
							header('Cache-Control: pre-check=0, post-check=0, max-age=0');
							header('Content-Transfer-Encoding: none');
							//This should work for IE & Opera
							header('Content-Type: '.$file->type.'; name="'.basename($file->name).'"');
							//This should work for the rest
							header('Content-Type: '.$file->type.'; name="'.basename($file->name).'"');
							header('Content-Disposition: attachment; filename="'.basename($file->name).'"');
							echo $file_data;
							exit;
						} //if substr
					}//if is_file
				}//if count == 1
			}//if count > 0
		}//if !PEAR::isError
	}//if name != ""
}//if isset(name)

header("Content-Type: text/plain");
echo "The file you requested cannnot be found";
exit;
?>


It uses PEAR::DB, db initialization is in the init.php, HZ_SelectFromTable is a wrapper for table access (handles errors and some other things and returns an array, by default it uses DB_FETCHMODE_OBJECT), HZ_Taint is essentially a wrapper for mysql_real_escape_string (plus a few other checks).

It relies on the file info (NOT the file data) previously being inserted into the database with paths.

It wouldn't take much to add a bit of code to track downloads to it.

I use this

$product_name=array('product1,product2');
$os_version=array('Windows XP','Mac OS X');
$file_name=array('product1.exe','product2.zip');

function redirect($url, $seconds = FALSE)
{
    if (!headers_sent() && $seconds == FALSE)
    {
        header("Location: " . $url);
    }
    else
    {
        if ($seconds == FALSE)
        {
            $seconds = "0";
        }
        echo "<meta http-equiv="refresh" content="$seconds;url=$url">";
    }
}


include("header.php");
$product=$_GET['prod']-1;
$osversion=$_GET['os']-1;
include("basic.php");
$cnt="download_counter_".$product."_".$osversion.".txt";
$open=@fopen($cnt,'r+');
$counter=@fread($open,filesize($cnt));
@fclose($open);
$counter++;
$write=fopen($cnt,'w+');
fputs($write,$counter);
fclose($write);

echo $product_name[$product]." (".$os_version[$osversion].")";
	  $prodotto_download=$file_name[$product+$osversion];
redirect("download/".$prodotto_download,5);



In the main page put the link to your program like this:

download.php?prod=1&os=1

Of course prod=1 and os=1 are the indexes of the arrays (products, OsVersion, file name) your previously create.

Basically its intercept the link to a file and increments by one a .txt file (download_counter_0_0.txt), then redirect() the input to the original file...
Well it works, but for many products it's better use a MySql database.

The script I posted does not pass the actual URL of the file to the user, thereby preventing people from linking to it without going through your script.

You could probably incorporate degac's tracking code, but if you're using a database to hold file info, then using the DB for tracking would make sense as well.

Interesting thanks. Degac's code may be fine as any legit sites should use my link and not link Direct. I'll have to study Perturbatio's code (and Degac's) a bit more as I don't really understand PHP, but it can't be too hard right?

I know it makes sense to use a database but I don't have the time or skills to set that up right now so I'll just use a text file for now.

So no way to check for completed downloads then...

Little snippet that I use to keep track of total number of downloads as well as direct the user to the item of interest:

include "_private/database.inc";

$result = mysql_query("SELECT * FROM product_downloads WHERE name = '$product'");
$row = mysql_fetch_array($result);
if (strlen($row) != 0)
{
	$total = ++$row["downloads"];
	$result = mysql_query("UPDATE product_downloads SET downloads='$total' WHERE name = '$product'");
}
if ($result)
{
	$myfile = "http://webappstogo.com/".$pfile;
	header("Location: $myfile");
	exit;
}

$pfile is passed in (URL) and looks like this:
http://www.webappstogo.com/dlds.html?&product=3DXmas&pfile=3dxmas/3DXmasSetup.exe

Table structure:
   Field  		Type		Attributes	Null 	Default	Extra  
   id			int(11)   			No    		auto_increment              
   name  		varchar(40)   			No                  
   description  	varchar(40)   			No                  
   downloads  		int(11)   			No  	0                
   video  		int(11)   			No  	0                
   google_ad  		int(11)   			No  	0	                
   google_click 	int(11)   			No  	0                
   halloween_ad 	int(11)   			No  	0                
   app_online_click	int(11)   			No  	0                
   link  		text   				No                
   backup  		int(11)   			No  	0               

It's quick and simple and accomplishes my own tasks. However, it will not keep track of completion of downloads. I really don't need that data.

JoeRetro: Thanks, so this one needs MySQL, I do have it on my server. I just heard about tracking completed downloads on another forum and thought it sounded useful.

I just heard about tracking completed downloads on another forum and thought it sounded useful.


You couldn't point me in the direction of that thread could you? It would be handy to know about.

On the MySQL subject, it's pretty easy to pick up and difficult to master (especially with multiple joins). For most websites though you don't need to know more than a few things.

some books I can recommend for learning PHP/MySQL:
PHP Hacks
Essential PHP Security

Perturbatio: Thanks for the info. To be honest I've no trouble at all with SQL and joins etc as I wrote business software in Delphi and SQL for 9 years! I just need to learn the syntax/setup of MySQL, and PHP.

Re: that other forum, the word "just" was misleading, I didn't mean I "just" saw it then I mean "it's *just* that a while ago I saw...", and what I saw wasn't a solution, it was just someone saying it's a good idea to track it. Sorry for the confusion...

Stop using MySQL!

Stop using MySQL!


Why?

Is that an order?

$result = mysql_query("SELECT * FROM product_downloads WHERE name = '$product'");
$row = mysql_fetch_array($result);
if (strlen($row) != 0)
{
	$total = ++$row["downloads"];
	$result = mysql_query("UPDATE product_downloads SET downloads='$total' WHERE name = '$product'");
}

What a mess! Replace the whole lot with :
$result = mysql_query("UPDATE product_downloads SET downloads=(downloads+1) WHERE name = '$product'  LIMIT 1");
Now that's better.

thanks mr optimiser.

What a mess! Replace the whole lot with :
Well, at least it works unlike that igloader thingy...doh! :>