Делаем счетчик просмотров для страницы с топиком



Вообщем решил я прикрутить к своему сайту, счетчик просмотров. А именно для страниц с топиком. Поиск по интернету дал решение, с которым я и делюсь ;)
Собственно на картинке всё видно, работает он как все стандартные счетчики, и учитывает только просмотр страницы…

И так поехали ;)

1. Нам нужно создать новую таблицу в MySQL, в которой естественно всё это дело будет храниться. Для этого запускаем phpMyAdmin → выбираем базу на которой работает сайт → на самом вверху вкладка SQL

Выполнить SQL-запрос(ы) к базе данных ХХХ_ХХХ:
CREATE TABLE `my_log` (
  `page_id` varchar(32) NOT NULL default '',
  `all` int(11) NOT NULL default '0',
  `today` int(11) NOT NULL default '0',
  `date` int(11) NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

вставляем это, и жмем ОК. Через пару секунд, должно написаться что таблица my_log готова.

Теперь в нашей Базе появилась таблица my_log


* * * * *
2. Теперь нам нужно создать сам php-счетчик. Для этого создаем новый файл (текстовый документ) и называем его counter.php Кодировку ставим ANSI as UTF8 (UTF8 без BOM)

<?php
///////////////////////////////////////////
/// Скрипт статистики просмотров станиц ///
///////////////////////////////////////////

/* данные для соединения с MySQL */
$INFO['sql_host'] = "localhost";
$INFO['sql_user'] = "Пользователь_БазыДанных";
$INFO['sql_pass'] = "Пароль";
$INFO['sql_database'] = "Имя_БазыДанных";

/* проверка, есть ли запись в MySQL */
/* таблице с таким id или ее нет */
function searchID($id)
{
$result = mysql_query ("SELECT * FROM `my_log` WHERE `page_id` LIKE '".$id."'");
$num_rows = mysql_num_rows($result);
if ($num_rows>0)
{
    return True;
}
else
{
    return False;
}
}


/* Читает запись из MySQL таблицы */
/* возвращает ассоциированный массив */
function MySQLRead($id)
{
$id = addslashes($id);
$result = mysql_query ("SELECT * FROM `my_log` WHERE `page_id` LIKE '".$id."'");
return (array)mysql_fetch_assoc($result);
}

/* Обновление времени для конкретной записи */
function UpdateTime($id, $time)
{
$id = addslashes($id);
$time = addslashes($time);
$result = mysql_query ("UPDATE `my_log` SET `date` = '".$time."' WHERE `page_id` = '".$id."'");
return $result;
}

/* Обновление счетчиков для записи с указанным id */
function UpdateCounders($id, $all, $today)
{
$id = addslashes($id);
$time = addslashes($time);
$result = mysql_query ("UPDATE `my_log` SET `all` = '".$all."',`today` = '".$today."' WHERE `page_id` = '".$id."'");
return $result;
}

/* Запись всех значений "По умолчанию" */
function Default_Write($id)
{
$id = addslashes($id);
$result = mysql_query ("INSERT INTO `my_log` ( `page_id` , `all` , `today` , `date` ) VALUES ('".$id."' , 1 , 1 , '".(time()+60*60*24)."');");
return $result;
}

$unical_page_id_gid = md5($_SERVER['REQUEST_URI']); // получение md5() хэша из url страницы

$link = mysql_connect($INFO['sql_host'], $INFO['sql_user'], $INFO['sql_pass']); // Соединение с MySQL
mysql_select_db ($INFO['sql_database']); // Выбор базы данных

if (!searchID($unical_page_id_gid)) // существует ли запись с таким id
{
    Default_Write($unical_page_id_gid); // запись всех значений по умолчанию
}
else // если не существует
{
$tmp = MySQLRead($unical_page_id_gid); // считаем значения
$all = $tmp['all'] + 1;
$today = $tmp['today'] +1;
if (time()>=$tmp['date']) // если сутки с момента записи прошли
{
    UpdateTime($unical_page_id_gid, (time()+60*60*24)); // обновим дату
    UpdateCounders($unical_page_id_gid, $all, 1); // обновим счетчики
    define("Today_and_all_counter", "Просмотров: 1. Сегодня: 1");
}
else // если еще нет
{
    /* обновим счетчики */
    UpdateCounders($unical_page_id_gid, $all, $today);
}
/* устанавливаем константу с текущими значениями счетчиков */
define("Today_and_all_counter", "Просмотров: $all. Сегодня: $today");
}

mysql_close($link); // Разрываем соединение с MySQL 
?>

вставляем это, и не забываем в самом начале указать данные для соединения с MySQL
База естественно та, в которой мы создали нашу новую таблицу.

Заливаем наш counter.php к себе на сайт, например в папку my_php
(тоесть чтоб файл был по адресу сайт.ру/my_php/counter.php)

* * * * *
3. Теперь нам необходимо создать файл .tpl, который мы будем подключать в наш шаблон. Для этого создаем новый файл (текстовый документ) и называем его topic_counter.php.tpl Кодировку ставим ANSI as UTF8 (UTF8 без BOM)
{php}
include('my_php/counter.php');
echo Today_and_all_counter;
{/php}

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

Все, заливаем наш файл topic_counter.php.tpl в папку шаблона /templates/skin/new/

* * * * *
4. Вот собственно почти и всё. Нам осталось только подключить наш php-счетчик, к нашему шаблону. Топаем в /templates/skin/new/topic.tpl ~59стока
Ищем:
<ul class="voting {if $oVote || ($oUserCurrent && $oTopic->getUserId()==$oUserCurrent->getId())|| strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')}{if $oTopic->getRating()>0}positive{elseif $oTopic->getRating()<0}negative{/if}{/if} {if !$oUserCurrent || $oTopic->getUserId()==$oUserCurrent->getId() || strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')}guest{/if} {if $oVote} voted {if $oVote->getDirection()>0}plus{elseif $oVote->getDirection()<0}minus{/if}{/if}">
	<li class="plus"><a href="#" onclick="lsVote.vote({$oTopic->getId()},this,1,'topic'); return false;"></a></li>
	<li class="total" title="{$aLang.topic_vote_count}: {$oTopic->getCountVote()}">{if $oVote || ($oUserCurrent && $oTopic->getUserId()==$oUserCurrent->getId()) || strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')} {if $oTopic->getRating()>0}+{/if}{$oTopic->getRating()} {else} <a href="#" onclick="lsVote.vote({$oTopic->getId()},this,0,'topic'); return false;">—</a> {/if}</li>
	<li class="minus"><a href="#" onclick="lsVote.vote({$oTopic->getId()},this,-1,'topic'); return false;"></a></li>
	<li class="date">{date_format date=$oTopic->getDateAdd()}</li>
	if $oTopic->getType()=='link'}
	<li class="link"><a href="{router page='link'}go/{$oTopic->getId()}/" title="{$aLang.topic_link_count_jump}: {$oTopic->getLinkCountJump()}">{$oTopic->getLinkUrl(true)}</a></li>						
	{/if}
	<li class="author"><a href="{$oUser->getUserWebPath()}">{$oUser->getLogin()}</a></li>
	{hook run='topic_show_info' topic=$oTopic}
</ul>


И почти в самом низу, перед {hook run='topic_show_info' topic=$oTopic} вставляем {include file='topic_counter.php.tpl'}

Должно пуличиться так:
<ul class="voting {if $oVote || ($oUserCurrent && $oTopic->getUserId()==$oUserCurrent->getId())|| strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')}{if $oTopic->getRating()>0}positive{elseif $oTopic->getRating()<0}negative{/if}{/if} {if !$oUserCurrent || $oTopic->getUserId()==$oUserCurrent->getId() || strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')}guest{/if} {if $oVote} voted {if $oVote->getDirection()>0}plus{elseif $oVote->getDirection()<0}minus{/if}{/if}">
	<li class="plus"><a href="#" onclick="lsVote.vote({$oTopic->getId()},this,1,'topic'); return false;"></a></li>
	<li class="total" title="{$aLang.topic_vote_count}: {$oTopic->getCountVote()}">{if $oVote || ($oUserCurrent && $oTopic->getUserId()==$oUserCurrent->getId()) || strtotime($oTopic->getDateAdd())<$smarty.now-$oConfig->GetValue('acl.vote.topic.limit_time')} {if $oTopic->getRating()>0}+{/if}{$oTopic->getRating()} {else} <a href="#" onclick="lsVote.vote({$oTopic->getId()},this,0,'topic'); return false;">—</a> {/if}</li>
	<li class="minus"><a href="#" onclick="lsVote.vote({$oTopic->getId()},this,-1,'topic'); return false;"></a></li>
	<li class="date">{date_format date=$oTopic->getDateAdd()}</li>
	if $oTopic->getType()=='link'}
	<li class="link"><a href="{router page='link'}go/{$oTopic->getId()}/" title="{$aLang.topic_link_count_jump}: {$oTopic->getLinkCountJump()}">{$oTopic->getLinkUrl(true)}</a></li>						
	{/if}
	<li class="author"><a href="{$oUser->getUserWebPath()}">{$oUser->getLogin()}</a></li>
	{include file='topic_counter.php.tpl'}
	{hook run='topic_show_info' topic=$oTopic}
</ul>


* * * * *
По дефолту выводиться считчик типа: Всего просмотров: 100. Сегодня: 5

Если нужно только Просмотров: 100, то в самом низу в файле counter.php, удаляем ненужное:
83строка / «Просмотров: 1. Сегодня: 1» заменяем на «Просмотров: 1»
91строка / «Просмотров: $all. Сегодня: $today» заменяем на «Просмотров: $all»

* * * * *
MySQL таблицы будут занимать очень мало места, а все из-за того, что все url будут хешированны с помощью php функции md5(), что гарантирует почти 100% неповторяющихся id для каждой страницы сайта. Делается это исключительно для ускорения работы php скрипта (при условии, что индексом является id страницы) и уменьшения размеров MySQL таблицы (за счет отсутствия длинных url).

page_id – уникальный id для каждой страницы сайта сгенерированный php функцией md5().
all – значение всех просмотров данной страницы.
today – просмотров страницы сегодня.
date – дата возвращаемая php функцией time() + 24 часа

* * * * *
Счетчик учитывает абсолютно всех, без исключения. Тоесть даже поисковые роботы, буду влиять на показания.

26 комментариев

avatar
было решение через хук, право нагрузку создавало ух
avatar
Дополнительные запросы к базе данных ни есть хорошо.
avatar
да это вообще проблема всех таких типов счетчиков
avatar
смотрите, вариант проще
создаём файл HookTopicView.class.php
class HookTopicView extends Hook {
	public function RegisterHook() {
		$this->AddHook('topic_show','TopicShow');
	}

	public function TopicShow($aParams) {
        $oTopic=$aParams['oTopic'];
        $oTopic->setCountRead($oTopic->getCountRead()+1);
        $this->Topic_UpdateTopic($oTopic);
    }
}


в шаблон
{$oTopic->getCountRead()}


проще? :)
avatar
спасибо Lora_GT
отлично работает через хук
avatar
В разы. Но я не знал об этом :)
avatar
Спасибо большое!

А как теперь еще реализовать вывод топиков по просмотрам в блоке «Рейтинг публикаций», который в плагине "Дополнительные блоки"?
avatar
я такой в своем шаблоне ligt использую. Само сабой через хук проще. но хочу спросить, возрастает ли нагрузка на сервер при таком методе?
avatar
проще, но он добавляет единицу просмотра при каждом обновлении страницы! это не годится. как сделать привязку к ip?
avatar
а для версии 0.5 плз?)
avatar
у меня работает нормально
avatar
а в какую папку хук кинули?
у меня рушит все в одной папке
avatar
сорри не внимательно посмотрел на топик, я делал вот так: livestreet.ru/blog/tips_and_tricks/1252.html#comment70719
avatar
У меня он не считает посещения. Версия ЛС 0.5.1
avatar
Можно подробнее для новичка? В какой директории создавать вышеозначенный .class.php-файл, и куда прописывать "{$oTopic->getCountRead()}"? Хватит ли этих двух действий или подразумевается что-то ещё?

Спасибо.
avatar
Я использую Google Analytics. В планах прикрутить через API счетчик для авторов блога
avatar
будет здорово если вы ещё и топик на эту тему напишите :)
avatar
надо обязательно попробовать
avatar
Ужасный скрипт =\
avatar
что не так?
avatar
Я пробежался по коду, он мне показался слишком тяжелым для такого вида функции.
Если я не ошибаюсь здесь просто каждый кто защёл на топик в DB в колонке с количеством посетителей страницы, прибавляется +1..?
avatar
да
avatar
Добрый день, отличный счётчик, использую для своей CMS, но всё же присоединяюсь к:
— dedmixei
— проще, но он добавляет единицу просмотра при каждом обновлении страницы! это не годится. как сделать привязку к ip?

Заинтересованные лица могут сделать накрутку определённой страницы — а это, как бы помягче сказать — не есть хорошо. Хочется реальных показателей т.е. подсчёт посетителя раз в сутки. Вывод: привязка по IP.
Очень жду добавления в счётчик такой фунции!
avatar
не пойму, по умолчанию счетчик просмотров топика в 1.0.3 не работает?
шаблон «симпл», плагин «ViewCount plugin» при активации выдает ошибку, типа не может найти php скрипт плагина
avatar
решено
avatar
Зачем Вы пишете «решено» если не показываете решения?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.