Référence: mod rewrite, URL rewriting et "pretty links" expliquée

"Assez de liens" est souvent un thème demandé, mais il est rarement pleinement expliqué. mod_rewrite est une façon de faire des "jolis liens", mais c'est complexe et sa syntaxe est très courte, difficile à grok et la documentation suppose un certain niveau de compétence en HTTP. Quelqu'un peut m'expliquer en termes simples comment "liens jolie" travail et comment mod_rewrite peut être utilisé pour les créer?

autres noms communs, alias, termes pour urls propres: URLs RESTful, URLs conviviales, SEO-friendly URLs, les Coups de liquide, MVC url (sans doute un abus de langage)

128
demandé sur Taryn 2013-12-13 14:07:37

4 réponses

pour comprendre ce que mod_rewrite vous devez d'abord comprendre comment un serveur web fonctionne. Un serveur web répond à "demandes HTTP . Une requête HTTP à son niveau le plus basique ressemble à ceci:

GET /foo/bar.html HTTP/1.1

C'est la requête simple d'un navigateur à un serveur web demandant le URL /foo/bar.html de lui. Il est important de souligner qu'il ne demande pas un fichier , il demande juste quelques URL arbitraires. La requête peut aussi ressembler à ceci:

GET /foo/bar?baz=42 HTTP/1.1

c'est tout aussi valable une requête pour une URL, et cela n'a évidemment rien à voir avec les fichiers.

le serveur web est une application écoutant sur un port, acceptant les requêtes HTTP entrant sur ce port et renvoyant une réponse. Un serveur web est entièrement libre de répondre à toute demande en aucune façon qu'il lui fit et de la manière dont vous avez configuré répondre. Cette réponse n'est pas un fichier, c'est un réponse HTTP qui peut ou ne peut pas avoir quoi que ce soit à voir avec des fichiers physiques sur n'importe quel disque. Un serveur web N'a pas besoin D'être Apache, il y a beaucoup d'autres serveurs web qui ne sont que des programmes qui tournent constamment et qui sont attachés à un port qui répond aux requêtes HTTP. Tu peux en écrire une toi-même. Ce paragraphe a été conçu pour vous séparer de toute notion que les URLs directement des fichiers égaux, ce qui est vraiment important pour comprendre. :)

la configuration par défaut de la plupart des serveurs web est de rechercher un fichier qui correspond à l'URL sur le disque dur. Si le document root du serveur est configuré pour, disons, /var/www , il peut regarder si le fichier /var/www/foo/bar.html existe et servir de ce si. Si le fichier se termine par ".php" qu'il invoquera le PHP interprète et puis retourner le résultat. Toute cette association est complètement configurable; un fichier ne à mettre fin à ".php" pour le serveur web de l'exécuter par L'intermédiaire de L'interpréteur PHP, et L'URL n'a pas à correspondre à un fichier particulier sur le disque pour que quelque chose se produise.

mod_rewrite est un moyen de réécrire le traitement interne des requêtes. Lorsque le serveur Web reçoit une requête pour L'URL /foo/bar , vous pouvez réécrire cette URL dans quelque chose d'autre avant que le serveur web va chercher un fichier sur le disque pour le faire correspondre. Simple exemple:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

cette règle dit chaque fois qu'une requête correspond à" /foo/bar", réécrivez-la en"/foo/baz". la requête sera alors traitée comme si /foo/baz avait été demandée à la place. Cela peut être utilisé pour divers effets, par exemple:

RewriteRule (.*) .html

cette règle correspond à tout ( .* ) et capture it ( (..) ), puis la réécrit en annexe".HTML." En d'autres termes, si /foo/bar était L'URL demandée, elle sera traitée comme si /foo/bar.html avait été demandée. Voir http://regular-expressions.info pour plus d'informations sur l'appariement, la capture et le remplacement des expressions régulières.

une autre règle souvent rencontrée est celle-ci:

RewriteRule (.*) index.php?url=

ceci, encore une fois, correspond à n'importe quoi et le réécrit à l'index du fichier.php avec L'URL demandée à l'origine et ajoutée à la requête url paramètre. C'est-à-dire: pour toutes les requêtes, l'index des fichiers.php est exécuté et ce fichier aura accès à la requête originale dans $_GET['url'] , donc il peut faire tout ce qu'il veut avec elle.

vous mettez principalement ces règles de réécriture dans votre fichier de configuration du serveur web . Apache vous permet également* de les mettre dans un fichier appelé .htaccess dans votre document root (i.e. à côté de votre .les fichiers php).

* si autorisé par le fichier de configuration principal Apache; c'est facultatif, mais souvent activé.

Ce que mod_rewrite n' pas faire

mod_rewrite ne rend pas magiquement toutes vos URLs "jolies". C'est une erreur courante. Si vous avez ce lien dans votre site web:

<a href="/my/ugly/link.php?is=not&amp;very=pretty">

il n'y a rien que mod_rewrite puisse faire pour rendre ça joli. Dans pour faire un joli lien, il faut:

  1. changer le lien vers un joli lien:

    <a href="/my/pretty/link">
    
  2. utilisez mod_rewrite sur le serveur pour traiter la requête à L'URL /my/pretty/link en utilisant l'une des méthodes décrites ci-dessus.

(on pourrait utiliser mod_substitute en conjonction pour transformer Les pages HTML et leurs liens contenus. Bien que ce soit généralement plus d'effort que la mise à jour de vos ressources HTML.)

il y a beaucoup de mod_rewrite que vous pouvez faire et des règles d'appariement très complexes que vous pouvez créer, y compris le chaînage de plusieurs réécritures, le remplacement de requêtes vers un service ou une machine complètement différente, la restitution de codes D'état HTTP spécifiques en tant que Réponses, la redirection de requêtes, etc. Il est très puissant et peut être utilisé pour le bien si vous comprenez les Mécanisme de requête-réponse HTTP. Il ne pas automatiquement rendre vos liens jolie.

voir la documentation officielle pour tous les drapeaux et options possibles.

90
répondu deceze 2018-05-15 16:03:30

pour développer sur la réponse de deceze , je voulais fournir quelques exemples et une explication d'une autre fonctionnalité mod_rewrite.

tous les exemples ci-dessous supposent que vous avez déjà inclus RewriteEngine On dans votre fichier .htaccess .

Exemple De Réécriture

prenons cet exemple:

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=&title= [NC,L,QSA]

la règle est divisée en 4 sections:

  1. RewriteRule - commence la règle de réécriture
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - cela s'appelle le modèle, mais je vais juste l'appeler comme le côté gauche de la règle - ce que vous voulez réécrire de
  3. blog/index.php?id=&title= - appelé la substitution, ou le côté droit d'une règle de réécriture-ce que vous voulez réécrire en
  4. [NC,L,QSA] sont des drapeaux pour la règle de réécriture, séparés par une virgule, que je vais expliquer plus plus tard

la réécriture ci-dessus vous permettrait de lier à quelque chose comme /blog/1/foo/ et il serait effectivement charger /blog/index.php?id=1&title=foo .

Gauche de la règle

  • ^ indique le début du nom de la page - ainsi il réécrira example.com/blog/... mais pas example.com/foo/blog/...
  • chaque série de parenthèses (…) représente une expression régulière que nous pouvons capturer en tant que variable dans le côté droit de la règle. Dans cet exemple:
    • le premier ensemble de crochets - ([0-9]+) - correspond à une chaîne de caractères d'une longueur minimale de 1 caractère et avec seulement des valeurs numériques (c.-à-d. 0-9). Ceci peut être référencé avec dans le côté droit de la règle
    • la deuxième série de parenthèses correspond à une chaîne de caractères d'une longueur minimale de 1 caractère, ne contenant que des caractères alphanumériques (a-Z, A-z, ou 0-9) ou - ou + (note + est échappé avec un antislash car sans y échapper ce sera exécuté comme un regex répétition Caractère ). Ceci peut être référencé avec dans le côté droit de la règle
  • ? signifie que le caractère précédent est facultatif, de sorte que dans ce cas /blog/1/foo/ et /blog/1/foo seraient réécrits au même endroit
  • $ indique que c'est la fin de la chaîne que nous voulons apparier

Drapeaux

ce sont des options qui sont ajoutées entre crochets à la fin de votre règle de réécriture pour spécifier certaines conditions. Encore une fois , il y a beaucoup de différents drapeaux que vous pouvez lire dans la documentation , mais je vais passer en revue certains des drapeaux les plus communs:

NC

aucun cas drapeau signifie que la règle de réécriture est insensible à la casse, donc pour l'exemple de règle ci-dessus cela signifierait que les deux /blog/1/foo/ et /BLOG/1/foo/ (ou toute variation de cette) seraient appariés.

L

le dernier drapeau indique qu'il s'agit de la dernière règle à traiter. Cela signifie que si et seulement si cette règle correspond, aucune autre règle ne sera évaluée lors du traitement de réécriture en cours. Si la règle ne correspond pas, toutes les autres règles s'être essayé dans l'ordre habituel. Si vous ne définissez pas le drapeau L , toutes les règles suivantes seront appliquées à L'URL réécrite par la suite.

END

depuis Apache 2.4, vous pouvez également utiliser le drapeau [END] . Une règle d'appariement avec elle complètement terminera le traitement ultérieur d'alias/rewrite. (Alors que le drapeau [L] peut souvent déclencher un second tour, par exemple lors de la réécriture dans ou hors des sous-répertoires.)

QSA

le drapeau d'ajout de chaîne de requête nous permet de passer en variables supplémentaires à L'URL spécifiée qui sera ajoutée aux paramètres get originaux. Pour notre exemple cela signifie que quelque chose comme /blog/1/foo/?comments=15 chargerait /blog/index.php?id=1&title=foo&comments=15

R

Ce drapeau n'est pas celui que j'ai utilisé dans l'exemple ci-dessus, mais je pensais que vaut la peine de mentionner. Cela vous permet de spécifier une redirection http, avec l'option d'inclure un code d'état (par ex. R=301 ). Par exemple, si vous vouliez faire une redirection 301 sur / myblog / to / blog / vous écririez simplement une règle quelque chose comme ceci:

RewriteRule ^/myblog/(*.)$ /blog/ [R=301,QSA,L]

Conditions De Réécriture

conditions de réécriture rendent les réécritures encore plus puissantes, vous permettant de spécifier des réécritures pour des situations plus spécifiques. Il ya beaucoup de conditions que vous pouvez lire dans la documentation , mais je vais toucher sur un peu d'exemples communs et de les expliquer:

# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

c'est une pratique très courante, qui préparera votre domaine avec www. (s'il n'y est pas déjà) et exécutera une redirection 301. Par exemple, charger http://example.com/blog/ vous redirigerait vers http://www.example.com/blog/

# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/ [L]

c'est un peu moins courant, mais c'est un bon exemple d'une règle qui ne s'exécute pas si le nom du fichier est un répertoire ou un fichier qui existe sur le serveur.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] n'exécutera la réécriture que pour les fichiers avec extension jpg, jpeg, gif ou png (insensible à la casse).
  • %{REQUEST_FILENAME} !-f vérifiera pour voir si le fichier existe sur le serveur courant, et n'exécutera la réécriture que si ce n'est pas le cas
  • %{REQUEST_FILENAME} !-d vérifiera pour voir si le fichier existe sur le serveur courant, et n'exécutera la réécriture que si ce n'est pas le cas
  • La réécriture va tenter de charger le même fichier sur un autre domaine
69
répondu Nick 2017-05-23 10:31:09

Références

Stack Overflow a beaucoup autres ressources considérables pour commencer:

Et les nouveaux arrivants-sympathique regex aperçus même:

Souvent utilisée par des espaces réservés

  • .* correspond à tout, même une chaîne vide. Vous ne voulez pas utiliser ce modèle partout, mais souvent dans la dernière règle de repli.
  • [^/]+ est le plus souvent utilisé pour les segments de chemin. Il correspond à tout sauf à la barre oblique.
  • \d+ correspond uniquement à des chaînes numériques.
  • \w+ correspond aux caractères alphanumériques. C'est un raccourci pour [A-Za-z0-9_] .
  • [\w\-]+ pour "slug"de style segments du chemin, en utilisant des lettres, des chiffres, des tirets - et _
  • [\w\-.,]+ ajoute des périodes et des virgules. Préférez un échappé \- tableau de bord […] charclasses.
  • \. dénote une période littérale. Autrement . en dehors de […] est un espace réservé pour tout symbole.

chacun de ces espaces porte habituellement la mention (…) entre parenthèses comme groupe de capture. Et l'ensemble des marqueurs ^………$ start + end. Citer "patterns" est facultatif.

RewriteRules

les exemples suivants sont PHP-centric et un peu plus incrémental, plus facile à adapter pour des cas similaires. Ils sont juste des résumés, souvent en lien plus de variations ou des questions et réponses détaillées.

  • cartographie statique

    /contact , /about

    Raccourcissement d'une page de quelques noms de fichier interne des régimes est la plus simple:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • identificateurs numériques

    /object/123

    introduire des raccourcis comme http://example.com/article/531 aux scripts PHP existants est également facile. Le paramètre numérique peut simplement être remappé à un paramètre $_GET :

     RewriteRule ^article/(\d+)$    article-show.php?id=
     #                      └───────────────────────────┘
    


  • /article/with-some-title-slug

    vous pouvez facilement étendre cette règle pour permettre /article/title-string placeholders:

     RewriteRule ^article/([\w-]+)$    article-show.php?title=
     #                       └────────────────────────────────┘
    

    Note que de votre script doit être en mesure (ou adapté) à la carte de ces titres dans la base de données-id. Les règles de réécriture seules ne peuvent pas créer ou deviner des informations à partir de rien.

  • limaces avec des préfixes numériques

    /readable/123-plus-title

    donc vous verrez souvent mixte /article/529-title-slug chemins utilisés dans la pratique:

     RewriteRule ^article/(\d+)-([\w-]+)$    article.php?id=&title=
     #                      └───────────────────────────────┘
    

    Maintenant vous ne pouvez pas passer le title= de toute façon, parce que votre script se basera généralement sur l'id de la base de données de toute façon. Le -title-slug est devenu une décoration D'URL arbitraire.

  • uniformité avec d'autres listes

    /foo/… /bar/… /baz/…

    si vous avez des règles similaires pour plusieurs chemins de page virtuels, alors vous pouvez les associer et les compacter avec des listes alternatives | . Et encore une fois, il suffit de les réassigner aux paramètres internes GET:

     #                               ┌─────────────────────────┐
     RewriteRule ^(blog|post|user)/(\w+)$  disp.php?type=&id=
     #               └───────────────────────────────────┘
    

    vous pouvez les diviser en 1519580920 "s si cela devient trop complexe.

  • Dispatching liées Url pour différents backends

    /date/SWITCH/backend

    une utilisation plus pratique des listes alternatives consiste à établir la correspondance entre les chemins de requête et les scripts distincts. Par exemple, pour fournir des URLs uniformes pour une application web plus ancienne et plus récente basée sur les dates:

     #                   ┌─────────────────────────────┐
     #                   │                 ┌───────────┼───────────────┐
     RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=
     RewriteRule ^blog/(\d+)/([\d-]+)/?$  modern/blog/index.php?start=
     #                          └──────────────────────────────────────┘
    

    il s'agit simplement de remaps 2009-2011 messages sur un script, et toutes les autres années implicitement à un autre gestionnaire. Notez le règle plus spécifique vient en premier . Chacun script pourrait utiliser des params différents.

  • autres délimiteurs que simplement / barre oblique

    /user-123-name

    vous voyez le plus souvent des règles de réécriture pour simuler une structure de répertoire virtuel. Mais tu n'es pas forcée d'être peu créative. Vous pouvez aussi utiliser les traits d'Union - pour segmenter ou structurer.

     RewriteRule ^user-(\d+)$    show.php?what=user&id=
     #                   └──────────────────────────────┘
     # This could use `(\w+)` alternatively for user names instead of ids.
    

    Pour le commun /wiki:section:Page_Name régime

     RewriteRule ^wiki:(\w+):(\w+)$  wiki.php?sect=&page= 
     #                   └─────┼────────────────────┘       │
     #                         └────────────────────────────┘
    

    occasionnellement, il est approprié d'alterner entre / - délimiteurs et : ou . dans la même règle même. Ou avoir deux règles de réécriture à nouveau pour mapper des variantes sur des scripts différents.

  • arrière optionnel / barre oblique

    /dir = /dir/

    en optant pour des chemins de style répertoire, vous pouvez le rendre accessible avec et sans un final /

     RewriteRule ^blog/([\w-]+)/?$  blog/show.php?id=
     #                         ┗┛
    

    maintenant, il s'agit à la fois de http://example.com/blog/123 et /blog/123/ . Et l'approche /?$ est facile à ajouter à n'importe quelle autre règle de réécriture.

  • Flexible segments pour les chemins virtuels

    .*/.*/.*/.*

    la plupart des règles que vous rencontrerez map Un ensemble limité de segments de chemin de ressources /…/ pour obtenir des paramètres individuels. Certains scripts gèrent un nombre variable d'options cependant. Le moteur regexp D'Apache ne permet pas d'en optionaliser un nombre arbitraire. Mais vous pouvez facilement l'étendre dans un bloc de règles vous-même:

     Rewriterule ^(\w+)/?$                in.php?a=
     Rewriterule ^(\w+)/(\w+)/?$          in.php?a=&b=
     Rewriterule ^(\w+)/(\w+)/(\w+)/?$    in.php?a=&b=&c=
     #              └─────┴─────┴───────────────────┴────┴────┘
    

    si vous avez besoin de jusqu'à cinq segments de chemin, alors copiez ce schéma en cinq règles. Vous pouvez bien sûr utiliser un placeholder plus spécifique [^/]+ chacun. Ici, l'ordre n'est pas important, ni chevauchements. Donc avoir les chemins Les plus fréquemment utilisés en premier est correct.

    alternativement vous pouvez utiliser les paramètres du tableau de PHPs via la chaîne de requête ?p[]=&p[]=&p[]=3 ici - si votre script Les préfère simplement pré-split. (Même si c'est plus commune juste utilisez une règle fourre-tout, et laissez le script lui-même étendre les segments à partir du REQUEST_URI.)

    voir aussi: comment transformer mes segments de chemin D'URL en paires clé-valeur de chaîne de requête?

  • segments optionnels

    prefix/opt?/.*

    une variante courante est d'avoir des préfixes optionnels à l'intérieur une règle. Cela a généralement du sens si vous avez des chaînes statiques ou des espaces plus restreints autour de:

      RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$  ?main=&opt=&suffix=
    

    maintenant le motif plus complexe (?:/([^/])+)? il enveloppe simplement un non-capturing (?:…) groupe, et le rend facultatif )? . Le contenu de l' le paramètre ([^/]+) serait un modèle de substitution , mais il serait vide s'il n'y avait pas de chemin /…/ moyen.

  • capturer le reste

    /prefix/123-capture/…/*/…whatever…

    comme dit plus haut, vous ne voulez pas souvent des modèles de réécriture trop génériques. Il est toutefois logique de combiner parfois des comparaisons statiques et spécifiques avec un .* .

     RewriteRule ^(specific)/prefix/(\d+)(/.*)?$  speci.php?id=&otherparams=
    

    cette option permet de choisir n'importe quel segment de /…/…/… . Ce qui nécessite bien sûr la manipulation script pour les séparer, et variabl-identifier paramètres extraits lui-même (ce qui est ce que Web - "MVC" cadres font).

  • extension de fichier arrière""

    /old/path.HTML

    Les URLs

    n'ont pas vraiment d'extension de fichier. Qui est ce que cette référence entière est au sujet (=URLs sont des locators virtuels, pas nécessairement un direct image du système de fichiers). Cependant, si vous avez déjà eu un mappage de fichier 1:1, vous can craft simpler rules:

     RewriteRule  ^styles/([\w\.\-]+)\.css$  sass-cache.php?old_fn_base=
     RewriteRule  ^images/([\w\.\-]+)\.gif$  png-converter.php?load_from=
    

    D'autres utilisations communes sont la refonte obsolète .html chemins vers les nouveaux .php handlers, ou tout simplement l'aliasing des noms de répertoires seulement pour les fichiers individuels (réels/réels).

  • Ping-Pong (les redirections et les réécrit à l'unisson)

    /ugly.html ←→ /pretty

    donc à un moment donné vous réécrivez vos pages HTML pour ne porter que de jolis liens, comme décrit par deceze . Pendant ce temps, vous recevrez toujours des demandes pour les chemins Vieux , parfois même à partir de signets. Comme solution , vous pouvez ping-pong navigateurs pour afficher / établir la nouvelle Url.

    Cette astuce courante consiste à envoyer un 30x / Location rediriger chaque fois qu'une URL entrante suit le schéma de nommage obsolète/laid. Les navigateurs rerequest la nouvelle/jolie URL, qui est ensuite réécrite (juste en interne) à l'emplacement original ou Nouveau.

     # redirect browser for old/ugly incoming paths
     RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]
    
     # internally remap already-pretty incoming request
     RewriteRule ^teams$ teams.php        [QSA,END]
    

    notez comment cet exemple utilise simplement [END] au lieu de [L] pour alterner en toute sécurité. Pour les versions plus anciennes D'Apache 2.2, vous pouvez utiliser autres solutions de rechange, en plus de refaire paramètres de chaîne de requête par exemple: Rediriger laid URL jolie, remap retour vers le truand chemin, sans les boucles infinies

  • espaces e-mail in patterns

    /this+that+

    ce n'est pas que jolie dans les barres d'adresse du navigateur, mais vous pouvez utilisez des espaces dans les URLs. Pour les modèles de réécriture utiliser backslash-échappée \␣ espaces. Autrement juste " - citer le modèle entier ou la substitution:

     RewriteRule  "^this [\w ]+/(.*)$"  "index.php?id="  [L]
    

    les clients sérialisent les URLs avec + ou %20 pour les espaces. Pourtant, dans les règles de réécriture, ils sont interprétés avec des caractères littéraux pour tous les segments de chemin relatif.

duplicata fréquents:

prévalent .htaccess pitfalls

prenez ceci avec un grain de sel. Pas chaque conseiller peut être généralisée à tous les contextes. Il ne s'agit là que d'un simple résumé des pierres d'achoppement bien connues et peu évidentes:

  • Activer mod_rewrite et .htaccess

    pour utiliser réellement les règles de réécriture dans les fichiers de configuration par répertoire, vous devez:

    • vérifiez que votre serveur a AllowOverride All activé . Sinon, vos directives .htaccess par répertoire seront ignorées, et les règles de réécriture ne fonctionneront pas.

    • évidemment ont mod_rewrite activé dans votre httpd.conf section modules.

    • préparez chaque liste de règles avec RewriteEngine On still. Alors que mod_rewrite est implicitement actif dans les sections <VirtualHost> et <Directory> , le répertoire .htaccess fichiers individuellement convoqués.

  • slash ^/ ne correspond pas

    vous ne devriez pas commencer votre .htaccess RewriteRule modèles avec ^/ normalement:

     RewriteRule ^/article/\d+$  …
                  ↑
    

    cela se voit souvent dans de vieux tutoriels. Et elle était correcte pour L'ancienne Apache 1.X versions. De nos jours, les chemins de requête sont commodément entièrement directory-relative dans .htaccess RewriteRules. Il suffit de laisser le / en tête.

    "15191810920 · * notez que la barre oblique avant est toujours correcte dans <VirtualHost> sections cependant. C'est pourquoi vous le voyez souvent ^/? optionalisé pour la parité de règles.

    · Ou en utilisant un RewriteCond %{REQUEST_URI} , vous correspondriez quand même à un / .

    · Voir aussi Webmaster.SE: Quand le slash principal (/) est-il nécessaire dans les patterns mod_rewrite?

  • <IfModule *> wrappers vas-t'en!

    vous avez probablement vu dans de nombreux exemples:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • Il ne faire sens <VirtualHost> sections - si elle était combinée avec une autre option de secours, tels que ScriptAliasMatch. (Mais personne ne l'a jamais fait).
    • et il est couramment distribué pour les règles par défaut .htaccess avec de nombreux projets open source. Là, il est juste signifié comme repli, et garde" laid " URLs de travail comme défaut.

    Toutefois vous ne veulent pas que d'habitude dans votre propre "1519260920 de fichiers".

    • premièrement, mod_rewrite ne se désengage pas de façon aléatoire. (Si c'était le cas, vous auriez plus de problèmes).
    • S'il était vraiment désactivé, vos règles de réécriture ne fonctionneraient toujours pas de toute façon.
    • il est destiné à prévenir les erreurs HTTP 500 . Ce qu'il accomplit habituellement est en train d'honorer vos utilisateurs avec des erreurs HTTP 404 à la place. (Pas tellement plus convivial si vous y pensez.)
    • pratiquement, il supprime simplement les entrées de journal plus utiles, ou les messages de notification de serveur. Vous seriez aucun le plus sage quant à la raison pour laquelle vos règles de réécriture ne fonctionnent jamais.

    ce qui semble séduisant comme garantie généralisée, se révèle souvent être un obstacle dans la pratique.

  • Ne pas utiliser RewriteBase si nécessaire

    de nombreux exemples de copier + coller contiennent une directive RewriteBase / . Ce qui se trouve être le défaut implicite de toute façon. Si vous n'avez pas réellement besoin de cela. Il s'agit d'une solution de contournement pour les schémas de réécriture virtuelshost de fantaisie, et des chemins DOCUMENT_ROOT erronés pour certains serveurs partagés.

    Il est logique de l'utiliser avec applications web individuelles dans des sous-répertoires plus profonds. Dans de tels cas, il peut raccourcir les patterns RewriteRule. En général, il est préférable de préférer les spécificateurs de chemin relatif dans les ensembles de règles par répertoire.

    Voir aussi Comment RewriteBase de travail .htaccess

  • Désactiver MultiViews quand les chemins virtuels chevauchement

    réécriture D'URL est principalement utilisé pour soutenir virtuel entrants chemins. Généralement, vous n'avez qu'un seul script de répartiteur ( index.php ) ou quelques manipulateurs individuels( articles.php , blog.php , wiki.php , ...). Ce dernier pourrait heurter avec des chemins de réécriture virtuels similaires.

    une demande pour /article/123 par exemple pourrait correspondre à article.php avec un /123 PATH_INFO implicitement. Vous auriez soit à garder vos règles alors avec le banale RewriteCond !-f + !-d , et / ou désactiver le support PATH_INFO, ou peut-être simplement désactiver Options -MultiViews .

    ce qui ne veut pas dire qu'on doit toujours à . La négociation de contenu n'est qu'un automatisme des ressources virtuelles.

  • la commande est importante

    voir Tout ce que vous avez toujours voulu savoir sur mod_rewrite si vous ne l'avez pas déjà. La combinaison de plusieurs règles de réécriture conduit souvent à une interaction. Ce n'est pas quelque chose à empêcher habituellement par [L] drapeau, mais un schéma que vous embrasserez une fois versé. Vous can re-re-re write chemins virtuels d'une règle à l'autre, jusqu'à ce qu'il atteigne un gestionnaire de cible réel.

    Encore vous serais souvent voulez avoir le plus de règles spécifiques (fixe chaîne /forum/… modèles", ou plus restrictive des espaces réservés [^/.]+ ) dans le début les règles. Les règles génériques slurp-all ( .* ) sont mieux laissées aux règles postérieures . (Une exception est un garde RewriteCond -f/-d comme bloc primaire.)

  • feuilles de style et les images d'arrêt de travail

    quand vous introduisez les structures de répertoires virtuels /blog/article/123 ceci répercussions références relatives aux ressources en HTML (comme <img src=mouse.png> ). Qui peut être résolu par:

    • utiliser uniquement le serveur-références absolues href="/old.html" ou src="/logo.png"
    • souvent simplement en ajoutant <base href="/index"> dans votre section HTML <head> . Cela rebinde implicitement les références relatives à ce qu'elles étaient avant.

    vous pouvez alternativement rédiger D'autres règles de réécriture à rebranchez .css ou .png vers leur emplacement d'origine. Mais c'est à la fois inutile, ou entraîne des redirections supplémentaires et entrave la mise en cache.

    Voir aussi: CSS, JS et les images ne s'affichent pas avec de jolies url

  • RewriteConds juste un masque RewriteRule

    une mauvaise interprétation courante est qu'une directive RewriteCond bloque plusieurs règles RewriteRules (parce qu'elles sont visuellement disposés ensemble):

     RewriteCond %{SERVER_NAME} localhost
     RewriteRule ^secret  admin/tools.php
     RewriteRule ^hidden  sqladmin.cgi
    

    ce qui n'est pas par défaut. Vous pouvez les enchaîner en utilisant le drapeau [S=2] . Autre chose que vous aurez à les répéter. Alors que parfois vous pouvez craft une règle primaire "inversée" pour [END] le traitement de réécriture tôt.

  • QUERY_STRING exempt from RewriteRules

    Vous ne pouvez pas correspondre à RewriteRule index.php\?x=y , parce que mod_rewrite compare juste contre les chemins relatifs par défaut. Vous pouvez les apparier séparément cependant via:

     RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
     RewriteRule ^add/(.+)$  add/%1/  # ←──﹪₁──┘
    

    Voir aussi Comment puis-je match des variables chaîne de requête avec le mod_rewrite?

  • .htaccess vs. <VirtualHost>

    si vous utilisez RewriteRules dans un fichier de configuration par répertoire, alors s'inquiéter des performances de regex est inutile. Apache conserve compiler Les patrons PCRE sont plus longs qu'un processus PHP avec un cadre de routage commun. Pour les sites à fort trafic, vous devriez envisager déplacement des règles dans la configuration du serveur vhost, une fois qu'elles ont été testées.

    dans ce cas, préférer le préfixe optionnel du séparateur de répertoires ^/? . Cela permet de déplacer librement les règles de réécriture entre PerDir et le serveur les fichiers de configuration.

  • Chaque fois que quelque chose de ne fonctionne pas

    ne vous inquiétez pas.

    • comparer access.log et error.log

      souvent, vous pouvez comprendre comment une règle RewriteRule se comporte mal en regardant votre error.log et access.log . Corrélez les temps d'accès pour voir quel chemin de requête est entré à l'origine, et quel chemin/fichier Apache n'a pas pu résoudre (erreur 404/500).

      cela ne vous dit pas qui réécrit est le coupable. Mais des chemins finals inaccessibles comme /docroot/21-.itle?index.php peuvent donner où inspecter plus loin. Sinon, désactivez les règles jusqu'à ce que vous ayez des chemins prévisibles.

    • activer le RewriteLog

      voir Apache RewriteLog docs. Pour le débogage, vous pouvez l'activer dans les sections vhost:

      # Apache 2.2
      RewriteLogLevel 5
      RewriteLog /tmp/rewrite.log
      
      # Apache 2.4
      LogLevel alert rewrite:trace5
      #ErrorLog /tmp/rewrite.log
      

      qui fournit un résumé détaillé de la façon dont les chemins de requête entrants sont modifiés par chaque règle:

      [..] applying pattern '^test_.*$' to uri 'index.php'
      [..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
      [..] applying pattern '^index\.php$' to uri 'index.php'
      

      qui aide à réduire les règles trop génériques et les accidents regex.

      Voir aussi:

      · .htaccess ne fonctionne pas (mod_rewrite)

      · Conseils pour le débogage .htaccess de réécrire les règles

    • avant de poser votre propre question

      comme vous le savez peut-être, Stack Overflow est très approprié pour poser des questions sur mod_rewrite. Faites-les sur le thème en incluant les recherches et les tentatives antérieures (éviter les réponses redondantes), démontrer de base comprendre, et:

      • comprend full exemples D'URL d'entrée, chemins cibles réécrits, votre véritable structure de répertoire.
      • l'ensemble complet de règles de réécriture, mais aussi singularise le présumé défectueux.
      • Apache et les versions de PHP, type de système d'exploitation, système de fichiers, DOCUMENT_ROOT, et PHPs $_SERVER environnement si il s'agit d'un paramètre de décalage.
      • Un extrait de votre access.log et error.log pour vérifier ce à quoi les règles existantes ont résolu. Mieux encore, un rewrite.log résumé.

      cela permet des réponses plus rapides et plus précises, et les rend plus utiles aux autres.

  • votre Commentaire .htaccess

    si vous copiez des exemples quelque part, veillez à inclure un # comment and origin link . Alors que c'est de mauvaises manières d'omettre attribution, Cela fait souvent très mal à l'entretien plus tard. Documentez n'importe quel code ou source de tutoriel. En particulier, tout en unversed vous devriez être d'autant plus intéressé à ne pas les traiter comme des boîtes noires magiques.

  • ce n'est pas "SEO" - URLs

    Avertissement: Juste une bête noire. vous entendez souvent de jolies URL réécrire des schémas appelés liens" SEO " ou quelque chose. Bien que cela soit utile pour googler des exemples, il est daté d'abus de langage.

    aucun des moteurs de recherche modernes ne sont vraiment dérangés par .html et .php dans les segments de chemin, ou ?id=123 chaînes d'interrogation pour cette matière. Les moteurs de recherche de vieux, tels que AltaVista, did éviter de ramper des sites Web avec des chemins d'accès potentiellement Ambigus. Les chenilles modernes sont souvent même en manque de ressources Web profondes.

    Ce "joli" Url conceptuellement être utilisé pour est la fabrication de sites Web convivial ".

    1. ayant des schémas de ressources lisibles et évidents.
    2. Assurer les Url sont de longue durée (AKA permaliens ).
    3. Fournir de la visibilité via les /common/tree/nesting .

    cependant, ne sacrifiez pas les exigences uniques pour conformisme.

outils

il existe divers outils en ligne pour générer des règles de réécriture pour la plupart des URLs GET-parameterish:

la plupart du temps juste sortie [^/]+ emplacements génériques, mais suffices probablement pour les sites triviaux.

35
répondu mario 2017-05-23 12:10:30

solutions de rechange " mod_rewrite

de nombreux schémas D'URL virtuelle de base peuvent être obtenus sans utiliser les règles de réécriture. Apache permet aux scripts PHP d'être invoqués sans extension .php , et avec un argument virtuel PATH_INFO .

  1. utilisez le PATH_INFO , Luke

    de nos jours AcceptPathInfo On est souvent activé par défaut. Ce qui en gros permet à .php et à D'autres URL de ressources de porter un argument virtuel:

    http://example.com/script.php/virtual/path
    

    maintenant ce /virtual/path apparaît en PHP comme $_SERVER["PATH_INFO"] où vous pouvez gérer tous les arguments supplémentaires comme vous voulez.

    ce n'est pas aussi pratique que D'avoir Apache séparer les segments de chemin d'entrée en , , et les passer en tant que variables distinctes $_GET à PHP. C'est simplement émuler "pretty URLs" avec moins d'effort de configuration.

  2. Activer MultiViews pour masquer la .php extension

    l'option la plus simple pour également éviter .php " extensions de fichier "dans les URLs est activer:

    Options +MultiViews
    

    Apache sélectionne article.php pour les requêtes HTTP sur /article en raison du nom de base correspondant. Et cela fonctionne bien avec le susmentionnés PATH_INFO fonctionnalité. Vous pouvez donc simplement utiliser des URLs comme http://example.com/article/virtual/title . Ce qui a du sens si vous avez une application web traditionnelle avec plusieurs points D'invocation/scripts PHP.

    notez que MultiViews a un but différent/plus large cependant. Il encourt une pénalité de performance très mineure , car Apache cherche toujours d'autres fichiers avec des noms de base correspondants. Il est en fait destiné à Content-Negotiation , donc les navigateurs reçoivent la meilleure alternative parmi les ressources disponibles (telles que article.en.php , article.fr.php , article.jp.mp4 ).

  3. SetType ou SetHandler pour extensionless .php scripts

    une approche plus directe pour éviter de transporter des suffixes .php dans les URLs est configurer le gestionnaire PHP pour d'autres schémas de fichiers. L'option la plus simple est d'annuler le type MIME/handler par défaut. via .htaccess :

    DefaultType application/x-httpd-php
    

    de cette façon, vous pouvez simplement renommer votre script article.php en juste article (sans extension), mais tout de même le faire traiter comme un script PHP.

    maintenant cela peut avoir des implications de sécurité et de performance, parce que tous les fichiers sans extension seraient acheminés par PHP maintenant. Par conséquent, vous pouvez également définir ce comportement pour les fichiers individuels seulement:

    <Files article>
      SetHandler application/x-httpd-php
      # or SetType 
    </Files>
    

    c'est cela dépend un peu de la configuration de votre serveur et de L'utilisation de PHP SAPI. Les variantes les plus courantes sont ForceType application/x-httpd-php ou AddHandler php5-script .

    à nouveau, notez que de tels paramètres se propagent d'un .htaccess aux sous-dossiers. Vous devez toujours désactiver l'exécution du script ( SetHandler None et Options -Exec ou php_flag engine off etc.) pour les ressources statiques, et de télécharger des répertoires/ etc.

  4. Autres Apaches programmes de réécriture 1519500920"

    parmi ses nombreuses options, Apache fournit des fonctionnalités mod_alias - qui fonctionnent parfois aussi bien que mod_rewrite s RewriteRules. Notez que la plupart de ceux-ci doivent être configurés dans une section <VirtualHost> cependant, pas dans les fichiers de configuration .htaccess par répertoire.

    • ScriptAliasMatch est principalement pour les scripts CGI, mais devrait également fonctionner pour PHP. Il permet regexps tout comme tout RewriteRule . En fait, c'est peut-être l'option la plus robuste pour configurer une manette avant fourre-tout.

    • Et un simple Alias permet avec un simple réécriture de systèmes.

    • même une directive simple "15191160920 ErrorDocument pourrait être utilisée pour laisser un script PHP gérer des chemins virtuels. Notez que c'est une solution de contournement toutefois encombrants, interdit tout sauf obtenir des requêtes, et inonde l'erreur.journal, par définition.

    voir http://httpd.apache.org/docs/2.2/urlmapping.html pour d'autres conseils.

5
répondu mario 2017-05-23 12:34:36