Вход Регистрация
Файл: 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 0int $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 0int $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 0int $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(000, (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 0int $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 0int $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 = [2345671];
        
$labels = ['Пн''Вт''Ср''Чт''Пт''Сб''Вс'];
        
$data = [];
        foreach (
$order as $i => $dw) {
            
$data[$labels[$i]] = $byMysql[$dw] ?? 0;
        }
        return 
$data;
    }

    public static function 
periodTotals(int $platformIdint $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 round($sumI $sumT 1002) : 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 7int $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($up0$limit),
            
'down' => array_slice($down0$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 24int $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 24int $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'] * 1002);
    }

    
/** Growth % hosts today vs yesterday from logs */
    
public static function hostGrowth(int $platformId 0): array
    {
        
$today self::dailyHosts($platformId2);
        
$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 round(($t $y) / $y 1001) : ($t 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 $userIdint $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($labels0);
        
$hits array_fill_keys($labels0);
        
$ins array_fill_keys($labels0);
        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
Реклама