Il s'agit d'une question canonique sur le mod_rewrite d'Apache.
La modification d'une URL de demande ou la redirection d'utilisateurs vers une URL différente de celle qu'ils avaient initialement demandée se fait à l'aide de mod_rewrite. Cela comprend des choses telles que:
Tout ce que vous avez toujours voulu savoir sur les règles Mod_Rewrite mais avez eu peur de demander!
Comment puis-je devenir un expert en rédaction de règles mod_rewrite?
Un endroit pour tester vos règles
Le site Web testeur htaccess est un endroit idéal pour jouer avec vos règles et les tester. Il montre même la sortie de débogage pour que vous puissiez voir ce qui correspond et ce qui ne fonctionne pas.
mod_rewrite a des règles de commande spécifiques qui affectent le traitement. Avant que rien ne soit fait, le RewriteEngine On
La directive doit être donnée car cela active le traitement mod_rewrite. Cela devrait être avant toute autre directive de réécriture.
RewriteCond
précédant RewriteRule
soumet cette règle UN au conditionnel. Toutes les règles de réécriture suivantes seront traitées comme si elles n'étaient pas soumises à des conditions.
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html $/blog/$1.sf.html
Dans ce cas simple, si le référent HTTP provient de serverfault.com, redirigez les demandes de blog vers des pages spéciales de défaut de serveur (nous sommes tout simplement spéciaux). Cependant, si le bloc ci-dessus avait une ligne RewriteRule supplémentaire:
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html $/blog/$1.sf.html
RewriteRule $/blog/(.*)\.jpg $/blog/$1.sf.jpg
Tous les fichiers .jpg iraient aux pages spéciales de défaut de serveur, pas seulement celles avec un référent indiquant qu'il vient d'ici. Ce n'est clairement pas l'intention de la façon dont ces règles sont écrites. Cela pourrait être fait avec plusieurs règles RewriteCond:
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html /blog/$1.sf.html
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.jpg /blog/$1.sf.jpg
Mais cela devrait probablement être fait avec une syntaxe de remplacement plus délicate.
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg) /blog/$1.sf.$2
Le RewriteRule plus complexe contient les conditions pour le traitement. La dernière parenthèse, (html|jpg)
indique à RewriteRule de correspondre à html
ou jpg
, et de représenter la chaîne correspondante comme $ 2 dans la chaîne réécrite. Ceci est logiquement identique au bloc précédent, avec deux paires RewriteCond/RewriteRule, il le fait simplement sur deux lignes au lieu de quatre.
Plusieurs lignes RewriteCond sont implicitement ET et peuvent être explicitement OU. Pour gérer les référents à la fois de ServerFault et de Super User (OU explicite):
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$) [OR]
RewriteCond %{HTTP_REFERER} ^https?://superuser\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg) /blog/$1.sf.$2
Pour servir les pages référencées ServerFault avec Chrome (ET implicite):
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*Chrome.*$
RewriteRule ^/blog/(.*)\.(html|jpg) /blog/$1.sf.$2
RewriteBase
est également spécifique à l'ordre car il spécifie comment les directives RewriteRule
suivantes gèrent leur traitement. Il est très utile dans les fichiers .htaccess. Si elle est utilisée, elle doit être la première directive sous "RewriteEngine on" dans un fichier .htaccess. Prenez cet exemple:
RewriteEngine On
RewriteBase /blog
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg) $1.sf.$2
Cela indique à mod_rewrite que cette URL particulière qu'il gère actuellement est arrivée par http://example.com/blog/ au lieu du chemin du répertoire physique (/ home/$ Username/public_html/blog ) et de le traiter en conséquence. Pour cette raison, le RewriteRule
considère que le début de chaîne se situe après le "/ blog" dans l'URL. Voici la même chose écrite de deux manières différentes. L'un avec RewriteBase, l'autre sans:
RewriteEngine On
##Example 1: No RewriteBase##
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule /home/assdr/public_html/blog/(.*)\.(html|jpg) $1.sf.$2
##Example 2: With RewriteBase##
RewriteBase /blog
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg) $1.sf.$2
Comme vous pouvez le voir, RewriteBase
permet aux règles de réécriture de tirer parti du chemin d'accès au contenu Web - site plutôt qu'au Web - serveur, qui peut les rendre plus intelligibles pour ceux qui éditent de tels fichiers. En outre, ils peuvent raccourcir les directives, ce qui présente un attrait esthétique.
RewriteRule lui-même a une syntaxe complexe pour faire correspondre les chaînes. Je couvrirai les drapeaux (des choses comme [PT]) dans une autre section. Parce que les administrateurs système apprennent par l'exemple plus souvent qu'en lisant un man-page je vais donner des exemples et expliquer ce qu'ils font.
RewriteRule ^/blog/(.*)$ /newblog/$1
Le .*
la construction correspond à n'importe quel caractère (.
) zéro ou plusieurs fois (*
). Le placer entre parenthèses lui indique de fournir la chaîne qui correspond à la variable $ 1.
RewriteRule ^/blog/.*/(.*)$ /newblog/$1
Dans ce cas, le premier. * N'était PAS placé entre parenthèses et n'est donc pas fourni à la chaîne réécrite. Cette règle supprime un niveau d'annuaire sur le nouveau site de blog. (/blog/2009/sample.html devient /newblog/sample.html).
RewriteRule ^/blog/(2008|2009)/(.*)$ /newblog/$2
Dans ce cas, la première expression entre parenthèses configure un groupe correspondant. Cela devient $ 1, ce qui n'est pas nécessaire et n'est donc pas utilisé dans la chaîne réécrite.
RewriteRule ^/blog/(2008|2009)/(.*)$ /newblog/$1/$2
Dans ce cas, nous utilisons $ 1 dans la chaîne réécrite.
RewriteRule ^/blog/(20[0-9][0-9])/(.*)$ /newblog/$1/$2
Cette règle utilise une syntaxe de parenthèse spéciale qui spécifie un caractère range. [0-9] correspond aux chiffres de 0 à 9. Cette règle spécifique traitera les années 2000 à 2099.
RewriteRule ^/blog/(20[0-9]{2})/(.*)$ /newblog/$1/$2
Cela fait la même chose que la règle précédente, mais la partie {2} lui indique de correspondre deux fois au caractère précédent (une expression entre crochets dans ce cas).
RewriteRule ^/blog/([0-9]{4})/([a-z]*)\.html /newblog/$1/$2.shtml
Cette casse correspondra à n'importe quelle lettre minuscule dans la deuxième expression correspondante et le fera pour autant de caractères que possible. Le \.
construct lui dit de traiter la période comme une période réelle, pas le caractère spécial qu'elle est dans les exemples précédents. Il se cassera cependant si le nom du fichier contient des tirets.
RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html /newblog/$1/$2.shtml
Cela intercepte les noms de fichiers avec des tirets. Cependant, comme -
est un caractère spécial dans les expressions entre crochets, il doit être le caractère en premier dans l'expression.
RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html /newblog/$1/$2.shtml
Cette version intercepte tout nom de fichier avec des lettres, des chiffres ou le -
caractère dans le nom de fichier. C'est ainsi que vous spécifiez plusieurs jeux de caractères dans une expression entre crochets.
Les drapeaux des règles de réécriture ont une multitude de significations et de cas particuliers .
RewriteRule ^/blog/([0-9]{4})/([-a-z]*).\html /newblog/$1/$2.shtml [L]
Le drapeau est le [L]
à la fin de l'expression ci-dessus. Plusieurs drapeaux peuvent être utilisés, séparés par une virgule. La documentation liée décrit chacun, mais les voici quand même:
[~ # ~] l [~ # ~] = Dernier. Arrêtez de traiter RewriteRules une fois que celui-ci correspond. La commande compte!
[~ # ~] c [~ # ~] = Chaîne. Continuez à traiter la prochaine règle de réécriture. Si cette règle ne correspond pas, la règle suivante ne sera pas exécutée. Plus d'informations à ce sujet plus tard.
[~ # ~] e [~ # ~] = Définir la variable d'environnement. Apache a diverses variables environnementales qui peuvent affecter le comportement du serveur Web.
[~ # ~] f [~ # ~] = Interdit. Renvoie une erreur 403-Interdit si cette règle correspond.
[~ # ~] g [~ # ~] = Fin. Renvoie une erreur 410-Gone si cette règle correspond.
[~ # ~] h [~ # ~] = Gestionnaire. Force la demande à être traitée comme s'il s'agissait du type MIME spécifié.
[~ # ~] n [~ # ~] = Suivant. Force la règle à recommencer et à faire correspondre à nouveau. FAITES ATTENTION! Des boucles peuvent en résulter.
[~ # ~] nc [~ # ~] = Aucun cas. Permet à jpg
de faire correspondre à la fois jpg et JPG.
[~ # ~] ne [~ # ~] = Pas d'échappement. Empêche la réécriture de caractères spéciaux (.? # & Etc) dans leurs équivalents de code hexadécimal.
[~ # ~] ns [~ # ~] = Aucune sous-demande. Si vous utilisez des inclusions côté serveur, cela empêchera les correspondances avec les fichiers inclus.
[~ # ~] p [~ # ~] = Proxy. Force la règle à être gérée par mod_proxy. Fournissez en toute transparence du contenu provenant d'autres serveurs, car votre serveur Web le récupère et le re-sert. C'est un drapeau dangereux, car un drapeau mal écrit transformera votre serveur Web en un proxy ouvert et c'est mauvais.
[~ # ~] pt [~ # ~] = Pass Through. Tenez compte des instructions Alias dans la correspondance RewriteRule.
[~ # ~] qsa [~ # ~] = QSAppend. Lorsque la chaîne d'origine contient une requête ( http://example.com/thing?asp=foo ) ajoutez la chaîne de requête d'origine à la chaîne réécrite. Normalement, il serait rejeté. Important pour le contenu dynamique.
[~ # ~] r [~ # ~] = Rediriger. Fournissez une redirection HTTP vers l'URL spécifiée. Peut également fournir le code de redirection exact [R = 303]. Très similaire à RedirectMatch
, qui est plus rapide et doit être utilisé lorsque cela est possible.
[~ # ~] s [~ # ~] = Ignorer. Ignorez cette règle.
[~ # ~] t [~ # ~] = Tapez. Spécifiez le type MIME du contenu renvoyé. Très similaire à la directive AddType
.
Vous savez comment j'ai dit que RewriteCond
s'applique à une et une seule règle? Eh bien, vous pouvez contourner cela en enchaînant.
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html /blog/$1.sf.html [C]
RewriteRule ^/blog/(.*)\.jpg /blog/$1.sf.jpg
Étant donné que le premier RewriteRule a l'indicateur Chain, la deuxième règle de réécriture s'exécutera lorsque le premier le fera, c'est-à-dire lorsque la règle RewriteCond précédente est mise en correspondance. Pratique si les expressions régulières Apache vous font mal au cerveau. Cependant, la méthode tout-en-un sur laquelle je pointe dans la première section est plus rapide du point de vue de l'optimisation.
RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html /newblog/$1/$2.shtml
Cela peut être simplifié grâce aux drapeaux:
RewriteRule ^/blog/([0-9]{4})/([-0-9a-z]*)\.html /newblog/$1/$2.shtml [NC]
En outre, certains indicateurs s'appliquent également à RewriteCond. Notamment, NoCase.
RewriteCond %{HTTP_REFERER} ^https?://serverfault\.com(/|$) [NC]
Correspondra à "ServerFault.com"
Quels sont le format et la structure fondamentaux des règles mod_rewrite?
Je m'en remets à l'excellente réponse de sysadmin1138 sur ces points.
De quelle forme/saveur d'expressions régulières ai-je besoin pour bien comprendre?
En plus de l'ordre de syntaxe, des expressions de correspondance de syntaxe/régulières et des indicateurs RewriteRule décrits par sysadmin1138, je pense qu'il convient de mentionner que mod_rewrite expose les variables d'environnement Apache en fonction des en-têtes de requête HTTP et de la configuration d'Apache.
Je recommanderais Didacticiel de débogage mod_rewrite d'AskApache pour une liste complète des variables qui peuvent être disponibles pour mod_rewrite.
Quelles sont les erreurs/pièges les plus courants lors de l'écriture de règles de réécriture?
La plupart des problèmes avec RewriteRule proviennent d'une mauvaise compréhension de la syntaxe PCRE/de l'échec à échapper correctement les caractères spéciaux ou d'un manque de compréhension du contenu des variables utilisées pour la correspondance.
Problèmes typiques et dépannage recommandé:
IfModule
conditionnel pour éviter ce scénario), vérifier la syntaxe des directives, commenter les directives jusqu'à ce que le problème soit identifiéQuelle est la bonne méthode pour tester et vérifier les règles mod_rewrite?
Tout d'abord, regardez le contenu de la ou des variables d'environnement que vous prévoyez de comparer - si vous avez PHP installé, c'est aussi simple que d'ajouter le bloc suivant à votre application:
<?php
var_dump($_SERVER);
?>
... puis écrivez vos règles (de préférence pour les tests sur un serveur de développement) et notez toute correspondance ou activité incohérente dans votre fichier Apache ErrorLog .
Pour des règles plus complexes, utilisez la directive RewriteLog
de mod_rewrite pour consigner l'activité dans un fichier et définissez RewriteLogLevel 3
Y a-t-il des implications en termes de référencement ou de performances des règles mod_rewrite que je devrais connaître?
AllowOverride all
affecte les performances du serveur car Apache doit vérifier .htaccess
fichiers et directives d'analyse à chaque demande - si possible, conservez toutes les directives dans la configuration VirtualHost de votre site ou activez .htaccess
remplace uniquement les répertoires qui en ont besoin.
Google Webmaster Guidelines déclare explicitement: "Ne trompez pas vos utilisateurs et ne présentez pas aux moteurs de recherche un contenu différent de celui que vous affichez aux utilisateurs, ce qui est communément appelé" masquage "." "- évitez de créer des directives mod_rewrite qui filtre pour les robots des moteurs de recherche.
Les robots des moteurs de recherche préfèrent un contenu 1: 1: le mappage d'URI (c'est la base pour classer les liens vers le contenu) - si vous utilisez mod_rewrite pour créer des redirections temporaires ou si vous servez le même contenu sous plusieurs URI, pensez à spécifier un RI canonique dans vos documents HTML.
Existe-t-il des situations courantes où mod_rewrite peut sembler être le bon outil pour le travail mais ne l'est pas?
Il s'agit d'un sujet énorme (et potentiellement litigieux) en soi - mieux (à mon humble avis) pour traiter les utilisations au cas par cas et laisser les demandeurs déterminer si les résolutions suggérées sont adaptées à leurs besoins.
Quels sont les exemples courants?
Astuces et conseils mod_rewrite d'AskApache couvre à peu près tous les cas d'utilisation courants qui apparaissent régulièrement, cependant, la solution "correcte" pour un utilisateur donné peut dépendre de la sophistication de la configuration de l'utilisateur et des directives existantes (qui C'est pourquoi c'est généralement une bonne idée de voir quelles directives autre un utilisateur a mises en place chaque fois qu'une question mod_rewrite se pose).
Comme de nombreux administrateurs/développeurs, je lutte depuis des années contre les subtilités des règles de réécriture et je ne suis pas satisfait de la documentation Apache existante. J'ai donc décidé, en tant que projet personnel, d'aller au fond de la façon dont mod_rewrite
fonctionne et interagit avec le reste du noyau Apache, donc au cours des derniers mois, j'ai instrumenté des cas de test avec strace
+ en forant dans le code source pour avoir une idée de tout cela.
.htaccess
) En traitement.Je dirais même que pour cette raison, vous devez presque diviser les communautés d'utilisateurs de réécriture en deux catégories et les traiter comme entièrement distinctes:
Ceux qui ont un accès root à la configuration Apache . Il s'agit généralement d'administrateur/développeur avec un serveur/VM dédié à l'application, et le message ici est assez simple: évitez d'utiliser .htaccess
fichiers si possible; faites tout dans votre configuration de serveur ou vhost. Le débogage est relativement facile car le développeur peut définir le débogage et a accès aux fichiers rewrite.log.
Utilisateurs d'un service hébergé partagé (SHS) .
.htaccess
/Traitement Perdir car aucune alternative n'est disponible..htaccess
le fichier est sélectionné et pourquoi. Il n'explique pas les subtilités du cycle PerDir et comment l'éviter.Il existe peut-être une troisième communauté: le personnel administratif et de soutien des prestataires de SHS qui se retrouvent avec un pied dans les deux camps et doivent en subir les conséquences.
J'ai écrit quelques articles de blog de style article (par exemple Plus d'informations sur l'utilisation des règles de réécriture dans les fichiers .htaccess ) qui couvrent de nombreux points détaillés que je ne répéterai pas ici pour garder cet article court. J'ai mon propre service partagé et je prends en charge certains projets dédiés & VM FLOSS. J'ai commencé par utiliser un LAMP standard VM comme véhicule de test pour mon SHS compte, mais à la fin j'ai trouvé mieux de faire un bon miroir VM (décrit ici ).
Cependant, en ce qui concerne la façon dont la communauté des administrateurs devrait prendre en charge .htaccess
utilisateurs, je pense que nous devons développer et offrir:
.htaccess
réécrire les règlesConseils sur la façon d'obtenir des diagnostics intégrés à partir de vos règles (par ex.
[E=VAR:EXPR]
exploitant le fait que EXPR
étendra les références arrières ($ N ou% N) pour les rendre disponibles en tant que diagnostics pour le script cible.Si vous ordonnez par voie topique vos règles de réécriture en utilisant les drapeaux [OR], [C], [SKIP] et [L] pour que le schéma de réécriture entier fonctionne sans la nécessité d'exploiter la redirection interne, alors vous peut ajouter ce qui suit en tant que règle 1 pour éviter tout problème de boucle:
RewriteCond %{ENV:REDIRECT_STATUS} !=""
RewriteRule . - [L]
Utilisation de la carte de réécriture
Il y a beaucoup de choses que vous pouvez faire avec les réécritures. Les Rewritemaps sont déclarés à l'aide de la directive Rewritemap et peuvent ensuite être utilisés à la fois dans les évaluations RewritCond et dans les subsitutions RewriteRule.
La syntaxe générale de RewriteMap est:
RewriteMap MapName MapType:MapSource
Par exemple:
RewriteMap examplemap txt:/path/to/file/map.txt
Vous pouvez ensuite utiliser le nom de carte pour des constructions comme celle-ci:
${examplemap:key}
La carte contient des paires clé/valeur. Si la clé est trouvée, la valeur est remplacée. Les cartes simples ne sont que des fichiers texte, mais vous pouvez utiliser des cartes de hachage et même des requêtes SQL. Plus de détails sont dans les documents:
http://httpd.Apache.org/docs/2.2/mod/mod_rewrite.html#rewritemap
Chaînes sans échappatoire.
Il existe quatre cartes internes que vous pouvez utiliser pour effectuer certaines manipulations. Des cordes particulièrement échappantes peuvent être utiles.
Par exemple: je veux tester la chaîne "café" dans la chaîne de requête. Cependant, le navigateur échappera à cela avant de l'envoyer à mon serveur, donc je devrai déterminer quelle est la version d'échappement de l'URL pour chaque chaîne que je souhaite faire correspondre, ou je peux simplement la déséchapper ...
RewriteMap unescape int:unescape
RewriteCond %{QUERY_STRING} (location|place)=(.*)
RewriteCond ${unescape:%2} café
RewriteRule ^/find/$ /find/1234? [L,R]
Notez comment j'utilise un RewriteCond pour capturer simplement l'argument avant le paramètre de chaîne de requête, puis utiliser la carte dans le deuxième rewriteCond pour le déséchapper. Cela est ensuite comparé. Notez également comment j'ai besoin de nous% 2 comme clé dans le plan de réécriture, car% 1 contiendra "emplacement" ou "lieu". Lorsque vous utilisez des parenthèses pour regrouper des motifs, ils seront également capturés, que vous envisagiez d'utiliser le résultat de la capture ou non ...
Quelles sont les erreurs/pièges les plus courants lors de l'écriture de règles de réécriture?
Un écueil vraiment facile est lorsque vous réécrivez des URL qui modifient le chemin apparent, par exemple de /base/1234/index.html
à /base/script.php?id=1234
. Aucune image ou CSS avec des chemins relatifs vers l'emplacement du script ne sera trouvée par le client. Un certain nombre d'options pour résoudre ce problème se trouvent sur cette FAQ .