Rewrite

# Utilisation de RewriteMap

Ce document est un complément à la documentation de référence du module mod_rewrite. Il décrit l'utilisation de la directive RewriteMap, et fournit des exemples pour chacun des différents types de RewriteMap.

Notez que la plupart de ces exemples ne fonctionneront pas en l'état dans le contexte de votre configuration particulière ; vous devez donc vous attacher à les comprendre, plutôt que de simplement les insérer dans votre configuration par copier/coller.

Documentation du module mod_rewrite
Introduction à mod_rewrite
Redirection et remise en correspondance
Contrôle d'accès
Serveurs virtuels
Mise en cache
Techniques avancées
Quand ne pas utiliser mod_rewrite

# Introduction

La directive RewriteMap définit une fonction externe qui peut être appelée depuis une directive RewriteRule ou RewriteCond pour accomplir une réécriture trop compliquée, ou trop spécialisée pour être effectuée à partir d'expressions rationnelles. Vous trouverez ci-dessous les différents types disponibles pour la source de données, ceux-ci étant par ailleurs énumérés dans la documentation de référence de RewriteMap.

La syntaxe de la directive RewriteMap est la suivante :

RewriteMap MapName MapType:MapSource

L'argument MapName est un nom arbitraire que vous associez à la table de correspondances, et que vous pourrez utilisez par la suite dans les directives de réécriture. Les recherches dans la table de correspondance s'effectuent en respectant cette syntaxe :

`${` nom-map `:` clé-recherche `}`
`${` nom-map `:` clé-recherche `|` DefaultValue `}`

Lorsque cette syntaxe est employée, la table de correspondances nom-map est consultée et la clé clé-recherche recherchée. Si la clé est trouvée, la fonction de recherche dans la table de correspondance est remplacée par SubstValue, ou par DefaultValue dans le cas contraire, ou par la chaîne vide si aucune DefaultValue n'a été spécifiée.

Par exemple, vous pouvez définir une directive RewriteMap comme suit :

RewriteMap examplemap "txt:/path/to/file/map.txt"

Vous pourrez par la suite utiliser cette table de correspondances dans une directive RewriteRule comme suit :

RewriteRule "^/ex/(.*)" "${examplemap:$1}"

Il est possible de spécifier une valeur par défaut qui sera utilisée si la recherche dans la table de correspondances est infructueuse :

RewriteRule "^/ex/(.*)" "${examplemap:$1|/not_found.html}"

## Contexte de répertoire et fichiers.htaccess

Vous ne pouvez utiliser la directive RewriteMap ni dans les sections Directory, ni dans les fichiers `.htaccess`. Vous devez déclarer la table de correspondances au niveau du serveur principal ou dans un contexte de serveur virtuel. En revanche, si vous ne pouvez pas déclarer la table dans une section <Directory> ou dans un fichier `.htaccess`, vous pourrez y faire référence dans ces contextes, une fois cette table créée.

Les sections suivantes décrivent les différents types de tables de correspondances type-map disponibles, et fournissent des exemples pour chacun d'entre eux.

# int: Fonction interne

Lorsque le type-map `int` est spécifié, la source est une des fonctions RewriteMap internes disponibles. Les développeurs de modules peuvent fournir des fonctions internes supplémentaires en les enregistrant via l'API `ap_register_rewrite_mapfunc`. Les fonctions fournies par défaut sont :

- toupper:
  Met tous les caractères de la clé en majuscules.
- tolower:
  Met tous les caractères de la clé en minuscules.
- escape:
  Protège les caractères spéciaux de la clé en les transformant en leur code hexadécimal.
- unescape:
  Retraduit les codes hexadécimaux de la clé en caractères spéciaux.

Pour utiliser une de ces fonctions, créez une `RewriteMap` faisant référence à cette fonction int, et utilisez-la dans votre règle `RewriteRule` :

Redirige un URI vers son équivalent en minuscules

RewriteMap lc int:tolower RewriteRule "(.*)" "${lc:$1}" [R]

Notez que cet exemple n'est fourni qu'à titre d'illustration, et ne constitue en aucun cas une recommandation. Si vous voulez rendre des URLs insensibles à la casse, vous devez plutôt vous tourner vers mod_speling.

# txt: tables de correspondances au format texte

Lorsqu'un type-map `txt` est utilisé, la source-map est un chemin du système de fichiers vers un fichier de correspondances au format texte, contenant sur chaque ligne une paire clé/valeur séparées par un espace. Il est possible d'insérer des commentaires sous la forme de chaînes commençant par le caractère '#'.

Voici un exemple d'entrées valides dans un fichier de correspondances :

# Ligne de commentaires
clé valeur-substitution
clé valeur-substitution # commentaire

Lorsque la table de correspondance fait l'objet d'une recherche, la valeur spécifiée est recherchée dans le premier champ, et si elle est trouvée, la valeur de substitution est renvoyée.

Par exemple, nous pourrions utiliser un fichier de correspondances pour traduire des noms de produits en identifiants produits pour obtenir des URLs plus simples à mémoriser, en utilisant la recette suivante :

Product to ID configuration

RewriteMap product2id "txt:/etc/apache2/productmap.txt" RewriteRule "^/product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

Nous supposons ici que le script `prods.php` sait quoi faire lorsqu'il reçoit un argument `id=NOTFOUND`, dans le cas où le produit ne se trouve pas dans la table de correspondances.

Le fichier `/etc/apache2/map-produit.txt` contient ce qui suit :

## Fichier de correspondances Produit - Identifiant

##
## map-produit.txt - Fichier de correspondances Produit - Identifiant
##
TELEVISION 993
STEREO 198
CANNE-A-PECHE 043
BALLON-BASKET 418
TELEPHONE 328

Ainsi, lorsqu'une requête pour `http://example.com/produit/TELEVISION` arrive, la directive RewriteRule s'applique, et la requête est transformée en interne en `/prods.php?id=993`.

## Note: fichiers .htaccess

L'exemple donné est conçu pour être utilisé dans un contexte de serveur principal ou de serveur virtuel. Si vous voulez l'utiliser dans un fichier `.htaccess`, vous devrez supprimer le slash de début dans le modèle de réécriture afin que ce dernier puisse correspondre à toute URL : RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

## Recherches mises en cache

Les clés de recherche sont mises en cache par httpd jusqu'à ce que le `mtime` (date de modification) du fichier de correspondances soit modifié, ou que le serveur httpd soit redémarré, ce qui améliore les performances pour les tables de correspondances consultées par de nombreuses requêtes.

# rnd: Fichier texte à valeurs de substitution multiples choisies de manière aléatoire

Lorsque le type-map spécifié est `rnd`, la source est un chemin du système de fichiers vers un fichier de correspondances au format texte dont chaque ligne contient une clé, et une ou plusieurs valeurs séparées par le caractère `|`. Si une clé convient, une des valeurs correspondantes sera choisie de manière aléatoire.

Par exemple, vous pouvez utiliser le fichier de correspondances et les directives suivants pour implémenter une répartition de charge aléatoire entre plusieurs serveurs d'arrière-plan, par l'intermédiaire d'un mandataire inverse. Les images sont envoyées vers un des serveurs de l'ensemble 'statique', tandis que tout le reste est envoyé vers un des serveurs de l'ensemble 'dynamique'.

## Fichier de correspondances

##
## map.txt -- table de réécriture
##
statique www1|www2|www3|www4
dynamique www5|www6

Directives de configuration

RewriteMap servers "rnd:/path/to/file/map.txt"

RewriteRule "^/(.*\.(png|gif|jpg))" "http://${servers:static}/$1" [NC,P,L] RewriteRule "^/(.*)" "http://${servers:dynamic}/$1" [P,L]

Ainsi, lorsqu'une image est demandée et que la première règle convient, RewriteMap recherche la chaîne `statique` dans le fichier de correspondances qui renvoie un des noms de serveurs spécifiés de manière aléatoire, ce dernier étant utilisé dans la cible de la règle RewriteRule.

Si vous voulez qu'un des serveurs soit plus souvent sollicité que les autres (par exemple s'il possède plus de mémoire, et peut donc traiter d'avantage de requêtes), spécifiez-le plusieurs fois dans la liste des serveurs.

statique www1|www1|www2|www3|www4

# dbm: Fichier condensé DBM

Lorsque le type-map `dbm` est utilisé, la source est un chemin du système de fichiers vers un fichier de données DBM contenant des paires clé/valeur permettant d'effectuer la correspondance. Le fonctionnement est identique à celui du type-map `txt`, mais beaucoup plus rapide car un fichier DBM est indexé, alors qu'un fichier texte ne l'est pas. L'accès à la clé recherchée est donc plus rapide.

Vous pouvez éventuellement spécifier un type dbm particulier :

RewriteMap examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"

Ce type peut être choisi parmi `sdbm`, `gdbm`, `ndbm` ou `db`. Il est cependant recommandé d'utiliser l'utilitaire httxt2dbm fourni avec le serveur HTTP Apache, car il utilise la bibliothèque DBM appropriée, à savoir celle qui a été utilisée lors de la compilation de httpd.

Pour créer un fichier dbm, créez tout d'abord un fichier de correspondances au format texte comme décrit dans la section txt. Traitez ensuite ce fichier avec `httxt2dbm` :

$ httxt2dbm -i fichier-map.txt -o fichier-map.map

Vous pouvez alors faire référence au fichier obtenu dans votre directive RewriteMap :

RewriteMap mapname "dbm:/etc/apache/mapfile.map"

Notez qu'avec certains types dbm, plusieurs fichiers possédant le même nom de base sont créés. Par exemple, vous pouvez obtenir deux fichiers nommés `fichier-map.map.dir` et `fichier-map.map.pag`. Ceci est tout à fait normal, et vous ne devez utiliser que le nom de base `fichier-map.map` dans votre directive RewriteMap.

## Mise en cache des recherches

Les clés de recherche sont mises en cache par httpd jusqu'à ce que le `mtime` (date de modification) du fichier de correspondances soit modifié, ou que le serveur httpd soit redémarré, ce qui améliore les performances pour les tables de correspondances consultées par de nombreuses requêtes.

# prg: Programme de réécriture externe

Lorque le type-map `prg` est spécifié, la source est un chemin du système de fichiers vers un programme exécutable destiné à effectuer la mise en correspondance. Il peut s'agir d'un fichier binaire compilé, ou d'un programme en langage interprété comme Perl ou Python.

Ce programme est lancé une fois au démarrage du serveur HTTP Apache, puis communique avec le moteur de réécriture via `STDIN` et `STDOUT`. En d'autres termes, pour chaque recherche de correspondance, il reçoit un argument via `STDIN`, et doit renvoyer en guise de réponse une chaîne terminée par un caractère nouvelle-ligne sur `STDOUT`. Si la recherche de correspondance est infructueuse, le programme doit l'indiquer en retournant la chaîne de quatre caractères "`NULL`".

Les programmes de réécriture externes ne sont pas lancés s'il n'ont pas été définis dans un contexte où la directive RewriteEngine est définie à `on`.

Par défaut, les programmes de réécriture externes sont lancés par l'utilisateur root. Pour en changer, il est possible sur les systèmes de style Unix de spécifier un autre couple utilisateur/groupe via le troisième argument de la directive RewriteMap, et ceci au format `utilisateur:groupe`.

Cette fonctionnalité utilise le mutex `rewrite-map` nécessaire à la fiabilité des communications avec le programme. Le mécanisme de mutex et le fichier verrou peuvent être définis via la directive Mutex.

Voici un exemple simple qui remplace tous les tirets par des caractères de soulignement dans l'URI de la requête.

Configuration de la réécriture

RewriteMap d2u "prg:/www/bin/dash2under.pl" apache:apache RewriteRule "-" "${d2u:%{REQUEST_URI}}"

dash2under.pl

#!/usr/bin/perl $| = 1; # Turn off I/O buffering while (<STDIN>) { s/-/_/g; # Remplace tous les tirets par des caractères de soulignement print $_; }

## Mises en garde !

- Votre programme doit être le plus simple possible. Si le programme se bloque, httpd va attendre indéfiniment une réponse de sa part, et par conséquent ne répondra plus aux requêtes.
- Assurez-vous de bien désactiver la mise en tampon dans votre programme. En Perl, ceci est effectué à la seconde ligne du script de l'exemple - `$| = 1;` - La syntaxe sera bien entendu différente dans d'autres langages. Si les entrées/sorties sont mises en tampon, httpd va attendre une sortie, et va par conséquent se bloquer.
- Rappelez-vous qu'il n'existe qu'une copie du programme lancé au démarrage du serveur, et que toutes les requêtes vont devoir passer par ce goulot d'étranglement. Ceci peut provoquer des ralentissements significatifs si de nombreuses requêtes doivent être traitées, ou si le script lui-même est très lent.

# dbd ou fastdbd: requête SQL

Lorsque le type-map `dbd` ou `fastdbd` est spécifié, la source est une requête SQL SELECT qui reçoit un argument et renvoie une seule valeur.

Pour que cette requête puisse être exécutée, mod_dbd doit être configuré pour attaquer la base de données concernée.

Ce type-map existe sous deux formes. Avec le type-map `dbd`, la requête est exécutée à chaque demande, tandis qu'avec le type-map `fastdbd`, les recherches dans la base de données sont mises en cache en interne. `fastdbd` est donc plus efficace et donc plus rapide ; par contre, il ne tiendra pas compte des modifications apportées à la base de données jusqu'à ce que le serveur soit redémarré.

Si une requête renvoie plusieurs enregistrements, un de ceux-ci sera sélectionné aléatoirement.

## Exemple

RewriteMap ma-requete "fastdbd:SELECT destination FROM rewrite WHERE source = %s"

# Résumé

La directive RewriteMap peut apparaître plusieurs fois. Utilisez une directive RewriteMap pour chaque fonction de mise en correspondance pour déclarer son fichier de correspondances.

Bien que l'on ne puisse pas déclarer de fonction de mise en correspondance dans un contexte de répertoire (fichier `.htaccess` ou section Directory), il est possible d'utiliser cette fonction dans un tel contexte.