This page has been robot translated, sorry for typos if any. Original content here.

Comment fonctionne réellement mod_rewrite. Un guide pour continuer

Как на самом деле работает mod_rewrite. Пособие для продолжающих

Cet article découle de l'idée d'une formation avancée pour notre personnel de support technique travaillant avec mod_rewrite. La pratique a montré qu’après avoir étudié un grand nombre de manuels en russe, la solution des problèmes types est bien fournie, mais l’élaboration de règles indépendantes se fait par essais et par de nombreuses erreurs. Le problème est que, pour bien comprendre le travail de mod_rewrite, il est nécessaire d’étudier la documentation originale en anglais, après quoi - soit une clarification supplémentaire, soit des heures d’expériences avec RewriteLog.

L'article décrit le mécanisme de mod_rewrite. Comprendre les principes de son travail vous permet de bien comprendre l'effet de chaque directive et de bien comprendre ce qui se passe à un moment ou à un autre dans mod_rewrite lors du traitement des directives.

Je suppose que le lecteur est déjà familiarisé avec ce que mod_rewrite est, et je ne décrirai pas ses bases, faciles à trouver sur Internet. Il convient également de noter que l’article met en évidence le travail de mod_rewrite lorsqu’il utilise ses directives dans le fichier .htaccess. Différences en travaillant dans le contexte énoncées à la fin de l'article.

Ainsi, vous avez étudié mod_rewrite, compilé plusieurs RewriteRule et réussi à rencontrer des redirections sans fin, le cas où la règle pour une raison quelconque ne capture pas votre demande, ainsi que le travail imprévisible du groupe de règles lorsque la règle suivante modifie de manière inattendue la demande préparée par les règles précédentes.

Qu'est-ce que RewriteRule fonctionne avec

Le premier RewriteRule reçoit le chemin d'accès de l'emplacement où se trouve le fichier .htaccess au fichier demandé. Cette ligne ne commence jamais par "/". Le résultat des conversions précédentes est transmis à la RewriteRule suivante.

Afin de bien comprendre le fonctionnement d'un RewriteRule, vous devez d'abord déterminer avec quoi il fonctionne . Considérez comment Apache obtient une chaîne qui est initialement transmise à un RewriteRule dans .htaccess.

Lorsque vous commencez à travailler avec mod_rewrite, il est logique de supposer que cela fonctionne avec des liens. Cependant, ce n'est pas le cas avec mod_rewrite dans .htaccess. En fait, le chemin d'accès au fichier demandé n'est pas transféré à RewriteRule.

En raison de l'architecture interne d'Apache au moment de l'entrée en vigueur de .htaccess, mod_rewrite ne peut fonctionner que sur le chemin d'accès au fichier à traiter. Cela est dû au fait qu'avant le transfert à la demande mod_rewrite, d'autres modules pouvaient déjà être modifiés (par exemple, mod_alias) et que le chemin d'accès final au fichier sur le site pouvait ne pas coïncider avec le lien d'origine. Si mod_rewrite fonctionnait avec le lien d'origine, cela violerait l'action des modules qui ont modifié la requête avant celle-ci.

Par conséquent, le chemin absolu du fichier à traiter est transféré vers mod_rewrite. De plus, mod_rewrite connaît le chemin d'accès à .htaccess, qui contient les règles RewriteRule. Pour créer quelque chose qui ressemble à un lien entre le chemin d'accès au fichier que le développeur du site envisage de travailler, mod_rewrite coupe une partie du chemin absolu vers le fichier .htaccess.

Ainsi, c’est ce chemin, à partir duquel le chemin de .htaccess est coupé, est transmis à la première RewriteRule. Par exemple:

  • Requête: http://example.com/templates/silver/images/logo.gif
  • DocumentRoot: /var/www/example.com
  • Chemin du fichier: /var/www/example.com/templates/silver/images/logo.gif
  • .htaccess est à: /var/www/example.com/templates/.htaccess
  • Le premier RewriteRule sera transféré: silver / images / logo.gif
  • Veuillez noter que "templates /" est également coupé.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Le chemin d'accès à .htaccess est coupé avec une barre oblique. Il en résulte une conséquence: la ligne initialement transmise au traitement de RewriteRule ne commence jamais par "/".

Il est important de se rappeler que RewriteRule ne le fait pas . Il ne traite pas le nom du site, les arguments qui sont transmis au script et le lien ne traite pas tout, si .htaccess n'est pas situé à la racine du site. RewriteCond est en train de faire tout cela, ce qui sera brièvement abordé plus tard. Donc:

# работать не будет - правило начинается со /
RewriteRule ^/index.php$ /my-index.php

# работать не будет - название сайта не анализируется RewriteRule
RewriteRule ^example.com/.* http://www.example.com

# работать не будет - аргументы ссылки не попадают в RewriteRule
RewriteRule index.php\?newspage=([0-9]+) news.php?page=$1
# работать не будет - правило начинается со /
RewriteRule ^/index.php$ /my-index.php

# работать не будет - название сайта не анализируется RewriteRule
RewriteRule ^example.com/.* http://www.example.com

# работать не будет - аргументы ссылки не попадают в RewriteRule
RewriteRule index.php\?newspage=([0-9]+) news.php?page=$1
# Будет работать только если .htaccess находится там же, где находится папка templates,
# например, в корне сайта. То есть, если .htaccess находится в templates/.htaccess , правило
# работать НЕ БУДЕТ, потому что mod_rewrite отрежет путь до .htaccess и на вход RewriteRule
# строка попадет уже без "templates/"
RewriteRule ^templates/common/yandex-money.gif$ templates/shared/yad.gif
# Будет работать только если .htaccess находится там же, где находится папка templates,
# например, в корне сайта. То есть, если .htaccess находится в templates/.htaccess , правило
# работать НЕ БУДЕТ, потому что mod_rewrite отрежет путь до .htaccess и на вход RewriteRule
# строка попадет уже без "templates/"
RewriteRule ^templates/common/yandex-money.gif$ templates/shared/yad.gif

Au début de l'utilisation de mod_rewrite, je vous recommande de ne l'utiliser qu'avec .htaccess à la racine du site. Cela simplifiera quelque peu le suivi de ses travaux.

Avec quoi RewriteRule fonctionne, nous l'avons compris. Voyons maintenant comment cela fonctionne .

Comment fonctionne RewriteRule

RewriteRule convertit simplement la chaîne en expressions régulières, c'est tout. RewriteRule fonctionne avec une chaîne, pas avec un lien ou un chemin d'accès au fichier.

Comme nous l'avons vu plus haut, le chemin de .htaccess au fichier demandé entre dans l'entrée de RewriteRule. Le moyen le plus pratique consiste maintenant à faire abstraction des chemins et des références et à traiter ce que fonctionne RewriteRule avec une ligne régulière. Cette ligne est passée de RewriteRule à RewriteRule, en modifiant si l’un des paramètres de RewriteRule a fonctionné.

En général, si nous excluons la difficulté d'utiliser des drapeaux (dont nous discuterons certains ci-dessous) et la difficulté de composer des expressions régulières (que nous aborderons à peine dans cet article), RewriteRule fonctionne très simplement.

  1. Ils ont pris une ficelle.
  2. Comparé à une expression régulière dans le premier argument.
  3. S'il y a correspondance, remplacez la ligne entière par la valeur du deuxième argument.
  4. Transféré la chaîne à la prochaine RewriteRule.

Ici, en général et tout. Pour illustrer le fait que RewriteRule fonctionne avec une chaîne, considérons l'exemple fantastique suivant:

# Запрос: http://mysite.com/info.html
# В первый RewriteRule попадет "info.html"

# Преобразовываем запрос в произвольную строку.
RewriteRule ^info.html$ "I saw a turtle in the hole. And it was dancing rock-n-roll. And it was smiling. All in all, it was a very funny doll."

# "info.html" -> "I saw a turtle..."

# Заменяем эту строку на внешнюю ссылку.
RewriteRule turtle https://example.com/information/index.html

# "I saw a turtle..." -> "https://example.com/information/index.html"

# Заменяем имя сайта!
RewriteRule ^(.*)example.com(.*)$ $1example.org$2

# "https://example.com/information/index.html" -> "https://example.org/information/index.html"

# Заменяем протокол!
RewriteRule ^https :( .*)$ ftp:$1

# "https://example.org/information/index.html" -> "ftp://example.org/information/index.html"

# Заменяем конечную ссылку.
RewriteRule ^(.*)/index.html$ $1/main.php

# "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"

Comme vous pouvez le constater, RewriteRule ne tient pas compte de ce qu'il faut utiliser, il convertit simplement la chaîne en fonction des arguments qui lui sont donnés. Si vous le souhaitez, vous pouvez stocker tous les tableaux de données de la chaîne. Si vous le souhaitez, de la persévérance et une bonne connaissance des expressions régulières, vous pouvez au moins écrire tic-tac-toe sur RewriteRule.

Ici, vous devez noter: même si RewriteRule fonctionne avec une ligne épurée, il est toujours orienté pour utiliser des liens. Par conséquent, il réagira de manière spéciale aux lignes commençant par «https: //» ou analogiques (rappelez-vous que nous voulions faire une redirection externe) et au «? (considérez les caractères suivants comme des arguments qui devront être substitués à la requête). Mais à présent, cela ne nous intéresse plus - il est important de comprendre que la règle Rewrite n’est pas magique - elle prend juste la chaîne et la change comme vous l’avez dit. Nous examinerons les redirections externes et les arguments plus loin dans l'article, il y a aussi des points à aborder.

Une fois toutes les conversions effectuées et la dernière exécution de RewriteRule exécutée, RewriteBase prend effet.

Qu'est-ce que RewriteBase?

Si la requête après transformation est relative et différente de celle d'origine, RewriteBase s'y ajoutera à gauche. Il est nécessaire de spécifier RewriteBase dans .htaccess. Sa signification est le chemin de la racine du site à .htaccess. RewriteBase est exécuté uniquement après tout RewriteRule, et non entre eux.

Nous avons déjà dit plus haut que dans mod_rewrite, travaillant dans .htaccess, obtenait le chemin absolu du fichier demandé. Pour le transmettre à la RewriteRule, mod_rewrite coupe le chemin d'accès à .htaccess. Ensuite, les règles RewriteRule changent la demande une par une. Et après la modification de la demande, Apache devrait restaurer le chemin absolu du fichier, qu'il devrait éventuellement traiter. RewriteBase est en fait un hack qui aide à restaurer le chemin d’origine du fichier.

RewriteBase est exécuté après toutes les conversions. Cela signifie qu'il ne changera pas la demande entre RewriteRule et ne prendra effet que lorsque tous les RewriteRule auront fonctionné.

Après toutes les transformations, le RewriteBase a l'air, le relatif s'est avéré être un chemin ou un absolu. Dans le contexte d'Apache, nous entendons un chemin relatif ou absolu, en partant de la racine du site:

  • images / logo.gif - relatif.
  • /images/logo.gif - absolute (au début de la barre oblique).
  • http://example.com/images/logo.gif est le plus absolu de tous.

Si le chemin est absolu, RewriteBase ne fait rien. Et si relative - RewriteBase s’ajoute à gauche. Cela fonctionne pour les redirections internes et externes:

# .htaccess находится в /images/
# RewriteBase указан /images/
RewriteBase /images/

# Запрос http://example.com/images/logo.gif
# На вход RewriteRule попадает "logo.gif"
RewriteRule ^logo.gif$ logo-orange.gif
# После RewriteRule: "logo.gif" -> "logo-orange.gif"
# После RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif"

# Запрос http://example.com/images/header.png
# На вход RewriteRule попадает "header.png"
RewriteRule ^header.png$ /templates/rebranding/header.png
# После RewriteRule: "header.png" -> "/templates/rebranding/header.png"
# После RewriteBase: ничего не меняется, так итоговый результат преобразований начинается со "/'.

# Запрос http://example.com/images/director.tiff
# На вход RewriteRule попадает "director.tiff"
# Используем внешний относительный редирект
RewriteRule ^director.tiff$ staff/manager/director.tiff [R=301]
# После RewriteRule: "director.tiff" -> "staff/manager/director.tiff"
# + mod_rewrite запомнил, что будет внешний редирект
# После RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/director.tiff"
# mod_rewrite вспомнил про внешний редирект:
# "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff

Habituellement, après une certaine familiarité avec mod_rewrite, l'habitude suivante se développe: 1) ajoutez «RewriteBase /» à chaque fichier .htaccess, 2) démarrez toutes les redirections avec un slash: «RewriteRule news.php /index.php?act=news». Cela aide à vous débarrasser des artefacts de RewriteBase, mais cela est faux. Maintenant que nous savons ce que fait RewriteBase, nous pouvons formuler les règles correctes suivantes:

  1. RewriteBase doit correspondre au chemin d'accès de la racine du site à .htaccess.
  2. Le démarrage des redirections avec "/" est nécessaire uniquement lorsque vous devez spécifier le chemin absolu de la racine du site au fichier.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Que se passe-t-il si vous ne spécifiez pas RewriteBase? Par défaut, Apache le rend égal au chemin d'accès absolu sur le système de fichiers avant .htaccess (par exemple, /var/www/example.com/templates/). L'inexactitude de cette hypothèse Apache se manifeste par des redirections relatives externes:

# Запрос http://example.com/index.php
# DocumentRoot: /var/www/example.com/
# .htaccess находится в корне сайта, и в нем НЕ УКАЗАН RewriteBase.
# Поэтому по умолчанию RewriteBase равен абсолютному пути до .htaccess: /var/www/example.com/

# На входе RewriteRule - "index.php"
RewriteRule ^index.php main.php [R]
# На выходе: "index.php" -> "main.php"
# mod_rewrite запомнил, что нужен внешний редирект

# Закончились RewriteRule
# mod_rewrite все равно выполняет RewriteBase, так как у него есть значение по умолчанию.
# Получается: "main.php" -> "/var/www/example.com/main.php"

# Здесь mod_rewrite вспоминает, что был внешний редирект:
# "/var/www/example.com/main.php" -> http://example.com/var/www/example.com/main.php

# Получилось совсем не то, что имели в виду.

La requête a donc passé par tous les RewriteRules, après quoi un RewriteBase y a été ajouté, si nécessaire. Apache doit-il maintenant donner le fichier, qui indique le chemin résultant? Non La requête résultante sera à nouveau traitée.

Comment fonctionne mod_rewrite Drapeau [L]

mod_rewrite commence à traiter la demande encore et encore, jusqu'à ce qu'elle cesse de changer. Et le drapeau [L] ne peut pas l'arrêter.

Lors de la compilation de configurations mod_rewrite plus ou moins complexes, il est important de comprendre que la modification de la requête ne se termine pas à la dernière RewriteRule . Une fois que la dernière règle de RewriteRule a fonctionné et que RewriteBase a été ajouté, mod_rewrite examine si la demande a été modifiée ou non. Si la demande est modifiée, son traitement recommence à partir du début de .htaccess.

Apache fait cela car il pourrait être redirigé vers un autre répertoire pendant le processus de changement de demande. Il peut avoir son propre fichier .htaccess, qui n’a pas été impliqué dans le traitement précédent de la demande. Dans le même nouveau fichier .htaccess, il peut y avoir des règles qui affectent le traitement d'une requête, à la fois les règles mod_rewrite et les règles d'autres modules. Pour gérer correctement cette situation, Apache doit redémarrer l'ensemble du cycle de traitement.

- Attendez, mais il y a un drapeau [L] qui arrête le traitement de la requête par mod_rewrite'om!

Pas tout à fait. L'indicateur [L] arrête l'itération en cours du traitement de la demande. Cependant, si la demande a été modifiée par ceux de RewriteRule, qui ont toujours réussi à résoudre le problème, Apache redémarre le cycle de traitement de la demande à partir du premier RewriteRule.

# Запрос: http://example.com/a.html

RewriteBase /

RewriteRule ^a.html$ b.html [L]
RewriteRule ^b.html$ a.html [L]

L'exemple ci-dessus mènera à une boucle sans fin de redirections et à «l'erreur de serveur interne» en conséquence. Dans cet exemple, la boucle infinie est évidente, mais dans les configurations plus complexes, il peut être nécessaire de se plonger dans les règles pour déterminer les requêtes en boucle.

Pour éviter de telles situations, il est recommandé d'utiliser l'indicateur [L] uniquement lorsque cela est nécessaire. La nécessité peut être de deux types:

  1. Lorsqu'une redirection externe est utilisée - [L, R = 301] ou [L, R = 302]. Dans le cas d'une redirection externe, le traitement ultérieur de la demande n'est pas souhaitable (voir ci-dessous l'indicateur [R]), et il serait préférable d'arrêter
  2. Dans .htaccess, il y a une boucle qui ne peut pas être éliminée et le traitement de la requête par mod_rewrite doit être arrêté de force. Dans ce cas, une conception spéciale est utilisée - voir les astuces sur ce sujet à la fin de l'article.

Mais l'exemple ci-dessous ne fera pas de boucle. Essayez de déterminer pourquoi et par conséquent, le fichier sera donné à Apache.

# Запрос: http://example.com/a.html
# Начало .htaccess

RewriteBase /
RewriteRule ^a.html$ b.html
RewriteRule ^b.html$ a.html

# Конец .htaccess

Comment fonctionne mod_rewrite Drapeau [R]

L'indicateur [R] n'arrête pas le traitement de la demande, renvoyant immédiatement une redirection externe. Au lieu de cela, il se souvient de la nécessité d'une redirection externe et le traitement de la demande se poursuit avec la RewriteRule suivante. Il est recommandé de toujours utiliser le drapeau [L].

L'indicateur [R] indique à Apache d'exécuter une redirection externe et non interne. Quelle est la difference entre external redirect from internal? La redirection interne modifie simplement le chemin d'accès au fichier qui sera attribué à l'utilisateur, tandis que l'utilisateur pense recevoir le fichier qu'il a demandé à l'origine. Lorsqu'une redirection externe, Apache au lieu du contenu du fichier, renvoie à l'utilisateur l'état de la réponse 301 ou 302 et indique le lien sur lequel le navigateur doit contacter pour recevoir le fichier.

Il semblerait que lors du traitement de l'indicateur [R], Apache devrait immédiatement arrêter le traitement de RewriteRule et renvoyer la redirection externe à l'utilisateur. Cependant, rappelons-nous un exemple fantastique de la section «Comment fonctionne RewriteRule». Dans celui-ci, nous avons d’abord indiqué le drapeau [R], indiquant la nécessité d’une redirection externe, puis nous avons continué à modifier le lien avec la règle suivante RewriteRule.

C’est exactement comme cela que fonctionne Apache lors de la spécification d’une redirection externe. Il se "marque" simplement qu'après l'accomplissement de toutes les règles, il est nécessaire de renvoyer le statut 302 (par défaut), mais il continue l'exécution de tous les RewriteRule plus bas dans la liste. Nous pouvons continuer à modifier la demande selon les besoins, la seule chose qui ne fonctionne pas est de rendre la redirection interne.

Cependant, il est peu probable que vous souhaitiez le modifier après une redirection externe. Par conséquent, il est recommandé, lorsque vous utilisez l'indicateur [R], de l'indiquer avec [L] :

# BlackJack переехал на красивое имя
RewriteRule ^bj/(.*) blackjack/$1 [R=301,L]

# Можно использовать просто внешнюю ссылку
RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]

Au lieu d'utiliser l'indicateur [R], vous pouvez simplement spécifier un lien externe. Dans ce cas, Apache lui-même devinera qu'il est nécessaire de faire une redirection externe. Ici, comme dans le cas de l'indication explicite du drapeau [R], il est recommandé d'utiliser le drapeau [L].

  • Si une redirection externe mène au même site, il est préférable d'utiliser l'indicateur [R] sans référence complète (en d'autres termes, utilisez une redirection externe relative). Cela rendra la règle indépendante du site.
  • Si une redirection externe mène à un autre site, sinon, en spécifiant un lien externe complet, cela ne fonctionnera pas.

Comment fonctionne mod_rewrite Spécification des paramètres de requête et de l'indicateur [QSA]

La modification des paramètres de requête dans RewriteRule ne modifie pas la ligne avec laquelle le prochain RewriteRule fonctionne. Cependant, lorsque les paramètres sont modifiés, la variable% {QUERY_STRING}, avec laquelle RewriteCond peut fonctionner, est modifiée.

Terminologie utilisée: "paramètres" - paramètres de requête, "arguments" - arguments RewriteRule.

Avec l’aide de RewriteRule, vous pouvez modifier non seulement le chemin du fichier à traiter, mais également les paramètres de la demande GET qui lui sera envoyée. Ceci est souvent utilisé pour transférer le traitement CNC vers un processeur de script commun, par exemple:

RewriteBase /

# Запрос: http://example.com/news/2010/07/12/grand-opening.html
# На входе: "news/2010/07/12/grand-opening.html"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После RewriteRule: "news/2010/07/12/grand-opening.html" -> "index.php"
# %{QUERY_STRING}: "" -> "act=news&what=2010/07/12/grand-opening.html"

Au moment où la règle RewriteRule rencontre un point d'interrogation dans le deuxième argument, elle comprend qu'il y a une modification des paramètres dans la demande. Le résultat est le suivant:

  1. RewriteRule remplace la ligne avec laquelle il travaille avec une partie du deuxième argument avant le point d'interrogation . Veuillez noter que les nouveaux paramètres de requête ne font pas partie de la ligne avec laquelle les règles RewriteRule suivantes fonctionneront.
  2. La partie du deuxième argument après le point d'interrogation se trouve dans la variable% {QUERY_STRING}. Si l'indicateur [QSA] a été spécifié, les paramètres de la requête seront ajoutés au début de% {QUERY_STRING}. Si l'indicateur n'est pas spécifié,% {QUERY_STRING} est complètement remplacé par les paramètres de requête de RewriteRule.

Quelques autres exemples:

RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/"

Très probablement, la règle ci-dessus ne fonctionne pas correctement, car l'argument de page est perdu. Corrigez ceci:

RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1 [QSA]
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/&page=2"

Nous avons ajouté uniquement l'indicateur [QSA] et la règle a commencé à fonctionner correctement.

Il est important de comprendre que la modification des paramètres de requête modifie% {QUERY_STRING} , qui peut être utilisé ultérieurement dans RewriteCond. Ceci doit être pris en compte lors de la rédaction de règles ultérieures qui vérifient les arguments.

- Bien sûr, cela change, car la demande est traitée à Apache pour un traitement répété!

Non,% {QUERY_STRING} est modifié immédiatement . Je ne donnerai pas la preuve - sur les paramètres déjà écrits plus qu’intéressant à lire :)

Que faire pour vérifier dans RewriteCond exactement les paramètres de requête que l'utilisateur a transmis, et non modifiés par RewriteRules? Voir les conseils à la fin de l'article.

RewriteCond et performance

Tout d'abord, la correspondance de la demande avec RewriteRule est vérifiée, puis les conditions supplémentaires de RewriteCond sont vérifiées.

Il faut dire quelques mots sur l’ordre dans lequel mod_rewrite exécute les directives. Comme .htaccess commence par RewriteCond, puis RewriteRule, il semble que mod_rewrite vérifie d’abord toutes les conditions, puis exécute RewriteRule.

En fait, tout se passe dans le sens inverse. Tout d'abord, mod_rewrite vérifie si la valeur actuelle de la demande correspond à l'expression RewriteRule habituelle, puis vérifie toutes les conditions répertoriées dans RewriteCond.

Donc, si vous avez une expression régulière de deux pages dans RewriteRule et que vous avez pensé aux performances, vous avez décidé de limiter l'exécution de cette règle à un RewriteCond supplémentaire, vous savez, cela ne fonctionnera pas. Dans ce cas, il est préférable d'utiliser les indicateurs RewriteRule [C] ou [S] pour ignorer la règle plus complexe, si les vérifications simples ne fonctionnent pas.

Variables et indicateurs RewriteCond, autres indicateurs RewriteRule, etc.

Lisez la documentation.

Nous nous sommes familiarisés avec les principes de fonctionnement de RewriteRule, RewriteBase, des indicateurs [L], [R] et [QSA], et avons également trié le mécanisme de traitement de la requête dans mod_rewrite. De la gauche non affectée: autres indicateurs RewriteRule, directives RewriteCond et RewriteMap.

Heureusement, ces directives et drapeaux ne contiennent aucun mystère et fonctionnent exactement comme décrit dans la plupart des manuels. Pour leur compréhension, il suffit de lire la documentation officielle. Tout d’abord, je vous recommande d’étudier la liste des variables pouvant être vérifiées dans RewriteCond -% {QUERY_STING},% {THE_REQUEST},% {REMOTE_ADDR},% {HTTP_HOST},% {HTTP: header}, etc.).

La différence dans le fonctionnement de mod_rewrite dans le contexte de .htaccess et dans le contexte de VirtualHost

Dans le contexte mod_rewrite fonctionne exactement l'inverse.

Comme je l'ai dit au début de l'article, tout ce qui est décrit ci-dessus concerne l'utilisation de mod_rewrite dans le contexte de .htaccess. Si mod_rewrite est utilisé dans Cela fonctionnera différemment:

  • Dans Le chemin d'accès complet à la demande, de la première barre oblique au début des paramètres GET, est placé dans le RewriteRule: "http://example.com/some/news/category/post.html?comments_page=3" -> "/ news / category / post. html ". Cette ligne commence toujours par /.
  • Le deuxième argument de RewriteRule doit également être démarré avec /, sinon il y aura une «requête incorrecte».
  • RewriteBase n'a pas de sens.
  • Le passage des règles ne se produit qu'une fois. Le drapeau [L] termine vraiment le traitement de toutes les règles décrites dans , sans aucune itération ultérieure.

Trucs et solutions

Voici quelques conseils qui pourraient être cités au cours de l’article, mais qui ont été exclus du texte principal pour des raisons de brièveté.

Compilation d'expression régulière

Essayez de créer des expressions régulières de manière à définir avec la plus grande exactitude les requêtes que vous souhaitez modifier, afin que les règles RewriteRule ne fonctionnent pas par inadvertance avec une autre requête. Par exemple:

# Начинайте все регулярные выражения с "^" (признак начала строки)
# и заканчивайте "$" (признак конца строки):
RewriteRule ^news.php$ index.php
# Даже если в этом нет необходимости - для универсальности и лучшего понимания конфигурации:
RewriteRule ^news/(.*)$ index.php

# Если под маску должны попадать только цифры - укажите это явно.
# Если какие-то цифры постоянны, укажите их явно.
# Если в оставшейся части запроса не могут присутствовать слеши, ограничьте их присутствие.
# Не забывайте экранировать "." (точки).
# Следующее правило нацелено на запросы вида http://example.com/news/2009/07/28/b-effect.html
RewriteRule ^news/20[0-9]{2}/[0-9]{2}/[0-9]{2}/[^/]+\.html index.php

Cependant, vous pouvez également lire des expressions régulières sur notre site Web:

Changer les redirections externes

Malgré le fait que mod_rewrite vous permet de modifier même les redirections externes externes à l'aide de RewriteRule, jusqu'au protocole, je vous recommande vivement de ne pas le faire. L'article utilise l'exemple de la modification des redirections externes uniquement pour se débarrasser de concepts tels que "liens" et "fichiers" et pour montrer plus clairement que RewriteRule fonctionne avec une simple chaîne.

Je ne pense pas que les développeurs de mod_rewrite aient supposé que quelqu'un le ferait, donc tout artefact est possible. Ne fais pas ça, s'il te plaît.

Comment arrêter une boucle sans fin

Parfois, la logique des redirections sur un site est telle que, sans actions spéciales, mod_rewrite les perçoit comme une boucle infinie de redirections. Prenons l'exemple suivant.

Le site était /info.html. Le spécialiste du référencement a décidé que les moteurs de recherche indexeraient mieux cette page si elle s’appelle /information.html et qu’on lui demandait de faire une redirection externe de info.html à information.html. Cependant, le développeur du site, pour quelque raison que ce soit, ne peut pas simplement renommer info.html en information.html et effectuer une redirection - il faut que les données soient nécessairement fournies directement à partir du fichier info.html. Il écrit la règle suivante:

# сделать внешний редирект
RewriteRule ^info.html information.html [R,L]
# но по запросу /information.html все равно отдать info.html
RewriteRule ^information.html info.html

... et fait face à une boucle sans fin. Chaque requête /information.html reçoit à nouveau une redirection externe vers /information.html.

Ce problème peut être résolu d'au moins deux manières. Sur Habré, l’un d’eux était déjà décrit: vous devez définir une variable d’environnement et, en fonction de sa valeur, arrêter les redirections. Le code ressemblera à ceci:

RewriteCond %{ENV:REDIRECT_FINISH} !^$
RewriteRule ^ - [L]

RewriteRule ^info.html$ information.html [R,L]
RewriteRule ^information.html$ info.html [E=FINISH:1]

Notez que mod_rewrite ajoute 'REDIRECT_' au nom de la variable.

La deuxième façon est de vérifier dans THE_REQUEST ce qui a été demandé exactement par l'utilisateur:

# Внешний редирект происходит только если пользователь запросил info.html.
# Если же info.html - это результат внутреннего перенаправления, правило срабатывать не будет.
RewriteCond %{THE_REQUEST} "^(GET|POST|HEAD) /info.html HTTP/[0-9.]+$"
RewriteRule ^info.html$ information.html [R,L]

RewriteRule ^information.html$ info.html

Analyse de la demande de l'utilisateur initial - la lutte contre la divulgation des liens Apache

Lors du traitement d'une requête, Apache révèle les caractères codés (codés par URL) de la requête d'origine. Dans certains cas, cela peut être indésirable - le développeur souhaite vérifier la demande utilisateur initiale non modifiée. Vous pouvez le faire en vérifiant la variable% {THE_REQUEST} dans RewriteCond:

RewriteCond %{THE_REQUEST} ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$
RewriteRule ^(.*)$ index.php?tag=%1 [L]

Documentation recommandée

Apache documentation officielle

Détails techniques