Hop, je fais le fainéant et je me contente de vous copier/coller le tuto que j’ai écrit pour le site du zéro :-°
Un magnifique tuto sur les secrets de l’URL rewriting et comment en faire même si le moteur de réécriture d’Apache est désactivé, grâce à PHP. Si c’est pas gentil de ma part ça
Ce tutoriel a pour but de faire connaître aux lecteurs du Site du Zéro les secrets de l’obscur URL rewriting.
Monsieur, c’est quoi l’URL rewriting ?
Haha, en voilà une bonne question. L’URL rewriting est ce qui permet aux gentils développeurs de coder leurs pages et leur navigation à grand coup de variables GET (les variables qui apparaissent dans les URL des pages du genre http://www.google.fr/search?hl=fr&q=url+rewriting&btnG=Recherche+Google&meta=&aq=0&oq=url) sans pour autant qu’on se retrouve au final avec un site aux URL “laides”.
L’URL rewriting va donc nous permettre de créer de belles URL, compréhensibles par vos utilisateurs et permettant au passage d’améliorer votre référencement (oui une page du style mes-supers-tutoriels.html sera mieux référencée que index.php?p=2&id=4)
Liens utiles pour ce tutoriel :
- Le cours de PHP de M@teo21
- Les expressions régulières et PHP par M@teo21
- La page Wikipedia dédiée aux expressions régulières
- La doc. Apache sur le rewrite engine
Sommaire du tutoriel :
Pourquoi faire de l’URL rewriting ?
Et bien comme dit en introduction, le but de l’URL rewriting dans la plupart des cas est d’obtenir des URLs propres. En effet, les sites dynamiques actuels présentent souvent des URLs complexes présentant des ? et des & pas forcément très compréhensible par les utilisateurs et encore moins par les robots d’indexation :
Exemple :
article.php?id=12&page=2&rubrique=5
Dans cet exemple, le fichier article.php est utilisé pour afficher un article dont le texte vient d’une base de données. C’est un fichier générique, qui peut afficher n’importe quel article, de n’importe quelle rubrique, page par page. Ici on cherche à afficher la page 2 de l’article numéro 12 qui fait partie de la rubrique 5.
Problème : les robots comme celui de Google n’indexent pas ce genre de pages (le googlebot s’arrête par exemple à 2 paramètres, notre exemple est donc oublié par le robot).
Ok mais ça avance à quoi ?
L’URL rewriting va nous permettre de mettre à l’intérieur de notre site des URLs plus “jolies” dans le sens où elles seront compréhensibles et indexables par les robots. Les URLs que nous allons ainsi placés ne correspondent en réalités à aucun fichier mais nous allons voir comment, grâce à l’URL rewriting, nous allons faire correspondre ces URLs factices aux URLs réellement interprétées par le serveur.
D’accord mais alors, à quoi ressemblent ces URLs propres ? Comment puis-je les faire ?
Pour reprendre notre exemple de tout à l’heure, plutôt que d’avoir
article.php?id=12&page=2&rubrique=5
, ne serait-il pas mieux d’avoir
12-2-5-nom-de-l-article.html
?
Vous vous rendez compte ? Grâce à ce type d’URL, le nom de votre article est directement référencé dans l’URL !
Les bases théoriques
Le rewrite engine est un module d’Apache qui gère les réécritures d’URL. Nous verrons plus tard comment peut être chargé de ce dernier.
Étudions en détail les options que nous offre le module :
La directive RewriteEngine
Description : active/désactive le moteur de réécriture.
Syntaxe : RewriteEngine on|off
Par défaut :RewriteEngine off
Contexte : configuration du serveur, serveur virtuel (virtual host), répertoire, .htaccess
La directive RewriteEngine active ou désactive le fonctionnement du moteur de réécriture.
Utilisez cette directive plutôt que de commenter toutes les directives RewriteRule .
A noter que la configuration de réécriture n’est pas héritée par les serveurs virtuels. Cela signifie que vous devez avoir une directive RewriteEngine on pour chaque hôte virtuel dans lequel vous souhaitez utiliser la réécriture d’URL.
La directive RewriteOptions
Description : défini quelques options particulières pour le moteur de réécriture.
Syntaxe : RewriteOptions Options
Contexte : configuration du serveur, serveur virtuel (virtual host), répertoire, .htaccess
La directive RewriteOptions définit certaines options spéciales pour la configuration actuelle du serveur ou répertoire. La chaîne Options ne peut pour l’instant qu’être :
inherit :
Cela force la configuration actuelle à hériter de la configuration du parent. Dans le contexte d’un serveur virtuel, cela signifie que les conditions et règles du serveur principal sont héritées. Dans le contexte d’un répertoire, cela signifie que les conditions et règles du fichier .htaccess du dossier parent sont héritées.
La directive RewriteLog
Description : Définie le nom du fichier utilisé pour journaliser le processus du moteur de réécriture.
Syntaxe : RewriteLog chemin/vers/le/fichier
Contexte : Configuration du serveur, serveur virtuel
La directive RewriteLog définit le nom du fichier dans lequel le serveur journalise toutes les actions de réécriture qu’il réalise. Si le nom ne commence pas par un slash (’/'), alors il est implicite que c’est relatif à la racine du serveur. La directive ne devrait apparaître qu’une fois par configuration de serveur.
Pour désactiver la journalisation des actions de réécriture, il n’est pas recommandé de définir le nom de fichier par /dev/null, car bien que physiquement il n’y a pas de sortie de la journalisation, le serveur créé quand même une journalisation en interne. Cela ralentira le serveur sans aucun avantage pour l’administrateur ! Pour désactiver la journalisation, enlevez ou commentez la directive RewriteLog ou utilisez RewriteLogLevel 0 !
Exemple :
RewriteLog ”/usr/local/var/apache/logs/rewrite.log”
La directive RewriteLogLevel
Description : Définit la pertinence du fichier de journalisation utilisé par le moteur de réécriture
Syntaxe : RewriteLogLevel Niveau
Par défaut : RewriteLogLevel 0
Contexte : configuration du serveur, serveur virtuel
La directive RewriteLogLevel définit le niveau de pertinence du fichier de journalisation de la réécriture. Le niveau par défaut 0 signifie pas de journalisation, alors que 9 ou plus signifie que presque toutes les actions sont journalisées.
Pour désactiver la journalisation des actions de réécriture, définissez simplement Niveau à 0. Cela désactive la journalisation de toute action de réécriture.
Utiliser une haute valeur pour Niveau ralentira de façon significative votre serveur Apache ! Utilisez un fichier de journalisation à un Niveau de plus de 2 uniquement pour le débogage !
Exemple
RewriteLogLevel 3
La directive RewriteBase
Description : Définit l’URL de base pour la réécriture dans un répertoire.
Syntaxe : RewriteBase URL
Par défaut : RewriteBase Chemin/physique/du/dossier
Contexte : répertoire, .htaccess
La directive RewriteBase définie explicitement l’URL de base pour les réécritures dans un répertoire.
La directive RewriteCond
Description : Définit une condition selon laquelle une réécriture sera effectuée.
Syntaxe : RewriteCond TestString CondPattern
Contexte : configuration serveur, serveurs 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 appliqué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.
La compréhension de ces deux références demande 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 extractions 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 : |
connexion & requête : |
| HTTP_USER_AGENT |
REMOTE_ADDR |
| HTTP_REFERER |
REMOTE_HOST |
| HTTP_COOKIE |
REMOTE_USER |
| HTTP_FORWARDED |
REMOTE_IDENT |
| HTTP_HOST |
REQUEST_METHOD |
| HTTP_PROXY_CONNECTION |
SCRIPT_FILENAME |
| HTTP_ACCEPT |
PATH_INFO |
|
QUERY_STRING |
|
AUTH_TYPE |
| Variables internes du serveur : |
Variables système : |
Variables spéciales : |
| DOCUMENT_ROOT |
TIME_YEAR |
API_VERSION |
| SERVER_ADMIN |
TIME_MON |
THE_REQUEST |
| SERVER_NAME |
TIME_DAY |
REQUEST_URI |
| SERVER_PORT |
TIME_HOUR |
REQUEST_FILENAME |
| SERVER_PROTOCOL |
TIME_MIN |
IS_SUBREQ |
| SERVER_SOFTWARE |
TIME_SEC |
|
| SERVER_VERSION |
TIME_WDAY |
|
|
TIME |
|
Ces variables correspondent 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 :
- 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).
- 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’Apache.
- 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:”.
- 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.
- 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 :
- 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é).
- 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 expressions 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 égales (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 : directory)
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 indiffé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 :
Code : Apache
1
2
3
4
|
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’existence de ce commutateur vous auriez du écrire trois fois l’ensemble des conditions plus la règle.
La directive RewriteRule
Description : Définit les règles pour le moteur de réécriture.
Syntaxe : RewriteRule motif substitution
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. Chaque 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écessairement 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 caractère qui précède
char déspécialise le méta caractère qui suit (ex. pour mentionner les caractères litté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’exprimer les conditions inverses ou comme dernière règle par défaut.
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. En plus du texte brut, vous pouvez utiliser :
- Des rétro-références $N sur des sous-motifs de la condition de règle
- Des rétro-références %N sur les sous-motifs de la RewriteCond précédente
- Des variables “serveur” de la même façon que dans les expressions de condition (%{VARNAME})
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.
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 successifs d’être testés sur la même URL avant que toute modification n’y soit portée.
Vous pouvez même, par une expression de substitution, réécrire une URL contenant des paramètres de requête. Il suffit pour cela 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.
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 lorsqu’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.
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)
Préfixez 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 souhaitez 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.
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édiatement 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éfinitivement “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.
Il vous faut nécessairement mentionner ProxyRequests On dans la 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 auparavant 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, vous pouvez l’utiliser pour réécrire l’URL d’accès à root (’/') vers une URL opérationnelle, comme ‘/e/www/’.
- ‘next|N‘ (rebouclage : next round)
Ré-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 ce commutateur lorsque vous 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 :
Code : Apache
1
2
|
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.
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.
- ‘skip|S=num‘ (sauter la/les 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 pseudos 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 une variable 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 utiliser cette fonctionnalité lorsque vous souhaitez enlever des portions d’URLs, tout en mémorisant les morceaux enlevés.
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 programmations 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.
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] |
non 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 |
Sources : Doc officielle Apache sur mod_rewrite (en)
Les prérequis
Le principal prérequis est que votre serveur Apache est son rewrite engine d’activé.
Comment savoir si mon rewrite engine est activé ?
Si vous êtes chez un hébergeur, allez vous renseigner auprès de votre hébergeur, c’est lui qui s’occupe de configurer votre serveur Apache. Si vous hébergez vous-même et que vous avez donc accès à votre configuration Apache, cherchez le fichier nommé httpd.conf et cherchez y la ligne suivante : LoadModule rewrite_module modules/mod_rewrite.so. Normalement, il devrait y avoir un # au début de la ligne, supprimez le. Le # sert en fait à commenter la ligne ce qui fait que le module n’était pas chargé. Une fois le # supprimé, redémarrez votre serveur Apache. S’il n’y avait pas de #, c’est que le module était déjà chargé, vous pouvez passer à la suite.
Si vous n’avez pas accès à la configuration d’Apache et que le module n’est pas activé, reportez-vous à la section L’URL rewriting sans le rewrite engine - utilisation de PHP.
Mon premier URL rewriting
On va faire un premier exemple d’URL rewriting simple : test.html qui sera en fait la page test.php.
Commençons par créer une page test.php et insérons-y le code suivant :
>?php
echo'mes debuts en url rewriting'
?>
Ensuite il nous faut créer un fichier .htaccess. Pour les personnes sous Windows,
selon les versions, on ne peut pas créer de fichier sans
nom, puisque pour lui .htaccess est une extension alors
qu’en réalité c’est un fichier destiné à être un fichier caché (sous les systèmes UNIX, les fichiers ou dossier commençant par un . sont des fichiers et dossiers cachés). Créez donc un fichier htaccess.txt, ouvrez le avec le bloc note par exemple et faites enregistrer-sous->.htaccess.
Ensuite éditez votre fichier .htaccess avec le bloc note par exemple et mettez y le code suivant :
RewriteEngine On
RewriteRule ^test.html$ /test.php
Voilà c’est fini. Si vous mettez vas fichiers test.php et .htaccess à la racine de votre serveur HTTP (dans le dossier www, par défaut) et que vous faites : http://127.0.0.1/test.html vous devriez obtenir : mes debuts en url rewriting
Si ça ne marche pas :
- Vérifiez que vous n’avez pas déjà de page test.html
- Faites ce qui suit :
Il se peut que votre serveur soit configuré de manière différente ou ai une version différente. Remplacez le code par le suivant :
RewriteEngine On
RewriteRule ^test.html$ /test.php [L]
Ca ne marche toujours pas ? On essaye avec ça :
RewriteEngine On
RewriteBase /
RewriteRule ^test.html$ test.php [L]
Et si ça ne marche toujours pas, vous êtes sûr que le module de rewrite est chargé ?
URL rewriting avancé
Tout ça c’est super mais je fais comment moi si mes URL sont plus dynamiques que ça et contiennent par exemple des variables GET représentant un identifiant ?
On y vient, on y vient. Reprenons l’exemple précédent : on a un fichier test.php et un fichier .htaccess. Admettons qu’on veuille accéder à la page test.php?p=x où x est un nombre. On va pouvoir récupérer ce x pour l’afficher dans notre page test.php
Dans le fichier test.php, insérer ce code :
<?php
echo $_GET['p'];
?>
Et dans le .htaccess :
RewriteEngine On
RewriteRule ^([0-9]+)-test.html$ /test.php?p=$1
Ensuite : http://localhost/1-test.html. Cela devrait vous afficher un 1. Vous pouvez vous amuser à changer le chiffre dans l’URL x-test.html et constater que le nombre affiché est bien celui-là.
Et bien les parenthèses que nous avons mis sont des parenthèses capturantes. Elles permettent de récupérer ce qu’il y a à l’intérieur grâce au $1 que nous avons mis plus loin. On peut bien sûr ajouter des parenthèses pour avoir des $2, $3, etc.
Votre hébergeur ne permet l’URL rewriting car le module de réécriture n’est pas chargé mais vous aimeriez quand même faire de la réécriture ? C’est possible ! Comment ? Avec un poil de .htaccess et surtout du PHP.
En théorie
Alors dans la théorie on va en fait utiliser le fichier .htaccess pour définir une page 404 personnalisée. Voir la page erreur 404 de Wikipedia.
C’est ensuite dans cette page d’erreur que nous définirons les règles de réécriture.
Dans la pratique
Prenons un fichier .htaccess, un fichier test.php et un fichier erreur404.php
Dans le fichier .htaccess mettons ceci :
ErrorDocument 404 /erreur404.php
Dans le fichier test.php :
<?php
echo $_GET['p'];
?>
Dans le fichier erreur404.php:
<?php
if(isset($_SERVER['REQUEST_URI'])){
if(preg_match('#^([0-9]+)-test.html$#',$_SERVER['REQUEST_URI'],$match)){
header('Status: 200 OK';, false, 200);
$_GET['p']=$match[1];
$_REQUEST['p']=$match[1];
include 'test.php';
}else{
?>
<h1>Erreur 404</h1>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:18px;">URL invalide, page introuvable</span>
<?php
}
}else{
?>
<h1>Erreur 404</h1>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:18px;">URL invalide, page introuvable</span>
<?php
}
?>
Tout ceci nous permet d’afficher un message d’erreur personnalisé plutôt que l’erreur 404 classique (ce qui peut être un plus, on peut par exemple mettre alors un formulaire de recherche pour l’utilisateur), et surtout de tester notre règle de réécriture. Ici on utilise directement de l’URL rewriting avancé avec récupération de variable.
Les parenthèses que nous avons mis sont des parenthèses capturantes. Elles permettent de récupérer ce qu’il y a à l’intérieur grâce au $match[1] que nous avons mis plus loin. On peut bien sûr ajouter des parenthèses pour avoir des $match[2], $match[3], etc.
Pour générer des URLs “propres” qui seront par la suite traitées avec de l’URL rewriting, ce n’est pas bien compliqué. Un peu de PHP et une bonne règle de réécriture feront l’affaire.
Prenons un exemple. J’ai une page PHP qui me permet d’afficher le descriptif d’un produit à partir de son ID et sa catégorie, le tout passé en variable GET dans les liens de mon site. J’ai donc pour le moment : http://monhôte/produit.php?id=x&cat=y
Comme on l’a dit avant, ce n’est pas terrible ni pour le référencement ni pour la compréhension par le visiteur.
Commençons par définir une règle de réécriture : on décide que désormais cette page aura pour URL : produit-x-y-nom-de-mon-produit.html. Ce qui est bien mieux que ça ne l’était auparavant.
Comment mettre ceci en place ?
Très simple !
Commençons par la règle de réécriture dans notre fichier .htaccess (par exemple) :
RewriteEngine on #Activation du moteur de réécriture
RewriteBase / #On définit la racine du site comme URL de base
RewriteRule ^produit-([0-9]{1,5})-([0-9]{1,5})-[w-]+$ produit.php?id=$1&cat=$2 #On définit la règle
Puis pour créer nos liens en PHP :
<?php
//Connexion à la base de données faite
$result=mysql_query("SELECT * FROM produits"); //On récupère tous les produits
while($produit=mysql_fetch_array($result)){ //Tant qu'il y a des produits, on traite
echo <a href="produit-'.$produit['id'].'-'.$produit['categorie'].'-'.preg_replace('/s+/','-',$produit['nom']).'.html">'.$produit['nom'].'</a><br />';
//On affiche un lien. preg_replace('/s+/','-',$produit['nom']) permet de remplacer les espaces par des '-'
}
?>
Ceci donne comme résultat (pour 3 produits ici) :
<a href="produit-1-1-produit-1.html">Produit 1</a><br />
<a href="produit-1-2-produit-2.html">Produit 2</a><br />
<a href="produit-2-3-produit-3.html">Produit 3</a>
Et voilà c’est donc fini, en 2 coups de cuillère à pot, on a fait de belles URLs qui permettront d’être référencé et d’avoir en plus notre noms de produit référencé directement dans l’URL de la page, ce qui est quand même un petit plus 
Mon exemple est minimaliste et ne prend pas en compte les accents qu’il faudrait enlever des URL générées avec PHP s’il y en avait. Des fonctions permettant d’enlever les caractères spéciaux d’une chaîne se trouvent facilement.
Voilà, c’est déjà la fin de ce tutoriel qui vous aura, j’espère, été utile.