This commit is contained in:
julien
2026-03-27 22:40:44 +01:00
parent 7757628a94
commit 38eea09710
3 changed files with 60 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
# F3 Simple Blog
Blog simple avec Fat-Free Framework.
Blog simple avec Fat-Free Framework, SQLite et une petite médiathèque dimages.
## Structure
@@ -8,25 +8,27 @@ Blog simple avec Fat-Free Framework.
project/
├── config.local.ini # Surcharges locales (gitignored)
├── app/
│ ├── config.ini # Routes et variables F3
│ ├── bootstrap.php # Initialisation (DB, session, cache, erreurs)
│ ├── config.ini # Configuration F3 (globals + routes)
│ ├── bootstrap.php # Initialisation (config, DB, session, erreurs)
│ ├── Controllers/
│ ├── Helpers/ # Fonctions utilitaires (App.php, Error.php)
│ ├── Helpers/ # Fonctions utilitaires
│ ├── Models/ # DB\SQL\Mapper (Post, Media, User)
│ ├── Services/ # MarkdownService
│ └── Views/
├── db/
│ └── app.sqlite
│ └── app.sqlite # Base SQLite persistante
├── logs/
── app.log
│ └── php-error.log
── php-error.log # Log PHP configuré au runtime
├── public/
│ ├── assets/ # Sources CSS/JS (servis minifiés via /min/@file)
│ ├── assets/ # Sources CSS/JS servies via /min/@file
│ └── uploads/
│ └── media/ # Images publiées (JPG conservé, PNG/WebP normalisés en PNG)
├── scripts/
│ ├── install.php # Initialisation idempotente de la base
│ └── create-admin.php # Création dun compte admin en CLI
└── tmp/
├── cache/ # Cache F3 (pages publiques + assets minifiés)
└── uploads/ # Transit Web::receive() nettoyé après chaque upload
├── cache/ # Cache F3 + assets minifiés
└── uploads/ # Transit Web::receive(), nettoyé après chaque upload
```
## Philosophie des dossiers runtime
@@ -43,15 +45,18 @@ Autrement dit, `tmp/` peut être vidé sans perte métier. Les données à sauve
## Fonctionnalités F3 utilisées
- **Routage nommé** — `config.ini [routes]`, filtre `alias` dans les templates, `reroute('@route')` dans les contrôleurs
- **Cache HTTP + serveur** — TTL déclarés directement dans `[routes]`, `Cache::reset('.url')` à la mutation
- **Cache HTTP / F3** — TTL appliqués dans les contrôleurs avec `expire()`
- accueil : `300 s`
- page article : `3600 s`
- assets minifiés : `86400 s`
- **Assets minifiés** — `Web::minify()` via `AssetController` (`GET /min/@file`)
- **Upload** — `Web::receive()` avec contrôle de taille, puis validation MIME/dimensions côté modèle
- **Images** — normalisation des médias via GD (`JPG` conservé, `PNG/WebP` convertis en `PNG` pour préserver la transparence)
- **Markdown** — `Markdown::instance()->convert()` + reconstruction DOM en liste blanche
- **Slugs** — `Web::instance()->slug()`
- **Session** — `$f3->set('JAR', …)`, hooks `beforeRoute()` sur les contrôleurs protégés, token CSRF créé seulement sur les vues qui contiennent des formulaires
- **Logging** — `Log` de F3 avec fallback `file_put_contents`
- **Session / CSRF** — `$f3->set('JAR', …)`, hooks `beforeRoute()` sur les contrôleurs protégés, jeton exposé via `@CSRF` puis recopié en session au rendu pour vérification lors du POST suivant
- **ORM** — `DB\SQL\Mapper` : `paginate()`, `copyfrom()`, `cast()`, `find()`
- **Erreurs** — gestion personnalisée en production via `ONERROR` + fallback HTML minimal sur erreur fatale
## Prérequis
@@ -59,7 +64,7 @@ Autrement dit, `tmp/` peut être vidé sans perte métier. Les données à sauve
- PHP 8.3+
- Composer
- Extensions PHP : `pdo_sqlite`, `dom`, `gd`, `mbstring`
- Extensions PHP : `pdo_sqlite`, `dom`, `gd`, `mbstring`, `intl`
### Déploiement Docker
@@ -84,10 +89,12 @@ app.env=prod
app.timezone=Europe/Paris
```
Le fichier `config.local.ini` sert uniquement aux surcharges d'environnement. Les chemins runtime restent les mêmes partout :
Le fichier `config.local.ini` sert uniquement aux surcharges denvironnement. Les chemins runtime restent les mêmes partout :
- `tmp/cache/` pour le cache F3 et les assets minifiés
- `tmp/uploads/` pour les fichiers temporaires d'upload
- `tmp/uploads/` pour les fichiers temporaires dupload
Les données persistantes restent hors de `tmp` : `db/`, `logs/`, `public/uploads/media/`.
## Développement local
@@ -115,9 +122,9 @@ cp config.local.ini.example config.local.ini
docker compose up -d --build
```
Docker ne monte que les dossiers persistants (`db/`, `logs/`, `public/uploads/media/`) et laisse `tmp/` dans le conteneur pour qu'il reste réellement éphémère.
Docker ne monte que les dossiers persistants (`db/`, `logs/`, `public/uploads/media/`) et laisse `tmp/` dans le conteneur pour quil reste réellement éphémère.
Si `config.local.ini` n'existe pas, le conteneur démarre avec les valeurs par défaut de `app/config.ini`.
Le fichier `config.local.ini` est monté en lecture seule. Si le fichier hôte nexiste pas, Docker peut créer un répertoire à la place ; lentrypoint le supprime et lapplication retombe alors sur les valeurs par défaut de `app/config.ini`.
Le service écoute sur `http://127.0.0.1:8888`.
@@ -130,17 +137,26 @@ docker compose exec app php scripts/create-admin.php admin
## Cache public et navigation
Les pages publiques (`/` et `/posts/@slug`) restent cacheables parce que leur rendu n'accède ni à la session, ni au token CSRF. La navigation publique affiche donc un lien statique vers la connexion / l'administration, tandis que les vues d'administration restent session-aware.
Les pages publiques restent cacheables pour un visiteur anonyme :
## Médias et limites d'upload
- `/` est servie avec un TTL de `300 s`
- `/posts/@slug` est servie avec un TTL de `3600 s`
- `/min/app.css` et `/min/app.js` sont servis avec un TTL de `86400 s`
- Formats acceptés à l'entrée : `JPG`, `PNG`, `WebP`
Quand un utilisateur est connecté, le layout dépend de la session (navigation admin + formulaire de déconnexion avec CSRF). Le rendu est alors forcé en non-cacheable avec `expire(0)`.
Le projet ne fait pas dinvalidation explicite du cache public lors des mutations darticles : la fraîcheur dépend donc des TTL ci-dessus.
## Médias et limites dupload
- Formats acceptés à lentrée : `JPG`, `PNG`, `WebP`
- Taille max du fichier reçu : `10 Mo`
- Dimensions max : `8000 × 8000 px`
- Limite de surface : `40 mégapixels`
- Sortie publiée : `JPG` pour les sources JPEG, `PNG` pour les sources PNG/WebP
- Texte alternatif initial dérivé du nom de fichier dorigine
La médiathèque admin est paginée et le picker dans l'éditeur charge seulement les images les plus récentes pour éviter de charger toute la bibliothèque en mémoire à chaque formulaire.
La médiathèque admin est paginée et le picker dans léditeur charge seulement les `60` images les plus récentes pour éviter de charger toute la bibliothèque en mémoire à chaque formulaire.
## Reverse proxy Caddy
@@ -164,11 +180,13 @@ blog.example.com {
}
```
Le fichier `Caddyfile.example` fournit en plus un jeu den-têtes de sécurité minimal.
## Données à sauvegarder
- `db/` — base SQLite
- `public/uploads/media/` — images
- `logs/` — optionnel
- `logs/` — optionnel, utile pour diagnostic
- `tmp/` — non persistant, recréable
## Mise à jour
@@ -179,6 +197,10 @@ docker compose up -d --build
## Logs
- Applicatifs : `logs/app.log`
- PHP : `logs/php-error.log`
- Apache (conteneur) : `docker compose logs -f app`
- Apache / conteneur : `docker compose logs -f app`
## Notes
- Les dates sont stockées en UTC (`gmdate`) puis formatées côté affichage avec le fuseau configuré.
- `scripts/install.php` peut être relancé sans danger : il crée les tables si elles nexistent pas.