4.9. Счетчик загрузок файлов
Работа всех счетчиков загрузок файлов основана на том, что посетителю в качестве ссылки для загрузки предоставляется не сам файл, а ссылка на скрипт, который учитывает загрузку и отправляет файл браузеру пользователя. Будем строить наш счетчик таким образом, чтобы ссылки на загрузку файла представляли собой ссылки на текущую страницу с передачей в качестве параметра имени файла, например, index.php?down=archive.zip . Скрипт будет проверять, передан ли параметр down , и если это так, то будет регистрировать загрузку архива в файле filecount.txt. При повторной загрузке страницы из файла будут извлекаться значения счетчиков для каждого из архивов для вывода в окно браузера. Передача файла на загрузку будет осуществляться отсылкой посетителю HTTP-заголовка Location с указанием пути к загружаемому архиву. Скрипт счетчика загрузок файлов может выглядеть так, как это представлено в листинге 4.31. Листинг 4.31. Счетчик загрузок файлов // Если такого файла нет — создаем его, // а статистику обнуляем?php>
226 | Глава 4 |
else < // Заполняем массив $count нулевыми значениями foreach($file_name as $file) < $count[$file] = 0; >// Упаковываем массив и помещаем его в счетчик file_put_contents($countname, serialize($count)); > // Проверяем, не передано ли значение параметра down // через метод GET if(isset($_GET[‘down’])) < // Проверяем, входит ли значение параметра $_GET['down'] // в массив $file_name if(in_array($_GET['down'],$file_name)) < // Регистрируем факт загрузки данного файла // Увеличиваем значение счетчика с ключом // $_GET['down'] на единицу $count[$_GET['down']]++; // Перезаписываем файл счетчика file_put_contents($countname, serialize($count)); // Предоставляем ссылку на его загрузку header("Location: $_GET[down]"); exit(); >> // Выводим ссылки на файлы foreach($file_name as $file) < echo "Файл $file был загружен ".intval($count[$file])." раз
«; > ?> Имена загружаемых файлов хранятся в массиве $file_name , добавление нового архива приводит к автоматическому его учету в системе. Предварительная регистрация в массиве необходима по нескольким причинам. Во-первых, принимая имя массива через параметр down , необходимо проверить, входит ли он в число файлов, разрешенных к загрузке. Во-вторых, обрабатывать имена файлов в массиве гораздо удобнее. Так массив $count , в котором хранится количество загрузок файлов, автоматически строится на основании массива зарегистрированных в системе файлов,
Файлы и каталоги | 227 |
массив удобно упаковывать при помощи функции serialize() в строку, а затем распаковывать обратно в массив при помощи функции unserialize() . З АМЕЧАНИЕ Важно помнить, что отправка всех HTTP-заголовков должна осуществляться до отправки основного содержимого, иначе их отправка будет невозможна и интерпретатор PHP выдаст предупреждение «Warning: Cannot modify header information — headers already sent by» (Предупреждение: невозможно модифицировать заголовочную информацию — заголовки уже отправлены). Это диктуется протоколом HTTP: сначала отправляются заголовки, затем содержимое документа, поэтому любой вывод в окно браузера воспринимается как окончание отправки заголовков и начало отправки тела документа. Если вывод в окно браузера до отправки заголовков неизбежен, необходимо прибегать к функциям управления выводом, помещая весь вывод в буфер и отправляя его в конце работы скрипта. Как видно из листинга 4.31, в скрипте обрабатывается ситуация первого запуска, когда отсутствует файл filecount.txt — он автоматически создается при первой загрузке страницы, инициированный нулевыми значениями для каждого файла из массива $file_name . Результат работы скрипта из листинга 4.31 можно видеть на рис. 4.4. Рис. 4.4. Результат работы счетчика файлов
4.10. Сохранение текстовых и графических файлов
Переход по ссылке на текстовые файлы или файлы HTML приводит к отображению их в окне браузера, что не всегда удобно, особенно, если файл предназначен для загрузки. Та же участь ожидает графические файлы и вообще любые файлы, которые браузер может отобразить. О содержимом файла браузер посетителя «узнает» от сервера, т. к. каждый файл сопровождается HTTP-заголовками, сообщающими клиенту о содержимом, размере загружаемого файла, необходимости установить cookie и т. п. Если тип файла не удалось определить, он отправляется просто как двоичный поток. Подавить такое поведение можно, отправив HTTP-заголовки, представленные в листинге 4.32.
228 | Глава 4 |
Листинг 4.32. Скрипт, позволяющий сохранять текстовые и графические файлы Скрипт в листинге 4.32 принимает в качестве GET-параметра имя файла, например, index.php?down=filetext.txt . При помощи функции basename() извлекается имя файла (на тот случай, если GET-параметр down содержит путь к файлу). HTTPзаголовок Content-Disposition задает имя сохраняемого файла, которое определяется атрибутом filename . В приведенном скрипте параметр filename совпадает с именем отправляемого файла, однако в качестве параметра filename может быть передано произвольное имя. HTTP-заголовок Content-type сообщает о том, что передаваемые данные являются двоичными, и браузеру их не следует интерпретировать. HTTP-заголовок Content-length передает клиенту размер файла. В последней строке выводится содержимое файла, переданное через параметр $_GET[‘down’] , которое извлекается при помощи функции file_get_contents() . Результат работы скрипта из листинга 4.32 представлен на рис. 4.5. З АМЕЧАНИЕ Важно, чтобы после вывода содержимого файла больше ничего не выводилось в поток: ни конструкцией echo , ни непосредственным выводом — иначе все будет прикреплено в конец файла. Это относится и к возможным пробелам, и к переводам строк после завершающего тега ?> .
Cчетчик скачиваний для сайта
Решил посмотреть сколько раз скачивают один из моих скриптов с сайта. Для этого решил написать счётчик скачиваний файлов для сайта. В интернете много реализаций данной задачи, но тем неменее ознакомтесь с моим решением.
Логика работы счётчика скачивания довольна проста. Для его реализации будем использовать мой любимый ajax. Вешаем на кнопку при возникновении событи clik обращение через ajax к php файлу счётчика. В php происходит обработка ajax запроса и запись в текстовый файл цифры суммарного количества скачек. После удачной записи возвращается ответ с суммарным счётчиком скачиваний и происходит редирект пользователя на ссылку для скачки файла (файл скачивается). Вот такая вот простая логика Теперь начнём её реализовать. Заранее создадим скачиваемый файл test.zip . Сделаем код кнопки и покажем счётчик скачек.
Количество скачек:
Мы создали кнопку с id=»btnSend» , выводить счётчик будем в span с id=»countView» , в атрибуте data-download будем хранить ссылку на скачиваемый файл
Теперь давайте прикрутим к кнопке обработчик клика. Здесь уже будем использовать js и jquery. Про то как реализовать clik силами jquery можно почитать здесь. Но перед установкой обработчика клика мы будем ajax обращаться к файлу count.php, в котором будет заключена вся работа счётчика. Подробнее о передаче данных ajax можно почитать здесь. Это нужно что бы вывести из файла куда пишет счётчик, количество уже сделанных закачек и вывести их в span с id=»countView»
/*получаем текущее кол-во закачек*/ $(document).ready(function()< //запрещаем кещировать ajax запрос //иначе счётчик будет брехать $.ajaxSetup(); var html; $.ajax(< //как будем передавать данные type: "GET", //куда передаём url: "count.php", //какие данные передаём data: , //событие после получения ответа от count.php success: function(data) < html=data; //выводим текущее кол-во закачек $('#countView').html(html); >>); /*вешаем событие на кнопку скачать файл*/ var clickevent=false;//флаг проверки нажатия //обработчик клика $('#btnSend').click(function()< if(!clickevent)< $.ajax(< //как будем передавать данные type: "GET", //куда передаём url: "count.php", //какие данные передаём data: , //событие перед отправкой ajax beforeSend: function()< //если кнопка была нажата то труе clickevent=true; >, //событие после получения ответа, //получаем данные в data success: function(data) < //после выполнения действий разрешаем опять //обрабатывать клик по кнопке clickevent=false; html=data; //выводим новый счётчик $('#countView').html(html); //получаем ссылку из data-download //редиректит по ссылке скачки, качаем файл window.location.href = $('#btnSend').data('download'); >>); > return false;//запрещаем обрабатывать событие при клике >); >);
Для предотвращения повторного ошибочного нажатия кнопки отправки я ввёл в скрипт флаг clickevent . Пока не вернётся ответ от count.php с обновившимися данными счётчика клик по кнопке будет запрещён. Я так думаю работа кода после клика по кнопке более менее ясна. После клика по кнопке скачать в файл count.php передаются данные, там они обрабатываются и возвращается обновлённые данные счётчика, происходит редирект на ссылку скачивания и соответственно сама закачка файла.
Давайте теперь разберём сердце нашего скрипта, а именно файл count.php.
function clearInt ($date) < //приводим date к числу, не отрицательному return abs((int)$date); >if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') < //проверяем какой флаг пришёл if(clearInt($_GET['flag']==1)) < //открываем файл для чтения $f=fopen("mycount.txt","a+"); //закрывает доступ к файлу из других программ flock($f,LOCK_EX); //получаем из файла значение счётчика $count=fread($f,100); //плюсуем счётчик @$count++; //затираем файл ftruncate($f,0); //пищем новое покакзание счётчика fwrite($f,$count); //закрываем файл fclose($f); //возвращаем значение echo $count; >if(clearInt($_GET['flag']==2)) < $c=fopen("mycount.txt","a+"); flock($c,LOCK_EX); $festc=fread($c,100); fclose($c); //возвращаем значение echo $festc; >>
Здесь я то же думаю всё просто. Если приходит флаг 1 то делаем перезапись счётчика. Если приходит флаг 2 то просто возвращаются данные о количестве закачек. Всё остальное я думаю понятно из комментариев в коде.
Cчетчик скачиваний Joomla
Решил прикрутить подобный счётчик на один из моих проектов на joomla. По идее нужно конечно написать либо отдельный модуль, либо интегрировать код в контроллер компонента com content, что бы данные счётчика писались не в файл, а в бд и для каждой статьи отдельно. Но на на такую разработку нет времени и я решил вопрос более просто. Счётчик мне был нужен для одной страницы. Я взял файл count.php и перенёс его в шаблон джумла, который на данный момент подключён ( в корне сайта templates/ваш_шаблон ). Не забываем вставить в самый верх count.php код defined(‘_JEXEC’) or die; (это для джумла). Кнопку закачки вставляем в создаваемую нами страницу, а js код можно так же встроить в страницу, либо подключить отдельным файлом. У меня например отдельным файлом (он находится в папке js шаблона). В самом шаблоне в хедере происходит подключение через код
И не забываем get запросом ajax мы обращаемся по адресу url: «/index.php?tmpl=count», а не url: «count.php», . Вот так вот просто я прикрутил счётчик скачиваний файлов к joomla.