first
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
services:
|
||||
fpm-monip:
|
||||
image: php:8.2-fpm-alpine
|
||||
container_name: fpm-monip
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./src:/var/www/html
|
||||
environment:
|
||||
TZ: "Europe/Paris"
|
||||
IPINFO_TOKEN: ${IPINFO_TOKEN}
|
||||
networks:
|
||||
- traefik-net
|
||||
monip:
|
||||
image: nginx:alpine
|
||||
container_name: monip
|
||||
restart: unless-stopped
|
||||
# ports:
|
||||
# - "8030:80"
|
||||
volumes:
|
||||
- ./src:/var/www/html
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d
|
||||
environment:
|
||||
TZ: "Europe/Paris"
|
||||
networks:
|
||||
- traefik-net
|
||||
|
||||
networks:
|
||||
traefik-net:
|
||||
external: true
|
||||
@@ -0,0 +1,27 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# Gestion des fichiers PHP via PHP-FPM
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass fpm-monip:9000; # Nom du service PHP-FPM dans docker-compose
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param HTTP_X_REAL_IP $remote_addr;
|
||||
fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# Cache des assets statiques
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Share+Tech+Mono&family=VT323&display=swap');
|
||||
|
||||
:root {
|
||||
--matrix-bg: #020403;
|
||||
--matrix-surface: #071009;
|
||||
--matrix-surface-2: #0a140c;
|
||||
--accent-primary: #00ff41;
|
||||
--accent-soft: color-mix(in srgb, var(--accent-primary) 35%, white);
|
||||
--accent-line: color-mix(in srgb, var(--accent-primary) 32%, transparent);
|
||||
--accent-glow: color-mix(in srgb, var(--accent-primary) 32%, transparent);
|
||||
--matrix-alert: #ff5a36;
|
||||
--matrix-warn: #d8e7c4;
|
||||
--matrix-muted: #6c8b73;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html { background: var(--matrix-bg); }
|
||||
|
||||
body.matrix-mode {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--matrix-bg);
|
||||
color: var(--accent-soft);
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: .78rem;
|
||||
letter-spacing: .025em;
|
||||
}
|
||||
|
||||
body.matrix-mode::before {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -2;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
background: radial-gradient(ellipse at 50% -10%, color-mix(in srgb, var(--accent-primary) 8.5%, transparent), transparent 58%), var(--matrix-bg);
|
||||
}
|
||||
|
||||
body.matrix-mode::after {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
opacity: .12;
|
||||
background: repeating-linear-gradient(to bottom, transparent 0, transparent 3px, color-mix(in srgb, var(--accent-primary) 16%, transparent) 4px, transparent 5px);
|
||||
}
|
||||
|
||||
.container { position: relative; z-index: 1; max-width: 1080px; }
|
||||
|
||||
.card {
|
||||
color: var(--accent-soft);
|
||||
background: rgba(7, 16, 9, .92);
|
||||
border: 1px solid var(--accent-line);
|
||||
border-radius: 0;
|
||||
box-shadow: 0 0 18px color-mix(in srgb, var(--accent-primary) 10%, transparent);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: color-mix(in srgb, var(--accent-primary) 68%, transparent);
|
||||
box-shadow: 0 0 22px color-mix(in srgb, var(--accent-primary) 15%, transparent);
|
||||
}
|
||||
|
||||
.card-header, .card-footer { border-color: var(--accent-line); border-radius: 0 !important; }
|
||||
.card-header { padding: .6rem .78rem .48rem; font-family: 'VT323', monospace; font-size: .85rem; letter-spacing: .09em; text-transform: uppercase; }
|
||||
.card-body { padding: .78rem; font-size: .78rem; }
|
||||
.card-footer { padding: .55rem .78rem; background: rgba(0, 0, 0, .28) !important; color: var(--matrix-muted) !important; font-size: .65rem; }
|
||||
|
||||
.header-main { color: var(--matrix-bg); background: var(--accent-primary); border-color: var(--accent-primary); }
|
||||
.header-main h2 { color: var(--matrix-bg); text-shadow: none; font-size: 1.05rem; }
|
||||
.header-alt { color: var(--accent-primary); background: color-mix(in srgb, var(--accent-primary) 10%, transparent); border-bottom: 1px solid var(--accent-primary); }
|
||||
.header-alert { color: #ff9a72; background: rgba(120, 24, 12, .55); border-bottom: 1px solid var(--matrix-alert); }
|
||||
.header-warn { color: var(--matrix-warn); background: rgba(140, 165, 98, .12); border-bottom: 1px solid rgba(216, 231, 196, .7); }
|
||||
.header-debug { color: #b7c0b9; background: rgba(86, 99, 90, .27); border-bottom: 1px solid rgba(183, 192, 185, .55); }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 { color: var(--accent-primary); text-shadow: 0 0 8px color-mix(in srgb, var(--accent-primary) 32%, transparent); }
|
||||
.header-main h2 { text-shadow: none; }
|
||||
strong { color: color-mix(in srgb, var(--accent-primary) 20%, white); font-weight: normal; }
|
||||
p { line-height: 1.4; }
|
||||
.text-muted { color: var(--matrix-muted) !important; }
|
||||
.text-danger { color: var(--matrix-alert) !important; text-shadow: 0 0 6px rgba(255, 90, 54, .3); }
|
||||
.text-success { color: var(--accent-primary) !important; }
|
||||
|
||||
pre {
|
||||
max-height: 26rem;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
padding: .78rem;
|
||||
color: var(--accent-primary);
|
||||
background: #010201;
|
||||
border: 1px solid var(--accent-line);
|
||||
border-radius: 0;
|
||||
font-family: 'JetBrains Mono', 'Menlo', 'Consolas', monospace;
|
||||
font-size: .68rem;
|
||||
line-height: 1.3;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.py-4 { padding-top: 2rem !important; padding-bottom: 2rem !important; }
|
||||
.shadow-sm { box-shadow: 0 0 26px color-mix(in srgb, var(--accent-primary) 11%, transparent) !important; }
|
||||
|
||||
.hue-toggle {
|
||||
position: fixed;
|
||||
right: .8rem;
|
||||
bottom: .65rem;
|
||||
z-index: 20;
|
||||
padding: .18rem .35rem;
|
||||
color: var(--accent-primary);
|
||||
background: rgba(2, 4, 3, .82);
|
||||
border: 1px solid var(--accent-line);
|
||||
border-radius: 0;
|
||||
font: .68rem 'Share Tech Mono', monospace;
|
||||
letter-spacing: .04em;
|
||||
cursor: pointer;
|
||||
opacity: .72;
|
||||
}
|
||||
|
||||
.hue-toggle:hover, .hue-toggle:focus-visible { opacity: 1; color: var(--accent-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--accent-primary) 22%, transparent); outline: none; }
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; }
|
||||
.card-header { font-size: .85rem; }
|
||||
.card-body { padding: .65rem; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
function fetchGeo(string $ip): array
|
||||
{
|
||||
$token = getenv('IPINFO_TOKEN') ?: '';
|
||||
$url = 'https://ipinfo.io/' . rawurlencode($ip) . '/json';
|
||||
|
||||
if ($token !== '') {
|
||||
$url .= '?token=' . rawurlencode($token);
|
||||
}
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
]);
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$data = $response ? json_decode($response, true) : [];
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function getRealClientIp(): string
|
||||
{
|
||||
$trustedProxies = [
|
||||
'172.16.0.0/12',
|
||||
'10.0.0.0/8',
|
||||
'192.168.0.0/16',
|
||||
'127.0.0.1',
|
||||
];
|
||||
$remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
|
||||
if (!ipInRanges($remoteAddr, $trustedProxies)) {
|
||||
return $remoteAddr;
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ips = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
|
||||
foreach ($ips as $ip) {
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP)) {
|
||||
return $_SERVER['HTTP_X_REAL_IP'];
|
||||
}
|
||||
return $remoteAddr;
|
||||
}
|
||||
|
||||
function ipInRanges(string $ip, array $ranges): bool
|
||||
{
|
||||
foreach ($ranges as $range) {
|
||||
if (ipInRange($ip, $range)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function ipInRange(string $ip, string $cidr): bool
|
||||
{
|
||||
if (strpos($cidr, '/') === false) {
|
||||
return $ip === $cidr;
|
||||
}
|
||||
[$subnet, $bits] = explode('/', $cidr);
|
||||
$ipLong = ip2long($ip);
|
||||
$subnetLong = ip2long($subnet);
|
||||
if ($ipLong === false || $subnetLong === false) {
|
||||
return false;
|
||||
}
|
||||
$mask = -1 << (32 - (int)$bits);
|
||||
$subnetLong &= $mask;
|
||||
return ($ipLong & $mask) === $subnetLong;
|
||||
}
|
||||
|
||||
function getWhoisServer(string $ip): string
|
||||
{
|
||||
// Convertir l'IP en nombre pour comparaison
|
||||
$ipLong = ip2long($ip);
|
||||
if ($ipLong === false) {
|
||||
return 'whois.iana.org'; // Fallback
|
||||
}
|
||||
|
||||
// Plages IP simplifiées (à adapter si besoin)
|
||||
if ($ipLong >= ip2long('192.0.0.0') && $ipLong <= ip2long('223.255.255.255')) {
|
||||
return 'whois.apnic.net'; // Asie-Pacifique
|
||||
} elseif ($ipLong >= ip2long('128.0.0.0') && $ipLong <= ip2long('191.255.255.255')) {
|
||||
return 'whois.arin.net'; // Amérique
|
||||
} elseif ($ipLong >= ip2long('185.0.0.0') && $ipLong <= ip2long('191.255.255.255')) {
|
||||
return 'whois.ripe.net'; // Europe (étendue)
|
||||
} elseif ($ipLong >= ip2long('200.0.0.0') && $ipLong <= ip2long('200.255.255.255')) {
|
||||
return 'whois.lacnic.net'; // Amérique Latine
|
||||
} else {
|
||||
return 'whois.ripe.net'; // Europe par défaut (pour ton cas)
|
||||
}
|
||||
}
|
||||
|
||||
function fetchLocalWhois(string $ip, int $timeout = 5): array
|
||||
{
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
return ['raw' => '', 'error' => 'IP invalide'];
|
||||
}
|
||||
|
||||
$escapedIp = escapeshellarg($ip);
|
||||
|
||||
// 1. Convertir l'IP en format in-addr.arpa (ex: 82.64.199.86 → 86.199.64.82.in-addr.arpa)
|
||||
$parts = explode('.', $ip);
|
||||
$reverseIp = implode('.', array_reverse($parts)) . '.in-addr.arpa';
|
||||
$escapedReverseIp = escapeshellarg($reverseIp);
|
||||
|
||||
// 2. Essayer avec whois.ripe.net + in-addr.arpa (méthode la plus fiable)
|
||||
$command = "timeout {$timeout} whois -h whois.ripe.net {$escapedReverseIp} 2>&1";
|
||||
$output = shell_exec($command);
|
||||
|
||||
// 3. Fallback : Essayer sans -h (utilise la config par défaut)
|
||||
if (empty(trim($output ?? '')) || strpos($output, 'no entries found') !== false) {
|
||||
$command = "timeout {$timeout} whois {$escapedReverseIp} 2>&1";
|
||||
$output = shell_exec($command);
|
||||
}
|
||||
|
||||
// 4. Fallback ultime : Essayer avec l'IP directe (si le client whois est bien configuré)
|
||||
if (empty(trim($output ?? '')) || strpos($output, 'no entries found') !== false) {
|
||||
$command = "timeout {$timeout} whois {$escapedIp} 2>&1";
|
||||
$output = shell_exec($command);
|
||||
}
|
||||
|
||||
return [
|
||||
'raw' => $output !== null ? trim($output) : '',
|
||||
'source' => 'local'
|
||||
];
|
||||
}
|
||||
|
||||
function fetchWhois2(string $ip): array
|
||||
{
|
||||
if (!function_exists('curl_init')) {
|
||||
return [];
|
||||
}
|
||||
$ch = curl_init("https://ipwhois.app/json/{$ip}");
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_CONNECTTIMEOUT => 3,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
]);
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($response === false || $httpCode !== 200) {
|
||||
return [];
|
||||
}
|
||||
$data = json_decode($response, true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function countryName(string $code): string
|
||||
{
|
||||
$countries = [
|
||||
'FR' => 'France',
|
||||
'US' => 'États-Unis',
|
||||
'GB' => 'Royaume-Uni',
|
||||
'DE' => 'Allemagne',
|
||||
'ES' => 'Espagne',
|
||||
'IT' => 'Italie',
|
||||
'BE' => 'Belgique',
|
||||
'CH' => 'Suisse',
|
||||
'CA' => 'Canada',
|
||||
'PT' => 'Portugal',
|
||||
'NL' => 'Pays-Bas',
|
||||
'LU' => 'Luxembourg',
|
||||
];
|
||||
|
||||
$normalizedCode = strtoupper(trim($code));
|
||||
return $countries[$normalizedCode] ?? $code;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
include "functions.php";
|
||||
|
||||
$apiKey = '';
|
||||
$showDebug = false;
|
||||
$ip = getRealClientIp();
|
||||
$reverseDns = gethostbyaddr($ip);
|
||||
$hostname = gethostbyaddr($ip);
|
||||
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'N/A';
|
||||
$httpReferer = $_SERVER['HTTP_REFERER'] ?? 'N/A';
|
||||
$httpHost = $_SERVER['HTTP_HOST'] ?? 'N/A';
|
||||
|
||||
// Appel API de géolocalisation.
|
||||
$geoData = filter_var($ip, FILTER_VALIDATE_IP) ? fetchGeo($ip) : [];
|
||||
|
||||
// Normalisation des champs ipinfo.io pour le rendu HTML.
|
||||
if (!empty($geoData)) {
|
||||
if (isset($geoData['loc']) && strpos((string)$geoData['loc'], ',') !== false) {
|
||||
[$lat, $lon] = explode(',', (string)$geoData['loc'], 2);
|
||||
$geoData['lat'] = trim($lat);
|
||||
$geoData['lon'] = trim($lon);
|
||||
}
|
||||
|
||||
// Conserver d'abord le code ISO brut avant de traduire le nom du pays.
|
||||
$geoData['countryCode'] = $geoData['country'] ?? null;
|
||||
$geoData['country'] = countryName((string)($geoData['countryCode'] ?? ''));
|
||||
$geoData['regionName'] = $geoData['region'] ?? null;
|
||||
$geoData['zip'] = $geoData['postal'] ?? null;
|
||||
$geoData['isp'] = $geoData['org'] ?? null;
|
||||
$geoData['status'] = 'success';
|
||||
}
|
||||
|
||||
// Suppression des valeurs null après la normalisation.
|
||||
$geoData = array_filter($geoData, static function ($value): bool {
|
||||
return $value !== null;
|
||||
});
|
||||
|
||||
// Récupération des informations WHOIS / ASN.
|
||||
// $whoisData = filter_var($ip, FILTER_VALIDATE_IP) ? fetchWhois2($ip) : [];
|
||||
// $whoisData = filter_var($ip, FILTER_VALIDATE_IP) ? fetchLocalWhois($ip) : [];
|
||||
|
||||
$whoisData = filter_var($ip, FILTER_VALIDATE_IP) ? fetchLocalWhois($ip) : [];
|
||||
if (empty($whoisData['raw']) || strpos($whoisData['raw'], 'no entries found') !== false) {
|
||||
$whoisData = fetchWhois2($ip); // Fallback vers l'API
|
||||
$whoisData['source'] = 'api';
|
||||
}
|
||||
|
||||
$whoisData = is_array($whoisData) ? $whoisData : ['raw' => $whoisData];
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>MONIP - <?= htmlspecialchars((string)$ip, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body class="matrix-mode">
|
||||
<div class="container py-4"><div class="row justify-content-center"><div class="col-lg-8">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header header-main"><h2 class="h4 mb-0">> VBLOG.IO IP TRACER</h2></div>
|
||||
<div class="card-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6"><div class="card h-100"><div class="card-header header-main"><h5 class="h6 mb-0">> ADRESSE IP SOURCE</h5></div>
|
||||
<div class="card-body">
|
||||
<p class="mb-1"><strong>IPv4:</strong> <?= htmlspecialchars((string)$ip, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>REVERSE DNS:</strong> <?= htmlspecialchars((string)($reverseDns ?: 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>HOSTNAME:</strong> <?= htmlspecialchars((string)($hostname ?: 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
</div></div></div>
|
||||
<div class="col-md-6"><div class="card h-100"><div class="card-header header-alt"><h5 class="h6 mb-0">> GÉOLOCALISATION</h5></div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($geoData['country'])): ?>
|
||||
<p class="mb-1"><strong>PAYS:</strong> <?= htmlspecialchars((string)($geoData['country'] ?? 'N/A') . ' (' . (string)($geoData['countryCode'] ?? 'N/A') . ')', ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>RÉGION:</strong> <?= htmlspecialchars((string)($geoData['regionName'] ?? 'N/A') . ' (' . (string)($geoData['region'] ?? 'N/A') . ')', ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>VILLE:</strong> <?= htmlspecialchars((string)($geoData['city'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>FUSEAU HORAIRE:</strong> <?= htmlspecialchars((string)($geoData['timezone'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>COORDONNÉES:</strong> <?= htmlspecialchars((string)($geoData['lat'] ?? 'N/A') . ', ' . (string)($geoData['lon'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<?php else: ?><p class="text-muted">DONNÉES GÉO INDISPONIBLES.</p><?php endif; ?>
|
||||
</div></div></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6"><div class="card h-100"><div class="card-header header-warn"><h5 class="h6 mb-0">> FOURNISSEUR (ISP)</h5></div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($geoData['isp'])): ?>
|
||||
<p class="mb-1"><strong>ISP:</strong> <?= htmlspecialchars((string)($geoData['isp'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>ORGANISATION:</strong> <?= htmlspecialchars((string)($geoData['org'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>AS:</strong> <?= htmlspecialchars((string)($geoData['as'] ?? 'N/A'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<?php else: ?><p class="text-muted">DONNÉES ISP INDISPONIBLES.</p><?php endif; ?>
|
||||
</div></div></div>
|
||||
<div class="col-md-6"><div class="card h-100"><div class="card-header header-alert"><h5 class="h6 mb-0">> SÉCURITÉ</h5></div>
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$isProxy = $geoData['proxy'] ?? false;
|
||||
$isHosting = $geoData['hosting'] ?? false;
|
||||
$isMobile = $geoData['mobile'] ?? false;
|
||||
?>
|
||||
<p class="mb-1"><strong>PROXY:</strong> <?= $isProxy ? '<span class="text-danger">OUI</span>' : 'Non'; ?></p>
|
||||
<p class="mb-1"><strong>HÉBERGÉ:</strong> <?= $isHosting ? '<span class="text-danger">OUI</span>' : 'Non'; ?></p>
|
||||
<p class="mb-1"><strong>MOBILE:</strong> <?= $isMobile ? '<span class="text-success">OUI</span>' : 'Non'; ?></p>
|
||||
</div></div></div>
|
||||
</div>
|
||||
<div class="card mb-3"><div class="card-header header-debug"><h5 class="h6 mb-0">> WHOIS / ASN</h5></div>
|
||||
<div class="card-body"><pre><?= !empty($whoisData['raw']) ? htmlspecialchars((string)$whoisData['raw'], ENT_QUOTES, 'UTF-8') : (!empty($whoisData['asn']) ? 'AS' . htmlspecialchars((string)($whoisData['asn'] ?? 'N/A'), ENT_QUOTES, 'UTF-8') . ' - ' . htmlspecialchars((string)($whoisData['isp'] ?? 'N/A'), ENT_QUOTES, 'UTF-8') : 'DONNÉES WHOIS INDISPONIBLES.'); ?></pre></div></div>
|
||||
<?php if ($showDebug): ?>
|
||||
<div class="card mb-3"><div class="card-header header-debug"><h5 class="h6 mb-0">> EN-TÊTES HTTP</h5></div>
|
||||
<div class="card-body"><pre><?= htmlspecialchars(print_r($_SERVER, true), ENT_QUOTES, 'UTF-8'); ?></pre></div></div>
|
||||
<?php endif; ?>
|
||||
<div class="card"><div class="card-header header-alt"><h5 class="h6 mb-0">> NAVIGATEUR & SYSTÈME</h5></div>
|
||||
<div class="card-body">
|
||||
<p class="mb-1"><strong>USER AGENT:</strong> <?= htmlspecialchars((string)$userAgent, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>RÉFÉRENT:</strong> <?= htmlspecialchars((string)$httpReferer, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-1"><strong>HOST:</strong> <?= htmlspecialchars((string)$httpHost, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p class="mb-0"><strong>DATE LOCALE:</strong> <?= date('Y-m-d H:i:s'); ?></p>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="card-footer text-muted small"><strong>MONIP</strong> | v1.0 | <?= date('Y-m-d H:i:s'); ?></div>
|
||||
</div>
|
||||
</div></div></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<button type="button" class="hue-toggle" id="hue-toggle" aria-label="Basculer la teinte d'accent">[ HUE::GRN ]</button>
|
||||
<script>
|
||||
(() => {
|
||||
const root = document.documentElement;
|
||||
const toggle = document.getElementById('hue-toggle');
|
||||
const hues = { GRN: '#00ff41', BLU: '#00cfff' };
|
||||
const savedHue = localStorage.getItem('monip-hue');
|
||||
// let hue = savedHue === 'GRN' ? 'GRN' : 'BLU';
|
||||
let hue = savedHue || 'BLU'; // Utilise la valeur sauvegardée, ou bleu si rien n'est enregistré
|
||||
const applyHue = (nextHue) => {
|
||||
hue = nextHue === 'BLU' ? 'BLU' : 'GRN';
|
||||
root.style.setProperty('--accent-primary', hues[hue]);
|
||||
toggle.textContent = `[ HUE::${hue} ]`;
|
||||
localStorage.setItem('monip-hue', hue);
|
||||
};
|
||||
applyHue(hue);
|
||||
toggle.addEventListener('click', () => applyHue(hue === 'GRN' ? 'BLU' : 'GRN'));
|
||||
})();
|
||||
</script>
|
||||
</body></html>
|
||||
|
||||
Reference in New Issue
Block a user