From 5357bc89155998b54cf584bd27de0eef8611bcce Mon Sep 17 00:00:00 2001 From: Edwin Noorlander Date: Wed, 29 Jul 2026 15:40:02 +0200 Subject: [PATCH] CodePress CMS v1.9.0: visitor statistics with SVG world map and GeoIP - Add GeoIP class with provider chain: local DB-IP Lite, MaxMind .mmdb, external API - Add built-in pure-PHP MMDBReader so .mmdb works without Composer - Add cli/geoip-update.php to download DB-IP Lite and build a compact binary index - Add cli/generate-world-map.php to generate the world map SVG from Natural Earth TopoJSON - Add Analytics class aggregating stats in admin/storage/stats.json with LOCK_EX - Add admin statistics page with choropleth world map, country list, top pages, daily chart, referrers and a period filter - Add GeoIP and privacy settings with database update and stats reset buttons - Add optional IP anonymization and configurable retention period - Add country field to requests.log (parser accepts 7, 8 or 9 fields) - Add country column to request log and KPI cards to the dashboard - Ignore GeoIP binaries and stats.json in Git - Update TODO.md, guides and version to 1.9.0 --- .gitignore | 2 + TODO.md | 33 ++- admin/templates/layout.php | 8 + admin/templates/pages/dashboard.php | 47 +++ admin/templates/pages/logs.php | 5 + admin/templates/pages/statistics.php | 368 +++++++++++++++++++++++ cli/generate-world-map.php | 159 ++++++++++ cli/geoip-update.php | 119 ++++++++ cms/core/class/Analytics.php | 265 +++++++++++++++++ cms/core/class/GeoIP.php | 425 +++++++++++++++++++++++++++ cms/core/class/RequestLogger.php | 29 +- cms/core/config.php | 37 +++ cms/core/index.php | 3 + config.json.example | 9 + guide/en.codepress.md | 1 + guide/nl.codepress.md | 4 + public/admin.php | 98 +++++- public/assets/img/world-map.svg | 154 ++++++++++ public/index.php | 30 +- version.php | 19 +- 20 files changed, 1804 insertions(+), 11 deletions(-) create mode 100644 admin/templates/pages/statistics.php create mode 100644 cli/generate-world-map.php create mode 100644 cli/geoip-update.php create mode 100644 cms/core/class/Analytics.php create mode 100644 cms/core/class/GeoIP.php create mode 100644 public/assets/img/world-map.svg diff --git a/.gitignore b/.gitignore index f5f9f98..0fca4d1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ Thumbs.db .cache/ .sass-cache/ admin/storage/cache/ +admin/storage/geoip/ +admin/storage/stats.json # Temporary files *.tmp diff --git a/TODO.md b/TODO.md index bcc6799..630acbc 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,34 @@ ## ✅ Voltooid (recent) +### Statistieken & GeoIP (v1.9.0) +- [x] `GeoIP` class met providerketen: lokaal (DB-IP Lite) → MaxMind `.mmdb` → externe API, met automatische fallback +- [x] Eigen pure-PHP MMDB-lezer (`MMDBReader`), geen Composer-afhankelijkheid nodig +- [x] `cli/geoip-update.php` — downloadt DB-IP Lite en bouwt compacte binaire index (354k IPv4 + 342k IPv6 records) +- [x] Binary search lookup via `fseek` voor IPv4 (10 bytes/record) en IPv6 (34 bytes/record) +- [x] Placeholder-landcodes (`ZZ`/`XX`) tellen als onbekend +- [x] `cli/generate-world-map.php` — genereert SVG-wereldkaart uit Natural Earth TopoJSON (publiek domein) met ISO alpha-2 id's +- [x] `Analytics` class met aggregatie in `admin/storage/stats.json` (LOCK_EX), overleeft het wissen van logs +- [x] Admin pagina `/admin/statistics`: KPI's, choropleth wereldkaart met tooltips, landenlijst met vlaggen, top pagina's, dagelijkse grafiek, referrers +- [x] Periodefilter 7 / 30 / 90 dagen / alles +- [x] GeoIP- en privacy-instellingen in admin (provider, `.mmdb` pad, API URL/sleutel, bewaartermijn) +- [x] Knop "GeoIP database bijwerken" en "Statistieken wissen" in admin +- [x] IP-anonimisering als schakelaar (`RequestLogger::anonymizeIp()`), standaard uit +- [x] Landkolom met vlag in requests log + KPI-kaarten op dashboard +- [x] `requests.log` uitgebreid met landcode (9e veld), parser accepteert 7/8/9 velden + +### Beveiliging (v1.8.0) +- [x] `BotGuard` engine: AI-crawlers, zoekmachines, scrapers en lege user-agents herkennen en blokkeren +- [x] Admin pagina `/admin/security` met schakelaars, rate limiting en IP block/allowlist +- [x] Rate limiting per IP (HTTP 429 met `Retry-After`) +- [x] Dynamische `/robots.txt` en `noai`/`noimageai` meta-tags +- [x] Statuskolom met badges in requests log +- [x] Echte bezoeker-IP achter HAProxy/PFSense (`RequestLogger::getClientIp()`, 2-pass publiek IP filter) +- [x] HAProxy/PFSense handleiding (`docs/haproxy-bot-blocking.md`) +- [x] Eén-klik systeemupdate via `/admin/update` met controle op Git-schrijfrechten +- [x] `config.json` en `admin/config/admin.json` uit Git, automatisch aangemaakt indien afwezig +- [x] **ARIAComponents.php parse error** — opgelost op regels 67, 137 en 262 (`'UTF-8)` → `'UTF-8')`) + ### Media & Editor - [x] Media browser modal met upload, thumbnail grid, en size-prompt - [x] Media knop in editor toolbar voor alle modes (md/html/php) @@ -87,4 +115,7 @@ - [ ] **Keyboard shortcuts** — Ctrl+S om op te slaan in editor, Ctrl+N voor nieuw bestand - [ ] **Dark mode** — Admin panel dark mode toggle - [ ] **Responsive admin** — Admin sidebar inklapbaar op mobiel (nu is het gestacked) -- [x] **ARIAComponents.php parse error** — Bestaande PHP parse error op regel 67 opgelost (`'UTF-8)` -> `'UTF-8')`) +- [ ] **stats.json bij hoog verkeer** — Nu één schrijfactie met LOCK_EX per request. Bij veel verkeer eventueel opsplitsen naar dagbestanden of APCu +- [ ] **Steden op de kaart** — Nu alleen landniveau; met een City-database ook stippen per stad plotten +- [ ] **Statistieken exporteren** — CSV/JSON export van bezoekersstatistieken +- [ ] **Automatische GeoIP-update** — Maandelijkse cron/schedule i.p.v. handmatig op de knop drukken diff --git a/admin/templates/layout.php b/admin/templates/layout.php index 6cf2b9d..00fb4f7 100644 --- a/admin/templates/layout.php +++ b/admin/templates/layout.php @@ -71,6 +71,11 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d'; Beveiliging +