From a1badb18f219a04cbe56b1d840b5999ba8702b34 Mon Sep 17 00:00:00 2001 From: Jules Date: Wed, 6 May 2026 09:58:18 +0200 Subject: [PATCH] =?UTF-8?q?perf:=20cache=20session=20vision=5Fcheck=20(15m?= =?UTF-8?q?in)=20=E2=80=94=20z=C3=A9ro=20requ=C3=AAte=20r=C3=A9seau=20par?= =?UTF-8?q?=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- web/includes/vision.php | 99 +++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 57 deletions(-) diff --git a/web/includes/vision.php b/web/includes/vision.php index fb61c27..f69629c 100644 --- a/web/includes/vision.php +++ b/web/includes/vision.php @@ -1,13 +1,13 @@ &machine_id=&hostname= - * Vérification toutes les 30 min, résultat mis en cache en BDD. + * Cache SESSION : aucune requête réseau pendant 15 min après le dernier check. + * Le check HTTP n'a lieu qu'une fois par session toutes les 15 minutes. */ define('VISION_LICENSE_URL', 'https://vision.copydev.fr/api/license.php'); define('VISION_PRODUCT', 'copymail'); -define('VISION_CACHE_TTL', 1800); // 30 minutes +define('VISION_CACHE_TTL', 900); // 15 minutes function vision_machine_id(): string { $id = cfg('vision_machine_id', ''); @@ -19,90 +19,75 @@ function vision_machine_id(): string { } function vision_check(): array { + // 1. Cache session : si le résultat est frais, on retourne immédiatement + if (!empty($_SESSION['vision_result']) && !empty($_SESSION['vision_checked_at'])) { + if ((time() - $_SESSION['vision_checked_at']) < VISION_CACHE_TTL) { + return $_SESSION['vision_result']; + } + } + + // 2. Clé non configurée $key = cfg('vision_license_key', ''); if (!$key) { - return ['valid' => false, 'msg' => 'Licence non configurée.', 'unconfigured' => true]; - } - - // Cache : si dernier check < 30 min et résultat valide, on ne re-vérifie pas - $lastCheck = (int)cfg('vision_last_check', '0'); - $lastResult = cfg('vision_last_result', ''); - if ($lastResult && (time() - $lastCheck) < VISION_CACHE_TTL) { - $cached = json_decode($lastResult, true); - if ($cached) return $cached; + $r = ['valid' => false, 'msg' => 'Licence non configurée.', 'unconfigured' => true]; + $_SESSION['vision_result'] = $r; + $_SESSION['vision_checked_at'] = time(); + return $r; } + // 3. Appel Vision (max 3s timeout) $url = VISION_LICENSE_URL . '?' . http_build_query([ 'key' => $key, 'machine_id' => vision_machine_id(), 'hostname' => cfg('hostname', gethostname()), ]); - $ctx = stream_context_create(['http' => [ - 'method' => 'GET', - 'timeout' => 5, - 'ignore_errors' => true, - ]]); - + $ctx = stream_context_create(['http' => ['method' => 'GET', 'timeout' => 3, 'ignore_errors' => true]]); $resp = @file_get_contents($url, false, $ctx); if ($resp === false) { - // Vision injoignable — mode dégradé selon offline_timeout + // Vision injoignable — mode dégradé $lastOk = (int)cfg('vision_last_ok', '0'); $timeout = (int)cfg('vision_offline_timeout', '72'); - $elapsed = (time() - $lastOk) / 3600; - if ($lastOk && $elapsed < $timeout) { - $result = ['valid' => true, 'msg' => "Vision injoignable — mode dégradé ({$timeout}h max)", 'degraded' => true]; + $elapsed = $lastOk ? (time() - $lastOk) / 3600 : PHP_INT_MAX; + $result = ($lastOk && $elapsed < $timeout) + ? ['valid' => true, 'msg' => "Vision injoignable — mode dégradé ({$timeout}h max)", 'degraded' => true] + : ['valid' => false, 'msg' => 'Vision injoignable et délai hors-ligne dépassé.']; + } else { + $data = json_decode($resp, true); + if (!empty($data['valid'])) { + $result = [ + 'valid' => true, + 'client' => $data['client'] ?? '', + 'product' => $data['product'] ?? '', + 'expires' => $data['expires_at'] ?? null, + 'devices' => $data['max_devices'] ?? 1, + ]; + cfg_set('vision_last_ok', (string)time()); + cfg_set('vision_offline_timeout', (string)($data['offline_timeout_hours'] ?? 72)); } else { - $result = ['valid' => false, 'msg' => 'Vision injoignable et délai hors-ligne dépassé.']; + $result = ['valid' => false, 'msg' => $data['message'] ?? 'Licence invalide ou désactivée.']; + cfg_set('vision_last_ok', '0'); } - return $result; } - $data = json_decode($resp, true); + // 4. Stocke en session + $_SESSION['vision_result'] = $result; + $_SESSION['vision_checked_at'] = time(); - if (!empty($data['valid'])) { - $result = [ - 'valid' => true, - 'client' => $data['client'] ?? '', - 'product' => $data['product'] ?? '', - 'expires' => $data['expires_at'] ?? null, - 'devices' => $data['max_devices'] ?? 1, - ]; - cfg_set('vision_last_ok', (string)time()); - cfg_set('vision_last_check', (string)time()); - cfg_set('vision_last_result', json_encode($result)); - cfg_set('vision_offline_timeout', (string)($data['offline_timeout_hours'] ?? 72)); - return $result; - } - - // Licence invalide / désactivée depuis Vision : invalide immédiatement le cache - $result = ['valid' => false, 'msg' => $data['message'] ?? 'Licence invalide ou désactivée.']; - cfg_set('vision_last_check', (string)time()); - cfg_set('vision_last_result', json_encode($result)); - cfg_set('vision_last_ok', '0'); // reset grace period return $result; } -/** - * Vérifie la licence et bloque si invalide. - * À appeler sur toutes les pages. - * Exception : la page de config (/admin/domain.php) reste accessible aux admins. - */ function vision_enforce(): void { $result = vision_check(); if ($result['valid']) return; $uri = $_SERVER['REQUEST_URI'] ?? ''; - - // L'admin peut toujours accéder à la config pour saisir la clé if (is_admin() && strpos($uri, '/admin/domain.php') !== false) return; - // Bloque tout le reste - $msg = htmlspecialchars($result['msg'] ?? 'Licence invalide.'); - $isAdmin = is_admin(); - $configLink = $isAdmin - ? 'Configurer la licence' + $msg = htmlspecialchars($result['msg'] ?? 'Licence invalide.'); + $configLink = is_admin() + ? 'Configurer la licence' : ''; http_response_code(403); echo "