Table of Contents

Parlons-en - Construire un Framework PHP Modulaire, partie 3

Auteur(s) : Louis Ouellet


Dans ce troisième volet de notre série Construire un Framework PHP Modulaire, nous allons aborder :

Nous allons poursuivre le travail entamé précédemment, en mettant l'accent sur la sécurité (CSRF), la configuration des routes pour l'API et une gestion plus avancée de la base de données.

Cross-Site Request Forgery (CSRF)

Qu'est-ce que le CSRF ? Le Cross-Site Request Forgery (CSRF) est une vulnérabilité de sécurité Web qui permet à un attaquant de duper un utilisateur afin qu'il effectue des actions non désirées sur un site ou une application Web où il est déjà authentifié. En d'autres termes, l'attaquant exploite la session du navigateur de l'utilisateur (y compris les cookies) pour envoyer des requêtes non autorisées, souvent sans que l'utilisateur s'en rende compte.

Pour se protéger contre le CSRF, nous générons et validons un jeton secret qui doit être inclus dans toutes les requêtes qui ne sont pas de type GET.

Nous nous assurons d'abord que la session est démarrée dans la classe Bootstrap :

// Start the session
if (!defined('STDIN') && session_status() === PHP_SESSION_NONE) {
    ini_set('session.cookie_samesite', 'Strict');
    ini_set('session.cookie_secure', 'On');
    session_start();
}

Ensuite, nous créons la classe CSRF :

Source: CSRF.php

La classe CSRF :

Configuration d'Apache (.htaccess)

Pour que notre application puisse gérer correctement les routes, nous créons deux fichiers .htaccess : l'un à la racine (root) et l'autre dans le sous-répertoire webroot.

Source: .htaccess

Source: .htaccess

Ces règles veillent à ce que les appels soient correctement dirigés vers index.php, et bloquent l'accès direct à certains fichiers (CLI, .htaccess).

Construction du module API

Le module API nous permet (et éventuellement à des tiers) de demander, d'échanger ou de synchroniser des données avec notre application. Notre logique se trouve principalement dans deux fichiers : API.php et Endpoint.php.

Source: API.php

Source: Endpoint.php

Comment ça marche :

  1. Nous analysons le namespace (chemin) de la requête pour déterminer l'endpoint et l'action.
  2. Nous tentons de charger une classe correspondante dans le dossier /Endpoint ou dans un plugin.
  3. Si elle existe, nous l'instancions et vérifions que la méthode demandée est disponible.
  4. Des vérifications optionnelles d'authentification et de permissions sont effectuées.
  5. L'action est exécutée et nous renvoyons le résultat en JSON avec le code HTTP approprié.

Gestion de la base de données

Dans la partie 2, nous avons introduit les models. Désormais, nous allons affiner la gestion de la base, incluant la création de requêtes et la gestion du schéma. Examinons brièvement les différentes classes.

La classe Database

Sources: Database.php

Cette classe charge la configuration de la base de données et instancie le Connector adéquat en fonction du fichier de config. Elle fournit aussi des méthodes utilitaires pour créer de nouveaux objets Query ou Schema.

Les classes Connector et MySQL

Sources: Connector.php

Sources: MySQL.php

La classe Connector est abstraite : chaque type de base de données (par exemple MySQL, SQLite ou PostgreSQL) doit implémenter les méthodes requises. Dans notre exemple, seule la classe MySQL est développée.

La classe Query

Sources: Query.php

La classe Query permet de construire des requêtes SQL de façon structurée et chaînable. Une fois la requête bâtie, un appel à →result() l'exécute. Par exemple :

$db = new Database();
$data = $db->query()
    ->select('*')
    ->table('users')
    ->filter()
    ->where('username', 'jdoe')
    ->result();

Les classes Schema et Definition

Sources: Schema.php

Sources: Definition.php

Ces classes vous permettent de gérer la structure des tables et leurs colonnes de manière plus programmatique. Vous pouvez :

Conclusion

Nous avons maintenant implémenté plusieurs fonctionnalités essentielles dans notre framework PHP :

Grâce à ces éléments, notre framework peut maintenant gérer une sécurité de base, des opérations de données robustes et des structures modulaires pour les endpoints. Dans les prochains volets, nous allons approfondir les mécanismes d'authentification, discuter de routage avancé ou d'architectures de plugins, et continuer à peaufiner notre framework pour qu'il soit à la fois extensible et sécurisé.

Dépôt GitHub

v0.0.11

Tags