['seconds' => 600, 'label' => '10 dernières minutes', 'short' => '10 min'], '20m' => ['seconds' => 1200, 'label' => '20 dernières minutes', 'short' => '20 min'], '30m' => ['seconds' => 1800, 'label' => '30 dernières minutes', 'short' => '30 min'], '1h' => ['seconds' => 3600, 'label' => 'dernière heure', 'short' => '1 h'], '8h' => ['seconds' => 28800, 'label' => '8 dernières heures', 'short' => '8 h'], '1d' => ['seconds' => 86400, 'label' => '24 dernières heures', 'short' => '24 h'], '7d' => ['seconds' => 604800, 'label' => '7 derniers jours', 'short' => '7 j'], '14d' => ['seconds' => 1209600, 'label' => '14 derniers jours', 'short' => '14 j'], '30d' => ['seconds' => 2592000, 'label' => '30 derniers jours', 'short' => '30 j'], '1y' => ['seconds' => 31536000, 'label' => 'dernière année', 'short' => '1 an'], ]; // Période active (affichage du top) $period = $_GET['period'] ?? '1d'; if (!array_key_exists($period, TENDANCES_PERIODS)) { $period = '1d'; } $seconds = TENDANCES_PERIODS[$period]['seconds']; $label = TENDANCES_PERIODS[$period]['label']; $cacheTtl = max(60, min(28800, (int) ($seconds / 5))); // Lecture seule du cache généré par /trending?period=… $cacheFile = DATA_PATH . '/_cache/trending_' . $period . '.json'; $topPaths = null; if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTtl) { $topPaths = json_decode((string) file_get_contents($cacheFile), true) ?: null; } // Index slug → article $articleManager = new ArticleManager(DATA_PATH); $now = time(); $privateCats = $articleManager->getPrivateCategories(); $slugIndex = []; foreach ($articleManager->getAll(publishedOnly: true) as $a) { if (strtotime((string) ($a['published_at'] ?? '')) > $now) { continue; } $cat = trim($a['category'] ?? ''); if ($cat !== '' && in_array($cat, $privateCats, true)) { continue; } $slugIndex[$a['slug']] = $a; } // Top articles pour la période affichée $topItems = []; foreach ($topPaths as $path => $visitors) { if (!preg_match('#^/post/([^/]+)$#', $path, $m)) { continue; } $article = $slugIndex[rawurldecode($m[1])] ?? null; if ($article === null) { continue; } $topItems[] = ['article' => $article, 'visitors' => (int) $visitors]; if (count($topItems) >= 20) { break; } } $base = rtrim(APP_URL, '/'); $pageTitle = 'Tendances — ' . siteTitle(); ob_start(); ?>

Tendances

Articles les plus consultés, calculés en temps réel depuis les journaux d'accès du serveur. Seuls les visiteurs uniques (une IP = un visiteur) sur des réponses 200 sont comptabilisés. Aucun cookie, aucun traceur tiers.

$info): ?>

Aucune donnée disponible pour cette période.

Top articles —

    ['article' => $a, 'visitors' => $v]): ?>
  1. vis.
Flux RSS disponibles

Chaque flux retourne les 50 articles les plus consultés pour la période choisie, mis à jour automatiquement. Abonnez-vous à celui qui correspond à vos besoins.

'2 min', '20m' => '4 min', '30m' => '6 min', '1h' => '12 min', '8h' => '96 min', '1d' => '5 h', '7d' => '8 h', '14d' => '8 h', '30d' => '8 h', '1y' => '8 h', ]; foreach (TENDANCES_PERIODS as $p => $info): $url = $base . '/trending?period=' . rawurlencode($p); ?>
Période Cache URL
/trending?period=
Méthodologie
  • Source : journaux d'accès Apache (access.log et rotations .gz).
  • Seules les requêtes GET sur /post/* avec code HTTP 200 sont comptabilisées.
  • Un visiteur = une adresse IP distincte par article sur la fenêtre temporelle.
  • Les IPs ne sont ni stockées ni transmises ; seuls les compteurs agrégés sont conservés en cache.
  • Les articles dans des catégories privées et les avant-premières ne figurent pas dans les résultats.
$pageTitle, 'content' => $content, 'mainClass' => '', ]; extract($templateVars); require BASE_PATH . '/templates/layout.php';