<?php
error_reporting(E_ALL);
ini_set('display_errors', 0);

date_default_timezone_set('Europe/Amsterdam');

require_once __DIR__ . '/vendor/autoload.php';

use GeoIp2\Database\Reader;

define('SITE_NAME', 'Bagejo.nl');
define('DB_PATH', '/var/www/private/ip_stats.sqlite');
define('GEOLITE_CITY_DB', '/var/www/private/GeoLite2-City.mmdb');
define('GEOLITE_ASN_DB', '/var/www/private/GeoLite2-ASN.mmdb');

function h($value): string
{
    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}

function getClientIp(): string
{
    $headers = [
        'HTTP_CF_CONNECTING_IP',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_REAL_IP',
        'HTTP_CLIENT_IP',
        'REMOTE_ADDR'
    ];

    foreach ($headers as $header) {
        if (!empty($_SERVER[$header])) {
            $ip = trim(explode(',', $_SERVER[$header])[0]);
            if (filter_var($ip, FILTER_VALIDATE_IP)) {
                return $ip;
            }
        }
    }

    return $_SERVER['REMOTE_ADDR'] ?? 'Onbekend';
}

function detectBrowser(string $ua): string
{
    if (stripos($ua, 'Edg/') !== false) return 'Microsoft Edge';
    if (stripos($ua, 'OPR/') !== false || stripos($ua, 'Opera') !== false) return 'Opera';
    if (stripos($ua, 'Firefox/') !== false) return 'Mozilla Firefox';
    if (stripos($ua, 'Chrome/') !== false) return 'Google Chrome';
    if (stripos($ua, 'Safari/') !== false) return 'Safari';
    return 'Onbekend';
}

function detectOs(string $ua): string
{
    if (stripos($ua, 'Windows NT 10') !== false) return 'Windows 10 / 11';
    if (stripos($ua, 'Windows') !== false) return 'Windows';
    if (stripos($ua, 'Mac OS X') !== false) return 'macOS';
    if (stripos($ua, 'iPhone') !== false) return 'iPhone / iOS';
    if (stripos($ua, 'iPad') !== false) return 'iPad / iPadOS';
    if (stripos($ua, 'Android') !== false) return 'Android';
    if (stripos($ua, 'Linux') !== false) return 'Linux';
    return 'Onbekend';
}

function geoLookup(string $ip): array
{
    $data = [
        'country' => 'Onbekend',
        'country_code' => '',
        'city' => 'Onbekend',
        'region' => 'Onbekend',
        'postal' => 'Onbekend',
        'timezone' => 'Onbekend',
        'latitude' => null,
        'longitude' => null,
        'asn' => 'Onbekend',
        'organization' => 'Onbekend',
        'network' => 'Onbekend'
    ];

    if (!filter_var($ip, FILTER_VALIDATE_IP)) {
        return $data;
    }

    try {
        if (file_exists(GEOLITE_CITY_DB)) {
            $reader = new Reader(GEOLITE_CITY_DB);
            $record = $reader->city($ip);

            $data['country'] = $record->country->names['nl'] ?? $record->country->name ?? 'Onbekend';
            $data['country_code'] = $record->country->isoCode ?? '';
            $data['city'] = $record->city->name ?? 'Onbekend';
            $data['region'] = $record->mostSpecificSubdivision->name ?? 'Onbekend';
            $data['postal'] = $record->postal->code ?? 'Onbekend';
            $data['timezone'] = $record->location->timeZone ?? 'Onbekend';
            $data['latitude'] = $record->location->latitude ?? null;
            $data['longitude'] = $record->location->longitude ?? null;
        }
    } catch (Throwable $e) {
        // GeoIP city lookup mag de pagina niet breken.
    }

    try {
        if (file_exists(GEOLITE_ASN_DB)) {
            $reader = new Reader(GEOLITE_ASN_DB);
            $record = $reader->asn($ip);

            $data['asn'] = !empty($record->autonomousSystemNumber)
                ? 'AS' . $record->autonomousSystemNumber
                : 'Onbekend';

            $data['organization'] = $record->autonomousSystemOrganization ?? 'Onbekend';
            $data['network'] = isset($record->network) ? (string)$record->network : 'Onbekend';
        }
    } catch (Throwable $e) {
        // ASN lookup mag de pagina niet breken.
    }

    return $data;
}

function getDb(): PDO
{
    $db = new PDO('sqlite:' . DB_PATH);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $db->exec("
        CREATE TABLE IF NOT EXISTS visits (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            ip TEXT,
            ip_type TEXT,
            reverse_dns TEXT,
            country TEXT,
            country_code TEXT,
            city TEXT,
            region TEXT,
            postal TEXT,
            timezone TEXT,
            latitude REAL,
            longitude REAL,
            asn TEXT,
            organization TEXT,
            network TEXT,
            browser TEXT,
            os TEXT,
            user_agent TEXT,
            accept_language TEXT,
            host TEXT,
            remote_port TEXT,
            https INTEGER,
            referer TEXT,
            created_at TEXT
        )
    ");

    return $db;
}

$ip = getClientIp();

$isIPv4 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
$isIPv6 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
$ipType = $isIPv4 ? 'IPv4' : ($isIPv6 ? 'IPv6' : 'Onbekend');

$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'Onbekend';
$browser = detectBrowser($userAgent);
$os = detectOs($userAgent);
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'Onbekend';
$host = $_SERVER['HTTP_HOST'] ?? 'Onbekend';
$remotePort = $_SERVER['REMOTE_PORT'] ?? 'Onbekend';
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
$referer = $_SERVER['HTTP_REFERER'] ?? 'Geen';
$time = date('Y-m-d H:i:s');

$reverseDns = 'Niet beschikbaar';
if (filter_var($ip, FILTER_VALIDATE_IP)) {
    $reverse = @gethostbyaddr($ip);
    if ($reverse && $reverse !== $ip) {
        $reverseDns = $reverse;
    }
}

$geo = geoLookup($ip);

try {
    $db = getDb();

    $stmt = $db->prepare("
        INSERT INTO visits (
            ip, ip_type, reverse_dns,
            country, country_code, city, region, postal, timezone,
            latitude, longitude, asn, organization, network,
            browser, os, user_agent, accept_language,
            host, remote_port, https, referer, created_at
        ) VALUES (
            :ip, :ip_type, :reverse_dns,
            :country, :country_code, :city, :region, :postal, :timezone,
            :latitude, :longitude, :asn, :organization, :network,
            :browser, :os, :user_agent, :accept_language,
            :host, :remote_port, :https, :referer, :created_at
        )
    ");

    $stmt->execute([
        ':ip' => $ip,
        ':ip_type' => $ipType,
        ':reverse_dns' => $reverseDns,
        ':country' => $geo['country'],
        ':country_code' => $geo['country_code'],
        ':city' => $geo['city'],
        ':region' => $geo['region'],
        ':postal' => $geo['postal'],
        ':timezone' => $geo['timezone'],
        ':latitude' => $geo['latitude'],
        ':longitude' => $geo['longitude'],
        ':asn' => $geo['asn'],
        ':organization' => $geo['organization'],
        ':network' => $geo['network'],
        ':browser' => $browser,
        ':os' => $os,
        ':user_agent' => $userAgent,
        ':accept_language' => $acceptLanguage,
        ':host' => $host,
        ':remote_port' => $remotePort,
        ':https' => $https ? 1 : 0,
        ':referer' => $referer,
        ':created_at' => $time
    ]);
} catch (Throwable $e) {
    // Logging mag de pagina niet breken.
}
?>
<!DOCTYPE html>
<html lang="nl">
<head>
    <meta charset="UTF-8">
    <title>Wat is mijn IP? - <?= h(SITE_NAME) ?></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <?php if ($geo['latitude'] && $geo['longitude']): ?>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
    <?php endif; ?>

    <style>
        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            min-height: 100vh;
            font-family: Arial, Helvetica, sans-serif;
            color: #ffffff;
            background:
                radial-gradient(circle at top left, rgba(91,167,255,.28), transparent 35%),
                radial-gradient(circle at bottom right, rgba(68,215,182,.22), transparent 35%),
                linear-gradient(135deg, #101827, #17233a);
        }

        .wrap {
            max-width: 1120px;
            margin: 0 auto;
            padding: 42px 20px;
        }

        .top {
            text-align: center;
            margin-bottom: 28px;
        }

        .badge {
            display: inline-block;
            padding: 9px 16px;
            border-radius: 999px;
            background: rgba(255,255,255,.10);
            border: 1px solid rgba(255,255,255,.18);
            color: #b8c2d6;
            font-size: 14px;
            margin-bottom: 18px;
        }

        h1 {
            margin: 0;
            font-size: clamp(36px, 6vw, 62px);
            letter-spacing: -1px;
        }

        .subtitle {
            margin-top: 14px;
            color: #b8c2d6;
            font-size: 17px;
        }

        .card {
            background: rgba(255,255,255,.10);
            border: 1px solid rgba(255,255,255,.18);
            border-radius: 26px;
            padding: 34px;
            box-shadow: 0 25px 80px rgba(0,0,0,.35);
            backdrop-filter: blur(14px);
        }

        .main-label {
            color: #b8c2d6;
            font-size: 15px;
            margin-bottom: 10px;
        }

        .main-ip {
            font-size: clamp(30px, 5vw, 54px);
            font-weight: 800;
            color: #44d7b6;
            word-break: break-all;
            margin-bottom: 20px;
        }

        .pills {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 28px;
        }

        .pill {
            padding: 9px 14px;
            border-radius: 999px;
            background: rgba(255,255,255,.10);
            border: 1px solid rgba(255,255,255,.18);
            color: #cbd5e1;
            font-size: 14px;
        }

        .grid {
            display: grid;
            grid-template-columns: 1.2fr .8fr;
            gap: 20px;
        }

        .table {
            overflow: hidden;
            border-radius: 20px;
            border: 1px solid rgba(255,255,255,.18);
            background: rgba(0,0,0,.16);
        }

        .row {
            display: grid;
            grid-template-columns: 230px 1fr;
            gap: 18px;
            padding: 15px 18px;
            border-bottom: 1px solid rgba(255,255,255,.14);
        }

        .row:last-child {
            border-bottom: none;
        }

        .name {
            color: #b8c2d6;
            font-weight: bold;
        }

        .value {
            word-break: break-word;
        }

        .ok {
            color: #44d7b6;
            font-weight: bold;
        }

        .no {
            color: #ff6b6b;
            font-weight: bold;
        }

        .side-card {
            background: rgba(0,0,0,.16);
            border: 1px solid rgba(255,255,255,.18);
            border-radius: 20px;
            padding: 20px;
            margin-bottom: 20px;
        }

        .side-title {
            color: #b8c2d6;
            font-size: 14px;
            margin-bottom: 8px;
        }

        .side-value {
            font-size: 24px;
            font-weight: bold;
            color: #44d7b6;
            word-break: break-word;
        }

        #map {
            height: 280px;
            border-radius: 18px;
            overflow: hidden;
            border: 1px solid rgba(255,255,255,.18);
            margin-top: 15px;
        }

        .buttons {
            margin-top: 28px;
            text-align: center;
            display: flex;
            justify-content: center;
            gap: 12px;
            flex-wrap: wrap;
        }

        .btn {
            display: inline-block;
            padding: 14px 24px;
            border-radius: 999px;
            background: #44d7b6;
            color: #07111f;
            font-weight: bold;
            text-decoration: none;
            border: 0;
            cursor: pointer;
        }

        .btn.secondary {
            background: rgba(255,255,255,.12);
            color: #fff;
            border: 1px solid rgba(255,255,255,.18);
        }

        .note {
            margin-top: 22px;
            color: #b8c2d6;
            font-size: 13px;
            text-align: center;
            line-height: 1.6;
        }

        @media(max-width: 900px) {
            .grid {
                grid-template-columns: 1fr;
            }
        }

        @media(max-width: 700px) {
            .card {
                padding: 24px;
            }

            .row {
                grid-template-columns: 1fr;
                gap: 5px;
            }
        }
    </style>
</head>
<body>

<div class="wrap">

    <div class="top">
        <div class="badge"><?= h(SITE_NAME) ?> IP Check</div>
        <h1>Wat is mijn IP-adres?</h1>
        <div class="subtitle">Bekijk je publieke IP-adres, locatie, provider en technische verbindingsinformatie.</div>
    </div>

    <div class="card">
        <div class="main-label">Je publieke IP-adres</div>

        <div class="main-ip" id="ipText"><?= h($ip) ?></div>

        <div class="pills">
            <div class="pill">Protocol: <strong><?= h($ipType) ?></strong></div>
            <div class="pill">Land: <strong><?= h($geo['country']) ?></strong></div>
            <div class="pill">Provider: <strong><?= h($geo['organization']) ?></strong></div>
            <div class="pill">Browser: <strong><?= h($browser) ?></strong></div>
            <div class="pill">OS: <strong><?= h($os) ?></strong></div>
            <div class="pill">HTTPS: <strong><?= $https ? 'Actief' : 'Niet actief' ?></strong></div>
        </div>

        <div class="grid">
            <div>
                <div class="table">
                    <div class="row">
                        <div class="name">IPv4-adres</div>
                        <div class="value <?= $isIPv4 ? 'ok' : 'no' ?>">
                            <?= $isIPv4 ? h($ip) : 'Niet gebruikt voor deze verbinding' ?>
                        </div>
                    </div>

                    <div class="row">
                        <div class="name">IPv6-adres</div>
                        <div class="value <?= $isIPv6 ? 'ok' : 'no' ?>">
                            <?= $isIPv6 ? h($ip) : 'Niet gebruikt voor deze verbinding' ?>
                        </div>
                    </div>

                    <div class="row">
                        <div class="name">Land</div>
                        <div class="value"><?= h($geo['country']) ?> <?= $geo['country_code'] ? '(' . h($geo['country_code']) . ')' : '' ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Stad</div>
                        <div class="value"><?= h($geo['city']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Regio</div>
                        <div class="value"><?= h($geo['region']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Postcode</div>
                        <div class="value"><?= h($geo['postal']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Tijdzone</div>
                        <div class="value"><?= h($geo['timezone']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Geschatte locatie</div>
                        <div class="value">
                            <?php if ($geo['latitude'] && $geo['longitude']): ?>
                                <?= h($geo['latitude']) ?>, <?= h($geo['longitude']) ?>
                            <?php else: ?>
                                Onbekend
                            <?php endif; ?>
                        </div>
                    </div>

                    <div class="row">
                        <div class="name">ASN</div>
                        <div class="value"><?= h($geo['asn']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Provider / organisatie</div>
                        <div class="value"><?= h($geo['organization']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Netwerk</div>
                        <div class="value"><?= h($geo['network']) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Reverse DNS</div>
                        <div class="value"><?= h($reverseDns) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Browser</div>
                        <div class="value"><?= h($browser) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Besturingssysteem</div>
                        <div class="value"><?= h($os) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">User Agent</div>
                        <div class="value"><?= h($userAgent) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Browsertaal</div>
                        <div class="value"><?= h($acceptLanguage) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Host</div>
                        <div class="value"><?= h($host) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Remote poort</div>
                        <div class="value"><?= h($remotePort) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">HTTPS</div>
                        <div class="value <?= $https ? 'ok' : 'no' ?>">
                            <?= $https ? 'Ja, beveiligde verbinding' : 'Nee' ?>
                        </div>
                    </div>

                    <div class="row">
                        <div class="name">Referer</div>
                        <div class="value"><?= h($referer) ?></div>
                    </div>

                    <div class="row">
                        <div class="name">Tijdstip controle</div>
                        <div class="value"><?= h(date('d-m-Y H:i:s', strtotime($time))) ?></div>
                    </div>
                </div>
            </div>

            <div>
                <div class="side-card">
                    <div class="side-title">Locatie</div>
                    <div class="side-value"><?= h($geo['city']) ?></div>
                    <div class="note" style="text-align:left;margin-top:10px;">
                        <?= h($geo['country']) ?> <?= $geo['country_code'] ? '(' . h($geo['country_code']) . ')' : '' ?>
                    </div>

                    <?php if ($geo['latitude'] && $geo['longitude']): ?>
                        <div id="map"></div>
                    <?php endif; ?>
                </div>

                <div class="side-card">
                    <div class="side-title">Provider</div>
                    <div class="side-value"><?= h($geo['organization']) ?></div>
                    <div class="note" style="text-align:left;margin-top:10px;">
                        <?= h($geo['asn']) ?><br>
                        <?= h($geo['network']) ?>
                    </div>
                </div>

                <div class="side-card">
                    <div class="side-title">Apparaat</div>
                    <div class="side-value"><?= h($browser) ?></div>
                    <div class="note" style="text-align:left;margin-top:10px;">
                        <?= h($os) ?>
                    </div>
                </div>
            </div>
        </div>

        <div class="buttons">
            <button class="btn" onclick="copyIp()">Kopieer IP-adres</button>
            <a class="btn secondary" href="/">Terug naar home</a>
            <a class="btn secondary" href="/stats.php">Statistieken</a>
        </div>

        <div class="note">
            Locatiegegevens zijn een schatting op basis van GeoIP en kunnen afwijken van je werkelijke locatie.
        </div>
    </div>

</div>

<?php if ($geo['latitude'] && $geo['longitude']): ?>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
    const map = L.map('map').setView([<?= json_encode($geo['latitude']) ?>, <?= json_encode($geo['longitude']) ?>], 10);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18,
        attribution: '&copy; OpenStreetMap'
    }).addTo(map);

    L.marker([<?= json_encode($geo['latitude']) ?>, <?= json_encode($geo['longitude']) ?>])
        .addTo(map)
        .bindPopup('Geschatte locatie')
        .openPopup();
</script>
<?php endif; ?>

<script>
function copyIp() {
    const ip = document.getElementById('ipText').innerText;

    navigator.clipboard.writeText(ip).then(function () {
        alert('IP-adres gekopieerd: ' + ip);
    });
}
</script>

</body>
</html>