Arborescence d'un site en PHP
Tech
2025-06-28

J'ai précisé dans le titre de la page que je propose, ici, une arborescence pour un site en PHP. C'est assez spécifique, mais j'aime bien programmer en PHP, je trouve ce langage simple, puissant et facile à utiliser pour créer et gérer un site internet. Quand je dis puissant, je veux dire que PHP est à la fois capable de proposer de la programmation fonctionnelle et de la programmation objet, et c'est là tout l'intérêt : utiliser des objets simples et des librairies qui peuvent mixer de l'objet et des fonctions, pour arriver à avoir un code simple et clair, facile à maintenir et à la mettre à jour, et sécurisé.
Mon ancienne méthode
Quand j'ai commencé le PHP, je trouvais ce langage intéressant car il suffisait de mettre des balises dans du code HTML pour afficher des données, comme ceci :
<h1>Voici le titre de mon blog : <?php echo $titre; ?></h1>
En utilisant cette syntaxe et en ajoutant au début du fichier les lignes de code nécessaire, je pouvais alors afficher des données en provenance de la base de données facilement.
Au fur et à mesure, j'ai ajouter un peu plus de code au début de ma page, et j'ai commencé à les regrouper dans des fichiers de fonctions, il suffisait alors d'appeler une fonction sur la page pour afficher ensuite le résultat du code qui était exécuté et se trouvait dans un fichier spécifique qui s'appelait fonctions et contenaient toutes les fonctions.
Tout cela tenait dans un seul dossier, et il suffisait alors d'appeler le nom de la page avec l'extension PHP pour que celle-ci affiche ce qu'elle était censé afficher.
Mais ça, c'était avant (et malheureusement, il reste encore du code comme ça qu'il me faut migrer ...).
Ma nouvelle méthode
Pour que l'arborescence du site soit parlante, j'ai changé la manière de fonctionner au niveau global du site. Désormais, ce n'est plus un site internet mais une application web. Tous les appels se font via un seul fichier, généralement index.php, grâce à un fichier .htaccess qui ressemble à ça :
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?path=$1 [QSA,L]
L'avantage de cette configuration est que tous les fichiers qui existent peuvent être appelés en direct, notamment pour ce qui est des fichiers CSS et JS, mais la redirection se fait vers le fichier index.php pour toutes les requêtes vers des URL qui ne représentent pas des fichiers. C'est pas toujours simple à mettre en œuvre, et ce qui pose généralement problème est que l'on ne veut pas que des utilisateurs mal intentionnés aient directement accès aux fichiers PHP ou JSON, d'où ce fichier .htaccess en plus dans chaque dossier de l'arborescence (sauf ceux qui contiennent les fichiers CSS, JS ou autres librairies) :
RewriteEngine On
RewriteRule ^(.*)$ - [R=404,L]
On pourrait aussi simplement rediriger l'URL vers la page d'accueil mais ça peut aussi servir, avec la réponse 404, en triant les fichiers logs, de bloquer les IPs des crawlers et autres robots de recherche ou de piratage qui veulent accéder à des pages auxquels ils ne sont pas censés accéder directement.
Ensuite, pour visualiser l'arborescence, il faut comprendre l'architecture MVC (Modèle, Vue, Contrôleur), qui permet de séparer les différents éléments du site : le code et les données. En réalité, ce ne sont pas juste MVC, mais plutôt VDC (Vue/Data/Code) et on peut y ajouter quelques variantes.
Les dossiers
A partir de là, je crée 7 dossiers qui contiennent ensuite les 5 différents types de fichiers :
- theme : c'est le dossier qui contient tous les fichiers du thème, que j'ai créé ou que j'ai acheté/téléchargé. A l'intérieur de ce dossier, on peut aussi trouver des dossiers comme css, js, fonts, img, ... La contrainte, dans ce dossier, est que tous les fichiers doivent être accessibles en direct, aucun fichier PHP ne doit s'y trouver et ce sont donc toujours des fichiers statiques.
- lib : ce sont des fichiers contenant des librairies, créées par moi ou utilisées depuis d'autres sources. Ce sont des fichiers PHP qui contiennent le plus souvent des objets ou des fonctions qui peuvent servir sur l'ensemble du site. Lorsqu'une requête arrive sur index.php, l'ensemble des fichiers qui se trouvent dans ce dossier est chargé, et tous les contrôleurs peuvent alors utiliser les fonctions qui s'y trouvent. Il n'y a pas de sous-dossiers dans ce dossier.
- data : dans ce dossier se trouvent des fichiers contenant des données utiles au fonctionnement du site. Ça peut être les données du routeur (voir plus bas) ou des données en SQLite, ou tout autre donnée, statique ou dynamique, mais qui ne doivent pas être accédées directement. Pas de fichier PHP dans ce dossier, mais des sous-dossiers peuvent s'y trouver.
- controllers : ce dossier contient tous les objets qui sont utilisés pour gérer le site internet. C'est dans ce dossier, dans ces objets, que se trouve le code qui va permettre de réaliser des opérations à la fois sur les données et sur les vues. Généralement, le contrôleur est là pour récupérer les données et les afficher, ou bien récupérer les modifications depuis la requête et modifier la base de données. C'est le coeur de l'application web. Tous les fichiers sont chargés à chaque requête ou bien ceux qui peuvent être utiles.
- views : ce dossier contient l'ensemble des vues. Ce sont des fichiers PHP qui contiennent un minimum de code, généralement uniquement du code qui permet l'affichage d'une donnée. Ces fichiers sont chargés par un contrôleur lorsqu'il veut afficher quelque chose. Soit c'est le contrôleur qui charge le fichier vue, soit c'est le fichier index.php qui le charge s'il en a besoin pour appeler le contrôleur ou suite à l'appel du contrôleur.
- modals : j'aime bien séparer les vues des modaux. Une vue peut nécessiter l'affichage d'un modal, et dans ce cas, il peut le charger, soit dynamiquement, soit de manière statique quand la vue est affichée (puis le modal est affiché en JS si besoin). Généralement, le modal va appeler, s'il est chargé de manière statique, un contrôleur, pour récupérer les données à afficher, mais cela n'est pas toujours nécessaire, toutefois je préfère mettre ces fichiers, PHP, dans ce dossier.
- db : certains appellent ce dossier autrement, entities par exemple, ou tables ou autre. Ce dossier peut contenir un objet qui va modéliser une table, principalement, ce qui permet alors de faire appel à cet objet pour avoir facilement accès aux données de cette table. Je n'utilise pas toujours ce dossier, cela va dépendre du site.
Le routeur
Quand un appel est fait sur le fichier index.php, alors on doit avoir une table de correspondance pour savoir quel contrôleur utiliser suivant l'URL appelée. Par exemple, si on a l'URL suivante :
https://fredsblog.fr/navigations/granville
Il faut que l'on sache quel contrôleur doit gérer cette requête pour afficher correctement le bon article. Pour cela, on utilise un routeur. C'est-à-dire d'un côté, une fonction qui va récupérer l'URL et chercher la correspondance dans une table. Ensuite, elle va appeler la fonction qu'il faut avec les bons paramètres et renvoyer les données à celui qui a fait l'appel.
Ici, on aura donc un appel qui sera traduit en :
index.php?path=/navigations/granville
Pour déterminer quelle fonction appeler, on a un fichier qui se nomme router.json qui contient un fichier au format JSON, avec une correspondance comme ceci, par exemple :
[
{
"verb": "GET",
"uri": "/",
"method": "HomeController.index",
"permission": "all"
},
{
"verb": "GET",
"uri": "/navigations/([a-z0-9.]*)",
"method": "NavigationController.post",
"params": [
"pwd_token"
]
}
]
Dans notre exemple, tous les appels contenant le mot navigations suivi d'un autre mot seront envoyés à la fonction post du contrôleur NavigationController, qui se chargera alors d'afficher le post.
Avantages
Cette méthode de gestion d'une application web est bien plus optimale que la méthode que j'utilisais avant, d'une part pour l'arborescence qui permet de gérer beaucoup de choses de manière claire. Seule contrainte pour que tout se passe bien, c'est de bien gérer le nom des contrôleurs et leur périmètre pour être sûr que lorsque l'on cherche du code qui fait quelque chose de particulier, on ne passe pas la journée à trouver dans quel contrôleur il se trouve. Le routeur aide aussi à trouver assez facilement les bonnes fonctions, donc tout est clair et transparent.
L'autre avantage non négligeable est la sécurité : si les fichiers .htaccess sont bien créés et fonctionnent correctement, alors tout passe par le fichier index.php. Dans ce cas, cela signifie que tout peut être sécurisé correctement, notamment pour ce qui est de la gestion des utilisateurs, de leurs droits, et des fuites qui pourraient apparaître si de nombreux fichiers servent de porte d'entrée. Ici, on peut sécuriser la transmission des données pour empêcher l'injection de code notamment, directement dans le fichier index.php pour l'ensemble du site, voire même on peut définir des types pour les variables transmises depuis le navigateur, et les nettoyer au moment où le fichier index.php les transmets au contrôleur.
Ce système n'a donc que des avantages, permet aussi de maintenir plus facilement le code, et globalement donne une meilleure visibilité sur celui-ci. Même s'il reste malheureusement une dette technique à ce niveau assez lourde, car transcrire un code non centralisé dans ce type d'application centralisée prend beaucoup de temps et peut potentiellement casser une partie des fonctionnalités, c'est un avantage énorme de le faire pour que le code soit ensuite réutilisé et surtout mis à jour facilement, c'est ce système que nous utilisons chez HaiSoft, pour nos applications métier, quand c'est possible.