Contador de descargas en PHP y MySQL

Ha pasado mucho tiempo desde que no te traemos por aquí un buen tutorial de PHP y MySQL, en programacion.net, por lo que hoy vamos a crear un simple, pero robusto, contador de descargas de archivos.

Cada archivo contará con su correspondiente fila en la base de datos, donde se guardará el número total de descargas del fichero. PHP actualizará la base de datos MySQL y redirigirá a los visitantes, a los archivos correspondientes.

Para realizar un seguimiento del número de descargas, solo necesitas subir tus archivos a la carpeta idónea para ello, y utilizar una URL especial para acceder a ella.

El XHTML

El primer paso es implementar el diseño XHTML del rastreador. Es bastante sencillo, tenemos el div gestor de archivos que contiene una lista desordenada con cada archivo como un elemento li.

Los archivos, que van a ser rastreados, se ponen en la carpeta de archivos asignada con permisos de escritura en el directorio raíz. PHP, a continuación, recorrerá todos los archivos y añadirá cada uno de ellos como un elemento li independiente en la lista desordenada.

demo.php

<div id="file-manager">

    <ul class="manager">

        <!-- The LI items are generated by php -->
        <li><a href="download.php?file=photoShoot-1.0.zip">photoShoot-1.0.zip
            <span class="download-count" title="Times Downloaded">0</span> <span class="download-label">download</span></a>
        </li>
    </ul>

</div>

Ten en cuenta que el atributo href del hipervínculo, pasa el nombre del archivo como parámetro para el download.php. Aquí es donde ocurre el seguimiento de las descargas, como verás dentro de un momento.

No estás limitado a esta interfaz para tener un rastreador de descargas, puedes enviar los enlaces a download.php en tus posts o páginas web, y todas las descargas estarán bien rastreadas.

El CSS

Con el diseño ya implementado, podemos concentrarnos en el estilo de nuestros componentes. En las reglas de CSS de más abajo se identifica el div del gestor de archivos por el id (con el símbolo hash), ya que está presente solo una vez en la página, y el resto de los elementos, por el nombre de la clase.

style.css

#file-manager{
	background-color:#EEE;
	border:1px solid #DDD;
	margin:50px auto;
	padding:10px;
	width:400px;
}

ul.manager li{
	background:url("img/bg_gradient.gif") repeat-x center bottom #F5F5F5;
	border:1px solid #DDD;
	border-top-color:#FFF;

	list-style:none;
	position:relative;
}

ul.manager li a{
	display:block;
	padding:8px;
}

ul.manager li a:hover .download-label{
	/* When a list is hovered over, show the download green text inside it: */
	display:block;
}

span.download-label{
	background-color:#64B126;
	border:1px solid #4E9416;
	color:white;
	display:none;
	font-size:10px;
	padding:2px 4px;
	position:absolute;
	right:8px;
	text-decoration:none;
	text-shadow:0 0 1px #315D0D;
	top:6px;

	/* CSS3 Rounded Corners */

	-moz-border-radius:3px;
	-webkit-border-radius:3px;
	border-radius:3px;
}

span.download-count{
	color:#999;
	font-size:10px;
	padding:3px 5px;
	position:absolute;
	text-decoration:none;
}

La parte interesante de todo esto es que el label download está oculto por defecto con display:none. Se mostrará con un display:block solo cuando se haga hover sobre su elemento padre, el tag de enlace, y por lo tanto se mostrará el label correctamente sin necesidad de utilizar Javascript. Utilizamos también un poco de CSS3 para redondear las esquinas del download label.

El PHP

Como he mencionado antes, PHP recorrerá la carpeta de archivos, y los mostrará como un elemento li dentro de la lista desordenada. Ahora vamos a echar un vistazo a cómo sucede esto:

demo.php - Sección superior

// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the DB connection file:
require 'connect.php';

$extension='';
$files_array = array();

/* Opening the thumbnail directory and looping through all the thumbs: */

$dir_handle = @opendir($directory) or die("There is an error with your file directory!");

while ($file = readdir($dir_handle))
{
	/* Skipping the system files: */
	if($file{0}=='.') continue;

	/* end() returns the last element of the array generated by the explode() function: */
	$extension = strtolower(end(explode('.',$file)));

	/* Skipping the php files: */
	if($extension == 'php') continue;

	$files_array[]=$file;
}

/* Sorting the files alphabetically */
sort($files_array,SORT_STRING);

$file_downloads=array();

$result = mysql_query("SELECT * FROM download_manager");

if(mysql_num_rows($result))
while($row=mysql_fetch_assoc($result))
{
	/* 	The key of the $file_downloads array will be the name of the file,
		and will contain the number of downloads: */

	$file_downloads[$row['filename']]=$row['downloads'];
}

Fíjate en cómo seleccionamos todas las filas de la tabla download_manager con mysql_query(), u después las añadimos el array $file_downloads con el nombre del fichero como key para el número de descargas. Con este método, podemos escribir $file_downloads['archive.zip'], y nos mostrará cuántas veces ha sido descargado el fichero archive.zip.

A continuación puedes ver el código para generar los elementos li.

demo.php - Sección media

foreach($files_array as $key=>$val)
{
    echo '<li><a href="download.php?file='.urlencode($val).'">'.$val.'
        <span class="download-count" title="Times Downloaded">'.(int)$file_downloads[$val].'</span> <span class="download-label">download</span></a>
    </li>';
}

Tan simple como eso, un bucle foreach en el array $files_array, y un echo que pinta todo el diseño de la página.

Ahora, vamos a ver más de cerca como se realiza el seguimiento de las descargas:

download.php

// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the connection file:
require('connect.php');

if(!$_GET['file']) error('Missing parameter!');
if($_GET['file']{0}=='.') error('Wrong file!');

if(file_exists($directory.'/'.$_GET['file']))
{
	/* If the visitor is not a search engine, count the downoad: */
	if(!is_bot())
	mysql_query("	INSERT INTO download_manager SET filename='".mysql_real_escape_string($_GET['file'])."'
					ON DUPLICATE KEY UPDATE downloads=downloads+1");

	header("Location: ".$directory."/".$_GET['file']);
	exit;
}
else error("This file does not exist!");

/* Helper functions: */

function error($str)
{
	die($str);
}

function is_bot()
{
	/* This function will check whether the visitor is a search engine robot */

	$botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
	"looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
	"Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
	"crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
	"msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
	"Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
	"Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
	"Butterfly","Twitturls","Me.dium","Twiceler");

	foreach($botlist as $bot)
	{
		if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
		return true;	// Is a bot
	}

	return false;	// Not a bot
}

Es importante asegurarnos si, por alguna razón, el visitante es un robot de cualquier buscador que está escaneando tus enlaces, y no es una persona real. Los robots no son malos, te integran en servicios como Google Search, pero en una situación como esta, distorsionarán tus estadísticas de descargas. Es por eso que la base de datos no se actualiza hasta que el visitante no pasa la validación is_bot().

El MySQL

Como hemos mencionado en el paso previo, el contador de descargas se almacena como una fila en la tabla download_manager de tu base de datos MySQL. Primero, vamos a explicar como funciona esta peculiar query:

INSERT INTO download_manager SET filename='filename.doc'
ON DUPLICATE KEY UPDATE downloads=downloads+1

Se le dice a MySQL que inserte una nueva fila en la tabla download_manager, y que establezca el nombre del fichero dentro del campo filename. De todas maneras, como hemos explicado antes, el campo filename es un unique index en la tabla. Esto significa que una fila puede ser insertada solo una vez, si no aparecerá un error de key duplicada.

Aquí es donde entra en acción la segunda parte de la query, ON DUPLICATE KEY UPDATE, que indica a MySQL que incremente la columna downloads a uno si el archivo existe en la base de datos.

De esta manera, los nuevos ficheros se insertarán en la tabla y los que ya existan, incrementarán su contador de descargas.

El jQuery

Para hacer que el rastreo de descargas parezca que se ejecuta en tiempo real, una muy buena idea es actualizar el contador de al lado del nombre del archivo una vez que el usuario inicie la descarga. De lo contrario tendrás que actualizar la página para que se muestren las nuevas estadísticas sobre el contador.

Vamos a lograr esto con un pequeño truco de jQuery:

script.js

$(document).ready(function(){
	/* This code is executed after the DOM has been completely loaded */

	$('ul.manager a').click(function(){

		var countSpan = $('.download-count',this);
		countSpan.text( parseInt(countSpan.text())+1);
	});
});

Asignamos un controlador de clic a los enlaces que apunten a los archivos, y cada vez que se haga clic en alguno de ellos, incrementamos el número dentro del span counter.

El .htaccess

Hay algo más que tenemos que hacer, antes de ejecutarlo todo. El archivo download.php redirige al visitante al archivo solicitado que se pasa como parámetro. Sin embargo, te habrás dado cuenta que, para ciertos tipos de archivos, el comportamiento por defecto del navegador es abrirlo directamente. No queremos abrirlo, queremos descargarlo. Esto se consigue con un par de líneas dentro del archivo .htacess.

<Files *.*>
ForceType application/octet-stream
</Files>

Con esto nuestro contador de descargas estaría completo.

Fuente: tutorialzine.com

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP