2.3Inclusions, organisation & gestion de fichiers
L'essentiel en 30 secondes
- Écrire une fois, inclure partout : header, footer, config et fonctions vivent dans des fichiers dédiés assemblés par require/include — zéro duplication.
- require pour l'indispensable : require échoue en fatal si le fichier manque (config, fonctions), include se contente d'avertir — *_once évite les redéfinitions.
- Uploads = entrées hostiles : type réel vérifié, taille limitée, fichier renommé, stockage sans exécution PHP — un PHP uploadé exécutable donne le serveur à l'attaquant.
Mini-cas filé — Riad range le site de l'association
Le site de l'association de Riad grandit : le même menu copié dans dix pages, la connexion à la base recopiée partout — chaque modification devient un calvaire. Il range : config.php pour les paramètres, header.php et footer.php pour la mise en page, fonctions.php pour les utilitaires, chaque page assemblée par require. Puis il ajoute l'envoi de photos d'événements : upload traité comme une entrée hostile — type réel vérifié, fichier renommé, stocké sans exécution PHP. En 2.4, il horodatera ces photos avec DateTime.
Suite du fil rouge 2.2 : le site de Riad passe du bricolage dupliqué à une structure propre — et continue en 2.4.
1. Inclusions : écrire une fois, réutiliser partout
Un site réel partage des éléments communs (en-tête, menu, pied de page, configuration) : les dupliquer dans chaque fichier est fastidieux et impossible à maintenir. PHP offre les instructions d'inclusion : include et require insèrent le contenu d'un fichier dans un autre. La différence : require provoque une ERREUR FATALE si le fichier est introuvable — pour les fichiers INDISPENSABLES (configuration, fonctions essentielles) ; include émet un simple avertissement et continue — pour les fichiers optionnels. Leurs variantes require_once et include_once garantissent une inclusion UNIQUE (pas de redéfinitions) — souvent à privilégier. Typique : header.php et footer.php inclus dans chaque page, config.php requis en haut des scripts. Riad modifie désormais son menu à un seul endroit. Point de SÉCURITÉ crucial : ne JAMAIS inclure un chemin venant d'une entrée utilisateur (include $_GET['page']) — c'est une faille d'inclusion de fichier arbitraire.
2. Organiser avant les frameworks
Ces inclusions fondent l'organisation d'un projet « à la main » : séparer le code en fichiers logiques (configuration, fonctions, éléments d'interface, pages) et les assembler — premier pas vers une architecture propre, qui aboutira au MVC (section 4-1) et à l'autoloading (section 3-3). Les principes : SÉPARER selon les responsabilités, RÉUTILISER par inclusions, SÉPARER la logique (traitement, requêtes) de l'affichage (le HTML après), ranger en dossiers clairs (includes/, pages, assets/, uploads/ sécurisé), et placer les fichiers sensibles (config avec identifiants) HORS de la racine web. Le site de Riad adopte cette structure : toute page commence par le require de la config, fait sa logique, puis inclut l'affichage.
3. Fichiers et uploads : lire, écrire, se méfier
PHP LIT et ÉCRIT des fichiers serveur : file_get_contents() (tout lire), file_put_contents() (écrire), fopen()/fread()/fwrite()/fclose() (par étapes, gros fichiers), file_exists(), unlink() (supprimer). Le cas sensible : les uploads, fichiers envoyés par l'utilisateur dans $_FILES — à traiter comme des entrées hostiles. Les protections, toutes ensemble : VÉRIFIER le type RÉEL (le contenu, pas l'extension déclarée, falsifiable) avec une liste blanche et la TAILLE ; RENOMMER le fichier (jamais le nom utilisateur) ; le stocker HORS de la racine web ou dans un dossier SANS exécution PHP — sinon un fichier PHP malveillant uploadé puis appelé par URL s'exécute et compromet le serveur ; déplacer avec move_uploaded_file() après contrôle du code d'erreur. Les photos d'événements de Riad suivent exactement ce protocole.
🔎 Exemple concret — 🔎 Exemple concret — Les photos d'événements de Riad, en sécurité
Toutes les protections, comme pour les uploads de Riad :
// vérifier error, taille, TYPE RÉEL (liste blanche)
$nom = bin2hex(random_bytes(8)) . '.jpg';
move_uploaded_file($_FILES['img']['tmp_name'],
__DIR__ . '/../uploads/' . $nom);
// dossier sans exécution PHP
Lecture : contrôle du contenu, renommage aléatoire, stockage sans exécution.
Leçon : ne jamais garder le nom fourni par l'utilisateur.
Vocabulaire de la section
- include / require
- Insèrent le contenu d'un fichier dans un autre ; require provoque une erreur FATALE si introuvable (indispensables), include un avertissement et continue (optionnels).
Exemple simple : Riad requiert config.php en haut de chaque page.
Ce que ce n'est pas : un copier-coller du même menu dans dix pages.
Réflexe : indispensable = require.
- require_once / include_once
- Garantissent qu'un fichier n'est inclus QU'UNE fois, évitant inclusions multiples et erreurs de redéfinition — souvent à privilégier.
Exemple simple : fonctions.php est requis en _once sur toutes les pages de Riad.
Ce que ce n'est pas : une inclusion répétée qui redéfinit les mêmes fonctions.
Réflexe : fichier partagé = _once par défaut.
- Organisation par inclusions
- Séparer le code en fichiers logiques (config, fonctions, header/footer, pages) assemblés par inclusions ; premier pas vers une architecture propre (MVC, autoloading).
Exemple simple : Le site de Riad : config, header/footer, pages assemblées.
Ce que ce n'est pas : un gros fichier mélangeant logique, requêtes et HTML dupliqué.
Réflexe : code dupliqué = fichier à extraire et inclure.
- Gestion de fichiers
- Lire et écrire des fichiers serveur : file_get_contents, file_put_contents, fopen/fread/fwrite, file_exists, unlink.
Exemple simple : Riad lit un modèle et écrit un export avec file_get_contents/put_contents.
Ce que ce n'est pas : un upload traité sans aucun contrôle.
Réflexe : fichier serveur = vérifier existence et droits.
- Uploads ($_FILES) — sécurité
- Fichiers envoyés par l'utilisateur ($_FILES) : vérifier type réel et taille, RENOMMER, stocker hors racine ou sans exécution PHP, limiter les extensions.
Exemple simple : Chaque photo de Riad est renommée et stockée sans exécution PHP.
Ce que ce n'est pas : un fichier gardé sous son nom d'origine dans un dossier exécutable.
Réflexe : upload = entrée hostile, protocole complet.
En pratique — En pratique — Organiser le code et gérer des fichiers
- Créez header.php et footer.php et incluez-les dans plusieurs pages avec require ; créez un config.php requis en haut des scripts.
- Comprenez la différence require (fatal) / include (avertissement) et l'intérêt de require_once (inclusion unique).
- Lisez et écrivez un fichier (file_get_contents / file_put_contents) ; vérifiez son existence (file_exists).
- Traitez un upload ($_FILES) EN SÉCURITÉ : vérifiez type réel et taille, RENOMMEZ le fichier, stockez-le dans un dossier sans exécution PHP — et n'incluez JAMAIS un chemin venant de l'utilisateur.
Script prêt à dire — expliquer le rangement au bureau associatif (30 s)
« J'ai rangé le site : le menu et le pied de page existent en un seul exemplaire, chaque page les inclut — une modification se fait à un endroit. Et pour les photos, chaque fichier est vérifié, renommé et stocké dans un dossier où aucun script ne peut s'exécuter : même un fichier piégé reste inoffensif. »
À dire en montrant une modification du menu répercutée partout instantanément.
Modèle copier-coller — squelette de page assemblée
Petit site vitrine
Cinq pages partagent header et footer : Riad corrige le menu une fois, tout le site suit.
Config protégée
Identifiants de base hors racine web, requis en haut : jamais exposés par URL, jamais dans le dépôt.
Export de données
La liste des adhérents s'écrit avec file_put_contents après file_exists : lecture et écriture contrôlées.
Photos d'événements
Uploads renommés, type réel vérifié, dossier sans exécution PHP : la galerie reste inoffensive.
✓ Bonnes pratiques
- Séparer le code en fichiers logiques et réutiliser par inclusions.
- Privilégier require pour les fichiers indispensables et *_once contre les redéfinitions.
- Traiter les uploads avec toutes les protections (type réel, renommage, sans exécution).
✗ Pièges fréquents
- Inclure un chemin venant d'une entrée utilisateur (inclusion de fichier arbitraire).
- Garder le nom d'un fichier uploadé fourni par l'utilisateur.
- Stocker les uploads dans un dossier où PHP s'exécute (prise de contrôle).
Points clés à retenir
- INCLUSIONS (include/require) : insérer un fichier dans un autre pour ne pas dupliquer (header, footer, config, fonctions). require = fatal si introuvable (indispensables) ; include = avertissement (optionnels) ; *_once = inclusion unique.
- Organiser le code en fichiers logiques assemblés par inclusions = premier pas vers une architecture propre (avant MVC/autoloading).
- FAILLE À ÉVITER : ne JAMAIS inclure un chemin venant d'une entrée UTILISATEUR (include $_GET['page']) — inclusion de fichier arbitraire.
- GESTION DE FICHIERS (file_get_contents/put_contents, fopen…) et surtout UPLOADS ($_FILES) EN SÉCURITÉ : vérifier type réel/taille, RENOMMER, stocker sans exécution PHP, limiter les extensions (source classique de failles graves).
Défi 48h — appliquez demain
Factorisez un vrai projet : extrayez header, footer et config en fichiers inclus par require/require_once, logique avant affichage. Puis sécurisez un upload réel : type réel, taille, renommage, dossier sans exécution PHP.
- Je peux expliquer require vs include et l'intérêt de *_once.
- Je sais structurer un projet (config, header/footer, logique avant affichage).
- J'ai sécurisé un upload réel avec le protocole complet.
Questions fréquentes
Comment organiser proprement un projet PHP « à la main » avant d'utiliser un framework ?
Visez la SÉPARATION et la RÉUTILISATION, contre le « code spaghetti » (tout mélangé, dupliqué, sans structure). (1) SÉPARER en fichiers logiques : configuration (config.php), fonctions réutilisables (ou classes, niveau 3), interface commune (header.php, footer.php), pages (contenu spécifique). (2) RÉUTILISER par inclusions : écrits une fois, inclus partout — une modification à un seul endroit. (3) SÉPARER logique et affichage : logique d'abord (traitement, requêtes), HTML ensuite — la voie vers le MVC (section 4-1). (4) STRUCTURER les dossiers : includes/, pages, assets/, uploads/ sécurisé. (5) SÉCURISER : fichiers sensibles HORS racine web, point d'entrée unique idéalement, secrets hors dépôt. Cette organisation enseigne les principes que les FRAMEWORKS formalisent (MVC, routage, autoloading, config, sécurité).
Pourquoi les uploads de fichiers sont-ils si sensibles en sécurité, et comment les gérer sûrement ?
Un upload laisse un utilisateur DÉPOSER un fichier sur VOTRE serveur. Le pire scénario : un fichier .php malveillant uploadé puis appelé par URL — le serveur l'EXÉCUTE et l'attaquant prend le contrôle (fichiers, base, tout). Autres risques : fichiers énormes (déni de service), types trompeurs, écrasement. Protections, toutes ensemble : (1) JAMAIS d'exécution — dossier sans PHP ou HORS racine web : LA protection clé. (2) RENOMMER (jamais le nom utilisateur) avec un nom sûr et une extension contrôlée. (3) VÉRIFIER le TYPE RÉEL (contenu, pas extension déclarée) — liste blanche. (4) LIMITER la taille. (5) Valider l'extension (liste blanche). (6) Contrôler le code d'erreur de $_FILES et déplacer avec move_uploaded_file(). En projet réel, préférez les outils éprouvés des frameworks sur un sujet aussi critique.
Quelle est LA protection clé pour les fichiers uploadés ?