<?php
/**
* This file is part of JohnCMS Content Management System.
*
* @copyright JohnCMS Community
* @license https://opensource.org/licenses/GPL-3.0 GPL-3.0
* @link https://johncms.com JohnCMS Project
*/
declare(strict_types=1);
namespace Johncms;
use Johncms\Notifications\Notification;
use Johncms\System\Legacy\Tools;
use Johncms\System\Users\User;
use PDO;
use Psr\Container\ContainerInterface;
class Counters
{
/** @var PDO */
private $db;
/** @var string */
private $homeurl;
/** @var User */
private $user;
public function __construct(PDO $pdo, Tools $tools, User $user, string $homeUrl)
{
$this->db = $pdo;
$this->user = $user;
$this->homeurl = $homeUrl;
}
/**
* Счетчик Фотоальбомов пользователей
*
* @return string
* @deprecated use albumCounters
* TODO: содержимое albumCounters перенести в этот метод после проверки на использование
*/
public function album()
{
$file = CACHE_PATH . 'count-albums.cache';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$album = $res['album'];
$photo = $res['photo'];
$new = $res['new'];
$new_adm = $res['new_adm'];
} else {
$album = $this->db->query('SELECT COUNT(DISTINCT `user_id`) FROM `cms_album_files`')->fetchColumn();
$photo = $this->db->query('SELECT COUNT(*) FROM `cms_album_files`')->fetchColumn();
$new = $this->db->query('SELECT COUNT(*) FROM `cms_album_files` WHERE `time` > ' . (time() - 259200) . ' AND `access` = 4')->fetchColumn();
$new_adm = $this->db->query('SELECT COUNT(*) FROM `cms_album_files` WHERE `time` > ' . (time() - 259200) . ' AND `access` > 1')->fetchColumn();
file_put_contents($file, json_encode(['album' => $album, 'photo' => $photo, 'new' => $new, 'new_adm' => $new_adm]), LOCK_EX);
}
$newcount = 0;
if ($this->user->rights >= 6 && $new_adm) {
$newcount = $new_adm;
} elseif ($new) {
$newcount = $new;
}
return $album . ' / ' . $photo .
($newcount ? ' / <span class="red"><a href="' . $this->homeurl . '/album/?act=top">+' . $newcount . '</a></span>' : '');
}
/**
* Счетчик загруз центра
*
* @return string
* @deprecated use downloadsCounters
* TODO: содержимое downloadsCounters перенести в этот метод после проверки на использование
*/
public function downloads()
{
$file = CACHE_PATH . 'count-downloads.cache';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$total = $res['total'] ?? 0;
$new = $res['new'] ?? 0;
$mod = $res['mod'] ?? 0;
} else {
$old = time() - (3 * 24 * 3600);
$total = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '2'")->fetchColumn();
$new = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '2' AND `time` > '${old}'")->fetchColumn();
$mod = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '3'")->fetchColumn();
file_put_contents($file, json_encode(['total' => $total, 'new' => $new, 'mod' => $mod]), LOCK_EX);
}
if ($new > 0) {
$total .= ' / <span class="red"><a href="downloads/?act=new_files">+' . $new . '</a></span>';
}
if ($this->user->rights == 4 || $this->user->rights >= 6) {
if ($mod) {
$total .= ' / <span class="red"><a href="downloads/?act=mod_files">м. ' . $mod . '</a></span>';
}
}
return $total;
}
/**
* Статистика Форума
*
* @return string
* @deprecated use forumCounters
* TODO: содержимое forumCounters перенести в этот метод после проверки на использование
*/
public function forum()
{
$file = CACHE_PATH . 'count-forum.cache';
$new = '';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$top = $res['top'];
$msg = $res['msg'];
} else {
$top = $this->db->query("SELECT COUNT(*) FROM `forum_topic` WHERE `deleted` != '1' OR deleted IS NULL")->fetchColumn();
$msg = $this->db->query("SELECT COUNT(*) FROM `forum_messages` WHERE `deleted` != '1' OR deleted IS NULL")->fetchColumn();
file_put_contents($file, json_encode(['top' => $top, 'msg' => $msg]), LOCK_EX);
}
if ($this->user->isValid() && ($new_msg = $this->forumNew()) > 0) {
$new = ' / <span class="red"><a href="' . $this->homeurl . '/forum/?act=new">+' . $new_msg . '</a></span>';
}
return $top . ' / ' . $msg . $new;
}
/**
* Счетчик непрочитанных тем на форуме
*
* $mod = 0 Возвращает число непрочитанных тем
* $mod = 1 Выводит ссылки на непрочитанное
*
* @param int $mod
* @return bool|int|string
* @deprecated use forumUnreadCount
*/
public function forumNew($mod = 0)
{
if ($this->user->isValid()) {
$total = $this->db->query(
"SELECT COUNT(*) FROM `forum_topic`
LEFT JOIN `cms_forum_rdm` ON `forum_topic`.`id` = `cms_forum_rdm`.`topic_id` AND `cms_forum_rdm`.`user_id` = '" . $this->user->id . "'
WHERE (`cms_forum_rdm`.`topic_id` IS NULL OR `forum_topic`.`last_post_date` > `cms_forum_rdm`.`time`)
" . ($this->user->rights >= 7 ? '' : ' AND (`forum_topic`.`deleted` != 1 OR `forum_topic`.`deleted` IS NULL)') . '
'
)->fetchColumn();
if ($mod) {
return $total ? '<a href="?act=new" class="pr-2">' . d__('system', 'Unread') . '</a><span class="badge badge-pill badge-danger mr-3">' . $total . '</span>' : '';
}
return $total;
}
if ($mod) {
return '<a href="?act=new">' . d__('system', 'Last activity') . '</a>';
}
return false;
}
/**
* @return int|mixed
*/
public function forumUnreadCount()
{
$total = 0;
if ($this->user->isValid()) {
$total = $this->db->query(
"SELECT COUNT(*) FROM `forum_topic`
LEFT JOIN `cms_forum_rdm` ON `forum_topic`.`id` = `cms_forum_rdm`.`topic_id` AND `cms_forum_rdm`.`user_id` = '" . $this->user->id . "'
WHERE (`cms_forum_rdm`.`topic_id` IS NULL OR `forum_topic`.`last_post_date` > `cms_forum_rdm`.`time`)
" . ($this->user->rights >= 7 ? '' : ' AND (`forum_topic`.`deleted` != 1 OR `forum_topic`.`deleted` IS NULL)') . '
'
)->fetchColumn();
}
return $total;
}
/**
* Статистика библиотеки
*
* @return string
* @deprecated use libraryCounters
* TODO: содержимое libraryCounters перенести в этот метод после проверки на использование
*/
public function library()
{
$file = CACHE_PATH . 'count-library.cache';
if (file_exists($file) && filemtime($file) > (time() - 3200)) {
$res = json_decode(file_get_contents($file), true);
$total = $res['total'];
$new = $res['new'];
$mod = $res['mod'];
} else {
$total = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `premod` = 1')->fetchColumn();
$new = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `time` > ' . (time() - 259200) . ' AND `premod` = 1')->fetchColumn();
$mod = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `premod` = 0')->fetchColumn();
file_put_contents($file, json_encode(['total' => $total, 'new' => $new, 'mod' => $mod]), LOCK_EX);
}
if ($new) {
$total .= ' / <span class="red"><a href="' . $this->homeurl . '/library/?act=new">+' . $new . '</a></span>';
}
if (($this->user->rights == 5 || $this->user->rights >= 6) && $mod) {
$total .= ' / <span class="red"><a href="' . $this->homeurl . '/library/?act=premod">M:' . $mod . '</a></span>';
}
return $total;
}
/**
* Счетчик посетителей онлайн
*
* @return string
*/
public function online()
{
$file = CACHE_PATH . 'count-online.cache';
if (file_exists($file) && filemtime($file) > (time() - 10)) {
$res = json_decode(file_get_contents($file), true);
$users = $res['users'];
$guests = $res['guests'];
} else {
$users = $this->db->query('SELECT COUNT(*) FROM `users` WHERE `lastdate` > ' . (time() - 300))->fetchColumn();
$guests = $this->db->query('SELECT COUNT(*) FROM `cms_sessions` WHERE `lastdate` > ' . (time() - 300))->fetchColumn();
file_put_contents($file, json_encode(['users' => $users, 'guests' => $guests]), LOCK_EX);
}
return $users . ' / ' . $guests;
}
/**
* Количество зарегистрированных пользователей
*
* @return string
* @deprecated use usersCounters
* TODO: содержимое usersCounters перенести в этот метод после проверки на использование
*/
public function users(): string
{
$counter = $this->usersCounters();
return $counter['total'] . ($counter['new'] ? ' / <span class="red">+' . $counter['new'] . '</span>' : '');
}
/**
* Количество непрочитанных личных сообщений
*
* @return mixed
*/
public function mail()
{
$new_mail = 0;
if (! $this->user->isValid()) {
$new_mail = $this->db->query(
"SELECT COUNT(*) FROM `cms_mail`
LEFT JOIN `cms_contact` ON `cms_mail`.`user_id`=`cms_contact`.`from_id` AND `cms_contact`.`user_id`='" . $this->user->id . "'
WHERE `cms_mail`.`from_id`='" . $this->user->id . "'
AND `cms_mail`.`sys`='0'
AND `cms_mail`.`read`='0'
AND `cms_mail`.`delete`!='" . $this->user->id . "'
AND `cms_contact`.`ban`!='1'"
)->fetchColumn();
}
return $new_mail;
}
/**
* Метод возвращает количество тем, сообщений и непрочитанных сообщений на форуме
*
* @return array
*/
public function forumCounters(): array
{
$file = CACHE_PATH . 'counters-forum.cache';
$new_messages = 0;
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$topics = $res['topics'];
$message = $res['messages'];
} else {
$topics = $this->db->query(
"SELECT COUNT(*)
FROM `forum_topic`
WHERE `deleted` != '1'
OR deleted IS NULL"
)->fetchColumn();
$message = $this->db->query(
"SELECT COUNT(*)
FROM `forum_messages`
WHERE `deleted` != '1'
OR deleted IS NULL"
)->fetchColumn();
file_put_contents($file, json_encode(['topics' => $topics, 'messages' => $message]), LOCK_EX);
}
if ($this->user->isValid() && ($new_msg = $this->forumNew()) > 0) {
$new_messages = $new_msg;
}
return [
'topics' => $topics,
'messages' => $message,
'new_messages' => $new_messages,
];
}
/**
* Счетчики гостевой и админклуба
*
* @param int $mod
* @return array
*/
public function guestbookCounters($mod = 0): array
{
$guestbook = $this->db->query('SELECT COUNT(*) FROM `guest` WHERE `adm` = 0 AND `time` > ' . (time() - 86400))->fetchColumn();
$admin_club = 0;
if ($this->user->rights >= 1) {
$admin_club = $this->db->query('SELECT COUNT(*) FROM `guest` WHERE `adm`=\'1\' AND `time`> ' . (time() - 86400))->fetchColumn();
}
return [
'guestbook' => $guestbook,
'admin_club' => $admin_club,
];
}
/**
* Счетчики загруз-центра
*
* @return array
*/
public function downloadsCounters(): array
{
$file = CACHE_PATH . 'counters-downloads.cache';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$total = $res['total'] ?? 0;
$new = $res['new'] ?? 0;
} else {
$old = time() - (3 * 24 * 3600);
$total = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '2'")->fetchColumn();
$new = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '2' AND `time` > '${old}'")->fetchColumn();
file_put_contents($file, json_encode(['total' => $total, 'new' => $new]), LOCK_EX);
}
return [
'total' => $total,
'new' => $new,
];
}
/**
* Статистика библиотеки
*
* @return array
*/
public function libraryCounters(): array
{
$file = CACHE_PATH . 'counters-library.cache';
if (file_exists($file) && filemtime($file) > (time() - 3200)) {
$res = json_decode(file_get_contents($file), true);
$total = $res['total'];
$new = $res['new'];
} else {
$total = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `premod` = 1')->fetchColumn();
$new = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `time` > ' . (time() - 259200) . ' AND `premod` = 1')->fetchColumn();
file_put_contents($file, json_encode(['total' => $total, 'new' => $new]), LOCK_EX);
}
return [
'total' => $total,
'new' => $new,
];
}
/**
* Количество зарегистрированных пользователей
*
* @return array
*/
public function usersCounters(): array
{
$file = CACHE_PATH . 'counters-users.dat';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$cache = json_decode(file_get_contents($file), true);
$total = $cache['total'];
$new = $cache['new'];
} else {
$total = (new Users\User())->approved()->count();
$new = (new Users\User())->approved()->where('datereg', '>', (time() - 86400))->count();
file_put_contents($file, json_encode(['total' => $total, 'new' => $new]), LOCK_EX);
}
return [
'total' => $total,
'new' => $new,
];
}
/**
* Счетчик Фотоальбомов пользователей
*
* @return array
*/
public function albumCounters(): array
{
$file = CACHE_PATH . 'counters-albums.cache';
if (file_exists($file) && filemtime($file) > (time() - 600)) {
$res = json_decode(file_get_contents($file), true);
$album = $res['album'];
$photo = $res['photo'];
$new = $res['new'];
$new_adm = $res['new_adm'];
} else {
$album = $this->db->query('SELECT COUNT(DISTINCT `user_id`) FROM `cms_album_files`')->fetchColumn();
$photo = $this->db->query('SELECT COUNT(*) FROM `cms_album_files`')->fetchColumn();
$new = $this->db->query('SELECT COUNT(*) FROM `cms_album_files` WHERE `time` > ' . (time() - 259200) . ' AND `access` = 4')->fetchColumn();
$new_adm = $this->db->query('SELECT COUNT(*) FROM `cms_album_files` WHERE `time` > ' . (time() - 259200) . ' AND `access` > 1')->fetchColumn();
file_put_contents($file, json_encode(['album' => $album, 'photo' => $photo, 'new' => $new, 'new_adm' => $new_adm]), LOCK_EX);
}
if ($this->user->rights >= 6 && $new_adm) {
$newcount = $new_adm;
} elseif ($new) {
$newcount = $new;
}
return [
'album' => $album,
'photo' => $photo,
'new' => $newcount ?? 0,
];
}
/**
* Счетчик всех новостей
*
* @deprecated
* @return array
*/
public function news(): array
{
return [
'total' => 0,
'new' => 0,
];
}
/**
* Уведомления
*
* @return array
*/
public function notifications(): array
{
$notifications = [];
if (! $this->user->isValid()) {
return $notifications;
}
if ($this->user->rights >= 7) {
$notifications['reg_total'] = $this->db->query("SELECT COUNT(*) FROM `users` WHERE `preg`='0'")->fetchColumn();
$notifications['library_mod'] = $this->db->query('SELECT COUNT(*) FROM `library_texts` WHERE `premod` = 0')->fetchColumn();
$notifications['downloads_mod'] = $this->db->query("SELECT COUNT(*) FROM `download__files` WHERE `type` = '3'")->fetchColumn();
}
if (! empty($this->user->ban)) {
$notifications['ban'] = 1;
}
if ($this->user->comm_count > $this->user->comm_old) {
$notifications['guestbook_comments'] = ($this->user->comm_count - $this->user->comm_old);
}
$notifications['new_mail'] = $this->db->query(
"SELECT COUNT(*) FROM `cms_mail`
LEFT JOIN `cms_contact` ON `cms_mail`.`user_id`=`cms_contact`.`from_id` AND `cms_contact`.`user_id`='" . $this->user->id . "'
WHERE `cms_mail`.`from_id`='" . $this->user->id . "'
AND `cms_mail`.`sys`='0'
AND `cms_mail`.`read`='0'
AND `cms_mail`.`delete`!='" . $this->user->id . "'
AND `cms_contact`.`ban`!='1'"
)->fetchColumn();
$notifications['new_album_comm'] = $this->db->query('SELECT COUNT(*) FROM `cms_album_files` WHERE `user_id` = \'' . $this->user->id . '\' AND `unread_comments` = 1')->fetchColumn();
// Временный костыль для обратной совместимости
$default = ['show_forum_unread' => false];
$settings = ! empty($this->user->notification_settings) ? json_decode($this->user->notification_settings, true) : [];
$notification_settings = array_merge($default, $settings);
if ($notification_settings['show_forum_unread']) {
$forum_counters = $this->forumCounters();
$notifications['forum_new'] = $forum_counters['new_messages'];
}
$notifications['notifications'] = (new Notification())->unread()->count();
$notifications['all'] = array_sum($notifications);
return $notifications;
}
/**
* Метод получает массив счетчиков различных систем аналитики
*
* @return array
*/
public function counters(): array
{
$counters = [];
$req = $this->db->query('SELECT * FROM `cms_counters` WHERE `switch` = 1 ORDER BY `sort`');
if ($req->rowCount()) {
while ($res = $req->fetch()) {
$link1 = ($res['mode'] === 1 || $res['mode'] === 2) ? $res['link1'] : $res['link2'];
$link2 = $res['mode'] === 2 ? $res['link1'] : $res['link2'];
$count = defined('_IS_HOMEPAGE') ? $link1 : $link2;
if (! empty($count)) {
$counters[] = $count;
}
}
}
return $counters;
}
}