Your IP : 216.73.216.23


Current Path : /home/www/hallgroupsolutions.com/home/
Upload File :
Current File : /home/www/hallgroupsolutions.com/home/admin.php

<?php
// =============================================
// admin.php - VERSI FINAL (AJAX JSON murni, dashboard rapi)
// =============================================

// Bersihkan buffer output sejak awal
if (ob_get_length()) ob_end_clean();

// Header anti-cache global
header('Cache-Control: no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: 0');

// Konfigurasi session lebih kompatibel
ini_set('session.use_strict_mode', 0);
ini_set('session.cookie_samesite', 'Lax');
session_start();

// ==================== PASSWORD ADMIN ====================
// GANTI PASSWORD INI SEKARANG JUGA!
$ADMIN_PASS = 'Cacad2424';   // ← GANTI DI SINI menjadi password kamu sendiri

// =============================================
// AJAX ENDPOINT - DIJALANKAN PERTAMA (sebelum output HTML)
// =============================================
if (isset($_GET['ajax']) && $_GET['ajax'] === '1') {
    header('Content-Type: application/json; charset=utf-8');

    if (empty($_SESSION['admin_logged_in'])) {
        echo json_encode(['error' => 'Session expired. Silakan login ulang.']);
        exit;
    }

    try {
        $db = new PDO('sqlite:visitors.db');
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $total  = $db->query("SELECT COUNT(*) FROM visits")->fetchColumn() ?: 0;
        $bots   = $db->query("SELECT COUNT(*) FROM visits WHERE is_bot = 1")->fetchColumn() ?: 0;
        $humans = $total - $bots;

        $stmt = $db->query("SELECT * FROM visits ORDER BY timestamp DESC LIMIT 500");
        $rows = [];

        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $bot_label = $row['is_bot'] ? '<span class="badge bg-danger">YA</span>' : '<span class="badge bg-success">Tidak</span>';
            $params = $row['query_params'] && $row['query_params'] !== '[]' 
                ? htmlspecialchars(substr($row['query_params'], 0, 150)) . (strlen($row['query_params']) > 150 ? '...' : '') 
                : '-';

            $rows[] = [
                'timestamp'   => $row['timestamp'] ?? '-',
                'ip'          => $row['ip'] ?? '-',
                'user_agent'  => htmlspecialchars($row['user_agent'] ?? '-'),
                'bot_label'   => $bot_label,
                'request_uri' => htmlspecialchars($row['request_uri'] ?? '-'),
                'params'      => $params
            ];
        }

        echo json_encode(compact('total', 'bots', 'humans', 'rows'));
    } catch (Exception $e) {
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }
    exit; // PASTIKAN EXIT DI SINI - AGAR TIDAK CETAK HTML
}

// =============================================
// HANDLE DOWNLOAD TXT
// =============================================
if (isset($_GET['download']) && !empty($_SESSION['admin_logged_in'])) {
    $type = $_GET['download'];
    $filename_prefix = ($type === 'human') ? 'visitor_nyata' : 'bot_cloud';

    try {
        $db = new PDO('sqlite:visitors.db');
        $where = ($type === 'human') ? "WHERE is_bot = 0" : "WHERE is_bot = 1";
        $stmt = $db->query("SELECT * FROM visits $where ORDER BY timestamp DESC");
        $total_filtered = $db->query("SELECT COUNT(*) FROM visits $where")->fetchColumn() ?: 0;

        header('Content-Type: text/plain; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filename_prefix . '_log_' . date('Y-m-d_H-i-s') . '.txt"');
        header('Cache-Control: no-cache, no-store, must-revalidate');

        echo "=== Log " . (($type === 'human') ? 'Visitor Nyata (Manusia)' : 'Bot & Cloud ISP') . " ===\n";
        echo "Generated: " . date('Y-m-d H:i:s') . " WIB\n";
        echo "Total records: $total_filtered\n\n";

        echo str_pad("Waktu", 20) . " | " .
             str_pad("IP", 18) . " | " .
             str_pad("User-Agent", 70) . " | " .
             "Link Diklik | Parameter\n";
        echo str_repeat("-", 140) . "\n";

        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $ua = $row['user_agent'] ?? '-';
            $params = $row['query_params'] && $row['query_params'] !== '[]' 
                ? substr($row['query_params'], 0, 60) . (strlen($row['query_params']) > 60 ? '...' : '') 
                : '-';

            echo str_pad($row['timestamp'], 20) . " | " .
                 str_pad($row['ip'], 18) . " | " .
                 str_pad(substr($ua, 0, 67) . (strlen($ua) > 67 ? '...' : ''), 70) . " | " .
                 $row['request_uri'] . " | " .
                 $params . "\n";
        }
        exit;
    } catch (Exception $e) {
        die("Error generate file: " . htmlspecialchars($e->getMessage()));
    }
}

// =============================================
// LOGIN, LOGOUT, RESET
// =============================================
if (isset($_POST['password'])) {
    if ($_POST['password'] === $ADMIN_PASS) {
        $_SESSION['admin_logged_in'] = true;
    } else {
        $error = "Password salah!";
    }
}
if (isset($_GET['logout'])) {
    session_destroy();
    header("Location: admin.php");
    exit;
}
if (isset($_GET['reset']) && $_GET['reset'] === 'confirm' && !empty($_SESSION['admin_logged_in'])) {
    try {
        $db = new PDO('sqlite:visitors.db');
        $db->exec("DELETE FROM visits");
        $db->exec("VACUUM");
        $reset_message = "<div class='alert alert-success'>Semua log berhasil dihapus!</div>";
    } catch (Exception $e) {
        $reset_message = "<div class='alert alert-danger'>Gagal reset: " . htmlspecialchars($e->getMessage()) . "</div>";
    }
}

// Jika belum login → tampilkan form login
if (empty($_SESSION['admin_logged_in'])) {
    ?>
    <!DOCTYPE html>
    <html lang="id">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Admin Login</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body class="bg-light">
    <div class="container mt-5">
        <div class="row justify-content-center">
            <div class="col-md-4">
                <div class="card shadow">
                    <div class="card-body">
                        <h3 class="text-center mb-4">Admin Panel</h3>
                        <?php if (isset($error)) echo "<div class='alert alert-danger'>$error</div>"; ?>
                        <form method="POST">
                            <div class="mb-3">
                                <input type="password" name="password" class="form-control" placeholder="Password" required autofocus>
                            </div>
                            <button type="submit" class="btn btn-primary w-100">Masuk</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
    </body>
    </html>
    <?php
    exit;
}
?>

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Admin - Statistik Visitor</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body { background:#f8f9fa; font-family: system-ui, sans-serif; }
        .card-header { background:#0d6efd; color:white; }
        .ua-column { max-width: 380px; overflow-x: auto; white-space: nowrap; }
        #loading { display:none; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:9999; }
        .table th { text-align: center; vertical-align: middle; }
        .table td { vertical-align: middle; }
    </style>
</head>
<body>
<div class="container py-4">

    <div class="d-flex justify-content-between align-items-center mb-4">
        <h2 class="mb-0">📊 Statistik Visitor & Bot</h2>
        <div>
            <a href="#" onclick="location.reload(); return false;" class="btn btn-outline-primary me-2">Home</a>
            <a href="?download=human" class="btn btn-outline-success me-2">Download Visitor (.txt)</a>
            <a href="?download=bot" class="btn btn-outline-warning me-2">Download Bot (.txt)</a>
            <a href="?reset=confirm" class="btn btn-outline-danger me-2" onclick="return confirm('Yakin hapus semua log?');">Reset Log</a>
            <a href="?logout=1" class="btn btn-outline-secondary">Logout</a>
        </div>
    </div>

    <?php if (isset($reset_message)) echo $reset_message; ?>

    <div class="card shadow">
        <div class="card-header text-center">
            <h5 class="mb-0">Data Kunjungan Terbaru</h5>
        </div>
        <div class="card-body position-relative">
            <div id="stats" class="row text-center mb-4 g-3"></div>

            <div class="table-responsive">
                <table class="table table-hover table-bordered align-middle">
                    <thead class="table-dark">
                        <tr>
                            <th>Waktu</th>
                            <th>IP</th>
                            <th class="ua-column">User-Agent</th>
                            <th>Bot?</th>
                            <th>Link Diklik</th>
                            <th>Parameter</th>
                        </tr>
                    </thead>
                    <tbody id="tableBody">
                        <tr><td colspan="6" class="text-center py-4">Memuat data...</td></tr>
                    </tbody>
                </table>
            </div>

            <div id="loading" class="spinner-border text-primary" role="status">
                <span class="visually-hidden">Loading...</span>
            </div>
        </div>
        <div class="card-footer text-muted text-center small">
            Update otomatis setiap 15 detik | Bot termasuk deteksi reverse DNS (amazon, azure, google, oracle, dll.)
        </div>
    </div>
</div>

<script>
function loadData() {
    document.getElementById('loading').style.display = 'block';

    fetch('admin.php?ajax=1', {
        credentials: 'same-origin',
        cache: 'no-cache',
        headers: { 'Cache-Control': 'no-cache' }
    })
    .then(r => {
        if (!r.ok) throw new Error('HTTP ' + r.status);
        return r.json();
    })
    .then(data => {
        if (data.error) {
            document.getElementById('tableBody').innerHTML = `<tr><td colspan="6" class="text-danger text-center">${data.error}</td></tr>`;
            console.error('Server error:', data.error);
        } else {
            document.getElementById('stats').innerHTML = `
                <div class="col-md-4"><div class="card border-primary"><div class="card-body text-center"><h4 class="text-primary mb-0">${data.total || 0}</h4><small>Total</small></div></div></div>
                <div class="col-md-4"><div class="card border-danger"><div class="card-body text-center"><h4 class="text-danger mb-0">${data.bots || 0}</h4><small>Bot/Cloud</small></div></div></div>
                <div class="col-md-4"><div class="card border-success"><div class="card-body text-center"><h4 class="text-success mb-0">${data.humans || 0}</h4><small>Manusia</small></div></div></div>
            `;

            let tbody = document.getElementById('tableBody');
            tbody.innerHTML = '';
            (data.rows || []).forEach(row => {
                let tr = document.createElement('tr');
                tr.innerHTML = `
                    <td>${row.timestamp}</td>
                    <td><code>${row.ip}</code></td>
                    <td class="ua-column" title="${row.user_agent}">${row.user_agent}</td>
                    <td>${row.bot_label}</td>
                    <td><code>${row.request_uri}</code></td>
                    <td><small>${row.params}</small></td>
                `;
                tbody.appendChild(tr);
            });
        }
        document.getElementById('loading').style.display = 'none';
    })
    .catch(err => {
        console.error('Fetch error:', err);
        document.getElementById('tableBody').innerHTML = '<tr><td colspan="6" class="text-danger text-center">Gagal memuat data realtime. Coba refresh (F5).</td></tr>';
        document.getElementById('loading').style.display = 'none';
    });
}

loadData();
setInterval(loadData, 15000);
</script>
</body>
</html>