Introduction & Philosophie

ArtiFrame est basé sur le principe de "Convention over Configuration" (Convention plutôt que Configuration). La force d'un framework ne vient pas de la richesse des outils qu'il propose, mais de la cohérence de l'ordre qu'il établit.

Zéro Surcharge (Zero Overhead)

Zéro dépendance aux paquets Composer, au cœur du framework ou aux bibliothèques tierces. Chaque ligne de code est la vôtre ; sans gonflement, sans couches d'abstraction inutiles.

La Sécurité d'Abord

La protection XSS, la validation CSRF, l'assainissement contre l'injection SQL et le contrôle de la méthode HTTP sont intégrés par défaut. La sécurité n'est pas une option, c'est un standard.

Ensemble de Règles Strict

Un développeur junior nouvellement intégré au projet comprend l'architecture data-js et la structure des répertoires en quelques minutes. La cohésion de l'équipe est garantie au niveau du framework.

Priorité à la CLI

Pas de création manuelle de fichiers view, API ou class. La CLI génère à partir de fichiers stub, établit des liens d'assets et maintient le projet cohérent.

ℹ️ Licence AGPLv3 : ArtiFrame est open source. Les travaux dérivés que vous produisez peuvent être utilisés librement, à condition que le code source reste ouvert. L'avis de droit d'auteur ne peut être supprimé.

Installation

ArtiFrame CLI est installé en tant qu'outil PHP global. Installé une fois, il est utilisé dans chaque projet.

1. Installer l'Outil CLI Globalement

# Installation globale via NPM
npm install -g @artilingo/artiframe-cli

# Vérifier l'installation
artiframe

2. Shell Interactif

Tapez simplement artiframe dans le terminal et appuyez sur Entrée. La CLI ne se ferme pas ; un shell interactif s'ouvre, à l'écoute des commandes en continu :

==================================================
        ArtiFrame CLI Interactive Shell v1.0.0
==================================================
Type 'help' for commands, or 'exit' to quit.

artiframe> 

3. Démarrer un Nouveau Projet

artiframe> new mon-projet

Cette commande crée le répertoire mon-projet/ et copie toute la structure squelette à l'intérieur : app/, bin/, config/, public/, src/, .env.example et la première page index.php.

4. Paramètres d'Environnement

cp .env.example .env

Ouvrez votre fichier .env et remplissez les informations de base de données et d'application. Ce fichier n'entre jamais dans le contrôle de version.

⚠️ Paramètre du Serveur Web : Dirigez le document root d'Apache/Nginx vers le dossier /public/. Les autres répertoires ne doivent jamais être exposés à l'extérieur.

Structure du Répertoire

L'architecture créée au démarrage du projet ; assure une séparation claire des responsabilités (SoC).

nom-du-projet/ ├── app/ # Couche d'infrastructure │ ├── ViewControl.php # Bootstrapper pour les vues (pages HTML) │ ├── ApiControl.php # Bootstrapper pour les endpoints API │ ├── Database.php # Connexion à la base de données basée sur PDO │ ├── DotEnv.php # Lecteur de .env │ └── R2Manager.php # Gestionnaire de fichiers Cloudflare R2 │ ├── bin/ # ⚠️ Système de base — ne pas modifier directement │ ├── SystemMethod.php # Utilitaires globaux API/Backend │ ├── ViewMethod.php # Utilitaires globaux View/Frontend │ └── stubs/ # Modèles utilisés par la CLI │ ├── view.stub │ ├── api-standart.stub │ ├── api-switch-case.stub │ └── class.stub │ ├── config/ # Fichiers de configuration │ └── app-version.php # Constantes APP_VERSION et APP_ENV │ ├── public/ # ← Le seul répertoire ouvert du serveur web │ ├── assets/ │ │ ├── css/ # Fichiers CSS spécifiques aux vues │ │ └── js/ # Fichiers JS spécifiques aux vues │ ├── includes/ # Composants partagés │ │ ├── head.php │ │ ├── header.php │ │ └── footer.php │ ├── api/ # Fichiers d'endpoints API │ └── index.php # Page d'accueil │ ├── src/ # Logique métier et classes ├── .env # Variables d'environnement (non suivies par git) ├── .env.example # Modèle — suivi par git └── guide_fr.html # Ce document
🚫 Ne touchez pas au répertoire bin/ : Les fichiers dans bin/ constituent le cœur du framework. La logique métier spécifique au projet n'est pas ajoutée ici. Les classes et les services que vous ajouterez se trouvent sous src/, et les composants d'infrastructure se trouvent sous app/.

Architecture Bootstrapper Critique

ArtiFrame utilise deux bootstrappers complètement indépendants. Cette architecture empêche fondamentalement les problèmes d'en-tête HTML et les failles de sécurité.

Vue ViewControl.php

Utilisé pour les pages HTML (fichiers de vue). Démarre la session, charge ViewMethod.

// public/profil.php — TOUT EN HAUT, avant d'imprimer le HTML
<?php
require_once $_SERVER['DOCUMENT_ROOT']
    . '/../app/ViewControl.php';
use Bin\ViewMethod;
?>
<!DOCTYPE html>
...

API ApiControl.php

Utilisé pour les fichiers d'endpoints API. Définit l'en-tête JSON, effectue le contrôle de la méthode HTTP, charge SystemMethod.

// public/api/utilisateur/obtenir.php
<?php
// $allowedMethods DOIT être défini avant require
$allowedMethods = ['GET'];

require_once $_SERVER['DOCUMENT_ROOT']
    . '/../app/ApiControl.php';

use Bin\SystemMethod;
🚫 ViewControl et ApiControl ne sont jamais mélangés : Si ViewControl est requis dans un fichier API, il peut renvoyer un en-tête HTML au lieu d'un en-tête JSON, et toute la réponse de l'API sera corrompue. Si ApiControl est requis dans une page HTML, la session ne démarre pas et la page se casse.

Ensemble de Règles Standard

Règle 1 : Architecture data-js Critique

Les événements JavaScript ne peuvent jamais être écoutés via une class ou un id. Ce sont des identités visuelles/de style. Toutes les interactions JS sont gérées par l'attribut data-js. Si CSS supprime une classe, JavaScript ne plante jamais.

<!-- ❌ Anti-Pattern — non pris en charge -->
<button id="submitBtn" class="btn">Envoyer</button>
// JS: document.getElementById('submitBtn').addEventListener(...)

<!-- ✅ Standard ArtiFrame -->
<button class="btn btn-primary" data-js="login-submit">Envoyer</button>
// JS: document.querySelector('[data-js="login-submit"]').addEventListener(...)

Règle 2 : Architecture de Thème

Les modes Sombre/Clair et les thèmes sont gérés via les attributs data-theme et data-mode de la balise <html>. Les classes de corps ne sont pas utilisées.

<!-- Balise d'ouverture HTML provenant du modèle view.stub -->
<html lang="fr" data-theme="default" data-mode="light">

/* Définition du thème dans app.css */
html[data-theme="default"][data-mode="dark"] {
    --bg-color: #0b0c0e;
    --text-main: #ffffff;
}
html[data-theme="default"][data-mode="light"] {
    --bg-color: #ffffff;
    --text-main: #111111;
}

Règle 3 : Flux de Données Sécurisé

Toutes les données provenant de la base de données sont enveloppées avec display() avant d'être imprimées sur le DOM. Chaque donnée entrant dans l'API est nettoyée avec sanitizeString() ou sanitizeInt() avant d'être traitée.

Règle 4 : Gestion des Erreurs avec APP_ENV

La valeur APP_ENV dans le fichier .env détermine la visibilité des erreurs. En production, aucun message d'erreur n'est affiché à l'utilisateur.

// config/app-version.php
define('APP_ENV', (int)$_ENV['APP_ENV']); // 1=Debug, 0=Production

if (APP_ENV === 1) {
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
} else {
    ini_set('display_errors', 0);
}

Écosystème CLI

ArtiFrame CLI ouvre un shell interactif lorsque vous tapez artiframe dans le terminal. Toutes les commandes s'exécutent dans ce shell. Les commandes peuvent également être exécutées en une seule fois.

# Mode interactif (recommandé)
artiframe
artiframe> make:view admin/utilisateurs.php

# Mode à usage unique
artiframe make:view admin/utilisateurs.php

new Commande CLI

Crée un nouveau projet ArtiFrame. Génère le squelette complet du répertoire, les fichiers bootstrapper et la première page d'index.

artiframe> new nom-du-projet

Structure créée :

nom-du-projet/ ├── app/ (ViewControl.php, ApiControl.php, Database.php, DotEnv.php) ├── bin/ (SystemMethod.php, ViewMethod.php, stubs/) ├── config/ (app-version.php) ├── public/ (index.php, assets/, includes/, api/) ├── src/ ├── .env.example └── guide_fr.html

make:view Commande CLI

Crée un nouveau fichier de page (view) et ses ressources CSS/JS dédiées. Les ressources sont automatiquement liées à la page avec une invalidation du cache (cache-busting) via ?v=APP_VERSION.

artiframe> make:view admin/utilisateurs.php

Fichiers créés :

✔  public/admin/utilisateurs.php
✔  public/assets/css/admin/utilisateurs.css
✔  public/assets/js/admin/utilisateurs.js

Le fichier view généré inclut déjà `ViewControl` au début, comprend les inclusions de head/header/footer, et les liens CSS/JS sont connectés avec le système de cache-busting.

make:api Commande CLI

Crée un fichier endpoint API en sélectionnant l'un des deux modèles disponibles. Dans chaque nouveau fichier API, la variable $allowedMethods et l'inclusion de ApiControl.php sont déjà préparées.

standart — API à Action Unique

Pour les endpoints qui effectuent une seule tâche (connexion, envoi, suppression). La logique métier y est écrite directement.

artiframe> make:api standart api/auth/connexion.php
<?php
$allowedMethods = ['POST']; // Accepte uniquement POST
require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';

use Bin\SystemMethod;

// Logique métier ici...
jsonResponse(['status' => 'success'], 200);

switch-case — API Multi-Actions

Une structure qui gère les opérations CRUD pour un module dans un seul endpoint. L'opération à effectuer est déterminée par le paramètre action.

artiframe> make:api switch-case api/utilisateur/gerer.php
<?php
$allowedMethods = ['POST'];
require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';

use Bin\SystemMethod;

$action = sanitizeString($_POST['action'] ?? '');

switch ($action) {
    case 'create':
        jsonResponse(['status' => 'success', 'message' => 'Créé.'], 200);
        break;
    case 'update':
        jsonResponse(['status' => 'success', 'message' => 'Mis à jour.'], 200);
        break;
    case 'delete':
        jsonResponse(['status' => 'success', 'message' => 'Supprimé.'], 200);
        break;
    default:
        jsonResponse(['status' => 'error', 'message' => 'Action non valide.'], 400);
}

make:class Commande CLI

Crée un nouveau fichier de classe PHP avec son espace de noms (namespace) et son modèle de classe déjà préparés.

artiframe> make:class src/Service/EmailService.php

Si le répertoire de la classe n'est pas spécifié, la commande renverra une erreur :

artiframe> make:class
❌ Erreur : Le répertoire de la classe doit être spécifié ! (par ex. /app ou /src)
Example: /src/Service/PaymentService

version Commande CLI

Met à jour le numéro de version dans config/app-version.php selon les règles du versionnage sémantique (SemVer). Format de version : MAJOR.MINOR.PATCH

CommandeDescriptionExemple
version upgrade patchCorrection de bogue, amélioration mineure1.2.3 → 1.2.4
version upgrade minorNouvelle fonctionnalité rétrocompatible1.2.3 → 1.3.0
version upgrade majorChangement majeur (rupture de compatibilité)1.2.3 → 2.0.0
version downgrade patchAnnuler le dernier patch1.2.4 → 1.2.3
version downgrade minorAnnuler la dernière version mineure1.3.0 → 1.2.0
version downgrade majorAnnuler la dernière version majeure2.0.0 → 1.0.0
artiframe> version upgrade minor
✔  La version a été mise à jour de 1.2.0 → 1.3.0.

View Helpers — display() ViewMethod

Applique une protection XSS obligatoire lors de l'impression de données provenant de la base de données ou de la saisie utilisateur sur le DOM. Au lieu de lancer une erreur sur des valeurs nulles ou vides, elle renvoie une valeur par défaut.

string display(mixed $data, string $default = '')
💡 Astuce : Utilisation de $default
Le deuxième paramètre ($default) est le texte de secours à afficher lorsque les données provenant de la base de données sont vides (null, false, chaîne vide). Par exemple, si vous utilisez display($nom, 'Anonyme') pour un utilisateur dont le nom n'a pas été saisi, votre page présentera un contenu significatif au lieu de vilains espaces vides.
<!-- ❌ Non sécurisé — crée une vulnérabilité XSS -->
<h1><?= $user['nom'] ?></h1>

<!-- ✅ Utilisation sécurisée d'ArtiFrame -->
<h1><?= display($user['nom'], 'Utilisateur Anonyme') ?></h1>

View Helpers — escapeUrl() ViewMethod

Utilisé lors de l'impression des liens reçus des utilisateurs (par exemple, les sites Web de profil) dans des balises <a href="..."> ou <img src="...">. Il neutralise les charges utiles dangereuses comme javascript:alert(1) (XSS stocké), empêchant l'exécution de code via le lien.

string escapeUrl(string $url)
<!-- ❌ Non sécurisé — le code JS peut fuiter via l'URL -->
<a href="<?= $user['website'] ?>">Visiter le Site</a>

<!-- ✅ Utilisation sécurisée d'ArtiFrame -->
<a href="<?= escapeUrl($user['website']) ?>">Visiter le Site</a>

View Helpers — csrfField() ViewMethod

Ajoute un champ de jeton caché aux formulaires HTML pour les protéger contre les attaques CSRF. Son utilisation est obligatoire sur chaque page contenant un formulaire POST.

string csrfField()
<form action="/api/sauvegarder.php" method="POST">
    <?= csrfField() ?>   <!-- Obligatoire pour la sécurité -->
    <input type="text" name="nom">
    <button type="submit" data-js="save-btn">Sauvegarder</button>
</form>

View Helpers — Fonctions de Date ViewMethod

Traite les chaînes de date au format Y-m-d H:i:s provenant de la base de données ou les valeurs timestamp UNIX. Toutes les sorties textuelles sont localisées selon la langue (tr, en, de, fr, es).

FonctionExemple de SortieDescription
day($date)24Jour uniquement
month($date)07Mois (chiffre) uniquement
year($date)2026Année
timeOnly($date)14:30Heure:Minute
fulldate($date)24.07.2026Date complète
formatDate($date, $format)24.07.2026 14:30Format personnalisé
monthName($date, $lang)Juillet / July / JuliNom du mois (selon la langue)
fulldateName($date, $lang)24 Juillet 2026 / July 24, 2026Date complète (avec nom du mois, selon la langue)
timeAgo($date, $lang)il y a 5 minutes / 5 minutes agoStyle réseaux sociaux (selon la langue)
💡 Comprendre les Paramètres : $format et $lang
  • $format (Format) : Utilisé uniquement avec la fonction formatDate(). Accepte les lettres de date standards de PHP. (Par exemple : 'd/m/Y' ➔ 24/07/2026, ou 'H:i' ➔ 15:30). Vous permet de créer votre propre modèle de date lorsque les fonctions prêtes à l'emploi (day, year, etc.) sont insuffisantes.
  • $lang (Langue) : Utilisé dans les fonctions dont la sortie contient du texte (nom du mois, mot "il y a"). Si vous laissez ce paramètre vide, le système fonctionne par défaut en 'en' (Anglais). Si vous créez un projet multilingue, il vous suffit de saisir le code de langue (tr, en, de, fr, es) dans le deuxième paramètre. (Ex : timeAgo($date, 'fr') ➔ il y a 5 minutes)
<!-- Supposons que nous ayons un timestamp UNIX obtenu via time() -->
<?php $date = time(); ?>

<!-- Date complète selon la langue -->
<span><?= fulldateName($date, 'fr') ?></span>
<!-- Sortie : 24 Juillet 2026 -->

<!-- Affichage de l'heure style réseaux sociaux -->
<span><?= timeAgo($date, 'en') ?></span>
<!-- Sortie : 5 minutes ago -->

<span><?= timeAgo($date, 'fr') ?></span>
<!-- Sortie : il y a 5 minutes -->

View Helpers — Formatage de Texte ViewMethod

truncate($text, $length, $append)

string truncate(string $text, int $length = 100, string $append = '...')

Tronque les textes longs (comme les résumés de blog) à la limite de caractères souhaitée sans couper le dernier mot et ajoute le suffixe spécifié à la fin.

<p><?= truncate($article['contenu'], 160, '...') ?></p>

View Helpers — money() ViewMethod

Formate le montant avec le symbole de la devise. Le code de la devise (ISO) détermine automatiquement l'emplacement du symbole. La devise par défaut est usd.

string money(float $amount, string $currency = 'usd')
CodeSortieDevise
usd$1.250,00Dollar Américain
eur1.250,00 €Euro
try / tl1.250,00 ₺Livre Turque
gbp£1.250,00Livre Sterling
jpy1.250,00 ¥Yen Japonais
inr1.250,00 ₹Roupie Indienne
rub1.250,00 ₽Rouble Russe
krw1.250,00 ₩Won Sud-Coréen
brlR$1.250,00Réal Brésilien
aed1.250,00 د.إDirham des EAU
<span><?= money($produit['prix'], 'eur') ?></span>
<!-- Sortie : 1.250,00 € -->

<span><?= money($produit['prix'], 'usd') ?></span>
<!-- Sortie : $1.250,00 -->

System Helpers — jsonResponse() SystemMethod

Définit l'en-tête JSON, fournit le code d'état HTTP et imprime la sortie de manière sécurisée avec json_encode, puis termine le script. Toutes les réponses de l'API doivent être données via cette fonction.

void jsonResponse(array $data, int $statusCode = 200)
// Réponse réussie
jsonResponse(['status' => 'success', 'data' => $utilisateur], 200);

// Réponse d'erreur
jsonResponse(['status' => 'error', 'message' => 'Accès non autorisé.'], 401);

System Helpers — verifyCsrf() SystemMethod

Vérifie que la requête POST entrante provient d'un formulaire légitime. Renvoie false si csrfField() n'a pas été ajouté au formulaire ou si le jeton n'est pas valide.

bool verifyCsrf(string $token)
if (!verifyCsrf($_POST['csrf_token'] ?? '')) {
    jsonResponse(['status' => 'error', 'message' => 'Jeton CSRF invalide.'], 403);
}

System Helpers — Fonctions Sanitize (Nettoyage) SystemMethod

FonctionDescription
sanitizeInt($value)Supprime toutes les lettres, symboles et virgules, en ne laissant que les chiffres entiers. Utilisé pour les ID ou les limites.
sanitizeFloat($value)Nettoie tout sauf les nombres décimaux. Utilisé pour les montants monétaires ou les métriques.
sanitizeString($value)Pour empêcher les attaques XSS et similaires, détruit toutes les balises HTML et PHP (<script>, <iframe>, etc.). Laisse un texte brut sécurisé.
sanitizeEmail($email)Filtre tous les caractères invalides et dangereux qui ne correspondent pas au format de l'e-mail.
$id    = sanitizeInt($_POST['id'] ?? 0);
$nom   = sanitizeString($_POST['nom'] ?? '');
$email = sanitizeEmail($_POST['email'] ?? '');

System Helpers — HTTP & Requête SystemMethod

getIP()

string getIP()

Obtient la véritable adresse IP de l'utilisateur, même derrière Cloudflare ou un Proxy.

getMethod()

string getMethod()

Renvoie la méthode de la requête HTTP active (GET, POST, PUT, DELETE).

System Helpers — Sécurité SystemMethod

generateToken($length)

string generateToken(int $length = 32)

Crée une chaîne hexadécimale cryptographiquement sécurisée. Utilisé pour les réinitialisations de mot de passe ou les jetons d'accès API.

API — Contrôle de Méthode HTTP ApiControl

Les fichiers d'API ArtiFrame n'autorisent aucune requête en dehors du tableau $allowedMethods. Si un pirate tente d'envoyer un POST à une API GET, la demande est bloquée avant même que le fichier ne soit lu, et une erreur HTTP 405 (Method Not Allowed) est renvoyée.

✅ Pratique Saine : Vous devez définir le tableau $allowedMethods tout en haut de votre page API (avant require).

API — Politique CORS ApiControl

ArtiFrame est livré configuré par défaut pour n'accepter que les requêtes de la même origine (Same-Origin). Si vous écrivez une API pour une application mobile (ex: React Native) ou un frontend distant, vous pouvez facilement gérer cela avec la variable $enableCors.

<?php
$allowedMethods = ['POST'];
$enableCors     = true; // Autorise l'accès de n'importe où

require_once $_SERVER['DOCUMENT_ROOT'] . '/../app/ApiControl.php';

API — Limitation de Débit (Rate Limiting)

La protection contre les requêtes excessives n'est pas encore activée par défaut, mais une architecture qui limite l'adresse IP pour empêcher les requêtes par force brute ou DoS au niveau du contrôleur d'API est en cours de développement (à venir dans la version 1.1).

Flux de Travail Complet

Voyons à quoi ressemble un flux de travail typique dans ArtiFrame. Supposons que nous voulions créer une page de connexion.

🎉 Prêt ! Vous savez maintenant comment gérer en toute sécurité l'ensemble du flux de données avec ArtiFrame. Bonne création avec un code fluide et sans dépendances !