В сегодняшней статье, мы создадим простую, но надежную систему учета загрузок файлов. Каждый файл будет иметь соответствующую строку в базе данных, где будет хранится общее число загрузок этого файла. 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
Это будет работать на любой cms ?
Думаю, да. По крайней мере не вижу препятствий
на вордпрессе точно не заработает, половину кода придется переделывать если не больше =/
на Joomlа тоже не смог настроить
Ох сколько нагородили :). Думал будет просто скрипт, а тут и всерстка, и стили, и яваскрипт.
И все эти защиты от ботов… а от повторных кликов? Мне кажется, тут проще не мудрить, а просто поставить капчу на скачку. Хотя, конечно, каждый поступает так, как сам считает нужным.
Ну верстка, и ява-скрипт опциональны, это по желанию. Так же как и защита от ботов, хотя я лично не вижу особой проблемы, ведь она уже написана ;)
Каптчу сейчас почти любой бот распознавать научился. Тут надо что либо новое, оригинальное.
это какой-же бот и какие капчи?
Для практикующих программистов, наверняка будут полезно. Новочики же просто возьмут готовый плагин для WP чтобы не заморачиваться с этими кодами.
Так еще вопросик: Это сильно будет нагружать сервер, у меня итак уже от всяких плагинов страницы долго грузятся?
Думаю не будет, кстати отличный урок) будем пробовать
Очень не плохо)
Ты как обучался ПХП, Ява, ХТМЛ?
Можешь какие-нибудь книги/видео/курсы посоветовать?
Любая книга подойдет, главное, сразу учиться применять знания на практике.
Классно, как бы себя заставить взяться за книгу:)
А возможно ли счетчик сделать не по нажатию ссылки , а уже по факту полного скачивания файла или хотя бы после начала его загрузки, как пользователь нажмет «сохранить»?
И еще вопросик: А можно ли выводить список файлов в сортированном виде например не по алфавиту , а по дате создания файла.
А так статья хорошая все работает :)