Очередной блог фрилансера

коротко и полезно о веб-разработке

Menu Close

Создаем счетчик загрузок файла с помощью PHP и MySQL

В сегодняшней статье, мы создадим простую, но надежную систему учета загрузок файлов. Каждый файл будет иметь соответствующую строку в базе данных, где будет хранится общее число загрузок этого файла. PHP будет обновлять базу данных MySQL, и перенаправлять пользователей на соответствующие файлы.

Чтобы отслеживать количество загрузок, вам понадобится только загрузить файлы в нужную папку, и использовать определенный URL для доступа к ним.

Шаг 1 – XHTML

Для начала нам понадобится XHTML-разметка. Она очень простая – это общий блок file-manager, содержащий маркированный список, в котором ссылка на каждый файл будет находится внутри элемента li.

Файлы, по которым будет учитываться количество скачиваний, нужно загрузить в папку files, расположенную в корневой директории скрипта (вы можете посмотреть как организована структура файлов, в архиве с приведенным примером). PHP будет проходить циклом по всем файлам в папке, и добавлять каждый файл в виде отдельного элемента li, в маркированный список.

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>

Обратите внимание, что атрибут href у ссылки передает имя загружаемого файла в качестве параметра для файла download.php. Именно здесь будет происходить подсчет загрузок, как вы увидите в дальнейшем.

Вам не обязательно пользоваться именно этим интерфейсом для организации подсчета загрузок. Вы можете просто разместить ссылки на download.php на страницах блога или сайта, и все загрузки будут подсчитаны правильно.

Шаг 2 – CSS

После того как наша XHTML-разметка готова, мы можем сконцентрироваться на внешнем виде нашего скрипта. CSS-стили, представленные ниже, назначают внешний вид блоку file-manager, через его ID, поскольку он у нас один на странице. Остальные элементы стилизуются через имена классов.

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

Обратите внимание, что здесь подпись “download” скрыта по умолчанию, с помощью свойства display: none. Она отображается через display:block, только при наведении мыши на ссылку, без использования JavaScript. Немного CSS3 используется для закругления уголков у подписи.

Шаг 3 – PHP

Как мы уже говорили выше, PHP проходит циклом по всей папке files, и выводит каждый файл в виде элемента li маркированного списка. Давайте рассмотрим подробнее, как это происходит.

demo.php  — Верхняя часть

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

Обратите внимание, как мы выбираем все записи из таблицы download_manager с помощью mysql_query() и затем добавляем их в массив $file_downloads, с ключом массива filename, и значением downloads. Таким образом, далее в коде, мы сможем записать $file_downloads[‘archive.zip’], и вывести количество загрузок этого файла.

Ниже представлен код, который используется для генерации элементов li маркированного списка.

demo.php – Центральная часть

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

Все очень просто – проходим циклом foreach по массиву $files_array, и выводим на страницу нужные данные в соответствующей разметке.

Теперь давайте более подробно рассмотрим как происходит учет загрузок.

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
}

Здесь обязательно нужно проверить, не является ли посетитель роботом поисковой системы, сканирующим ваши ссылки. Роботы – это хорошие посетители, поскольку они помогают включить ваш сайт в поисковые сервисы, однако в нашем случае, они могут исказить статистику загрузок. Вот почему база данных обновляется только после того, как посетитель пройдет проверку is_bot().

Шаг 4 – MySQL

Как мы упоминали в предыдущем шаге, количество загрузок записывается в виде строки, в таблицу download_manager, базы данных MySQL. Сначала, позвольте объяснить как работает эта часть запроса:

download.php

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

Первая часть запроса говорит MySQL вставить новую строчку в таблицу download_manager, и установить значение поля filename равным имени запрашиваемого для загрузки файла. Кроме этого, поле filename определено как уникальный индекс таблицы. Это значит, что строка с конкретным именем файла, может быть вставлена только один раз, иначе произойдет ошибка дублирования ключевых полей.

Именно в этом случае, вступает в силу вторая часть запроса — ON DUPLICATE KEY UPDATE, которая увеличивает значение поля downloads на единицу, если этот файл уже записан в базе данных.

Таким образом, новые файлы будут автоматически вставляться в базу данных в первый раз, после того как загружены.

Шаг 5 – 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);
	});
});

Мы просто назначили обработчик события на клик по ссылке. Каждый раз, после того, как пользователь кликнет по ссылке, мы увеличиваем текущее значение загрузок на единицу.

Шаг 6 – htaccess

Нам осталось сделать еще одну вещь, прежде чем можно будет назвать работу законченной. Возможно, вы уже заметили, что некоторые типы файлов, браузер по умолчанию пытается сразу же открывать. Вместо этого, нам нужно запускать загрузку файла. Это довольно легко сделать, добавив несколько строчек внутри файла .htaccess, расположенного в папке files:

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

Вот и все, наш счетчик загрузок готов.

Заключение

Чтобы запустить этот пример на своем собственном сервере, вам понадобится создать таблицу download_manager в базе данных MySQL, к которой у вас разумеется есть доступ. В архиве с примером, есть файл table.sql, который содержит необходимый SQL-код, который создаст нужную таблицу.

После этого, просто укажите свои данные подключения к базе, в файле configuration.php.

Смотреть демо.

Архив с приведенным примером.

Перевод статьи “PHP & MySQL File Download Counter”, автор Martin Angelov

Рассказать друзьям

Понравилась статья? Лучший способ сказать спасибо - поделиться ссылкой в социальных сетях: