Contador de descargas de archivos PHP y MySQL

Ha pasado un tiempo desde que hicimos un tutorial adecuado de PHP y MySQL aquí, en Tutorialzine, por lo que hoy estamos creando un rastreador de descarga de archivos simple pero robusto.

Cada archivo tendrá una fila correspondiente en la base de datos, donde se guarda el número total de descargas. PHP actualizará la base de datos MySQL y redirigirá a los visitantes a los archivos apropiados.

Para realizar un seguimiento del número de descargas, solo necesita cargar sus archivos en archivos y use una URL especial para acceder a ellos.

Paso 1 - XHTML

El primer paso es establecer el marcado XHTML del rastreador. Es bastante sencillo:tenemos el administrador de archivos div, que contiene una lista desordenada con cada archivo como un li elemento.

Los archivos, que van a ser rastreados, se colocan en los archivos carpeta en el directorio raíz del script (puede ver cómo se organiza la estructura del archivo en el archivo zip de demostración). PHP luego recorre todos los archivos y agrega cada uno como un li separado elemento a 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>

Observe el href atributo del hipervínculo:pasa el nombre del archivo como parámetro a download.php . Aquí es donde ocurre el seguimiento de la descarga, como verá en un momento.

No está limitado a esta interfaz para proporcionar seguimiento de descargas; simplemente puede publicar los enlaces a download.php en las publicaciones de su blog o en las páginas de su sitio, y todas las descargas se rastrearán correctamente.

Paso 2:CSS

Con el marcado XHTML en su lugar, ahora podemos concentrarnos en el lado de presentación del script. Las siguientes reglas de CSS apuntan al administrador de archivos div por id (con el símbolo hash ), ya que está presente una sola vez en la página, y el resto de elementos por nombres de clase .

estilos.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 aquí es que la etiqueta de descarga está oculta de forma predeterminada con display:none . Se muestra con display:block solo cuando nos desplazamos sobre su padre y, por lo tanto, se muestra la etiqueta correcta sin necesidad de usar JavaScript. Un poco de CSS3 también se usa para redondear las esquinas de la etiqueta de descarga.

Paso 3 - PHP

Como se mencionó anteriormente, PHP recorre los archivos carpeta y genera cada archivo como un li elemento en la lista desordenada. Ahora echemos un vistazo más de cerca 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'];
}

Observe cómo estamos seleccionando todas las filas del download_manager tabla con mysql_query() y luego agregarlos a $file_downloads matriz con el nombre del archivo como clave para el número de descargas. De esta forma, más adelante en el código, podemos escribir $file_downloads['archive.zip'] y muestra cuántas veces se ha descargado este archivo.

Puedes ver el código que usamos para generar el li elementos a continuación.

demo.php - Sección intermedia

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>';
}

Así de simple:un foreach bucle en el $files_array matriz y una declaración de eco que imprime todo el marcado en la página.

Ahora echemos un vistazo más de cerca a cómo se rastrean exactamente las descargas.

descargar.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 verificar si, por casualidad, el visitante es un robot de motor de búsqueda que escanea sus enlaces y no una persona real. Los robots son algo bueno, ya que lo incluyen en servicios como la Búsqueda de Google, pero en una situación como esta, pueden sesgar sus estadísticas de descarga. Esta es la razón por la cual la fila de la base de datos se actualiza solo después de que el visitante pasa el is_bot() validación.

Paso 4 - MySQL

Como se mencionó en el paso anterior, el recuento de descargas se almacena como una fila en el download_manager tabla en su base de datos MySQL. Primero, expliquemos cómo funciona esta consulta en particular:

descargar.php

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

Le dice a MySQL que inserte una nueva fila en el download_manager y configure el nombre de archivo campo de la fila al valor del archivo solicitado para descargar. Sin embargo, el nombre de archivo el campo se define como un índice único en la mesa. Esto significa que una fila se puede insertar solo una vez, de lo contrario, un error de clave duplicada ocurrirá.

Aquí es donde entra en juego la segunda parte de la consulta:EN ACTUALIZACIÓN DE CLAVE DUPLICADA le dirá a MySQL que incremente la columna de descargas en uno si el archivo ya existe en la base de datos.

De esta forma, los nuevos archivos se insertarán automáticamente en la base de datos la primera vez que se descarguen.

Paso 5:jQuery

Para hacer que el seguimiento de descargas se sienta casi como en tiempo real, será una buena adición actualizar el contador junto al nombre del archivo una vez que el usuario inicie la descarga. De lo contrario, tendrían que iniciar una actualización de la página para que se muestren las nuevas estadísticas del contador.

Lo lograremos con un pequeño truco de jQuery:

secuencia de comandos.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);
    });
});

Simplemente asignamos un controlador de clics a los enlaces que apuntan a los archivos, y cada vez que se hace clic en uno de ellos, incrementamos el número dentro de la etiqueta del contador.

Paso 6 - htaccess

Hay una cosa más que tenemos que hacer, antes de dar por terminado el día. Qué descargar.php lo que hace es redirigir al visitante al archivo solicitado que se pasó como parámetro. Sin embargo, es posible que haya notado que, para ciertos tipos de archivos, el comportamiento predeterminado del navegador es abrirlos directamente. Queremos iniciar una descarga en su lugar. Esto se logra con un par de líneas dentro de un .htacess archivo, que se encuentra en los archivos directorio:

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

¡Con esto nuestro contador de descargas de archivos está completo!

Conclusión

Para ejecutar la demostración en su propio servidor, deberá volver a crear el download_manager tabla en una base de datos MySQL a la que tenga acceso. Puede encontrar el SQL necesario código que creará la tabla para usted en table.sql , que puede encontrar en el archivo de descarga.

Después de esto, simplemente agregue sus datos de inicio de sesión para la base de datos (según lo proporcionado por su servidor web) a configuration.php .

¿Qué opinas? ¿Cómo mejorarías este ejemplo?