# Documentation Technique API RESTful PHP 8.3 ## Table des matières 1. [Structure du projet](#structure-du-projet) 2. [Configuration du serveur](#configuration-du-serveur) 3. [Flux d'une requête](#flux-dune-requête) 4. [Architecture des composants](#architecture-des-composants) 5. [Base de données](#base-de-données) 6. [Sécurité](#sécurité) 7. [Endpoints API](#endpoints-api) 8. [Changements récents](#changements-récents) ## Structure du projet ```plaintext /api/ ├── docs/ │ └── TECHBOOK.md ├── src/ │ ├── Controllers/ │ │ └── UserController.php │ ├── Core/ │ │ ├── Router.php │ │ ├── Request.php │ │ ├── Response.php │ │ ├── Session.php │ │ └── Database.php │ └── Config/ │ └── config.php ├── index.php └── .htaccess ``` ## Configuration du serveur ### Prérequis - Debian 12 - NGINX - PHP 8.3-FPM - MariaDB 10.11 ### Configuration NGINX Le serveur NGINX est configuré pour rediriger toutes les requêtes vers le point d'entrée `index.php` de l'API. ### Configuration PHP-FPM PHP-FPM est configuré pour gérer les processus PHP avec des paramètres optimisés pour une API. ## Flux d'une requête Exemple détaillé du parcours d'une requête POST /api/users : 1. **Entrée de la requête** - La requête arrive sur le serveur NGINX - NGINX redirige vers PHP-FPM via le socket unix - Le fichier .htaccess redirige vers index.php 2. **Initialisation (index.php)** - Chargement des dépendances - Initialisation de la configuration - Démarrage de la session - Configuration des headers CORS - Initialisation du routeur 3. **Routage** - Le Router analyse la méthode HTTP (POST) - Analyse de l'URI (/api/users) - Correspondance avec les routes enregistrées - Instanciation du Controller approprié 4. **Traitement (UserController)** - Vérification de l'authentification - Récupération des données JSON - Validation des données reçues - Traitement métier - Interaction avec la base de données - Préparation de la réponse 5. **Réponse** - Formatage de la réponse en JSON - Configuration des headers de réponse - Envoi au client ## Architecture des composants ### Core Components #### Router - Gère le routage des requêtes - Associe les URLs aux Controllers - Gère les paramètres d'URL - Dispatch vers les méthodes appropriées #### Request - Parse les données entrantes - Gère les différents types de contenu - Nettoie et valide les entrées - Fournit une interface unifiée pour accéder aux données #### Response - Formate les réponses en JSON - Gère les codes HTTP - Configure les headers de réponse - Assure la cohérence des réponses #### Session - Gère l'état des sessions - Stocke les données d'authentification - Vérifie les permissions - Sécurise les données de session #### Database - Gère la connexion à MariaDB - Fournit une interface PDO - Gère le pool de connexions - Assure la sécurité des requêtes ## Base de données ### Structure des tables principales #### Table `users` - `encrypted_user_name` : Identifiant de connexion chiffré (unique) - `encrypted_email` : Email chiffré (unique) - `user_pass_hash` : Hash du mot de passe - `encrypted_name`, `encrypted_phone`, `encrypted_mobile` : Données personnelles chiffrées - Autres champs : `first_name`, `sect_name`, `fk_role`, `fk_entite`, etc. #### Table `entites` (Amicales) - `chk_mdp_manuel` (DEFAULT 0) : Gestion manuelle des mots de passe - `chk_username_manuel` (DEFAULT 0) : Gestion manuelle des identifiants - `chk_stripe` : Activation des paiements Stripe - Données chiffrées : `encrypted_name`, `encrypted_email`, `encrypted_phone`, etc. #### Table `medias` - `support` : Type de support (entite, user, operation, passage) - `support_id` : ID de l'élément associé - `file_category` : Catégorie (logo, export, carte, etc.) - `file_path` : Chemin complet du fichier - `processed_width/height` : Dimensions après traitement - Utilisée pour stocker les logos des entités ### Chiffrement des données Toutes les données sensibles sont chiffrées avec AES-256-CBC : - Emails, noms, téléphones - Identifiants de connexion - Informations bancaires (IBAN, BIC) ### Migration de base de données Script SQL pour ajouter les nouveaux champs : ```sql -- Ajout de la gestion manuelle des usernames ALTER TABLE `entites` ADD COLUMN `chk_username_manuel` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'Gestion des usernames manuelle (1) ou automatique (0)' AFTER `chk_mdp_manuel`; -- Index pour optimiser la vérification d'unicité ALTER TABLE `users` ADD INDEX `idx_encrypted_user_name` (`encrypted_user_name`); ``` ## Sécurité ### Mesures implémentées - Validation stricte des entrées - Protection contre les injections SQL (PDO) - Hachage sécurisé des mots de passe - Headers de sécurité HTTP - Gestion des CORS - Session sécurisée - Authentification requise - Chiffrement AES-256 des données sensibles - Envoi séparé des identifiants par email ## Endpoints API ### Routes Publiques vs Privées L'API distingue deux types de routes : #### Routes Publiques - POST /api/login - POST /api/register - GET /api/health #### Routes Privées (Nécessitent une session authentifiée) - Toutes les autres routes ### Authentification L'authentification utilise le système de session PHP natif. #### Login ```http POST /api/login Content-Type: application/json { "email": "user@example.com", "password": "SecurePassword123" } ``` **Réponse réussie :** ```json { "message": "Connecté avec succès", "user": { "id": 123, "email": "user@example.com" } } ``` **Notes importantes :** - Un cookie de session PHP sécurisé est automatiquement créé - Le cookie est httpOnly, secure et SameSite=Strict - L'ID de session est régénéré à chaque login réussi #### Logout ```http POST /api/logout ``` **Réponse réussie :** ```json { "message": "Déconnecté avec succès" } ``` ### Sécurité des Sessions La configuration des sessions inclut : - Sessions PHP natives sécurisées - Protection contre la fixation de session - Cookies httpOnly (protection XSS) - Mode strict pour les cookies - Validation côté serveur à chaque requête - use_strict_mode = 1 - cookie_httponly = 1 - cookie_secure = 1 - cookie_samesite = Strict - Régénération de l'ID de session après login - Destruction complète de la session au logout ### Users #### Création d'utilisateur La création d'utilisateur s'adapte aux paramètres de l'entité (amicale) : ```http POST /api/users Content-Type: application/json Authorization: Bearer {session_id} { "email": "john@example.com", "name": "John Doe", "first_name": "John", "role": 1, "fk_entite": 5, "username": "j.doe38", // Requis si chk_username_manuel=1 pour l'entité "password": "SecurePass123", // Requis si chk_mdp_manuel=1 pour l'entité "phone": "0476123456", "mobile": "0612345678", "sect_name": "Secteur A", "date_naissance": "1990-01-15", "date_embauche": "2020-03-01" } ``` **Comportement selon les paramètres de l'entité :** | chk_username_manuel | chk_mdp_manuel | Comportement | |---------------------|----------------|--------------| | 0 | 0 | Username et password générés automatiquement | | 0 | 1 | Username généré, password requis dans le payload | | 1 | 0 | Username requis dans le payload, password généré | | 1 | 1 | Username et password requis dans le payload | **Validation du username (si manuel) :** - Format : 10-30 caractères - Commence par une lettre - Caractères autorisés : a-z, 0-9, ., -, _ - Doit être unique dans toute la base **Réponse réussie :** ```json { "status": "success", "message": "Utilisateur créé avec succès", "id": 123, "username": "j.doe38", // Toujours retourné "password": "xY7#mK9@pL2" // Retourné seulement si généré automatiquement } ``` **Envoi d'emails :** - **Email 1** : Identifiant de connexion (toujours envoyé) - **Email 2** : Mot de passe (toujours envoyé, 1 seconde après le premier) **Codes de statut :** - 201: Création réussie - 400: Données invalides ou username/password manquant si requis - 401: Non authentifié - 403: Accès non autorisé (rôle insuffisant) - 409: Email ou username déjà utilisé - 500: Erreur serveur #### Vérification de disponibilité du username ```http POST /api/users/check-username Content-Type: application/json Authorization: Bearer {session_id} { "username": "j.doe38" } ``` **Réponse si disponible :** ```json { "status": "success", "available": true, "message": "Nom d'utilisateur disponible", "username": "j.doe38" } ``` **Réponse si déjà pris :** ```json { "status": "success", "available": false, "message": "Ce nom d'utilisateur est déjà utilisé", "suggestions": ["j.doe38_42", "j.doe381234", "j.doe3825"] } ``` #### Autres endpoints - GET /api/users - GET /api/users/{id} - PUT /api/users/{id} - DELETE /api/users/{id} - POST /api/users/{id}/reset-password ### Entités (Amicales) #### Upload du logo d'une entité ```http POST /api/entites/{id}/logo Content-Type: multipart/form-data Authorization: Bearer {session_id} Body: logo: File (image/png, image/jpeg, image/jpg) ``` **Restrictions :** - Réservé aux administrateurs d'amicale (fk_role == 2) - L'admin ne peut uploader que le logo de sa propre amicale - Un seul logo actif par entité (le nouveau remplace l'ancien) **Traitement de l'image :** - Formats acceptés : PNG, JPG, JPEG - Redimensionnement automatique : 250x250px maximum (ratio conservé) - Résolution : 72 DPI (standard web) - Préservation de la transparence pour les PNG **Stockage :** - Chemin : `/uploads/entites/{id}/logo/logo_{id}_{timestamp}.{ext}` - Enregistrement dans la table `medias` - Suppression automatique de l'ancien logo **Réponse réussie :** ```json { "status": "success", "message": "Logo uploadé avec succès", "media_id": 42, "file_name": "logo_5_1234567890.jpg", "file_path": "/entites/5/logo/logo_5_1234567890.jpg", "dimensions": { "width": 250, "height": 180 } } ``` #### Récupération du logo d'une entité ```http GET /api/entites/{id}/logo Authorization: Bearer {session_id} ``` **Réponse :** ```json { "status": "success", "logo": { "id": 42, "data_url": "data:image/png;base64,iVBORw0KGgoAAAANS...", "file_name": "logo_5_1234567890.png", "mime_type": "image/png", "width": 250, "height": 180, "size": 15234 } } ``` **Note :** Le logo est également inclus automatiquement dans la réponse du login si disponible. #### Mise à jour d'une entité ```http PUT /api/entites/{id} Content-Type: application/json Authorization: Bearer {session_id} { "name": "Amicale de Grenoble", "adresse1": "123 rue de la Caserne", "adresse2": "", "code_postal": "38000", "ville": "Grenoble", "phone": "0476123456", "mobile": "0612345678", "email": "contact@amicale38.fr", "chk_stripe": true, // Activation paiement Stripe "chk_mdp_manuel": false, // Génération auto des mots de passe "chk_username_manuel": false, // Génération auto des usernames "chk_copie_mail_recu": true, "chk_accept_sms": false } ``` **Paramètres de gestion des membres :** | Paramètre | Type | Description | |-----------|------|-------------| | chk_mdp_manuel | boolean | `true`: L'admin saisit les mots de passe
`false`: Génération automatique | | chk_username_manuel | boolean | `true`: L'admin saisit les identifiants
`false`: Génération automatique | | chk_stripe | boolean | Active/désactive les paiements Stripe | **Note :** Ces paramètres sont modifiables uniquement par les administrateurs (fk_role > 1). #### Réponse du login avec paramètres entité Lors du login, les paramètres de l'entité sont retournés dans le groupe `amicale` : ```json { "status": "success", "session_id": "abc123...", "session_expiry": "2025-01-09T15:30:00+00:00", "user": { "id": 9999980, "fk_entite": 5, "fk_role": 2, "fk_titre": null, "first_name": "Pierre", "sect_name": "", "date_naissance": "1990-01-15", // Maintenant correctement récupéré "date_embauche": "2020-03-01", // Maintenant correctement récupéré "username": "pv_admin", "name": "VALERY ADM", "phone": "0476123456", // Maintenant correctement récupéré "mobile": "0612345678", // Maintenant correctement récupéré "email": "contact@resalice.com" }, "amicale": { "id": 5, "name": "Amicale de Grenoble", "chk_mdp_manuel": 0, "chk_username_manuel": 0, "chk_stripe": 1, "logo": { // Logo de l'entité (si disponible) "id": 42, "data_url": "data:image/png;base64,iVBORw0KGgoAAAANS...", "file_name": "logo_5_1234567890.png", "mime_type": "image/png", "width": 250, "height": 180 } // ... autres champs } } ``` Ces paramètres permettent à l'application Flutter d'adapter dynamiquement le formulaire de création de membre. ## Intégration Frontend ### Configuration des Requêtes Toutes les requêtes API depuis le frontend doivent inclure : ```javascript fetch('/api/endpoint', { credentials: 'include', // Important pour les cookies de session // ... autres options }); ``` ### Gestion des Sessions - Les cookies de session sont automatiquement gérés par le navigateur - Pas besoin de stocker ou gérer des tokens manuellement - Redirection vers /login si session expirée (401) ## Maintenance et Déploiement ### Logs - Logs d'accès NGINX : /var/log/nginx/api-access.log - Logs d'erreur NGINX : /var/log/nginx/api-error.log - Logs PHP : /var/log/php/php-error.log ### Déploiement 1. Pull du repository 2. Vérification des permissions 3. Configuration de l'environnement 4. Tests des endpoints 5. Redémarrage des services ### Surveillance - Monitoring des processus PHP-FPM - Surveillance de la base de données - Monitoring des performances - Alertes sur erreurs critiques ## Changements récents ### Version 3.0.6 (Janvier 2025) #### 1. Correction des rôles administrateurs - **Avant :** Les administrateurs d'amicale devaient avoir `fk_role > 2` - **Après :** Les administrateurs d'amicale ont `fk_role > 1` (donc rôle 2 et plus) - **Impact :** Les champs `chk_stripe`, `chk_mdp_manuel`, `chk_username_manuel` sont maintenant modifiables par les admins d'amicale (rôle 2) #### 2. Envoi systématique des deux emails lors de la création d'utilisateur - **Avant :** Le 2ème email (mot de passe) n'était envoyé que si le mot de passe était généré automatiquement - **Après :** Les deux emails sont toujours envoyés lors de la création d'un membre - Email 1 : Identifiant (username) - Email 2 : Mot de passe (1 seconde après) - **Raison :** Le nouveau membre a toujours besoin des deux informations pour se connecter #### 3. Ajout des champs manquants dans la réponse du login - **Champs ajoutés dans la requête SQL :** - `fk_titre` - `date_naissance` - `date_embauche` - `encrypted_phone` - `encrypted_mobile` - **Impact :** Ces données sont maintenant correctement retournées dans l'objet `user` lors du login #### 4. Système de gestion des logos d'entité - **Nouvelle fonctionnalité :** Upload et gestion des logos pour les amicales - **Routes ajoutées :** - `POST /api/entites/{id}/logo` : Upload d'un nouveau logo - `GET /api/entites/{id}/logo` : Récupération du logo - **Caractéristiques :** - Réservé aux administrateurs d'amicale (fk_role == 2) - Un seul logo actif par entité - Redimensionnement automatique (250x250px max) - Format base64 dans les réponses JSON (compatible Flutter) - Logo inclus automatiquement dans la réponse du login #### 5. Amélioration de l'intégration Flutter - **Format d'envoi des images :** Base64 data URL pour compatibilité multiplateforme - **Structure de réponse enrichie :** Le logo est inclus dans l'objet `amicale` lors du login - **Optimisation :** Pas de requête HTTP supplémentaire nécessaire pour afficher le logo