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

Comment mod_rewrite fonctionne réellement. Allocation pour continuer

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

Cet article est né de l'idée d'une formation avancée de notre personnel de support technique travaillant avec mod_rewrite. La pratique a montré qu'après avoir étudié le disponible dans un grand nombre de manuels en russe, le support est bien donné à la solution des tâches modèles, mais ici la compilation indépendante des règles se fait par essais et erreurs. Le problème est que pour une bonne compréhension du travail de mod_rewrite il est nécessaire d'étudier la documentation originale en anglais, après cela - soit des explications supplémentaires ou des heures d'expériences avec RewriteLog.

L'article décrit le mécanisme de l'opération mod_rewrite. Comprendre les principes de son travail vous permet de comprendre clairement le fonctionnement de chaque directive et d'imaginer clairement ce qui se passe à un moment donné dans mod_rewrite lors du traitement des directives.

Je suppose que le lecteur est déjà familier avec ce que mod_rewrite est, et je ne vais pas décrire ses fondamentaux, qui sont faciles à trouver sur Internet. Il convient également de noter que l'article met en évidence le travail de mod_rewrite lors de l'utilisation de ses directives dans le fichier .htaccess. Différences dans le contexte de travail sont indiqués à la fin de l'article.

Ainsi, vous avez étudié mod_rewrite, composé plusieurs RewriteRules et réussi à rencontrer des redirections sans fin, dans le cas où la règle n'attraperait pas votre requête, et avec le travail imprévisible du groupe de règles, lorsque la règle suivante modifie de manière inattendue la requête soigneusement préparée par les règles précédentes.

Avec quoi RewriteRule fonctionne-t-il?

Le premier RewriteRule est passé le chemin de l'endroit où .htaccess est situé dans le fichier demandé. Cette ligne ne commence jamais par "/". RewriteRule ultérieures transfère le résultat des transformations précédentes.

Pour bien comprendre comment fonctionne RewriteRule, vous devez d'abord déterminer avec quoi il fonctionne . Considérez comment Apache obtient une chaîne initialement transmise à RewriteRule pour traitement dans .htaccess.

Lorsque vous commencez à travailler avec mod_rewrite, il est logique de supposer que cela fonctionne avec les liens. Cependant, dans le cas de l'utilisation de mod_rewrite dans .htaccess, ce n'est pas le cas. En fait, RewriteRule ne transmet pas le lien, mais le chemin d'accès au fichier demandé .

En raison de l'architecture interne d'Apache au moment où .htaccess entre en action, mod_rewrite ne peut gérer que le chemin vers le fichier qui doit être traité. Cela est dû au fait qu'avant le transfert vers mod_rewrite, la requête pouvait déjà être modifiée par d'autres modules (par exemple, mod_alias), et le chemin final vers le fichier sur le site peut déjà ne pas coïncider avec le lien d'origine. Si mod_rewrite travaillait avec le lien source, cela violerait l'action des modules qui ont modifié la requête avant lui.

Par conséquent, dans mod_rewrite, un chemin absolu est transmis au fichier qui doit être traité. Mod_rewrite connaît également le chemin vers .htaccess, dans lequel les règles de RewriteRule sont placées. Pour faire du chemin vers le fichier quelque chose de similaire au lien avec lequel le développeur du site a l'intention de travailler, mod_rewrite coupe le chemin absolu du fichier .htaccess.

Donc, c'est ce chemin, à partir duquel le chemin vers .htaccess est coupé, est passé à la première RewriteRule. Par exemple:

  • Demande: http://example.com/templates/silver/images/logo.gif
  • DocumentRoot: /var/www/example.com
  • Chemin d'accès au fichier: /var/www/example.com/templates/silver/images/logo.gif
  • .htaccess est situé à: /var/www/example.com/templates/.htaccess
  • Dans la première RewriteRule sera transféré: silver / images / logo.gif
  • Note: "templates /" a également été coupé.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Le chemin vers .htaccess est coupé avec le slash. De ceci il y a un effet: la chaîne qui est initialement passée au traitement RewriteRule ne commence jamais par "/".

Il est important de se souvenir de ce que fait RewriteRule . Il ne traite pas le nom du site, les arguments qui sont passés au script, et le lien ne gère pas tout, si .htaccess n'est pas situé à la racine du site. Tout cela est fait par RewriteCond, qui sera brièvement discuté un peu 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 recommande de ne travailler qu'avec .htaccess à la racine du site. Cela simplifiera quelque peu le contrôle de son fonctionnement.

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

Comment fonctionne RewriteRule

RewriteRule convertit simplement une chaîne en fonction des expressions régulières, et 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, l'entrée de RewriteRule provient du chemin de .htaccess vers le fichier demandé. Il est plus pratique maintenant de faire abstraction des chemins et des références et de considérer ce que RewriteRule fonctionne avec une ligne normale. Cette ligne est passée de RewriteRule à RewriteRule, en modifiant si l'une des RewriteRules a fonctionné.

En général, si vous excluez les difficultés avec l'utilisation de drapeaux (dont nous parlerons plus loin) et la difficulté de créer des expressions régulières (que nous n'aborderons pas dans cet article), RewriteRule fonctionne TRÈS simple.

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

C'est, en général, c'est tout. Afin d'illustrer 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 voir, RewriteRule ne se soucie pas de quoi travailler - il convertit juste la chaîne en accord avec les arguments qu'elle spécifie. Si vous voulez, vous pouvez stocker des tableaux de données dans la ligne, si vous voulez, 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 prendre note: bien que RewriteRule fonctionne avec une chaîne propre, il est toujours orienté pour fonctionner avec des liens. Par conséquent, il répondra d'une manière spéciale aux lignes commençant par "https: //" ou analogues (rappelez-vous que nous voulions faire une redirection externe) et le "?" (comptera les caractères suivants comme arguments qui doivent être substitués à la requête). Mais maintenant cela ne nous intéresse pas - il est important de comprendre qu'il n'y a pas de magie dans RewriteRule - il suffit de prendre une ligne et de la changer comme vous l'avez dit. Les redirections externes et les arguments que nous examinerons plus loin dans l'article, là aussi, il y a quelque chose à discuter.

Une fois toutes les transformations terminées et la dernière RewriteRule exécutée, RewriteBase prend effet.

À quoi sert RewriteBase?

Si la requête résultante après la conversion est relative et différente de l'original, RewriteBase s'y ajoute à gauche. Vous devez spécifier RewriteBase dans .htaccess. Sa valeur est le chemin de la racine du site vers .htaccess. RewriteBase s'exécute uniquement après toutes RewriteRules, pas entre eux.

Nous avons déjà mentionné plus haut que mod_rewrite, travaillant dans .htaccess, obtient le chemin absolu vers le fichier demandé. Pour le passer à RewriteRule, mod_rewrite coupe le chemin vers .htaccess. Ensuite, les règles de RewriteRule, une par une, modifient constamment la requête. Et après la modification de la requête, Apache doit restaurer le chemin absolu vers le fichier, qu'il doit éventuellement traiter. RewriteBase est en fait un hack qui aide à restaurer le chemin source d'un fichier.

RewriteBase est exécuté après toutes les transformations. Cela signifie qu'il ne changera pas la requête entre RewriteRule, et ne prendra effet que lorsque toutes les RewriteRules seront exécutées.

Après toutes les conversions, RewriteBase regarde, le relatif s'est avéré être le chemin final ou absolu. Dans le contexte d'Apache, nous entendons un chemin relatif ou absolu, à partir 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 - le plus absolu de tous.

Si le chemin est absolu, RewriteBase ne fait rien. Et si relatif - 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 connaissance avec mod_rewrite, l'habitude suivante se développe: 1) ajouter "RewriteBase /" à chaque .htaccess, 2) toutes les redirections commencent par une barre oblique: "RewriteRule news.php /index.php?act=news". Cela permet de se débarrasser des artefacts de RewriteBase, mais c'est faux de le faire. Maintenant que nous savons ce que fait RewriteBase, nous pouvons formuler les règles correctes suivantes:

  1. RewriteBase doit correspondre au chemin de la racine du site vers .htaccess.
  2. Vous devez démarrer la redirection à partir de "/" uniquement si vous devez spécifier un chemin absolu entre la racine du site et le fichier.
Как на самом деле работает mod_rewrite. Пособие для продолжающих

Que se passe-t-il si je ne spécifie pas RewriteBase? Par défaut, Apache le rend égal au chemin absolu sur le système de fichiers avant .htaccess (par exemple, /var/www/example.com/templates/). L'inexactitude d'une telle hypothèse Apache se manifeste sur 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

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

Ainsi, la requête a traversé toutes les RewriteRules, après quoi RewriteBase a été ajouté, si nécessaire. Est-ce qu'Apache devrait maintenant donner le fichier sur lequel le chemin résultant apparaît? Non, ça ne l'est pas. Maintenant, la requête résultante sera traitée à nouveau.

Comment fonctionne mod_rewrite. Drapeau [L]

mod_rewrite démarre le traitement de la requête encore et encore, jusqu'à ce qu'il cesse de changer. Et le drapeau [L] ne peut pas l'arrêter.

Lors de la composition de configurations plus ou moins complexes de mod_rewrite, il est important de comprendre que la modification de la requête ne se termine pas avec la dernière RewriteRule . Après que la dernière règle de RewriteRule a fonctionné et que RewriteBase a été ajouté, mod_rewrite ressemble, la requête a changé ou non. Si la demande a changé, son traitement recommence depuis le début de .htaccess.

Apache fait cela car il pourrait être redirigé vers un autre répertoire lors de la modification de la requête. Il peut avoir son propre .htaccess, qui n'a pas participé au traitement de la requête précédente. Dans le même nouveau .htaccess, il peut y avoir des règles qui affectent le traitement de la requête - à la fois les règles mod_rewrite et les règles des autres modules. Pour gérer correctement cette situation, Apache doit réexécuter tout le cycle de traitement.

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

Pas exactement. L'indicateur [L] arrête l'itération en cours du traitement de la requête. Cependant, si la requête a été modifiée par les RewriteRules qui ont quand même réussi à fonctionner, Apache recommencera le cycle de traitement de la requête à partir de la première RewriteRule.

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

RewriteBase /

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

L'exemple ci-dessus conduira à une boucle de redirection infinie et à la "Erreur interne du serveur" à la fin. Dans cet exemple, une boucle infinie est évidente, mais dans des configurations plus complexes, il peut être nécessaire de creuser dans les règles pour déterminer quelles requêtes sont en boucle l'une par rapport à l'autre.

Pour éviter de telles situations, il est recommandé d'utiliser le drapeau [L] seulement si 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, un traitement ultérieur de la requête n'est pas souhaitable (voir ci-dessous à propos de l'indicateur [R]), et il vaudra mieux l'arrêter
  2. Dans .htaccess, il y a une boucle qui ne peut pas être éliminée et la requête de mod_rewrite doit être terminée. Dans ce cas, une construction spéciale est utilisée - voir les conseils sur ce sujet à la fin de l'article.

Mais l'exemple ci-dessous ne sera pas bloqué. Essayez de déterminer pourquoi et quel fichier sera finalement donné à Apache.

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

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

# Конец .htaccess

Comment fonctionne mod_rewrite. Le drapeau [R]

L'indicateur [R] n'arrête pas le traitement de la demande, renvoyant immédiatement la 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 le RewriteRule suivant. Il est recommandé de toujours utiliser le drapeau [L].

L'indicateur [R] indique à Apache qu'il ne s'agit pas d'une redirection interne mais externe, qui doit être exécutée. Quelle est la différence entre une redirection externe et une redirection interne? La redirection interne change simplement le chemin vers le fichier qui sera donné à l'utilisateur, tandis que l'utilisateur pense qu'il obtient le fichier qu'il a initialement demandé. Dans le cas d'une redirection externe, Apache renvoie l'état de la réponse 301 ou 302 au lieu du contenu du fichier et signale le lien par 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 un exemple fantastique de la section "Comment fonctionne RewriteRule". Dans celui-ci, nous avons d'abord spécifié l'indicateur [R], indiquant le besoin d'une redirection externe, puis nous avons continué à modifier le lien avec le RewriteRule suivant.

C'est ainsi qu'Apache fonctionne lorsqu'il spécifie une redirection externe. Il se "marque" simplement qu'après toutes les règles sont remplies, il est nécessaire de retourner le statut 302 (par défaut), mais en même temps il continue à exécuter toutes les règles de réécriture plus bas dans la liste. Nous pouvons continuer à modifier la requête comme nous avons besoin, la seule chose qui ne fonctionne pas est de rendre la redirection interne.

Néanmoins, il est peu probable que vous souhaitiez le modifier de quelque façon que ce soit après avoir abandonné la redirection externe. Par conséquent , lorsque vous utilisez le drapeau [R] , il est recommandé de le spécifier avec [L] :

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

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

Au lieu d'utiliser le drapeau [R], vous pouvez simplement spécifier une référence externe. Dans ce cas, Apache devinera qu'il est nécessaire de faire une redirection externe. Ici, comme pour 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 spécifier de référence complète (en d'autres termes, utiliser une redirection externe relative). Cela rendra la règle indépendante du nom du site.
  • Si une redirection externe mène à un autre site, sinon, comme indiquant un lien externe complet, cela ne fonctionnera pas.

Comment fonctionne mod_rewrite. Spécification des paramètres de requête et du drapeau [QSA]

La modification des paramètres de requête dans RewriteRule ne modifie pas la chaîne avec laquelle le prochain RewriteRule est exécuté. Cependant, lorsque vous modifiez les paramètres, la variable% {QUERY_STRING} est modifiée, avec laquelle RewriteCond peut fonctionner.

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

Avec RewriteRule, vous pouvez modifier non seulement le chemin d'accès au fichier à traiter, mais également les paramètres de la requête GET qui lui sera transmise. Ceci est souvent utilisé pour transférer le traitement NC à un gestionnaire 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 second argument, elle comprend qu'il y a un changement dans les paramètres de la requête. En conséquence, les événements suivants se produisent:

  1. RewriteRule remplace la chaîne avec laquelle il fonctionne, par une partie du second argument avant le point d'interrogation . Notez que les nouveaux paramètres de requête ne tombent pas dans la chaîne avec laquelle les règles RewriteRule suivantes fonctionneront.
  2. Une partie du second argument après le point d'interrogation tombe dans la variable% {QUERY_STRING}. Si le drapeau [QSA] a été spécifié, les paramètres de requête seront ajoutés au début de% {QUERY_STRING}. Si le drapeau n'a pas été spécifié,% {QUERY_STRING} sera complètement remplacé par les paramètres de requête de RewriteRule.

Un autre couple d'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. Réglons 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é seulement le drapeau [QSA], et la règle a commencé à fonctionner correctement.

Vous pouvez comprendre que la modification des paramètres de requête modifie% {QUERY_STRING} , ce qui peut être utilisé plus tard dans RewriteCond. Cela devrait être pris en compte lors de l'élaboration des règles suivantes qui vérifient les arguments.

- Bien sûr, ça change, car la requête va à nouveau traiter Apache'm!

Non,% {QUERY_STRING} change immédiatement . Je ne vais pas donner la preuve - sur les paramètres et donc déjà écrit plus qu'intéressant à lire :)

Que puis-je faire pour vérifier dans RewriteCond exactement les paramètres de requête que l'utilisateur a transférés, plutôt que modifiés par RewriteRules? Voir les conseils à la fin de l'article.

RewriteCond et Performance

Tout d'abord, la requête est comparée à RewriteRule, et ce n'est que la condition supplémentaire RewriteCond.

Un couple de mots devrait être dit sur l'ordre dans lequel mod_rewrite exécute les directives. Comme .htaccess est d'abord suivi par RewriteCond, puis par RewriteRule, il semble que mod_rewrite vérifie d'abord toutes les conditions, puis commence à exécuter RewriteRule.

En fait, tout se passe dans l'autre sens. Le premier mod_rewrite vérifie si la valeur courante de la requête correspond à l'expression régulière RewriteRule, et seulement alors il vérifie toutes les conditions listées dans RewriteCond.

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

Variables et drapeaux de RewriteCond, autres drapeaux de RewriteRule et autres

Lisez la documentation.

Nous nous sommes familiarisés avec les principes du travail de RewriteRule, RewriteBase, flags [L], [R] et [QSA], et nous avons également démonté le mécanisme de traitement des requêtes à l'intérieur de mod_rewrite. Du reste non affecté est resté: d'autres drapeaux de RewriteRule, les directives RewriteCond et RewriteMap.

Heureusement, ces directives et drapeaux ne contiennent pas d'énigmes 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 recommande d'étudier la liste des variables qui peuvent être vérifiées dans RewriteCond -% {QUERY_STING},% {THE_REQUEST},% {REMOTE_ADDR},% {HTTP_HOST},% {HTTP: en-tête}, etc.

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

Dans le contexte de mod_rewrite fonctionne exactement le contraire.

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 dans RewriteRule obtient le chemin complet de la requête, en commençant par la première barre, se terminant par le début des paramètres GET: "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 commencer par /, sinon il y aura une "mauvaise requête".
  • RewriteBase n'a pas de sens.
  • Le passage des règles ne se produit qu'une seule fois. L'indicateur [L] arrête réellement de traiter toutes les règles décrites dans , sans aucune itération ultérieure.

Conseils et solutions

Voici des conseils recueillis qui pourraient être apportés au cours de l'article, mais qui ont été exclus du texte principal pour la brièveté de la présentation du matériel.

Créer des expressions régulières

Essayez de créer des expressions régulières afin qu'elles définissent précisément les requêtes que vous souhaitez modifier, afin que les règles RewriteRule ne fonctionnent pas accidentellement pour 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 lire des expressions régulières sur notre site Web:

Modification des redirections externes

Malgré le fait que mod_rewrite vous permette de modifier même les redirections externes en utilisant RewriteRule, jusqu'au protocole, je recommande fortement de ne pas le faire. Dans l'article, un exemple avec changement de redirections externes est utilisé uniquement pour se débarrasser de concepts tels que "liens" et "fichiers" et montrer plus clairement que RewriteRule fonctionne avec une chaîne simple.

Je ne pense pas que les développeurs de mod_rewrite aient supposé que quelqu'un le ferait, donc toutes sortes d'artefacts sont possibles. Ne fais pas ça, s'il te plait.

Comment arrêter une boucle infinie

Parfois, la logique de redirection sur le site est telle que, sans actions spéciales, mod_rewrite les traite comme un cycle de redirection infini. Prenons l'exemple suivant.

Le site était /info.html. Un spécialiste du référencement a décidé que les moteurs de recherche indexerait mieux cette page si elle s'appelait /information.html et a demandé une redirection externe avec info.html sur information.html. Cependant, pour une raison quelconque, le développeur du site ne peut pas simplement renommer info.html dans information.html et faire une redirection - il a besoin que les données soient 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 rencontre un cycle infini. Chaque requête /information.html reçoit à nouveau une redirection externe sur /information.html.

Résolvez ce problème d'au moins deux façons. Sur Habré, l'un d'entre eux a déjà été décrit - il est nécessaire de définir la variable d'environnement et, en fonction de sa valeur, d'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 seconde façon est de vérifier dans THE_REQUEST ce qui a été demandé 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

Analyser la demande de l'utilisateur original - lutter contre la divulgation des liens Apache

Lors du traitement de la requête, Apache développe les caractères codés (codés en URL) de la requête d'origine. Dans certains cas, cela peut être indésirable - le développeur veut vérifier exactement la requête 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

Documentation officielle d'Apache

Détails techniques