Вход Регистрация
Файл: new_top/core/classes/Stats.php
Строк: 376
<?php
/**
 * Statistics helpers — daily series, device split, online
 */

declare(strict_types=1);

class 
Stats
{
    
/** Last N days labels (Y-m-d) */
    
public static function dayLabels(int $days = 14): array
    {
        
$labels = [];
        for (
$i = $days - 1; $i >= 0; $i--) {
            
$labels[] = date('Y-m-d', strtotime("-{$i} days"));
        }
        return 
$labels;
    }

    
/**
     * Daily unique hosts from hs table for platform (0 = all)
     * @return array date => count
     */
    
public static function dailyHosts(int $platformId = 0, int $days = 14): array
    {
        
$since = strtotime('-' . ($days - 1) . ' days 00:00:00');
        
$sql = 'SELECT FROM_UNIXTIME(time, "%Y-%m-%d") AS d, COUNT(DISTINCT ip) AS c
                FROM hs WHERE time >= ?'
;
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        
$sql .= ' GROUP BY d ORDER BY d';
        
$rows = Database::fetchAll($sql, $params);
        
$map = [];
        foreach (
$rows as $r) {
            
$map[$r['d']] = (int)$r['c'];
        }
        
$out = [];
        foreach (
self::dayLabels($days) as $d) {
            
$out[$d] = $map[$d] ?? 0;
        }
        return 
$out;
    }

    
/** Daily total hits from ht */
    
public static function dailyHits(int $platformId = 0, int $days = 14): array
    {
        
$since = strtotime('-' . ($days - 1) . ' days 00:00:00');
        
$sql = 'SELECT FROM_UNIXTIME(time, "%Y-%m-%d") AS d, COUNT(*) AS c
                FROM ht WHERE time >= ?'
;
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        
$sql .= ' GROUP BY d ORDER BY d';
        
$rows = Database::fetchAll($sql, $params);
        
$map = [];
        foreach (
$rows as $r) {
            
$map[$r['d']] = (int)$r['c'];
        }
        
$out = [];
        foreach (
self::dayLabels($days) as $d) {
            
$out[$d] = $map[$d] ?? 0;
        }
        return 
$out;
    }

    
/** Device split for platform or global */
    
public static function deviceSplit(int $platformId = 0): array
    {
        if (
$platformId > 0) {
            
$row = Database::fetch('SELECT mb, pc FROM platforms WHERE id = ?', [$platformId]);
            return [
                
'mobile' => (int)($row['mb'] ?? 0),
                
'pc'     => (int)($row['pc'] ?? 0),
            ];
        }
        
$row = Database::fetch('SELECT COALESCE(SUM(mb),0) AS mb, COALESCE(SUM(pc),0) AS pc FROM platforms');
        return [
            
'mobile' => (int)($row['mb'] ?? 0),
            
'pc'     => (int)($row['pc'] ?? 0),
        ];
    }

    public static function 
onlineCount(int $platformId = 0, int $windowSec = 600): int
    
{
        
$sql = 'SELECT COUNT(*) FROM on_log WHERE time > ?';
        
$params = [time() - $windowSec];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        return (int) 
Database::fetchColumn($sql, $params);
    }

    public static function 
topPlatforms(int $limit = 10): array
    {
        return 
Database::fetchAll(
            
'SELECT id, url, hs, ht, mb, pc FROM platforms WHERE mode = 0 AND ban = 0 ORDER BY hs DESC LIMIT ' . (int)$limit
        
);
    }

    public static function 
summary(): array
    {
        return [
            
'platforms' => (int) Database::fetchColumn('SELECT COUNT(*) FROM platforms'),
            
'active'    => (int) Database::fetchColumn('SELECT COUNT(*) FROM platforms WHERE mode = 0 AND ban = 0'),
            
'banned'    => (int) Database::fetchColumn('SELECT COUNT(*) FROM platforms WHERE ban = 1'),
            
'mod'       => (int) Database::fetchColumn('SELECT COUNT(*) FROM platforms WHERE mode = 1'),
            
'users'     => (int) Database::fetchColumn('SELECT COUNT(*) FROM user'),
            
'hs'        => (int) Database::fetchColumn('SELECT COALESCE(SUM(hs),0) FROM platforms'),
            
'ht'        => (int) Database::fetchColumn('SELECT COALESCE(SUM(ht),0) FROM platforms'),
            
'in'        => (int) Database::fetchColumn('SELECT COALESCE(SUM(in_count),0) FROM platforms'),
            
'online'    => self::onlineCount(),
            
'cats'      => (int) Database::fetchColumn('SELECT COUNT(*) FROM cat'),
        ];
    }

    
/** Short day labels for charts (d.m) */
    
public static function shortLabels(array $ymdKeys): array
    {
        
$out = [];
        foreach (
$ymdKeys as $d) {
            
$out[] = date('d.m', strtotime($d));
        }
        return 
$out;
    }

    
/** Hits by hour for today (0..23) for platform or global */
    
public static function hourlyHits(int $platformId = 0): array
    {
        
$dayStart = mktime(0, 0, 0, (int)date('m'), (int)date('d'), (int)date('Y'));
        
$sql = 'SELECT HOUR(FROM_UNIXTIME(time)) AS h, COUNT(*) AS c FROM ht WHERE time >= ?';
        
$params = [$dayStart];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        
$sql .= ' GROUP BY h';
        
$rows = Database::fetchAll($sql, $params);
        
$map = [];
        foreach (
$rows as $r) {
            
$map[(int)$r['h']] = (int)$r['c'];
        }
        
$out = [];
        for (
$h = 0; $h < 24; $h++) {
            
$out[$h] = $map[$h] ?? 0;
        }
        return 
$out;
    }

    
/** Rank position by hosts among active platforms */
    
public static function rankPosition(int $platformId): int
    
{
        
$pf = Database::fetch('SELECT hs, ht FROM platforms WHERE id = ? AND mode = 0 AND ban = 0', [$platformId]);
        if (!
$pf) {
            return 
0;
        }
        
$better = (int) Database::fetchColumn(
            
'SELECT COUNT(*) FROM platforms WHERE mode = 0 AND ban = 0 AND (hs > ? OR (hs = ? AND ht > ?) OR (hs = ? AND ht = ? AND id < ?))',
            [(int)
$pf['hs'], (int)$pf['hs'], (int)$pf['ht'], (int)$pf['hs'], (int)$pf['ht'], $platformId]
        );
        return 
$better + 1;
    }

    public static function 
latestNews(int $limit = 5): array
    {
        try {
            return 
Database::fetchAll(
                
'SELECT * FROM news WHERE active = 1 ORDER BY time_add DESC LIMIT ' . (int)$limit
            
);
        } catch (
Throwable $e) {
            return [];
        }
    }

    
/** Daily inbound clicks from in_log */
    
public static function dailyIn(int $platformId = 0, int $days = 14): array
    {
        
$since = strtotime('-' . ($days - 1) . ' days 00:00:00');
        
$sql = 'SELECT FROM_UNIXTIME(time, "%Y-%m-%d") AS d, COUNT(*) AS c FROM in_log WHERE time >= ?';
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        
$sql .= ' GROUP BY d';
        
$rows = Database::fetchAll($sql, $params);
        
$map = [];
        foreach (
$rows as $r) {
            
$map[$r['d']] = (int)$r['c'];
        }
        
$out = [];
        foreach (
self::dayLabels($days) as $d) {
            
$out[$d] = $map[$d] ?? 0;
        }
        return 
$out;
    }

    
/** Hits by weekday (1=Mon..7=Sun) for last N days */
    
public static function weekdayHits(int $platformId = 0, int $days = 28): array
    {
        
$since = strtotime('-' . ($days - 1) . ' days 00:00:00');
        
$sql = 'SELECT DAYOFWEEK(FROM_UNIXTIME(time)) AS dw, COUNT(*) AS c FROM ht WHERE time >= ?';
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        
$sql .= ' GROUP BY dw';
        
$rows = Database::fetchAll($sql, $params);
        
// MySQL DAYOFWEEK: 1=Sun .. 7=Sat → remap to Mon-first labels
        
$byMysql = [];
        foreach (
$rows as $r) {
            
$byMysql[(int)$r['dw']] = (int)$r['c'];
        }
        
// order Mon..Sun → mysql 2,3,4,5,6,7,1
        
$order = [2, 3, 4, 5, 6, 7, 1];
        
$labels = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
        
$data = [];
        foreach (
$order as $i => $dw) {
            
$data[$labels[$i]] = $byMysql[$dw] ?? 0;
        }
        return 
$data;
    }

    public static function 
periodTotals(int $platformId, int $days): array
    {
        
$hosts = self::dailyHosts($platformId, $days);
        
$hits = self::dailyHits($platformId, $days);
        
$ins = self::dailyIn($platformId, $days);
        
$sumH = array_sum($hosts);
        
$sumT = array_sum($hits);
        
$sumI = array_sum($ins);
        
$ctr = $sumT > 0 ? round($sumI / $sumT * 100, 2) : 0.0;
        return [
            
'hosts' => $sumH,
            
'hits'  => $sumT,
            
'in'    => $sumI,
            
'ctr'   => $ctr,
        ];
    }

    
/** Save today's ranks for all active platforms */
    
public static function snapshotRanks(): int
    
{
        
$day = date('Y-m-d');
        
$list = Database::fetchAll(
            
'SELECT id, hs, ht FROM platforms WHERE mode = 0 AND ban = 0 ORDER BY hs DESC, ht DESC, id ASC'
        
);
        
$n = 0;
        foreach (
$list as $i => $p) {
            
$rank = $i + 1;
            
Database::query(
                
'INSERT INTO rank_snap (pf, day, rank, hs, ht) VALUES (?, ?, ?, ?, ?)
                 ON DUPLICATE KEY UPDATE rank = VALUES(rank), hs = VALUES(hs), ht = VALUES(ht)'
,
                [(int)
$p['id'], $day, $rank, (int)$p['hs'], (int)$p['ht']]
            );
            
$n++;
        }
        return 
$n;
    }

    
/** Rank delta vs yesterday snapshot (negative = rose) */
    
public static function rankDelta(int $platformId): ?array
    {
        
$today = self::rankPosition($platformId);
        
$y = date('Y-m-d', strtotime('-1 day'));
        try {
            
$prev = Database::fetch('SELECT rank, hs FROM rank_snap WHERE pf = ? AND day = ?', [$platformId, $y]);
        } catch (
Throwable $e) {
            
$prev = null;
        }
        if (!
$prev) {
            return [
'rank' => $today, 'delta' => null, 'prev' => null];
        }
        
$prevRank = (int)$prev['rank'];
        return [
            
'rank' => $today,
            
'prev' => $prevRank,
            
'delta' => $prevRank - $today, // positive = improved (moved up)
        
];
    }

    public static function 
categorySummary(): array
    {
        return 
Database::fetchAll(
            
'SELECT c.id, c.name,
                COUNT(p.id) AS pf_cnt,
                COALESCE(SUM(p.hs),0) AS hs,
                COALESCE(SUM(p.ht),0) AS ht,
                COALESCE(SUM(p.in_count),0) AS inn
             FROM cat c
             LEFT JOIN platforms p ON p.cat_id = c.id AND p.mode = 0 AND p.ban = 0
             GROUP BY c.id, c.name
             ORDER BY hs DESC, c.sort'
        
);
    }

    
/** Platforms with no hits in last N days */
    
public static function stalePlatforms(int $days = 7, int $limit = 30): array
    {
        
$since = time() - $days * 86400;
        return 
Database::fetchAll(
            
'SELECT p.id, p.url, p.hs, p.ht, p.user_id, p.time_add
             FROM platforms p
             WHERE p.mode = 0 AND p.ban = 0
               AND NOT EXISTS (SELECT 1 FROM ht WHERE ht.pf = p.id AND ht.time >= ?)
             ORDER BY p.time_add DESC
             LIMIT ' 
. (int)$limit,
            [
$since]
        );
    }

    public static function 
movers(int $limit = 10): array
    {
        
$y = date('Y-m-d', strtotime('-1 day'));
        try {
            
$rows = Database::fetchAll(
                
'SELECT s.pf, s.rank AS prev_rank, p.url, p.hs, p.ht
                 FROM rank_snap s
                 INNER JOIN platforms p ON p.id = s.pf AND p.mode = 0 AND p.ban = 0
                 WHERE s.day = ?
                 ORDER BY p.hs DESC
                 LIMIT 200'
,
                [
$y]
            );
        } catch (
Throwable $e) {
            return [
'up' => [], 'down' => []];
        }
        
$up = [];
        
$down = [];
        foreach (
$rows as $r) {
            
$cur = self::rankPosition((int)$r['pf']);
            if (
$cur < 1) {
                continue;
            }
            
$delta = (int)$r['prev_rank'] - $cur;
            
$item = [
                
'id' => (int)$r['pf'],
                
'url' => $r['url'],
                
'rank' => $cur,
                
'prev' => (int)$r['prev_rank'],
                
'delta' => $delta,
            ];
            if (
$delta > 0) {
                
$up[] = $item;
            } elseif (
$delta < 0) {
                
$down[] = $item;
            }
        }
        
usort($up, static function ($a, $b) { return $b['delta'] <=> $a['delta']; });
        
usort($down, static function ($a, $b) { return $a['delta'] <=> $b['delta']; });
        return [
            
'up' => array_slice($up, 0, $limit),
            
'down' => array_slice($down, 0, $limit),
        ];
    }

    
/** Global daily hosts/hits for admin overview */
    
public static function globalDaily(int $days = 14): array
    {
        return [
            
'hosts' => self::dailyHosts(0, $days),
            
'hits'  => self::dailyHits(0, $days),
            
'in'    => self::dailyIn(0, $days),
        ];
    }

    
/** Top referrers approx from in_log by platform (most inbound) */
    
public static function topByIn(int $limit = 10): array
    {
        return 
Database::fetchAll(
            
'SELECT id, url, in_count, hs, ht FROM platforms WHERE mode = 0 AND ban = 0 ORDER BY in_count DESC LIMIT ' . (int)$limit
        
);
    }

    
/** New platforms registered last N days */
    
public static function newPlatformsCount(int $days = 7): int
    
{
        
$since = time() - $days * 86400;
        return (int) 
Database::fetchColumn(
            
'SELECT COUNT(*) FROM platforms WHERE time_add >= ?',
            [
$since]
        );
    }

    
/** Hits last N hours (rolling) */
    
public static function hitsLastHours(int $hours = 24, int $platformId = 0): int
    
{
        
$since = time() - $hours * 3600;
        
$sql = 'SELECT COUNT(*) FROM ht WHERE time >= ?';
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        return (int) 
Database::fetchColumn($sql, $params);
    }

    
/** Unique hosts last N hours */
    
public static function hostsLastHours(int $hours = 24, int $platformId = 0): int
    
{
        
$since = time() - $hours * 3600;
        
$sql = 'SELECT COUNT(DISTINCT ip) FROM ht WHERE time >= ?';
        
$params = [$since];
        if (
$platformId > 0) {
            
$sql .= ' AND pf = ?';
            
$params[] = $platformId;
        }
        return (int) 
Database::fetchColumn($sql, $params);
    }

    
/** Peak hour today */
    
public static function peakHour(int $platformId = 0): array
    {
        
$hourly = self::hourlyHits($platformId);
        
$peakH = 0;
        
$peakV = 0;
        foreach (
$hourly as $h => $v) {
            if (
$v > $peakV) {
                
$peakV = $v;
                
$peakH = (int)$h;
            }
        }
        return [
'hour' => $peakH, 'hits' => $peakV];
    }

    
/** CTR for platform: in / hits * 100 today-ish using totals */
    
public static function ctr(int $platformId): float
    
{
        
$pf = Database::fetch('SELECT ht, in_count FROM platforms WHERE id = ?', [$platformId]);
        if (!
$pf || (int)$pf['ht'] < 1) {
            return 
0.0;
        }
        return 
round((int)$pf['in_count'] / (int)$pf['ht'] * 100, 2);
    }

    
/** Growth % hosts today vs yesterday from logs */
    
public static function hostGrowth(int $platformId = 0): array
    {
        
$today = self::dailyHosts($platformId, 2);
        
$keys = array_keys($today);
        if (
count($keys) < 2) {
            return [
'today' => 0, 'yesterday' => 0, 'pct' => 0];
        }
        
$y = (int)$today[$keys[0]];
        
$t = (int)$today[$keys[1]];
        
$pct = $y > 0 ? round(($t - $y) / $y * 100, 1) : ($t > 0 ? 100.0 : 0.0);
        return [
'today' => $t, 'yesterday' => $y, 'pct' => $pct];
    }

    
/** User totals for all their platforms */
    
public static function userSummary(int $userId): array
    {
        
$row = Database::fetch(
            
'SELECT COUNT(*) AS n,
                    COALESCE(SUM(hs),0) AS hs,
                    COALESCE(SUM(ht),0) AS ht,
                    COALESCE(SUM(in_count),0) AS inc,
                    COALESCE(SUM(hs_all),0) AS hs_all,
                    COALESCE(SUM(ht_all),0) AS ht_all
             FROM platforms WHERE user_id = ? AND ban = 0'
,
            [
$userId]
        );
        return 
$row ?: ['n' => 0, 'hs' => 0, 'ht' => 0, 'inc' => 0, 'hs_all' => 0, 'ht_all' => 0];
    }

    
/** Combined daily for all platforms of a user */
    
public static function userDaily(int $userId, int $days = 14): array
    {
        
$ids = Database::fetchAll('SELECT id FROM platforms WHERE user_id = ? AND ban = 0', [$userId]);
        
$labels = self::dayLabels($days);
        
$hosts = array_fill_keys($labels, 0);
        
$hits = array_fill_keys($labels, 0);
        
$ins = array_fill_keys($labels, 0);
        foreach (
$ids as $row) {
            
$id = (int)$row['id'];
            foreach (
self::dailyHosts($id, $days) as $d => $v) {
                
$hosts[$d] = ($hosts[$d] ?? 0) + (int)$v;
            }
            foreach (
self::dailyHits($id, $days) as $d => $v) {
                
$hits[$d] = ($hits[$d] ?? 0) + (int)$v;
            }
            foreach (
self::dailyIn($id, $days) as $d => $v) {
                
$ins[$d] = ($ins[$d] ?? 0) + (int)$v;
            }
        }
        return [
'hosts' => $hosts, 'hits' => $hits, 'in' => $ins];
    }
}
Онлайн: 1
Реклама