drik's wiki informatique Module mod_rewrite d'apache

Une des fonctions les plus puissantes permises par le fichier .htaccess est la réécriture « à la volée » des URL. Sur le site officiel Apache, le module mod_rewrite est présenté à raison comme le couteau suisse de la manipulation.

Il est utile de préciser que certains hébergeurs n’ont pas activé le module de réécriture. Dans ce cas, vous n’avez malheureusement aucune possibilité de l’utiliser, à moins de casser le petit cochon en porcelaine qui traîne chez vous et changer d’hébergeur.

Ce module est implémenté dans le fichier mod_rewrite.c, à partir de la version 1.2 d'Apache. Il fournit un interpréteur de règles dont l'action est de réécrire "au vol" les URL requises. mod_rewrite n'est pas compilé par défaut. Pour exploiter ce module, vous devez ajouter les lignes suivantes dans le fichier Configuration de configuration de compilation :

AddModule  modules/standard/mod_rewrite.o

Résumé

Ce module utilise une fonction de réécriture configurable par règles (construit à partir d'un interpréteur d'expressions régulières) pour réécrire au vol des URL.

Il accepte un nombre illimité de règles supplémentaires (qui peuvent apérer sur un grand nombre de variables, dont les en-têtes HTTP) pouvant rechercher ds correspondances granulaires et rechercher des données dans des bases de données externes (soit par des tables plates, des fichiers associatifs DBM ou des processus externes), aboutissant à de puissantes fonctions de substitution d'URL.

Il traite l'URL dansson intégralité (y compris la partie PATH_INFO) à la fois dans le contexte serveur (httpd.conf) que dans chacun des contextes locaux de répertoires (.htaccess) et peut générer des parties QUERY_STRING (arguments de requêtes situés derrière le '?')à partir de ses résultats. L'URL résultante peut alors être conservée pour un nouveau traitement interne, une redirection externe ou un transfert vers un proxy interne.

La première écriture de ce module a été réalisée en Avril 1996 et offerte confidentiellement au groupe Apache en Jullet 1997 par

Ralf S. Engelschall
rse@engelschall.com
www.engelschall.com

Directives

Directives de configuration

Directive : RewriteEngine

Syntaxe : RewriteEngine on|off
Défaut : RewriteEngine off
Contexte : configuration serveur, hôtes virtuels, répertoire, .htaccess

La directive RewriteEngine active ou désactive le moteur de réécriture. Sur off ce module n'effectue aucun traitement. Il ne modifie pas même les variables d'environnement SCRIPT_URx.

Utilisez cette directive pour désactiver entièrement ce module plutôt que passer en commentaires toutes les directives RewriteRule !

Notez que, par défaut, les configurations de réécriture ne sont pas héritées à partir du serveur principal. Ceci signifie que vous devrez avoir une directive RewriteEngine on pour tous les hôtes virtuels dans lesquels vous souhaiter activer cette fonctionnalité, à moins que l'option RewriteOptions inherit soit définie.

Directive : RewriteOptions

Syntaxe : RewriteOptions Option ...
Défaut : Aucun
Contexte : configuration serveur, hôtes virtuels, répertoire, .htaccess

La directive RewriteOptions commute certaines options spéciales pour la configuration de contexte serveur ou répertoire courante. Les chaînes Option peuvent être l'un parmi :

  • inherit
    Ceci force la configuration courante d'hériter de la configuration du parent. Dans un contexte d'hôtes virtuels, ceci signifie que les tables, conditions et règles du serveur principal sont héritées par l'hôte virtuel. Dans un contexte de répertoire, ceci signifie que les conditions et règles sont héritées à partir de celles définies dans le fichier .htaccess du répertoire père.

Directive : RewriteLog

Syntaxe : RewriteLog nomFichier
Défaut : Aucun
Contexte : configuration serveur, hôtes virtuels

La directive RewriteLog déinit le nom du fichier dans lequel le serveur tracera toutes les actions de réécriture qu'il effectuera. Si le nom ne débute pas par un slash ('/') alors le chemin d'accès spécifié l'est relativement à Server Root. Cette directive ne doit apparaître qu'une fois par configuration de serveur.

Pour désactiver la trace des opérations de réécriture, il est déconseillé donner à nomFichier la valeur /dev/null. En effet, bien que le moteur de réécriture ne produise pas le fiochier de trace, il continue à générer ses informations en interne. Le serveur serait donc ralenti, sans rien apporter de plus à l'administrateur !. Pour désactiver complètement la trace, supprimez totalement la directive RewriteLog (ou mettez-la en commentaire), ou utilisez la directive RewriteLogLevel 0 !

Exemple

RewriteLog "/usr/local/var/apache/logs/rewrite.log"

Directive : RewriteLogLevel

Syntaxe : RewriteLogLevel degré
Défaut : RewriteLogLevel 0
Contexte : configuration serveur, hôtes virtuels

La directive RewriteLogLevel définit le degré de "bavardise" de la trace d'actions de réécriture. Le degré 0 (par défaut) singifie pas de trace du tout, tandis qu'avec un degré de 9 ou plus, pratiquement toutes les actions seront tracées.

Pour désactiver complètement la trace, d"finissez simplement un degré 0 pour la trace. Aucune trace ne sera générée dans ce cas.

Note : Une très grande valeur du degré ralentira le serveur Apache dramatiquement ! Ces valeurs ne sont proposées que pour des phases de déboguage. Le dégré sur un serveur opérationnel ne devra pas dépasser 2 !

Exemple :

RewriteLogLevel 3

Directive : RewriteMap

Syntaxe : RewriteMap nomTable txt|dbm|prg: nomFichier
Défaut : Non utilisé pour le défaut
Contexte : configuration serveur, hôtes virtuels

La directive RewriteMap définit une table de réécriture externe qui peut être exploitée dans les instructions de substitution spécifiées dans les règles de réécriture via des fonctions de correspondance qui insèreront/substitueront des champs sur contrôle d'une clef.

nomTable est le nom de la table qui sera utilisée pour définir une fonction de correspondance utilisée par les chaînes de substitution d'une règle de réécriture via

${nomTable : Clef | DefaultValue }

Lorsqu'une telle directive intervient, la table nomTable est consultée et la clef Clef y est recherchée. Si cette clef est trouvée, la fonction de correspondance utilise la valeur SubstValue (voir ci-dessous) pour la substitution. Si elle n'est pas trouvée, c'est DefaultValue qui sera prise en compte.

NomFichier doit être un chemin d'accès Unix valide, pointant vers un fichier de l'un des formats suivants :

Format texte brut

Un fichier ASCII qui contient des lignes vides, des lignes de commentaires (lorsqu'elles commencent par un '#') ou des paires : Clef SubstValue

à raison de une paire par ligne. Vous pourrez créer ces fichier manuellement, avec votre éditeur favori, ou en utilisant les programmes mapcollect et mapmerge dans le répertoire /support de la distribution du module mod_rewrite.

Pour déclarer une telle table, obtenue à partir d'un fichier nomFichier ASCII écrit ainsi :

#
#   map.real-to-user -- maps realnames to usernames
#
Ralf.S.Engelschall    rse   # Bastard Operator From Hell
Dr.Fred.Klabuster     fred  # Mr. DAU

vous appellerez ce fichier en utilisant le préfixe txt: :

RewriteMap real-to-host txt:/path/to/file/map.real-to-user
Fichier associatif au format DBM

Il s'agit d'un fichier NDBM binaire contenant le même contenu que le fichier texte. Vous pouvez créer un tel fichier avec n'importe quel outil NDBM ou par le programme dbmmanage livré dans le sous-répertoire /support de la distribution Apache.

Pour déclarer un tel fichier, préfixez nomFichier par dbm:.

Format programme

Il s'agit d'un exécutable Unix, et non d'un fichier de données. Vous pouvez l'écrire dans le language de votre choix, pourvu que l'exécutable produit soit un binaire exécutable sous Unix (c'est-à-dire un fichier objet ou un script routé vers son interpréteur par la formule "magique" '#!/chemin/interpreteur' inscrite en première ligne. Ex. #/usr/bin/perl).

Ce programme est démarré une fois au lancement d'Apache et communique avec le moteur de réécriture par ses entrées et sorties standard stdin et stdout. Pour chacune des recherches demandées par une fonction de correspondance, il recevra la clef à rechercher sous forme d'un chaîne terminée par un caractère Newline dans stdin. Il devra retourner la valeur résultat sous la même forme dans stdout ou la chaîne à quatre caractères "NULL" s'il échoue (c'est-à-dire, qu'il n'existe pas de valeur correspondante à cette clef). Un programme trivial implémentant une correspondance 1:1 (c'est-à-dire qu'à une clef correspond une valeur unique) pourrait s'écrire :

#!/usr/bin/perl
$| = 1;
while (<STDIN>) {
# ...implémenter ici toute transformation
# ou recherche...
print $_;
}
Faites cependant très attention
  1. "Garder ce programme aussi simple que possible, voire stupide" , car si ce programme se bloque, c'est tout le serveur Apache qui peut se bloquer lors de l'examen d'une règle.
  2. Evitez une erreur courante : n'utilisez jamais le mode bufferisé des I/O sur stdout ! C'est la meilleure manière de tout bloquer ! D'où la ligne "$|=1" de l'exemple ci-dessus...

Pour déclarer un tel fichier, préfixez nomFichier par prg:.

Pour finir

La directive RewriteMap peut être utilisée plusieurs fois. Pour chaque fonction de correspondance, utilisez une directive RewriteMap afin de déclarer sa table de réécriture. Bien que vous ne puissiez pas déclarer ces tables dans le contexte de répertoire, il sera néanmoins bien sûr possible d'utilisez ces tables dans ce niveau de contexte.

Pour les formats texte et DBM, les clefs de recherche restent enregistrées dans la mémoire du noyau jusqu'à ce que la valeur mtime de la table change ou le serveur redémarre. De cette manière vous pouvez définir des fonctions de correspondance de règles qui seront valables toutes les requêtes. Ce n'est pas un problème, car les résolutions externes n'interviennent qu'une fois !

Directive : RewriteBase

Syntaxe : RewriteBase BaseURL
Défaut : le chemin d'accès physique
Contexte : répertoire, .htaccess

La directive RewriteBase définit explicitement l'URL de base pour les réécritures par répertoire. Comme vous pourrez le voir ci-après, RewriteRule peut être utilisée dans des fichiers de contexte répertoire par répertoire (.htaccess). Dans ce cas, son action sera localisée, c'est-à-dire, la partie de chemin d'accès correpondant à ce répertoire est enlevée et la règle de réécriture n'agit que sur ce qui reste. Après la réécriture, la partie répertoire est ajoutée de nouveau en tête du résultat.

Lorsqu'une nouvelle URL est substituée, ce module doit réinjecter l'URL dans le serveur. Pour ce faire, il devra savoir quel est le préfixe ou la base. Par défaut, ce préfixe est le chamin d'accès à la ressource elle-même. Mais dansla plupart des sites, les URL NE correspondent PAS directement au chemin physique, et cette supposition "par défaut" sera en général erronée ! C'est dans ce cas que vous devez utiliser la directive RewriteBase pour définir le préfixe URL.

De ce fait, si les URL sur votre site Web NE sont PAS en correspondance directe avec les chemins d'accès physiques des fichiers, vous devrez utiliser une directive RewriteBase dans chacun des fichiers .htaccess où vous souhaitez utiliser des directives RewriteRule.

Exemple : Supposons que nous disposions du fichier de configuration suivant dans un répertoire :

#
#  /abc/def/.htaccess -- configuration pour le répertoire /abc/def
#  Se souvenir que : /abc/def est le chemin physique pour /xyz, c'est-à-dire que le
#      serveur a une directive 'Alias /xyz /abc/def'
#
RewriteEngine On
#  indiquons au serveur que nous sommes atteint via /xyz et non par
#  le préfixe de chemin physique /abc/def
RewriteBase   /xyz
#  les règles de réécriture
RewriteRule   ^oldstuff\.html$  newstuff.html

Dans l'exemple ci-dessus, une requête vers /xyz/oldstuff.html sera réécrite pour pointer sur le fichier d'adresse physique /abc/def/newstuff.html.

Pour les bidouilleurs d'Apache :

La liste suivante donne des informations détaillées sur les étapes de traitement interne :

Requête :
/xyz/oldstuff.html
Traitement interne :
/xyz/oldstuff.html     -> /abc/def/oldstuff.html
(Aliasing de contexte serveur)
/abc/def/oldstuff.html -> /abc/def/newstuff.html
(RewriteRule de contexte répertoire)
/abc/def/newstuff.html -> /xyz/newstuff.html
(RewriteBase de contexte répertoire)
/xyz/newstuff.html     -> /abc/def/newstuff.html
(Aliasing de contexte serveur)
Résultat :
/abc/def/newstuff.html

Ceci semble bien compliqué mais représente bien le comportement interne d'Apache, parce que la réécriture de niveau répertoire intervient assez tard dans la chaîne de traitement. De plus, lorsque la réécriture intervient, la requête obtenue doit être re-injectée dans le kernel Apache ! En fait, il n'y a pas de réel problème dans la mesure ou cette ré-injection est complètement interne, et que le même mécanisme est déjà utilisé de longue date dans le serveur, pour preuve de sa stabilité.

Directive : RewriteCond

Syntaxe : RewriteCond TestString CondPattern
Défaut : Aucun
Contexte : configuration serveur, hôtes virtuels, répertoire, .htaccess

La directive RewriteCond définit une condition d'application de la règle. Vous ferez précéder une directive RewriteRule par une ou plusieurs directives RewriteCond. La règle de réécriture qui suit ces conditions n'est applisuée que si son motif correspond à l'URI de la requête ET si ces conditions supplémentaires ainsi définies sont remplies.

TestString est une chaîne contenant les constructions suivantes et du texte brut :

  • Rétroréférence sur la RewriteRule: Ce sont des références sous la forme

    $N

    (1 <= N <= 9) par lesquelles on peut récupérer la valeur de sous-motif (parenthésé !) du motif défini dans la règle RewriteRule associée (celle qui suit le présent groupe de directives RewriteCond), après application du motif.

  • Rétroréférence sur la RewriteCond: Ce sont des références sous la forme

    %N

    (1 <= N <= 9) par lesquelles on peut récupérer la valeur de sous-motif (parenthésé !) du motif trouvé lors de l'application par la dernière directive RewriteCond du bloc de conditions courant.

    NdT : La compréhension de ces deux références demandent une bonne connaissance des expressions régulières et de leur fonctionnement. Une expression régulière permet de définir un motif de correspondance, appliqué à une portion de texte ASCII. Ce motif peut comprendre des sous-motifs, lesquels seront extraits individuellement lors de l'application du motif complet. Le résultat de ces extraction est usuellement rangé (sous Unix) dans des variables prédéfinies notées $1 à $9. Ces deux références utilisent ce principe pour réutiliser les sous-motifs obtenus par les applications successives des motifs de chaque condition (références %N), ou de la règle associée (références $N).

  • Variables-serveur: Ce sont des variables sous la forme

    %{ NOM_DE_VARIABLE }

    dans laquelle NOM_DE_VARIABLE peut être une chaîne à prendre dans la liste suivante :

    En-têtes HTTP
    HTTP_USER_AGENT
    HTTP_REFERER
    HTTP_COOKIE
    HTTP_FORWARDED
    HTTP_HOST
    HTTP_PROXY_CONNECTION
    HTTP_ACCEPT
    connexion & requête
    REMOTE_ADDR
    REMOTE_HOST
    REMOTE_USER
    REMOTE_IDENT
    REQUEST_METHOD
    SCRIPT_FILENAME
    PATH_INFO
    QUERY_STRING
    AUTH_TYPE
    Variables internes du serveur
    DOCUMENT_ROOT
    SERVER_ADMIN
    SERVER_NAME
    SERVER_PORT
    SERVER_PROTOCOL
    SERVER_SOFTWARE
    SERVER_VERSION
    Variables système
    TIME_YEAR
    TIME_MON
    TIME_DAY
    TIME_HOUR
    TIME_MIN
    TIME_SEC
    TIME_WDAY
    TIME
    Variables spéciales
    API_VERSION
    THE_REQUEST
    REQUEST_URI
    REQUEST_FILENAME
    IS_SUBREQ

    Ces variables correspondend toutes aux noms de champs d'en-tête HTTP, aux variables C du serveur Apache ou aux champs de la structure struct tm du système Unix.

Notes spéciales :

  1. Les variables SCRIPT_FILENAME et REQUEST_FILENAME contiennent la même valeur, à savoir, la valeur du champ filename de la structure C interne request_rec du serveur Apache. Le premier nom de variable correspond au nom usuel de la variable CGI tandis que le second est la contrepartie de la variable REQUEST_URI (correspondant au contenu du champ uri dans la structure request_rec).
  2. On pourra utiliser le format spécial : %{ENV:variable} dans lequel variable peut être tout nom de variable d'environnement. Cette variable sera recherchée dans les structures de données internes d'Apache ou (si elle n'y est pas trouvée) via la fonction C getenv() exécutée par le processus serveur d'Apapche.
  3. On pourra également utiliser le format spécial : %{HTTP:header} dans lequel header peut être tout nom MIME de champ d'en-tête HTTP. Sa valeur est obtenue à partir de la requête HTTP. Exemple : %{HTTP:Proxy-Connection} récupère la valeur du champ d'en-tête HTTP "Proxy-Connection:".
  4. On notera un autre format spécial : %{LA-U:url} pour des résolutions internes sur URL. Son utilisation déclenche une sous-requête interne pour connaître l'URL finale pour l'URL url.
  5. On définit un dernier format spécial : %{LA-F:fichier} pour des résolutions internes sur fichier. Son utilisation déclenche une sous-requête interne pour connaître la valeur finale de fichier.

CondPattern est le motif définissant la condition, c'est-à-dire une expression régulière à appliquer à la valeur courante de TestString, c'est à dire que TestString sera évaluée et le motif CondPattern y sera recherché.

Souvenez-vous : CondPattern est une expression régulière étendue standard avec quelques ajouts :

  1. Vous pouvez faire précéder la chaîne de motif par '!' (point d'exclamation) pour inverser le sens du test (la condition est vraie si le motif n'est pas trouvé).
  2. Il existe certaines variantes particulières de CondPatterns. A la place d'une chaîne d'expression régulière, vous pourrez utiliser l'une des expression suivantes :
    • '<CondPattern' (est lexicographiquement inférieur à)
      Traite CondPattern comme une chaîne de texte brut et la compare lexicographiquement à TestString. Le résultat est vrai si TestString est lexicographiquement inférieur à CondPattern.
    • '>CondPattern' (est lexicographiquement supérieur à)
      Traite CondPattern comme une chaîne de texte brut et la compare lexicographiquement à TestString. Le résultat est vrai si TestString est lexicographiquement supérieur à CondPattern.
    • '=CondPattern' (est lexicographiquement égal à)
      Traite CondPattern comme une chaîne de texte brut et la compare lexicographiquement à TestString. Le résultat est vrai si TestString est lexicographiquement égal à CondPattern, c'est-à-dire que les deux chaînes sont rigoureusement églaes (caractère par caractère). Si CondPattern se limite à "" (la chaîne vide), TestString est comparé (logiquement) à la chaîne vide.
    • '-d' (est un répertoire : ddirectory)
      Considère TestString comme un chemin d'accès et teste si l'objet existe et est un répertoire.
    • '-f' (est un fichier normal : file)
      Considère TestString comme un chemin d'accès et teste si l'objet existe et est un fichier normal (c'est à dire ni un répertoire, ni un lien symbolique).
    • '-s' (est un fichier normal non vide : sized file)
      Considère TestString comme un chemin d'accès et teste si l'objet existe et est un fichier normal (c'est à dire ni un répertoire, ni un lien symbolique) et est de taille non nulle.
    • '-l' (est un lien symbolique : link)
      Considère TestString comme un chemin d'accès et teste si l'objet existe et est un lien symbolique.
    • '-F' (est un fichier existant, via une sous-requête)
      Vérifie si TestString représente un fichier valide et accessible compte tenues toutes les restrictions d'accès configurées pour ce serveur et ce chemin d'accès. Cette expression lance une sous-requête interne pour tester cet état, et il est prudent de l'utiliser avec parcimonie car elle diminue les performances globales du serveur !
    • '-U' (is existing URL via subrequest)
      Vérifie si TestString représente une URL valide et accessible compte tenues toutes les restrictions d'accès configurées pour ce serveur et ce chemin d'accès. Cette expression lance une sous-requête interne pour tester cet état, et il est prudent de l'utiliser avec parcimonie car elle diminue les performances globales du serveur !
    Note : Tous ces tests peuvent être préfixés du caractère ('!') pour en inverser le sens d'interprétation.

Vous pouvez de plus ajouter certains commutateurs au CondPattern en ajoutant un troisième argument :

[flags]

à la directive RewriteCond. Flags est une liste de commutateurs ci-après définis séparés par des virgules :

  • 'nocase|NC' (Pas de casse : no case)
    La casse est indiférente dans ce cas, c'est-à-dire qu'il n'y aura aucune différence entre les lettres 'A-Z' et 'a-z', que ce soit dans la chaîne TestString ou CondPattern.
  • 'ornext|OR' (ou condition suivante)
    Utilisez ce commutateur pour lier deux conditions dans un OU local plutôt que le ET implicite. Exemple typique :
    RewriteCond %{REMOTE_HOST}  ^hôte1.*  [OR]
    RewriteCond %{REMOTE_HOST}  ^hôte2.*  [OR]
    RewriteCond %{REMOTE_HOST}  ^hôte3.*
    RewriteRule ...la règle vaut pour l'un de ces trois hôtes...
    Sans l'existance de ce commutateur vous auriez du écrire trois fois l'ensemble des conditions plus la règle.

Exemple :

Pour réécrire la Homepage d'un site suivant la valeur du champ User-Agent: de la requête, vous pouvez utiliser les écritures suivantes :

RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
RewriteRule  ^/$                 /homepage.max.html  [L]
RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
RewriteRule  ^/$                 /homepage.min.html  [L]
RewriteRule  ^/$                 /homepage.std.html  [L]

Interprétation : si vous utilisez Netscape Navigator (qui s'identifie lui-même sous le nom 'Mozilla'), alors vous récupérerez la version "haute définition" de la homepage, avec les cadres, les images, etc. Si vous utilisez le navigateur Lynx (basé sur une approche Terminal), alors vous serez routé vers la Homepage "basse définition", qui est écrite sans images, sans tables, etc. Si vous utilisez n'importe quel autre navigateur, on vous routera sur une version "moyenne".

Directive : RewriteRule

Syntaxe : RewriteRule motif substitution
Défaut : Aucun
Contexte : configuration serveur, hôtes virtuels, répertoire, .htaccess

La directive RewriteRule est le véritable cheval de trait de la réécriture. Elle peut apparaître plus d'une fois. Chque directive définit alors une règle unique de réécriture. L'ordre dans lequel les définitions de ces règles est faite a une grande importance, car cet ordre conditionne celui dans lequel les règles sont appliquées à l'exécution.

Motif peut être une expression régulière (Système V8 pour Apache 1.1.x et POSIX pour Apache 1.2.x) qui sera appliquée sur l'URL courante. Ici, "courante" signifie la valeur de l'URL au moment ou la règle est appliquée. Celle-ci n'est pas nécéssairement l'URL initialement demandée, car plusieurs directives de réécriture auront pu altérer cette URL avant que celle-ci soit applicable.

Voici quelques notes au sujet de la syntaxe d'expressions régulières :

^           Recherche en début de ligne
$           Recherche en fin de ligne
.           Un caractère quelque soit sa valeur
[chars]     Un caractère dans la liste
[^chars]    Un caractère autre que ceux de a liste
?<          0 ou 1 fois le caractère qui précède
*           0 à N fois le caractère qui précède
+           1 à N fois le caracère qui précède
\char       despécialise le métacaractère qui suit
(ex. pour mentionner les caractères litéraux ".[]()" etc.)
(string)    sous-motif (le Nième sous-motif peut être  réutilisé dans l'expression
de substitution par la variable prédéfinie $N)

En plus des règles standard d'expressions régulières, l'opérateur de négation unaire ('!') peut être préfixé au motif. Ceci permet de demander la condition inverse (logiquement) pour dire par exemple : "si l'URL courante NE CORRESPOND PAS à ce motif". Ceci peut être utilisé lorsqu'il est plus facile d'exprimr les conditions inverses ou comme dernière règle par défaut.

Attention ! Lorsque vous utilisez l'opérateur ! pour inverser la signification du motif, vous ne pouvez pas définir de sous motif dans ce motif. C'est effectivement incohérent du fait que comme le motif n'est pas trouvé dans la chaîne analysée, les sous-motifs ne peuvent pas recevoir décemment de contenu. Donc, lorsque vous utilisez cet opérateur, vous ne pouvez utiliser les variables $N dans l'expression de substitution !

L'expression de Substitution d'une règle de réécriture est une chaîne qui définit par quoi est substituée (ou remplacée) l'URL qui correspond au motif. Beside plain text you can use

  1. Des rétro-références $N sur des sous-motifs de la condition de règle
  2. Des rétro-références %N sur les sous-motifs de la RewriteCond précédente
  3. Des variables "serveur" de la même façon que dans les expressions de condition (%{VARNAME})
  4. Des appels à des fonctions de correspondance (${nomTable:clef|défaut})

Les rétro-références $N (N=1..9) sont des "variables prédéfinies" qui permettent d'accéder au contenu du Nième sous-motif du motif trouvé. Les variables "serveur" sont les mêmes que celles utilisées dans les directives TestString ou RewriteCond. Les fonctions de correspondance sont déduites des directives RewriteMap et sont expliquées dans le paragraphe qui s'y rapporte. Ces trois types de variables sont interprétées dans l'ordre ci-dessous exposé.

Comme il y a déjà été fait allusion, toutes les règles de réécriture sont appliquées à la Substitution précédente (dans l'ordre où elles sont définies dans le fichier de configuration). L'URL est complètement remplacée par l'expression de substitution et le traitement de recomposition de l'URL finale continue tant qu'il reste encore des règles à appliquer (où alors explicitement lorsque le commutateur spécial L est marqué en fin de ligne - voir ci-dessous).

Il est défini une expression de substitution spéciale '-' qui signifie : PAS de substitution ! Bizarre, non ? Non, il est utile de disposer de règles de réécriture qui "déclenchent" sur une certaine URL tout en n'effectuant aucune modification, par exemple, en conjonction avec le commutateur C (chaînage) qui permet à plusieurs motifs succéssifs d'être testés sur la même URL avant que toute modification n'y soit portée.

Une dernière note : Vous pouvez même, par une expression de substitution, réécrire une URL contenant des paramètres de requête. Il suffit pour celà d'ajouter le célèbre point d'interrogation ('?') qui sépare habituellement la partie URI de la partie argument de requête lequel sera passé à la variable QUERY_STRING. Si vous voulez effacer une chaîne de requête déjà présente dans l'URL originale, terminez l'expression de substitution par un point d'interrogation seul.

Attention : Voici une fonctionnalité spéciale. Lorsque vous préfixez une expression de substitution par http://cetHôte[:cePort] alors le module mod_rewrite arrête automatiquement son traitement. Cette auto-réduction en cas d'URL redirigées implicitement en externe est une fonction utile et importante lorsque'elle vient en combinaison d'une fonction de correspondance qui génère la partie "hôte" de l'adresse. Voir le premier exemple dans la section d'exemples ci après pour comprendre pourquoi.

Souvenez-vous : Une redirection externe inconditionnelle vers votre propre serveur ne fonctionnera pas lorsque le préfixe http://cetHôte apparaît, à cause de ce principe. pour effectuer une telle auto-redirection, Vous devrez utiliser le commutateur R (voir ci-dessous).

Vous pouvez de plus ajouter certains commutateurs au champ substitution en ajoutant un troisième argument sous la forme :

[flags]

à la directive RewriteRule. Flags est une liste de commutateurs ci-après définis séparés par des virgules :

  • 'redirect|R[=code]' (force la redirection)
    Prefixez substitution par une chaîne de type http://cetHôte[:cePort]/ (qui fait de cette nouvelle URL une URI) pour forcer une redirection externe. Si aucun code n'est mentionné, un code de réponse HTTP 302 (MOVED TEMPORARILY) sera utilisé par défaut. Si vous souhaîtez renvoyer un autre code de réponse, dans les séries 300 ou 400, mentionnez ce code sous forme numérique ou utilisez l'une des constantes symboliques ci-après : temp (défaut), permanent, seeother. Utilisez cette fonction pour des règles qui auraient tendance à canoniser les URL et les renvoyer ainsi au client, ex. qui traduisent "/~" en "/u/" ou ajoutent systématiquement un slash à /u/user, etc.

    Attention : Lorsque vous marquez ce commutateur, assurez-vous que l'expression de substitution est bien une URL valide ! Si ce n'est pas le cas, vous redirigez la requête vers un document qui n'existe pas ! Souvenez-vous aussi que l'action de ce commutateur ne fait que préfixer l'URL par http://cetHôte[:cePort]/, et c'est la procédé classique de réécriture qui fait le reste. Vous souhaiterez de plus arrêter, en général, le traitement de réécriture à ce moment et déclencher la redirection immédiatement. Vous devrez pour ce faire marquer en plus le commutateur 'L'.
  • 'forbidden|F' (force l'URL à apparaître comme interdite : forbidden)
    Ceci force l'URL courante sur l'URL interdite, c'est à dire que le serveur enverra immédiatemment une réponse HTTP de code 403 (FORBIDDEN). Utilisez ce commutateur en conjonction avec des directives RewriteConds appropriées pour bloquer l'accès à certaines URL sous certaines conditions.
  • 'gone|G' (force l'URL à apparaître come une redirection définitive : gone)
    Ceci force une réponse HTTP de code 410 (GONE). Utilisez ce commutateur pour marquer que les ressources demandées ont définitvement "déménagé".
  • 'proxy|P' (force la redirection sur proxy)
    Ce commutateur force l'URL substituée être redirigée en interne au titre de requête proxy (et arrête de ce fait tout processus de réécriture) et passe immédiatement le résultat au module proxy. Vous devez vous assurer que l'expression de substitution est bien une URI valide (ex. typique http://) qui peut être traitée par le module proxy d'Apache. Sinon, vous génèrerez une erreur dans le gestionnaire proxy. Utilisez ce commutateur pour obtenir une implémentation plus puissante de la directive ProxyPass du module mod_proxy, permettant d'intégrer des ressources distantes à l'espace du serveur local.

    Attention : Il vous faut nécessairement mentionner ProxyRequests On dansla configuration de votre serveur pour éviter que des requêtes proxy ne se terminent en un "core-dump" du kernel Apache. Si vous n'avez pas compilé le module proxy dans Apache, alors vous n'avez pas ce problème, car le module mod_rewrite vérifie auparavent la disponibilité du module proxy et ignore les redirections proxy si ce module se révèle indisponible.
  • 'last|L' (dernière règle : last rule)
    Arrête le traitement de réécriture en ce point et n'applique plus aucune règle de réécriture postérieure. Ceci correspond à l'instruction Perl last ou au break du C dans une boucle. Utilisez ce commutateur pour éviter que l'URL réécrite par cette règle ne soit à son tour modifiée une nouvelle fois par d'autres règles pour lesquelles le motif pourrait correspondre. Par exemple, vouspouvez l'utiliser pour réécrire l'URL d'accès à root ('/') vers une URL opérationnelle, comme '/e/www/'.
  • 'next|N' (rebouclage : next round)
    Re-exécute le traitement de réécriture (en recommençant par la première règle), mais à partir de l'URL obtenue par application de la règle courante (et non à partir de l'URL originale, d'où on ne sortirait pas). Ceci correspond à l'instruction Perl next ou continue du langage C. Utilisez ce commutateur pour recommencer le traitement de réécriture, c'est-à-dire pour immédiatement reboucler au début de la boucle.
    Faîtes très attention de ne pas créer de boucle infinie !
  • 'chain|C' (chainage à la règle suivante)
    Ce commutateur chaîne la règle courante à la règle suivante (laquelle peut à son tour être chaînée à la régle encore suivante etc.). Ceci à l'effet suivant : si une règle est "déclenchée", alors le traitement se continue comme d'habitude, c'est-à-dire que ce commutateur n'a pas d'effet particulier. Si la règle n'est pas activée, alors toutes les règles chaînées qui suivent sont ignorées. Par exemple, vous pourriez l'utiliser pour éliminer la partie ".www" dans une règle de contexte répertoire définie pour des cas de redirection externe (où la partie ".www" ne doit pas apparaître !).
  • 'type|T=type-mime' (force le type MIME)
    Force le type MIME du fichier cible à la valeur spécifiée par mime-type. Par exemple, il peut permettre le simuler l'ancienne directive ScriptAlias du module mod_alias par laquelle on attribuerait à tous les fichiers d'un répertoire un type MIME "application/x-httpd-cgi", quelle que soit leur extension.
  • 'nosubreq|NS' (utilisé uniquement si la requête n'est pas une sous requête interne : no internal sub-request)
    Ce commutateur force le moteur de réécriture à sauter la règle si la requête courante est une sous-requête interne. Un exemple d'utilisation de sous-requêtes intervient lorsque le module mod_include d'Apache essaie de rechercher des informations sur l'existence éventuelle de fichiers par défaut dans les répertoires (index.xxx). Lors de ces sous-requêtes, il n'est pas toujours utile, voir parfois même carrément néfaste d'appliquer une nouvelle fois tout l'ensemble de règles de réécriture. Vous utiliserez alors ce commutateur pour exclure ces règles pouvant conduire à une erreur de traitement.

    Vous pouvez vous appuyer sur la règle suivante pour prendre votre décision : lorsque vous préfixez certaines URL vers des scripts CGI, pour les forcer à exécutées en tant que CGI, il y a de fortes chances que vous tombiez sur un os (ou même sur une défaillance générale) lors des sous-requêtes. Dans ce cas, utilisez ce commutateur.
  • 'qsappend|QSA' (Ajout de chaîne de requête : query string append)
    Ce commutateur force l'ajout d'une chaîne argument de requête dans l'URL substituée à l'argument existant, au lieu de remplacer purement et simplement cet argument comme dans le cas normal. Vous utiliserez cecommutateur lorsque vouzs voudrez ajouter des paramètres à une requête argumentée par une opération de réécriture.
  • 'passthrough|PT' (pass through)
    Ce commutateur force le moteur de réécriture à renseigner le champ uri de la structure interne request_rec avec la valeur du champ filename. Ce commutateur est juste une "bidouille" pour permettre un post-traitement de la sortie de directives RewriteRule par des directives Alias, ScriptAlias, Redirect, et autres translateurs URI-vers-fichier. Voici un exemple trivial pour en décrire la sémantique :
    Si vous souhaitez translater /abc en /def via le moteur de réécriture du module mod_rewrite puis /def en /ghi par une directive de mod_alias :
    RewriteRule ^/abc(.*)  /def$1 [PT]
    Alias       /def       /ghi
    Si vous omettez le commutateur PT alors mod_rewrite fera le travail attendu, c'est-à-dire transformera uri=/abc/... en filename=/def/... comme n'importe quel translateur URI-vers-fichier conforme à l'API Apache l'aurait fait. Puis mod_alias intervient et essaie d'effectuer sa translation dans laquelle elle échouera, essayant de se baser sur l'URL originale et non l'URL modifiée par la précédente.
    Attention : Vous DEVEZ utiliser ce commutateur si vous souhaitez mélanger des directives de différents modules actionnant des translateurs URL-vers-fichier. L'exemple typique est cette utilisation de mod_alias et mod_rewrite.

    Pour les bidouilleurs d'Apache :

    Si l'API actuelle d'Apache pouvait fournir une translation fichier-vers-fichier en plus de la translation URI-vers-fichier alors nous n'aurions pas besoin de ce commutateur ! Mais sans cette dérivation, ce commutateur est la seule solution. Le groupe Apache a discuté de ce problème et prévoit d'implémenter cette translation dans la future version 2.0 d'Apache.
  • 'skip|S=num' (sauter la prochaine(s) règle(s))
    Ce commutateur force le moteur de réécriture à sauter les num règles suivantes lorsque la règle courante s'applique. Vous pouvez l'utiliser pour simuler des pseudo structures de contrôle de type SI-ALORS-SINON : La dernière règle de la section ALORS doit devenir une règle sautant N nouvelles règles (skip=N), ces N règles suivantes constituant ainsi la section SINON de la structure. (Ceci est différent du comportement du commutateur 'chain|C' !).
  • 'env|E=VAR:VAL' (définir unevariable d'environnement)
    Force la définition d'une variable d'environnement VAR à la valeur VAL. VAL peut être exprimée par une expression contenant des rétroréférences $N et %N qui seront substituées à l'initialisation de la variable. Vouspouvez utiliser ce commutateur plusieurs fois pour définir plusieurs variables en même temps. Ces variables pourront être par la suite réutilisées dans de nombreuses situations, dont les plus courantes sont à l'intérieur d'un traitement XSSI (via la commande <!--#echo var="VAR"-->) ou d'un CGI (ex. $ENV{'VAR'}). Vous pourrez aussi l'atteindre dans un motif de RewriteCond ultérieur via l'écriture %{ENV:VAR}. Vous pouvez utilsier cette fonctionnalité lorsque vous souhaitez enlever des portions d'URLs, tout en mémorisant les morceaux enlevés.

Souvenez-vous : N'oubliez jamais que le motif est appliqué à l'URL entière lorsque les conditions sont écrites dans un contexte de configuration serveur. Par contre, dans un contexte de répertoire, le préfixe de chemin d'accès (le chemin partiel vers ce répertoire, qui devrait toujours être le même !) est d'abord retiré de l'URL avant que le motif ne soit appliqué, puis rajouté de nouveau tel que après la substitution. Ce comportement est fondamental dans de nombreuses programmation de réécriture, dans la mesure où, sans cette opération sur le chemin d'accès partiel, il vous faudrait un motif complet prenant en compte l'arborescence aïeule, ce qui n'est pas toujours possible.

Une exception à cela : lorsqu'une expression de substitution commence par "http://" alors le préfixe indiquant le chemin partiel au répertoire courant ne sera pas rajouté, et une redirection externe ou un transfert au proxy (si le commutateur P est marqué !) est opérée.

Attention ! Pour pouvoir exploiter le moteur de réécriture sur une base de configuration de contexte répertoire, vous devrez inscrire RewriteEngine On dans les fichiers de configuration .htaccess et avoir l'Option FollowSymLinks disponible. Si votre administrateur a désactivé la surcharge des options FollowSymLinks pour votre répertoire utilisateur, vous ne pourrez pas utiliser le moteur de réécriture. Cette restriction est nécessaire pour des raisons de sécurité.

Ci dessous sont données les diverses combinaisons de substitution et leur signification :

Dans une configuration de niveau "serveur" (httpd.conf)
pour une requête "GET /unChemin/uneInfo":

Règle                                           Substitution résultante
----------------------------------------------  ----------------------------------
^/unChemin(.*) autreChemin$1                      non supporté, car non valide !
^/unChemin(.*) autreChemin$1  [R]                 non supporté, car non valide !
^/unChemin(.*) autreChemin$1  [P]                 non supporté, car non valide !
----------------------------------------------  ----------------------------------
^/unChemin(.*) /autreChemin$1                     /autreChemin/uneInfo
^/unChemin(.*) /autreChemin$1 [R]                 http://cetHôte/autreChemin/uneInfo
via une redirection externe
^/unChemin(.*) /autreChemin$1 [P]                 non supporté !
----------------------------------------------  ----------------------------------
^/unChemin(.*) http://cetHôte/autreChemin$1       /autreChemin/uneInfo
^/unChemin(.*) http://cetHôte/autreChemin$1 [R]   http://cetHôte/autreChemin/uneInfo
via une redirection externe
^/unChemin(.*) http://cetHôte/autreChemin$1 [P]   non supporté !
----------------------------------------------  ----------------------------------
^/unChemin(.*) http://autreHôte/autreChemin$1     http://autreHôte/autreChemin/uneInfo
via une redirection externe
^/unChemin(.*) http://autreHote/autreChemin$1 [R] http://autreHôte/autreChemin/uneInfo
via une redirection externe
(le flag [R] est redondant)
^/unChemin(.*) http://autreHôte/autreChemin$1 [P] http://autreHôte/autreChemin/uneInfo
via proxy interne

Dans un fichier de configuration pour le répertoire /unChemin
(c-à-d. un fichier /.htaccess dans le répertoire /chemin/physique/vers/unChemin contenant une directive RewriteBase /unChemin)
pour une requête "GET /somepath/localpath/uneInfo" :

Règle                                            Substitution résultante
-------------------------------------------------  ----------------------------------
^cheminLocal(.*) autreChemin$1                      /unChemin/autreChemin/uneInfo
^cheminLocal(.*) autreChemin$1  [R]                 http://cetHôte/unChemin/autreChemin/uneInfo
via une redirection externe
^cheminLocal(.*) autreChemin$1  [P]                 non supporté !
-------------------------------------------------  ----------------------------------
^cheminLocal(.*) /autreChemin$1                     /autreChemin/uneInfo
^cheminLocal(.*) /autreChemin$1 [R]                 http://cetHôte/autreChemin/uneInfo
via une redirection externe
^cheminLocal(.*) /autreChemin$1 [P]                 non supporté !
-------------------------------------------------  ----------------------------------
^cheminLocal(.*) http://cetHôte/autreChemin$1      /autreChemin/uneInfo
^cheminLocal(.*) http://cetHôte/autreChemin$1 [R]  http://cetHôte/autreChemin/uneInfo
via une redirection externe
^cheminLocal(.*) http://cetHôte/autreChemin$1 [P]   not supporté !
-------------------------------------------------  ----------------------------------
^cheminLocal(.*) http://autreHôte/autreChemin$1     http://autreHôte/autreChemin/uneInfo
via une redirection externe
^cheminLocal(.*) http://autreHôte/autreChemin$1 [R] http://autreHôte/autreChemin/uneInfo
via une redirection externe
(le flag [R] est redondant)
^cheminLocal(.*) http://autreHôte/autreChemin$1 [P] http://autreHôte/autreChemin/uneInfo
via proxy interne

Exemple :

Mettons que nous souhaitions réécrire des URL de la forme /Language/~Realname/.../File en /u/Username/.../File.Language

Nous déduirions la table de correspondance des règles ci-dessus et l'enregistrerions dans le fichier /nimportou/map.real-vers-hote. Il ne nous resterait plus qu'à écrire les lignes suivantes dans le fichier de configuration d'Apache :

RewriteLog   /nimportou/reecriture.log
RewriteMap   real-vers-user               txt:/nimportou/map.real-vers-hote
RewriteRule  ^/([^/]+)/~([^/]+)/(.*)$   /u/${real-vers-user:$2|nobody}/$3.$1

Fonctionnalités additionnelles

Variables d'Environnement

Ce module garde la trace de deux variables d'environnement CGI/SSI supplémentaires (non standard) nommées SCRIPT_URL et SCRIPT_URI . Elles contiennent l'adresse logique de la ressource courante "vue du navigateur", tandis que les variables CGI/SSI standard SCRIPT_NAME et SCRIPT_FILENAME contiennent l'adresse physique de la même ressource "vue du système".

Attention : Ces variables contiennent les URI/URL telles qu'elles sont inscrites dans la requête initiale, c'est-à-dire leur expression avant toute opération de réécriture. Ceci a une certazine importance car le procédé de réécriture est principalement utilisé pour transcrire ces adresses logiques en adresses physiques.

Exemple :

SCRIPT_NAME=/v/sw/free/lib/apache/global/u/rse/.www/index.html
SCRIPT_FILENAME=/u/rse/.www/index.html
SCRIPT_URL=/u/rse/
SCRIPT_URI=http://en2.en.sdm.de/u/rse/
apache, informatique, rewrite, module, wiki, drik, directives, additionnelles, fonctionnalita, configuration, suma, directive, rewriteloglevel, rewriteoptions, rewriteengine, environnement, rewriterule, rewritebase, rewritecond, rewritelog, rewritemap, variables, exemple, bidouilleurs, pour