Stats : détail articles/books/recherches par réseau, par pays et par visiteur #92

Open
opened 2026-05-16 08:59:17 +00:00 by cedricAbonnel · 1 comment
Owner

Contexte

La page /admin/stats affiche actuellement la répartition des visites par réseau (ASN) (nombre de hits total par AS). Elle ne précise pas ce que chaque réseau consulte, et ne propose pas de vue par pays ni par visiteur individuel.

Problème

On ne peut pas savoir, pour un réseau donné (ex : un opérateur, un bot, un hébergeur) ou un pays donné :

  • quels articles il consulte le plus
  • quels livres il parcourt
  • quelles recherches il effectue

Idem par visiteur (IP) : pas de vue permettant de voir le comportement d'un visiteur spécifique.

Ce qu'on veut

1. Vue par réseau (ASN) — détail du contenu

Dans le tableau "Répartition par réseau", rendre chaque ligne cliquable pour afficher un sous-détail avec :

  • Top articles (/post/…) consultés par ce réseau
  • Top livres (/book/…) consultés par ce réseau
  • Top recherches effectuées par ce réseau

2. Vue par pays

Ajouter un tableau "Répartition par pays" listant les pays classés par hits, avec pour chaque pays le même sous-détail dépliable (articles / books / recherches les plus consultés depuis ce pays).

3. Vue par visiteur (IP)

Ajouter une section "Par visiteur" listant les IPs les plus actives, avec pour chaque IP :

  • Nombre total de hits
  • Organisation/réseau (ASN — déjà résolu via AsnLookup)
  • Pays
  • Top articles, livres et recherches liés à cette IP

Données disponibles

  • AccessLogParser::stats() retourne déjà pages, books, ips (hits par IP, triés)
  • AsnLookup résout déjà les 200 premières IPs → nom de réseau, ASN, pays
  • SearchLogParser fournit les recherches (à corréler avec l'IP)
  • Les logs Apache COMBINED contiennent l'IP sur chaque ligne → corrélation IP ↔ contenu possible

Travail technique à faire

  1. AccessLogParser : enrichir stats() (ou ajouter statsByIp()) pour retourner, par IP, le détail des pages et books consultés
  2. Backend (index.php, action admin / tab stats) :
    • Alimenter stats_visitors : top IPs avec détail contenu + résolution ASN/pays
    • Alimenter stats_as_detail : top articles/books/recherches par ASN
    • Alimenter stats_countries : agrégation par pays (depuis le champ country de AsnLookup) avec détail contenu
  3. Template (admin_stats.php) :
    • Lignes ASN et Pays cliquables → expand/collapse inline
    • Nouvelle section "Par visiteur" avec sous-détail dépliable
  4. Cache : inclure les nouvelles structures dans le cache stats (TTL ≈ 10 min)

Critères d'acceptation

  • Cliquer sur un réseau dans le tableau ASN affiche ses top articles / books / recherches
  • Un tableau "Par pays" liste les pays avec le même sous-détail
  • Une section "Par visiteur" liste les IPs les plus actives avec leur détail de contenu
  • Les données sont cachées (TTL ≈ 10 min)
  • La vue reste lisible sur mobile (tableaux responsifs, expand/collapse)

Maquette approximative

Répartition par réseau
──────────────────────────────────────────────────────────
#  Réseau                  Pays  Visites  [▼]
1  Free SAS   AS12322       FR     1 234
   ├─ Articles : Post A (45), Post B (30), Post C (12)
   ├─ Livres   : Dune (8), 1984 (3)
   └─ Recherches : "php" (5), "folio" (3)
──────────────────────────────────────────────────────────

Répartition par pays
──────────────────────────────────────────────────────────
#  Pays  Visites  [▼]
1  FR      8 450
   ├─ Articles : Post A (400), Post B (220)
   ├─ Livres   : Dune (50)
   └─ Recherches : "php" (30)
──────────────────────────────────────────────────────────

Par visiteur (IP)
──────────────────────────────────────────────────────────
#  IP             Réseau        Pays  Visites  [▼]
1  1.2.3.4        Free SAS       FR       87
   ├─ Articles : Post A (20), Post B (15)
   ├─ Livres   : Dune (4)
   └─ Recherches : "php" (2)
──────────────────────────────────────────────────────────
## Contexte La page `/admin/stats` affiche actuellement la répartition des **visites par réseau (ASN)** (nombre de hits total par AS). Elle ne précise pas *ce que* chaque réseau consulte, et ne propose pas de vue par pays ni par visiteur individuel. ## Problème On ne peut pas savoir, pour un réseau donné (ex : un opérateur, un bot, un hébergeur) ou un pays donné : - quels **articles** il consulte le plus - quels **livres** il parcourt - quelles **recherches** il effectue Idem par visiteur (IP) : pas de vue permettant de voir le comportement d'un visiteur spécifique. ## Ce qu'on veut ### 1. Vue par réseau (ASN) — détail du contenu Dans le tableau "Répartition par réseau", rendre chaque ligne **cliquable** pour afficher un sous-détail avec : - **Top articles** (`/post/…`) consultés par ce réseau - **Top livres** (`/book/…`) consultés par ce réseau - **Top recherches** effectuées par ce réseau ### 2. Vue par pays Ajouter un tableau **"Répartition par pays"** listant les pays classés par hits, avec pour chaque pays le même sous-détail dépliable (articles / books / recherches les plus consultés depuis ce pays). ### 3. Vue par visiteur (IP) Ajouter une section **"Par visiteur"** listant les IPs les plus actives, avec pour chaque IP : - Nombre total de hits - Organisation/réseau (ASN — déjà résolu via `AsnLookup`) - Pays - Top articles, livres et recherches liés à cette IP ## Données disponibles - `AccessLogParser::stats()` retourne déjà `pages`, `books`, `ips` (hits par IP, triés) - `AsnLookup` résout déjà les 200 premières IPs → nom de réseau, ASN, **pays** - `SearchLogParser` fournit les recherches (à corréler avec l'IP) - Les logs Apache COMBINED contiennent l'IP sur chaque ligne → corrélation IP ↔ contenu possible ## Travail technique à faire 1. **`AccessLogParser`** : enrichir `stats()` (ou ajouter `statsByIp()`) pour retourner, par IP, le détail des `pages` et `books` consultés 2. **Backend (`index.php`, action `admin` / tab `stats`)** : - Alimenter `stats_visitors` : top IPs avec détail contenu + résolution ASN/pays - Alimenter `stats_as_detail` : top articles/books/recherches par ASN - Alimenter `stats_countries` : agrégation par pays (depuis le champ `country` de `AsnLookup`) avec détail contenu 3. **Template (`admin_stats.php`)** : - Lignes ASN et Pays cliquables → expand/collapse inline - Nouvelle section "Par visiteur" avec sous-détail dépliable 4. **Cache** : inclure les nouvelles structures dans le cache stats (TTL ≈ 10 min) ## Critères d'acceptation - [ ] Cliquer sur un réseau dans le tableau ASN affiche ses top articles / books / recherches - [ ] Un tableau "Par pays" liste les pays avec le même sous-détail - [ ] Une section "Par visiteur" liste les IPs les plus actives avec leur détail de contenu - [ ] Les données sont cachées (TTL ≈ 10 min) - [ ] La vue reste lisible sur mobile (tableaux responsifs, expand/collapse) ## Maquette approximative ``` Répartition par réseau ────────────────────────────────────────────────────────── # Réseau Pays Visites [▼] 1 Free SAS AS12322 FR 1 234 ├─ Articles : Post A (45), Post B (30), Post C (12) ├─ Livres : Dune (8), 1984 (3) └─ Recherches : "php" (5), "folio" (3) ────────────────────────────────────────────────────────── Répartition par pays ────────────────────────────────────────────────────────── # Pays Visites [▼] 1 FR 8 450 ├─ Articles : Post A (400), Post B (220) ├─ Livres : Dune (50) └─ Recherches : "php" (30) ────────────────────────────────────────────────────────── Par visiteur (IP) ────────────────────────────────────────────────────────── # IP Réseau Pays Visites [▼] 1 1.2.3.4 Free SAS FR 87 ├─ Articles : Post A (20), Post B (15) ├─ Livres : Dune (4) └─ Recherches : "php" (2) ────────────────────────────────────────────────────────── ```
Author
Owner

Compléments après relecture du code

1. Sélecteur de période manquant

L'onglet Recherches accepte déjà ?days=7|14 (ligne 2686 de index.php), mais l'onglet Stats est figé à 14j ($cutoff14 hardcodé ligne 2708). Il faudra aligner les deux : les vues par réseau / pays / visiteur doivent respecter le même filtre de période que les recherches.

2. SearchLogParser ne permet pas la corrélation IP ↔ termes

SearchLogParser::parseLine() stocke déjà les IPs en interne ($visitors[$q][$ip]), mais seule topTerms() est exposée (comptage agrégé). Pour afficher les recherches dans le sous-détail par visiteur / réseau / pays, il faudra ajouter une méthode termsByIp() retournant [ip => [terme => count]] — sans quoi la corrélation recherche ↔ IP est impossible sans re-parser les logs une 2e fois.

3. Bots / crawlers non isolés

Le log Apache COMBINED contient le User-Agent (champ capturé dans le commentaire du regex de AccessLogParser mais non parsé). Actuellement, toutes les vues (réseau, pays, visiteur) mélangent bots et trafic humain : un crawler actif gonfle les stats d'un AS ou d'un pays entier. Il faudrait :

  • Extraire le UA dans parseLine()
  • Appliquer une liste de patterns bot connus (Googlebot, GPTBot, AhrefsBot, etc.)
  • Soit les filtrer des stats humaines, soit les isoler dans une section dédiée "Bots"

Note d'implémentation : AsnLookup::batchLookup ne résout que le top 200 IPs (array_slice(..., 0, 200) dans index.php). Pour la vue visiteur ce plafond est correct côté perf, mais il faut le documenter — les IPs au-delà du top 200 n'auront pas de résolution ASN/pays.

## Compléments après relecture du code ### 1. Sélecteur de période manquant L'onglet **Recherches** accepte déjà `?days=7|14` (ligne 2686 de `index.php`), mais l'onglet **Stats** est figé à 14j (`$cutoff14` hardcodé ligne 2708). Il faudra aligner les deux : les vues par réseau / pays / visiteur doivent respecter le même filtre de période que les recherches. ### 2. `SearchLogParser` ne permet pas la corrélation IP ↔ termes `SearchLogParser::parseLine()` stocke déjà les IPs en interne (`$visitors[$q][$ip]`), mais seule `topTerms()` est exposée (comptage agrégé). Pour afficher les recherches dans le sous-détail par visiteur / réseau / pays, il faudra ajouter une méthode **`termsByIp()`** retournant `[ip => [terme => count]]` — sans quoi la corrélation recherche ↔ IP est impossible sans re-parser les logs une 2e fois. ### 3. Bots / crawlers non isolés Le log Apache COMBINED contient le User-Agent (champ capturé dans le commentaire du regex de `AccessLogParser` mais non parsé). Actuellement, toutes les vues (réseau, pays, visiteur) **mélangent bots et trafic humain** : un crawler actif gonfle les stats d'un AS ou d'un pays entier. Il faudrait : - Extraire le UA dans `parseLine()` - Appliquer une liste de patterns bot connus (Googlebot, GPTBot, AhrefsBot, etc.) - Soit les filtrer des stats humaines, soit les isoler dans une section dédiée "Bots" --- *Note d'implémentation* : `AsnLookup::batchLookup` ne résout que le top 200 IPs (`array_slice(..., 0, 200)` dans `index.php`). Pour la vue visiteur ce plafond est correct côté perf, mais il faut le documenter — les IPs au-delà du top 200 n'auront pas de résolution ASN/pays.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: cedricAbonnel/folio#92