Routeur PHP avec pages Markdown
Le routeur analyse l'URL, extrait un mot-clé, cherche un fichier .md correspondant, le convertit en HTML et l'affiche dans un template.
1. Structure des dossiers
mon-site/
├── .htaccess
├── index.php
├── template.html
└── pages/
├── accueil.md
└── contact.md
2. Fichier .htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
3. Fichier index.php
<?php
// index.php - Routeur principal
define('PAGES_DIR', __DIR__ . '/pages/');
$uri = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri, PHP_URL_PATH);
$uri = trim($uri, '/');
$motCle = empty($uri) ? 'accueil' : explode('/', $uri)[0];
$fichierMD = PAGES_DIR . $motCle . '.md';
if (file_exists($fichierMD)) {
$contenuMD = file_get_contents($fichierMD);
$contenuHTML = convertirMarkdown($contenuMD);
} else {
http_response_code(404);
$contenuHTML = '<h1>404 - Page non trouvée</h1>';
}
function convertirMarkdown($md) {
$html = $md;
$html = preg_replace('/^# (.*)$/m', '<h1>$1</h1>', $html);
$html = preg_replace('/^## (.*)$/m', '<h2>$1</h2>', $html);
$html = preg_replace('/^### (.*)$/m', '<h3>$1</h3>', $html);
$html = preg_replace('/\*\*(.*?)\*\*/', '<strong>$1</strong>', $html);
$html = preg_replace('/\*(.*?)\*/', '<em>$1</em>', $html);
$html = preg_replace('/\[(.*?)\]\((.*?)\)/', '<a href="$2">$1</a>', $html);
$html = preg_replace('/^>\s*(.*)$/m', '<blockquote>$1</blockquote>', $html);
$html = preg_replace('/^---$/', '<hr>', $html);
$html = preg_replace('/\n\s*\n/', '</p><p>', $html);
$html = '<p>' . $html . '</p>';
$html = preg_replace('/<p>\s*<\/p>/', '', $html);
return $html;
}
$template = file_get_contents('template.html');
$template = str_replace('{{ CONTENU }}', $contenuHTML, $template);
echo $template;
?>
4. Fichier template.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Mon Site</title>
</head>
<body>
<main>
{{ CONTENU }}
</main>
</body>
</html>
5. Exemple pages/accueil.md
# Accueil
Bienvenue.
[Contact](/contact)
6. Exemple pages/contact.md
# Contact
Téléphone : 04 68 00 00 00
7. Traitement de formulaire (AJAX)
À ajouter en haut de index.php.
<?php
$uri = trim($_SERVER['REQUEST_URI'], '/');
if ($uri === 'envoyer-contact' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$nom = $_POST['nom'] ?? '';
$email = $_POST['email'] ?? '';
$message = $_POST['message'] ?? '';
$errors = [];
if (empty($nom)) $errors['nom'] = 'Nom obligatoire';
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Email invalide';
}
if (empty($message)) $errors['message'] = 'Message obligatoire';
if (!empty($errors)) {
header('Content-Type: application/json');
echo json_encode(['status' => 'KO', 'errors' => $errors]);
exit;
}
mail('destinataire@exemple.fr', 'Contact', $message, "From: $email");
header('Content-Type: application/json');
echo json_encode(['status' => 'OK']);
exit;
}
?>
8. Sécurisation
À ajouter après avoir défini $fichierMD.
<?php
$fichierReel = realpath($fichierMD);
$dossierPages = realpath(PAGES_DIR);
if ($fichierReel === false || strpos($fichierReel, $dossierPages) !== 0) {
http_response_code(403);
die('Accès interdit');
}
?>
9. Règles de délimitation
- Dans la documentation : les blocs de code sont indentés avec 4 espaces.
- Dans les fichiers PHP : le code est entre
<?phpet?>. - Dans .htaccess : pas de délimiteur.
10. Résumé du fonctionnement
- Requête HTTP → /contact.
- .htaccess → index.php.
- index.php extrait "contact".
- Cherche pages/contact.md.
- Convertit en HTML.
- Insère dans template.html.
- Affiche.
FIN
// 1. Installer AltoRouter via Composer
// composer require altorouter/altorouter
// 2. index.php avec AltoRouter
<?php
require 'vendor/autoload.php';
$router = new AltoRouter();
// Définir les routes
$router->map('GET', '/', 'accueil');
$router->map('GET', '/contact', 'contact');
$router->map('POST', '/envoyer-contact', 'traiterContact');
// Exécuter
$match = $router->match();
if ($match) {
// Appeler la fonction correspondante
$nomFonction = $match['target'];
$nomFonction();
} else {
http_response_code(404);
echo '404 - Page non trouvée';
}
function accueil() {
echo 'Page d\'accueil';
}
function contact() {
echo 'Page de contact';
}
function traiterContact() {
// Traiter le formulaire
echo 'Formulaire traité';
}
?>
Routeur PHP : principe et fonctionnement
1. Qu'est-ce qu'un routeur ?
Un routeur est un composant logiciel qui analyse l'URL demandée par un visiteur et décide quel code exécuter pour générer la réponse.
Exemple concret :
- Le visiteur demande
https://monsite.fr/contact - Le routeur analyse cette URL
- Il détermine qu'il faut afficher la page de contact
- Il exécute le code correspondant
2. Le problème que résout le routeur
Sans routeur, chaque page correspond à un fichier physique :
mon-site/
├── index.php # Page d'accueil
├── contact.php # Page de contact
├── mentions.php # Mentions légales
└── actualites.php # Actualités
Inconvénients :
- Multiples fichiers à gérer.
- Redondance du code (entête, pied de page).
- Difficile à maintenir.
Avec un routeur :
mon-site/
├── index.php # Routeur unique
├── template.html # Structure commune
└── pages/
├── accueil.md
├── contact.md
└── mentions.md
Avantages :
- Un seul point d'entrée.
- Code factorisé.
- Nouvelles pages = nouveaux fichiers .md.
3. Fonctionnement étape par étape
Étape 1 : Redirection Apache
Toutes les requêtes sont redirigées vers le routeur (index.php).
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Étape 2 : Analyse de l'URL
Le routeur récupère l'URL demandée et en extrait un mot-clé.
$uri = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri, PHP_URL_PATH);
$uri = trim($uri, '/');
$motCle = empty($uri) ? 'accueil' : explode('/', $uri)[0];
Exemples :
| URL demandée | Mot-clé extrait |
|---|---|
/ |
accueil |
/contact |
contact |
/mentions |
mentions |
Étape 3 : Correspondance
Le routeur cherche un fichier correspondant au mot-clé.
$fichierMD = PAGES_DIR . $motCle . '.md';
Exemple : /contact → pages/contact.md
Étape 4 : Exécution
Si le fichier existe, son contenu est chargé, converti et affiché.
if (file_exists($fichierMD)) {
$contenuMD = file_get_contents($fichierMD);
$contenuHTML = convertirMarkdown($contenuMD);
} else {
// Erreur 404
}
4. Le routeur comme table de correspondance
Le routeur peut aussi fonctionner comme une table de correspondance explicite.
$routes = [
'/' => 'accueil',
'/contact' => 'contact',
'/mentions' => 'mentions-legales',
'/blog' => 'liste-articles',
'/blog/123' => 'article-123',
];
Avec paramètres dynamiques :
$routes = [
'/article/{id}' => 'afficherArticle',
];
5. Routeur "maison" vs solution existante
| Critère | Routeur maison | AltoRouter | Slim Framework |
|---|---|---|---|
| Complexité | Simple | Légère | Modérée |
| Flexibilité | Totalement modifiable | Standards | Standards |
| Courbe d'apprentissage | Nulle | Faible | Faible |
| Maintenance | À assurer | Assurée par la communauté | Assurée par la communauté |
| Performance | Rapide | Rapide | Bonne |
6. Exemple de routeur avec AltoRouter
<?php
// index.php avec AltoRouter
require 'vendor/autoload.php';
$router = new AltoRouter();
// Définition des routes
$router->map('GET', '/', 'accueil');
$router->map('GET', '/contact', 'contact');
$router->map('POST', '/envoyer', 'traiterFormulaire');
$router->map('GET', '/article/[i:id]', 'article');
// Exécution
$match = $router->match();
if ($match) {
$nomFonction = $match['target'];
$nomFonction($match['params']);
} else {
http_response_code(404);
echo '404 - Page non trouvée';
}
function accueil() {
echo 'Page d\'accueil';
}
function contact() {
echo 'Page de contact';
}
function article($params) {
echo 'Article n°' . $params['id'];
}
?>
7. Routeur avec paramètres dynamiques
URL : /article/123
Extraction :
- Mot-clé :
article - Paramètre :
id = 123
Code :
<?php
$motCle = explode('/', $uri)[0]; // 'article'
$param = explode('/', $uri)[1] ?? null; // '123'
if ($motCle === 'article') {
$id = (int)$param;
afficherArticle($id);
}
?>
8. Routeur avec contenu Markdown
Le routeur le plus simple :
<?php
// index.php
define('PAGES_DIR', __DIR__ . '/pages/');
$uri = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri, PHP_URL_PATH);
$uri = trim($uri, '/');
$motCle = empty($uri) ? 'accueil' : explode('/', $uri)[0];
$fichierMD = PAGES_DIR . $motCle . '.md';
if (file_exists($fichierMD)) {
$contenu = file_get_contents($fichierMD);
$contenu = convertirMarkdown($contenu);
} else {
http_response_code(404);
$contenu = '<h1>404</h1>';
}
$template = file_get_contents('template.html');
$template = str_replace('{{ CONTENU }}', $contenu, $template);
echo $template;
?>
9. Avantages et inconvénients
| Avantages | Inconvénients |
|---|---|
| URLs propres et esthétiques | Nécessite une configuration (.htaccess) |
| Code centralisé et organisé | Toutes les requêtes passent par un seul fichier |
| Facile à modifier et à étendre | Surcharge du fichier index.php si mal organisé |
| Séparation du contenu et du code | Complexité supplémentaire pour les débutants |
| Nouvelles pages sans nouveau code | Gestion des erreurs à prévoir |
10. Résumé
Le routeur est un analyseur d'URL :
- Capturer : .htaccess redirige vers index.php.
- Analyser : extraire le mot-clé de l'URL.
- Correspondre : trouver le fichier .md associé.
- Exécuter : convertir et afficher le contenu.
C'est un mécanisme simple mais puissant qui permet de créer des sites dynamiques avec des URLs claires et une maintenance facile.
FIN DE L'EXPLICATION