Referenz: mod_rewrite, URL-Umschreibung und "hübsche Links" erklärt

142

"Hübsche Links" ist ein häufig nachgefragtes Thema, das jedoch selten vollständig erklärt wird. mod_rewrite ist eine Möglichkeit, "hübsche Links" zu erstellen, aber es ist komplex und seine Syntax ist sehr knapp, schwer zu verstehen, und die Dokumentation setzt ein gewisses Maß an HTTP-Kenntnissen voraus. Kann jemand in einfachen Worten erklären, wie "hübsche Links" funktionieren und wie mod_rewrite verwendet werden kann, um sie zu erstellen?

Andere gebräuchliche Namen, Aliase, Begriffe für saubere URLs: RESTful- URLs, benutzerfreundliche URLs, SEO- freundliche URLs, Slugging- und MVC-URLs (wahrscheinlich eine falsche Bezeichnung)

täuschen
quelle
2
Slug oder Slugging ist ein weiterer gebräuchlicher Alias ​​/ Begriff für hübsche URLs.
Mike B
2
@ Mike Irgendwie, aber Slugs sind oft Teil hübscher URLs. Ein Slug ist ziemlich spezifisch, wenn beispielsweise die Überschrift eines Artikels in eine URL-freundliche Form umgewandelt wird, die dann als Kennung dieses Artikels fungiert. So reference-mod-rewrite-url-rewriting-explainedist die Schnecke, /questions/20563772/reference-mod-rewrite-url-rewriting-explainedist die hübsche URL.
Täuschung
2
Ich denke , dass die .htaccessund mod-rewriteTags aktualisiert werden sollte einen Link zu dieser Frage aufzunehmen, wie es viel abdeckt , was regelmäßig gefragt wird. Gedanken?
Mike Rockétt

Antworten:

110

Um zu verstehen, was mod_rewrite tut, müssen Sie zuerst verstehen, wie ein Webserver funktioniert. Ein Webserver antwortet auf HTTP-Anfragen . Eine HTTP-Anfrage auf ihrer grundlegendsten Ebene sieht folgendermaßen aus:

GET /foo/bar.html HTTP/1.1

Dies ist die einfache Anforderung eines Browsers an einen Webserver, der die URL /foo/bar.html von diesem anfordert . Es ist wichtig zu betonen, dass keine Datei angefordert wird , sondern nur eine beliebige URL. Die Anfrage kann auch so aussehen:

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

Dies ist eine ebenso gültige Anfrage nach einer URL und hat offensichtlich nichts mit Dateien zu tun.

Der Webserver ist eine Anwendung, die einen Port überwacht, HTTP-Anforderungen akzeptiert, die an diesem Port eingehen, und eine Antwort zurückgibt. Es steht einem Webserver völlig frei, auf jede Anfrage so zu antworten, wie er es für richtig hält oder wie Sie sie für die Beantwortung konfiguriert haben. Diese Antwort ist keine Datei, sondern eine HTTP-Antwort, die möglicherweise nichts mit physischen Dateien auf einer Festplatte zu tun hat. Ein Webserver muss nicht Apache sein, es gibt viele andere Webserver, bei denen es sich ausschließlich um Programme handelt, die dauerhaft ausgeführt werden und an einen Port angeschlossen sind, der auf HTTP-Anforderungen reagiert. Sie können selbst eine schreiben. Dieser Absatz sollte Sie von jeder Vorstellung trennen, dass URLs direkt Dateien entsprechen, was wirklich wichtig ist, um sie zu verstehen. :) :)

Die Standardkonfiguration der meisten Webserver besteht darin, nach einer Datei zu suchen, die der URL auf der Festplatte entspricht. Wenn das Dokumentstammverzeichnis des Servers beispielsweise auf "festgelegt" ist /var/www, wird möglicherweise geprüft, ob die Datei /var/www/foo/bar.htmlvorhanden ist, und in diesem Fall bereitgestellt . Wenn die Datei endet in „.php“ wird es den PHP - Interpreter aufrufen und dann das Ergebnis zurück. All diese Zuordnungen sind vollständig konfigurierbar. Eine Datei muss nicht mit ".php" enden, damit der Webserver sie über den PHP-Interpreter ausführen kann, und die URL muss nicht mit einer bestimmten Datei auf der Festplatte übereinstimmen, damit etwas passiert.

mod_rewrite ist eine Möglichkeit, die interne Anforderungsbearbeitung neu zu schreiben . Wenn der Webserver eine Anforderung für die URL erhält /foo/bar, können Sie diese URL in eine andere URL umschreiben , bevor der Webserver nach einer passenden Datei auf der Festplatte sucht. Einfaches Beispiel:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

Diese Regel besagt, dass eine Anfrage , wenn sie mit "/ foo / bar" übereinstimmt, in "/ foo / baz" umgeschrieben wird. Die Anfrage wird dann so behandelt, als wäre /foo/bazsie stattdessen angefordert worden. Dies kann für verschiedene Effekte verwendet werden, zum Beispiel:

RewriteRule (.*) $1.html

Diese Regel stimmt mit any ( .*) überein, erfasst es ( (..)) und schreibt es dann neu, um ".html" anzuhängen. Mit anderen Worten, wenn /foo/bardie angeforderte URL war, wird sie so behandelt, als ob /foo/bar.htmlsie angefordert worden wäre. Weitere Informationen zum Abgleichen, Erfassen und Ersetzen regulärer Ausdrücke finden Sie unter http://regular-expressions.info .

Eine andere häufig anzutreffende Regel lautet:

RewriteRule (.*) index.php?url=$1

Dies stimmt wiederum mit allem überein und schreibt es in die Datei index.php mit der ursprünglich angeforderten URL, die im urlAbfrageparameter angehängt ist. Das heißt, für alle eingehenden Anforderungen wird die Datei index.php ausgeführt, und diese Datei hat Zugriff auf die ursprüngliche Anforderung in $_GET['url'], sodass sie damit alles tun kann, was sie will.

In erster Linie fügen Sie diese Umschreiberegeln in Ihre Webserver-Konfigurationsdatei ein . Mit Apache * können Sie sie auch in eine Datei .htaccesseinfügen, die in Ihrem Dokumentstamm aufgerufen wird (dh neben Ihren .php-Dateien).

* Wenn von der primären Apache-Konfigurationsdatei zugelassen; Es ist optional, aber oft aktiviert.

Was mod_rewrite nicht macht

mod_rewrite macht nicht alle Ihre URLs auf magische Weise "hübsch". Dies ist ein häufiges Missverständnis. Wenn Sie diesen Link auf Ihrer Website haben:

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

Es gibt nichts, was mod_rewrite tun kann, um das hübsch zu machen. Um dies zu einem hübschen Link zu machen, müssen Sie:

  1. Ändern Sie den Link in einen hübschen Link:

    <a href="https://stackoverflow.com/my/pretty/link">
    
  2. Verwenden Sie mod_rewrite auf dem Server, um die Anforderung an die URL /my/pretty/linkmit einer der oben beschriebenen Methoden zu verarbeiten.

(Man könnte mod_substitutein Verbindung verwenden, um ausgehende HTML-Seiten und ihre enthaltenen Links zu transformieren. Dies ist jedoch normalerweise mehr Aufwand als nur das Aktualisieren Ihrer HTML-Ressourcen.)

Es gibt viel, was mod_rewrite tun kann, und sehr komplexe Übereinstimmungsregeln, die Sie erstellen können, einschließlich der Verkettung mehrerer Umschreibungen, der Weiterleitung von Anforderungen an einen völlig anderen Dienst oder Computer, der Rückgabe bestimmter HTTP-Statuscodes als Antworten, der Umleitung von Anforderungen usw. Es ist sehr leistungsfähig und kann verwendet werden Sehr gut, wenn Sie den grundlegenden HTTP-Anforderungs-Antwort-Mechanismus verstehen. Es macht Ihre Links nicht automatisch hübsch.

In der offiziellen Dokumentation finden Sie alle möglichen Flags und Optionen.

täuschen
quelle
6
Erwähnen Sie möglicherweise die in Version 2.2.16 eingeführte FallbackResource-Direktive als bevorzugte Methode zum Umschreiben in einen Dispatcher.
Darsstar
78

Um die Antwort von deceze zu erweitern , wollte ich einige Beispiele und Erklärungen für einige andere mod_rewrite-Funktionen geben.

Bei allen folgenden Beispielen wird davon ausgegangen, dass Sie bereits RewriteEngine Onin Ihre .htaccessDatei aufgenommen haben.

Beispiel umschreiben

Nehmen wir dieses Beispiel:

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

Die Regel ist in 4 Abschnitte unterteilt:

  1. RewriteRule - Startet die Umschreiberegel
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - Dies wird als Muster bezeichnet, ich bezeichne es jedoch nur als die linke Seite der Regel - woraus Sie neu schreiben möchten
  3. blog/index.php?id=$1&title=$2 - wird als Substitution oder rechte Seite einer Umschreiberegel bezeichnet - auf was Sie umschreiben möchten
  4. [NC,L,QSA] sind Flags für die Umschreiberegel, die durch ein Komma getrennt sind, worauf ich später noch näher eingehen werde

Das obige Umschreiben würde es Ihnen ermöglichen, auf so etwas zu verlinken, /blog/1/foo/und es würde tatsächlich geladen /blog/index.php?id=1&title=foo.

Linke Seite der Regel

  • ^Gibt den Beginn des Seitennamens an - wird also neu geschrieben, example.com/blog/...aber nichtexample.com/foo/blog/...
  • Jeder Satz von (…)Klammern stellt einen regulären Ausdruck dar, den wir als Variable auf der rechten Seite der Regel erfassen können. In diesem Beispiel:
    • Der erste Satz von Klammern - ([0-9]+)- entspricht einer Zeichenfolge mit mindestens 1 Zeichen Länge und nur numerischen Werten (dh 0-9). Dies kann $1auf der rechten Seite der Regel angegeben werden
    • Der zweite Satz von Klammern entspricht eine Zeichenkette mit mindestens 1 Zeichen lang, die nur alphanumerische Zeichen (AZ, az oder 0-9) oder -oder +(Note +mit einem umgekehrten Schrägstrich als ohne es zu entkommen dies als ausführen wird regex Wiederholungscharakter ). Dies kann $2auf der rechten Seite der Regel angegeben werden
  • ?bedeutet, dass das vorhergehende Zeichen optional ist, also in diesem Fall beide /blog/1/foo/und /blog/1/fooan derselben Stelle neu schreiben würden
  • $ Gibt an, dass dies das Ende der Zeichenfolge ist, mit der wir übereinstimmen möchten

Flaggen

Dies sind Optionen, die am Ende Ihrer Umschreiberegel in eckigen Klammern eingefügt werden, um bestimmte Bedingungen anzugeben. Auch hier gibt es viele verschiedene Flags, die Sie in der Dokumentation nachlesen können , aber ich werde einige der gebräuchlichsten Flags durchgehen:

NC

Das No-Case-Flag bedeutet, dass bei der Umschreiberegel nicht zwischen Groß- und Kleinschreibung unterschieden wird. Für die obige Beispielregel würde dies bedeuten, dass beide /blog/1/foo/und /BLOG/1/foo/(oder eine Variation davon) übereinstimmen würden.

L

Das letzte Flag zeigt an, dass dies die letzte Regel ist, die verarbeitet werden soll. Dies bedeutet, dass genau dann, wenn diese Regel übereinstimmt, im aktuellen Umschreibverarbeitungslauf keine weiteren Regeln ausgewertet werden. Wenn die Regel nicht übereinstimmt, werden alle anderen Regeln wie gewohnt ausprobiert. Wenn Sie das LFlag nicht setzen , werden alle folgenden Regeln anschließend auf die neu geschriebene URL angewendet .

END

Seit Apache 2.4 können Sie auch das [END]Flag verwenden. Eine übereinstimmende Regel beendet die weitere Alias- / Rewrite-Verarbeitung vollständig . (Während das [L]Flag häufig eine zweite Runde auslösen kann, beispielsweise beim Umschreiben in oder aus Unterverzeichnissen.)

QSA

Mit dem Flag zum Anhängen von Abfragezeichenfolgen können wir zusätzliche Variablen an die angegebene URL übergeben, die zu den ursprünglichen get-Parametern hinzugefügt werden. In unserem Beispiel bedeutet dies, dass so etwas /blog/1/foo/?comments=15geladen werden würde/blog/index.php?id=1&title=foo&comments=15

R

Diese Flagge habe ich im obigen Beispiel nicht verwendet, aber ich dachte, sie ist erwähnenswert. Auf diese Weise können Sie eine http-Umleitung angeben und einen Statuscode (z R=301. B. ) einfügen . Wenn Sie beispielsweise eine 301-Umleitung auf / myblog / to / blog / durchführen möchten, schreiben Sie einfach eine Regel wie die folgende:

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

Bedingungen umschreiben

Durch das Umschreiben werden die Umschreibungen noch leistungsfähiger, sodass Sie Umschreibungen für spezifischere Situationen festlegen können. Es gibt viele Bedingungen, über die Sie in der Dokumentation lesen können , aber ich werde einige allgemeine Beispiele ansprechen und sie erklären:

# 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]

Dies ist eine sehr verbreitete Vorgehensweise, bei der Ihrer Domain www.(sofern noch nicht vorhanden) eine 301-Umleitung vorangestellt wird. Wenn Sie es beispielsweise laden, werden http://example.com/blog/Sie zu weitergeleitethttp://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/$1 [L]

Dies ist etwas seltener, aber ein gutes Beispiel für eine Regel, die nicht ausgeführt wird, wenn der Dateiname ein Verzeichnis oder eine Datei ist, die auf dem Server vorhanden ist.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] führt das Umschreiben nur für Dateien mit der Dateierweiterung jpg, jpeg, gif oder png aus (Groß- und Kleinschreibung wird nicht berücksichtigt).
  • %{REQUEST_FILENAME} !-f prüft, ob die Datei auf dem aktuellen Server vorhanden ist, und führt das Umschreiben nur aus, wenn dies nicht der Fall ist
  • %{REQUEST_FILENAME} !-d prüft, ob die Datei auf dem aktuellen Server vorhanden ist, und führt das Umschreiben nur aus, wenn dies nicht der Fall ist
  • Beim Umschreiben wird versucht, dieselbe Datei in eine andere Domäne zu laden
Nick
quelle
39

Verweise

Stack Overflow bietet viele weitere nützliche Ressourcen für den Einstieg:

Und Newcomer-freundliche Regex-Übersichten sogar:

Oft verwendete Platzhalter

  • .*passt zu allem, sogar zu einer leeren Zeichenfolge. Sie möchten dieses Muster nicht überall verwenden, sondern häufig in der letzten Fallback-Regel.
  • [^/]+wird häufiger für Pfadsegmente verwendet. Es passt zu allem anderen als dem Schrägstrich.
  • \d+ stimmt nur mit numerischen Zeichenfolgen überein.
  • \w+stimmt mit alphanumerischen Zeichen überein. Es ist im Grunde eine Abkürzung für [A-Za-z0-9_].
  • [\w\-]+für Pfadsegmente im "Slug" -Stil mit Buchstaben, Zahlen, Bindestrich - und _
  • [\w\-.,]+fügt Punkte und Kommas hinzu. Bevorzugen Sie einen maskierten \-Bindestrich in […]Zeichenklassen.
  • \.bezeichnet eine wörtliche Periode. Andernfalls ist .außerhalb von […]ein Platzhalter für ein Symbol.

Jeder dieser Platzhalter wird normalerweise (…)als Erfassungsgruppe in Klammern gesetzt. Und das ganze Muster oft in ^………$Start + End-Markierungen. Das Zitieren von "Mustern" ist optional.

RewriteRules

Die folgenden Beispiele sind PHP-zentriert und etwas inkrementeller und für ähnliche Fälle einfacher anzupassen. Es handelt sich lediglich um Zusammenfassungen, die häufig auf weitere Variationen oder detaillierte Fragen und Antworten verweisen.

  • Statische Zuordnung
    /contact,/about

    Das Kürzen einiger Seitennamen auf interne Dateischemata ist am einfachsten:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • Numerische Bezeichner
    /object/123

    Das Einführen von Verknüpfungen http://example.com/article/531zu vorhandenen PHP-Skripten ist ebenfalls einfach. Der numerische Platzhalter kann einfach einem $_GETParameter neu zugeordnet werden:

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
     #                      └───────────────────────────┘
    
  • Platzhalter im Slug-Stil
    /article/with-some-title-slug

    Sie können diese Regel leicht erweitern, um /article/title-stringPlatzhalter zu berücksichtigen:

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

    Beachten Sie, dass Ihr Skript in der Lage (oder angepasst) sein muss, diese Titel wieder Datenbank-IDs zuzuordnen. RewriteRules allein kann keine Informationen aus dem Nichts erstellen oder erraten.

  • Schnecken mit numerischen Präfixen
    /readable/123-plus-title

    Daher /article/529-title-slugwerden in der Praxis häufig gemischte Pfade verwendet:

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

    Jetzt können Sie das Übergeben einfach title=$2trotzdem überspringen , da Ihr Skript normalerweise sowieso von der Datenbank-ID abhängt. Das -title-slugist zu einer willkürlichen URL-Dekoration geworden.

  • Einheitlichkeit mit alternativen Listen
    /foo/… /bar/… /baz/…

    Wenn Sie ähnliche Regeln für mehrere virtuelle Seitenpfade haben, können Sie diese mit |alternativen Listen abgleichen und komprimieren . Und wieder ordnen Sie sie einfach den internen GET-Parametern zu:

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

    Sie können sie in einzelne RewriteRules aufteilen, falls dies zu komplex wird.

  • Versenden verwandter URLs an verschiedene Backends
    /date/SWITCH/backend

    Eine praktischere Verwendung alternativer Listen besteht darin, Anforderungspfade unterschiedlichen Skripten zuzuordnen. Zum Beispiel, um einheitliche URLs für eine ältere und eine neuere Webanwendung basierend auf Datumsangaben bereitzustellen:

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

    Dadurch werden die Beiträge für 2009-2011 einfach einem Skript und alle anderen Jahre implizit einem anderen Handler zugeordnet. Beachten Sie die spezifischere Regel, die zuerst kommt . Jedes Skript verwendet möglicherweise andere GET-Parameter.

  • Andere Trennzeichen als nur /Pfad-Schrägstriche
    /user-123-name

    Am häufigsten sehen Sie RewriteRules, um eine virtuelle Verzeichnisstruktur zu simulieren. Aber du bist nicht gezwungen, unkreativ zu sein. Sie können auch -Bindestriche für die Segmentierung oder Strukturierung verwenden.

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

    Für das ebenfalls übliche /wiki:section:Page_NameSchema:

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

    Gelegentlich ist es , um zwischen dem geeigneten /-delimiters und :oder .in derselben Regel auch. Oder haben Sie erneut zwei RewriteRules, um Varianten verschiedenen Skripten zuzuordnen.

  • Optionaler abschließender /Schrägstrich
    /dir=/dir/

    Wenn Sie sich für Pfade im Verzeichnisstil entscheiden, können Sie diese mit und ohne Finale erreichen /

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

    Dies behandelt nun sowohl http://example.com/blog/123als auch /blog/123/. Und der /?$Ansatz lässt sich leicht an jede andere RewriteRule anhängen.

  • Flexible Segmente für virtuelle Pfade
    .*/.*/.*/.*

    Bei den meisten Regeln wird ein eingeschränkter Satz von /…/Ressourcenpfadsegmenten einzelnen GET-Parametern zugeordnet. Einige Skripte verarbeiten jedoch eine variable Anzahl von Optionen . Die Apache-Regexp-Engine erlaubt keine optionale Anzahl von ihnen. Sie können es jedoch ganz einfach selbst zu einem Regelblock erweitern:

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

    Wenn Sie bis zu fünf Pfadsegmente benötigen, kopieren Sie dieses Schema in fünf Regeln. Sie können natürlich jeweils einen spezifischeren [^/]+Platzhalter verwenden. Hier ist die Reihenfolge nicht so wichtig, da sich keine überlappt. Es ist also in Ordnung, zuerst die am häufigsten verwendeten Pfade zu haben.

    Alternativ können Sie hier PHPs-Array-Parameter über eine Abfragezeichenfolge verwenden ?p[]=$1&p[]=$2&p[]=3- wenn Ihr Skript diese lediglich vor dem Teilen bevorzugt. (Obwohl es üblicher ist, nur eine Catch-All-Regel zu verwenden und das Skript selbst die Segmente aus REQUEST_URI erweitern zu lassen.)

    Siehe auch: Wie transformiere ich meine URL-Pfadsegmente in Schlüssel-Wert-Paare für Abfragezeichenfolgen?

  • Optionale Segmente
    prefix/opt?/.*

    Eine übliche Variante besteht darin, optionale Präfixe innerhalb einer Regel zu haben. Dies ist normalerweise sinnvoll, wenn statische Zeichenfolgen oder eingeschränktere Platzhalter vorhanden sind:

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

    Das komplexere Muster (?:/([^/])+)?umschließt nun einfach eine nicht erfassende (?:…) Gruppe und macht sie optional )?. Der enthaltene Platzhalter ([^/]+)wäre ein Substitutionsmuster $2, aber leer, wenn es keinen mittleren /…/Pfad gibt.

  • Erfassen Sie den Rest
    /prefix/123-capture/…/*/…whatever…

    Wie bereits erwähnt, möchten Sie nicht oft zu allgemeine Umschreibemuster. Es ist jedoch sinnvoll, statische und spezifische Vergleiche mit einem .*manchmal zu kombinieren .

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

    Dadurch wurden alle /…/…/…nachfolgenden Pfadsegmente optional . Was dann natürlich erfordert, dass das Handling-Skript sie aufteilt und variabel die Parameter selbst extrahiert (was Web- "MVC" -Frameworks tun).

  • Nachfolgende Datei "Erweiterungen"
    /old/path.HTML

    URLs haben nicht wirklich Dateierweiterungen. Darum geht es in dieser gesamten Referenz (= URLs sind virtuelle Locators, nicht unbedingt ein direktes Dateisystem-Image). Allerdings , wenn Sie eine 1 haben: vor 1 Dateizuordnung Sie können einfachere Regeln Handwerk:

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

    Andere häufige Verwendungszwecke sind das Neuzuordnen veralteter .htmlPfade zu neueren .phpHandlern oder das Aliasing von Verzeichnisnamen nur für einzelne (tatsächliche / echte) Dateien.

  • Ping-Pong (leitet und leitet unisono um)
    /ugly.html← →/pretty

    Irgendwann schreiben Sie Ihre HTML-Seiten so um, dass sie nur hübsche Links enthalten, wie von täuschung beschrieben . In der Zwischenzeit erhalten Sie immer noch Anfragen für die alten Pfade, manchmal sogar von Lesezeichen. Als Abhilfe können Sie Browser - Anzeige / etablieren die neuen URLs Ping-Pong.

    Dieser häufige Trick besteht darin, eine 30x / Location- Umleitung zu senden, wenn eine eingehende URL dem veralteten / hässlichen Namensschema folgt. Browser fordern dann die neue / hübsche URL erneut an, die anschließend (nur intern) an den ursprünglichen oder neuen Speicherort umgeschrieben wird.

     # 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]
    

    Beachten Sie, wie in diesem Beispiel nur verwendet wird, [END]anstatt [L]sicher zu wechseln. Für ältere Apache 2.2-Versionen können Sie andere Problemumgehungen verwenden und außerdem Abfragezeichenfolgenparameter neu zuordnen, z. B.: Hässliche zu hübscher URL umleiten, ohne Endlosschleifen wieder auf den hässlichen Pfad zuordnen

  • Räume in Mustern
    /this+that+

    In Adressleisten des Browsers ist es nicht so hübsch , aber Sie können Leerzeichen in URLs verwenden. Verwenden Sie zum Umschreiben von Mustern \␣Leerzeichen mit umgekehrten Schrägstrichen . "Andernfalls zitieren Sie einfach das gesamte Muster oder die Substitution:

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

    Clients serialisieren URLs mit +oder %20für Leerzeichen. In RewriteRules werden sie jedoch mit Literalzeichen für alle relativen Pfadsegmente interpretiert.

Häufige Duplikate:

Häufige .htaccessFallstricke

Nehmen Sie dies nun mit einem Körnchen Salz. Nicht jeder Rat kann auf alle Kontexte verallgemeinert werden. Dies ist nur eine einfache Zusammenfassung bekannter und einiger nicht offensichtlicher Stolpersteine:

  • Aktivieren mod_rewriteund.htaccess

    Um RewriteRules tatsächlich in Konfigurationsdateien pro Verzeichnis zu verwenden, müssen Sie:

    • Überprüfen Sie, ob Ihr Server AllowOverride Allaktiviert ist . Andernfalls werden Ihre .htaccessDirektiven pro Verzeichnis ignoriert und RewriteRules funktioniert nicht.

    • Offensichtlich haben mod_rewriteaktiviert in Ihrem httpd.confModule Abschnitt.

    • Stellen Sie jeder Regelliste RewriteEngine OnStill vor. Während mod_rewrite implizit in <VirtualHost>und <Directory>Abschnitten aktiv ist, müssen die .htaccessDateien pro Verzeichnis einzeln aufgerufen werden.

  • Der führende Schrägstrich ^/passt nicht zusammen

    Sie sollten Ihre .htaccessRewriteRule-Muster nicht ^/normal starten :

     RewriteRule ^/article/\d+$  …
                  ↑
    

    Dies wird oft in alten Tutorials gesehen. Früher war es für alte Apache 1.x-Versionen korrekt. Heutzutage sind Anfrage Wege bequem vollständig verzeichnis relativ in .htaccessRewriteRules. Lass einfach die Führung /aus.

    · Beachten Sie, dass der führende Schrägstrich in <VirtualHost>Abschnitten immer noch korrekt ist . Aus diesem Grund wird es häufig ^/?für die Regelparität optional angezeigt.
    · Oder wenn RewriteCond %{REQUEST_URI}Sie ein verwenden, stimmen Sie immer noch mit einem führenden überein /.
    · Siehe auch Webmaster.SE: Wann wird der führende Schrägstrich (/) in mod_rewrite-Mustern benötigt?

  • <IfModule *> Wrapper beginnen!

    Sie haben dies wahrscheinlich in vielen Beispielen gesehen:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • Es macht Sinn in <VirtualHost>Abschnitten - wenn es mit einer anderen Ersatzoption, wie ScriptAliasMatch kombiniert wurde. (Aber das macht niemand).
    • Und es wird häufig für Standardregelsätze .htaccessmit vielen Open Source-Projekten verteilt. Dort ist es nur als Fallback gedacht und sorgt dafür, dass "hässliche" URLs standardmäßig funktionieren.

    Allerdings möchten Sie das normalerweise nicht in Ihren eigenen .htaccessDateien.

    • Erstens wird mod_rewrite nicht zufällig deaktiviert. (Wenn ja, hätten Sie größere Probleme).
    • Wäre es wirklich deaktiviert, würden Ihre RewriteRules trotzdem nicht funktionieren.
    • Es soll HTTP- 500Fehler verhindern . In der Regel werden Ihre Benutzer 404stattdessen mit HTTP- Fehlern versehen. (Nicht viel benutzerfreundlicher, wenn Sie darüber nachdenken.)
    • Praktisch werden nur die nützlicheren Protokolleinträge oder Serverbenachrichtigungsmails unterdrückt. Sie würden nicht schlauer , warum Ihre RewriteRules nie funktionieren.

    Was als allgemeiner Schutz verlockend erscheint, stellt sich in der Praxis häufig als Hindernis heraus.

  • Nicht verwenden, es RewriteBasesei denn, dies wird benötigt

    Viele Beispiele zum Kopieren und Einfügen enthalten eine RewriteBase /Direktive. Was sowieso der implizite Standard ist. Das brauchst du also eigentlich nicht. Es ist eine Problemumgehung für ausgefallene VirtualHost-Umschreibeschemata und falsch gestaltete DOCUMENT_ROOT-Pfade für einige gemeinsam genutzte Hoster.

    Es ist sinnvoll, mit einzelnen Webanwendungen in tieferen Unterverzeichnissen zu arbeiten. In solchen Fällen können RewriteRule-Muster verkürzt werden. Im Allgemeinen ist es am besten, relative Pfadspezifizierer in Regelsätzen pro Verzeichnis zu bevorzugen.

    Siehe auch Wie funktioniert RewriteBase in .htaccess?

  • Deaktivieren, MultiViewswenn sich virtuelle Pfade überschneiden

    Das Umschreiben von URLs wird hauptsächlich zur Unterstützung virtueller eingehender Pfade verwendet. Häufig nur Sie einen Dispatcher - Skript (haben index.php) oder ein paar einzelnen Handler ( articles.php, blog.php, wiki.php, ...). Letzteres kann mit ähnlichen virtuellen RewriteRule-Pfaden kollidieren.

    Eine Anforderung zum /article/123Beispiel könnte implizit article.phpeinem /123PATH_INFO zugeordnet werden. Sie müssten entweder Ihre Regeln dann mit dem alltäglichen RewriteCond !-f+ !-dschützen und / oder die PATH_INFO-Unterstützung deaktivieren oder einfach nur deaktivieren Options -MultiViews.

    Das heißt nicht, dass Sie immer müssen . Content-Negotiation ist nur ein Automatismus für virtuelle Ressourcen.

  • Bestellung ist wichtig

    Sehen Sie alles, was Sie schon immer über mod_rewrite wissen wollten, wenn Sie es noch nicht getan haben. Das Kombinieren mehrerer RewriteRules führt häufig zu Interaktionen. Dies ist nicht etwas, das gewohnheitsmäßig pro [L]Flagge verhindert werden soll, sondern ein Schema, das Sie annehmen werden, wenn Sie sich einmal auskennen. Sie können virtuelle Pfade von einer Regel zur anderen erneut schreiben , bis sie einen tatsächlichen Zielhandler erreichen.

    Dennoch möchten Sie häufig die spezifischsten Regeln (feste Zeichenfolgenmuster /forum/…oder restriktivere Platzhalter [^/.]+) in den frühen Regeln haben. Generische Slurp-All-Regeln ( .*) sollten besser den späteren überlassen werden. (Eine Ausnahme ist ein RewriteCond -f/-dGuard als Primärblock.)

  • Stylesheets und Bilder funktionieren nicht mehr

    Wenn Sie virtuelle Verzeichnisstrukturen einführen, /blog/article/123wirkt sich dies auf relative Ressourcenreferenzen in HTML aus (z. B. <img src=mouse.png>). Was gelöst werden kann durch:

    • Nur mit server-absoluten Referenzen href="https://stackoverflow.com/old.html"odersrc="/logo.png"
    • Oft einfach durch Hinzufügen <base href="https://stackoverflow.com/index">in Ihren HTML- <head>Bereich. Dies bindet implizit relative Verweise auf das, was sie vorher waren.

    Sie können alternativ weitere RewriteRules erstellen, um sie neu zu binden, .cssoder .pngPfade zu ihren ursprünglichen Positionen. Dies ist jedoch nicht erforderlich oder führt zu zusätzlichen Weiterleitungen und behindert das Caching.

    Siehe auch: CSS, JS und Bilder werden nicht mit hübscher URL angezeigt

  • RewriteConds maskiert nur eine RewriteRule

    Eine häufige Fehlinterpretation besteht darin, dass eine RewriteCond mehrere RewriteRules blockiert (weil sie visuell zusammen angeordnet sind):

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

    Was es nicht standardmäßig ist. Sie können sie mit der [S=2]Flagge verketten. Sonst musst du sie wiederholen. Manchmal können Sie eine "invertierte" Primärregel erstellen, um die Umschreibeverarbeitung frühzeitig zu beenden.

  • QUERY_STRING von RewriteRules ausgenommen

    Sie können nicht übereinstimmen RewriteRule index.php\?x=y, da mod_rewrite standardmäßig nur mit relativen Pfaden verglichen wird. Sie können sie jedoch separat abgleichen über:

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

    Siehe auch Wie kann ich Abfragezeichenfolgenvariablen mit mod_rewrite abgleichen?

  • .htaccess vs. <VirtualHost>

    Wenn Sie RewriteRules in einer Konfigurationsdatei pro Verzeichnis verwenden, ist es sinnlos, sich Gedanken über die Regex-Leistung zu machen. Apache behält kompilierte PCRE-Muster länger bei als ein PHP-Prozess mit einem gemeinsamen Routing-Framework. Bei stark frequentierten Websites sollten Sie jedoch in Betracht ziehen, Regelsätze in die vhost-Serverkonfiguration zu verschieben, sobald sie im Kampf getestet wurden.

    Bevorzugen Sie in diesem Fall das optionale ^/?Präfix für das Verzeichnistrennzeichen. Dadurch können RewriteRules frei zwischen PerDir- und Serverkonfigurationsdateien verschoben werden.

  • Wann immer etwas nicht funktioniert

    Ärgern Sie sich nicht.

    • Vergleiche access.logunderror.log

      Oft können Sie herausfinden, wie sich eine RewriteRule schlecht verhält, wenn Sie nur auf Ihr error.logund schauen access.log. Korrelieren Sie die Zugriffszeiten, um festzustellen, welcher Anforderungspfad ursprünglich eingegangen ist und in welchen Pfad / welche Datei Apache nicht aufgelöst werden konnte (Fehler 404/500).

      Dies sagt Ihnen nicht, welche RewriteRule der Schuldige ist. Aber unzugängliche Endwege wie /docroot/21-.itle?index.phpkönnen verraten, wo weiter inspiziert werden soll. Deaktivieren Sie andernfalls die Regeln, bis Sie einige vorhersehbare Pfade erhalten.

    • Aktivieren Sie das RewriteLog

      Siehe Apache RewriteLog- Dokumente. Zum Debuggen können Sie es in den vhost-Abschnitten aktivieren:

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

      Dies ergibt eine detaillierte Zusammenfassung, wie eingehende Anforderungspfade durch jede Regel geändert werden:

      [..] 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'
      

      Dies hilft, übermäßig allgemeine Regeln und Regex-Pannen einzugrenzen.

      Siehe auch:
      · .htaccess funktioniert nicht (mod_rewrite)
      · Tipps zum Debuggen von .htaccess-Umschreiberegeln

    • Bevor Sie Ihre eigene Frage stellen

      Wie Sie vielleicht wissen, eignet sich Stack Overflow sehr gut, um Fragen zu mod_rewrite zu stellen. Machen Sie sie thematisch, indem Sie frühere Recherchen und Versuche einbeziehen (vermeiden Sie redundante Antworten), und demonstrieren Sie die Grundlagen verstehen und:

      • Fügen Sie vollständige Beispiele für Eingabe-URLs, falsch umgeschriebene Zielpfade und Ihre reale Verzeichnisstruktur hinzu.
      • Das komplette RewriteRule-Set, aber auch das vermutete defekte.
      • Apache- und PHP-Versionen, Betriebssystemtyp, Dateisystem, DOCUMENT_ROOT und PHP- $_SERVERUmgebung, wenn es sich um eine Parameterinkongruenz handelt.
      • Ein Auszug aus Ihrem access.logund um error.logzu überprüfen, wozu die bestehenden Regeln aufgelöst wurden. Besser noch eine rewrite.logZusammenfassung.

      Dies führt zu schnelleren und genaueren Antworten und macht sie für andere nützlicher.

  • Kommentieren Sie Ihre .htaccess

    Wenn Sie Beispiele von irgendwoher kopieren, achten Sie darauf, a einzuschließen # comment and origin link. Während es nur schlechte Manieren sind, die Zuschreibung wegzulassen, schadet es der Wartung später oft wirklich. Dokumentieren Sie jeden Code oder jede Tutorialquelle. Insbesondere wenn Sie nicht versiert sind, sollten Sie umso mehr daran interessiert sein, sie nicht wie magische Blackboxen zu behandeln.

  • Es ist nicht "SEO" -URLs

    Haftungsausschluss: Nur ein Haustier ärgern. Sie hören oft hübsche URL-Umschreibungsschemata, die als "SEO" -Links oder ähnliches bezeichnet werden. Dies ist zwar nützlich zum Googeln von Beispielen, aber eine datierte Fehlbezeichnung.

    Keine der modernen Suchmaschinen wird wirklich von .htmlund .phpin Pfadsegmenten oder ?id=123Abfragezeichenfolgen gestört . Alte Suchmaschinen wie AltaVista haben das Crawlen von Websites mit möglicherweise mehrdeutigen Zugriffspfaden vermieden. Moderne Crawler verlangen oft sogar nach tiefen Webressourcen.

    "Konzeptionell sollten" hübsche "URLs verwendet werden, um Websites benutzerfreundlich zu gestalten .

    1. Lesbare und offensichtliche Ressourcenschemata haben.
    2. Sicherstellen, dass URLs langlebig sind (AKA- Permalinks ).
    3. Auffindbarkeit durch /common/tree/nesting.

    Opfern Sie jedoch nicht die besonderen Anforderungen an den Konformismus.

Werkzeuge

Es gibt verschiedene Online-Tools zum Generieren von RewriteRules für die meisten GET-parametrischen URLs:

Meistens werden nur [^/]+generische Platzhalter ausgegeben , dies reicht jedoch wahrscheinlich für triviale Websites aus.

Mario
quelle
Muss noch ein bisschen umgeschrieben werden, mehr Links und die vielen Unterüberschriften sind etwas widerlich. Es gibt einige Überschneidungen mit den anderen Antworten hier, kann also vielleicht reduziert werden. Es geht jedoch hauptsächlich um die visuellen Beispiele und diese Liste gängiger Fallstricke.
Mario
3
Ich habe eine so schöne Antwort schon lange nicht mehr gesehen! Meine Augen leuchten, während ich es lese. Bitte hören Sie nicht auf, solche Antworten zu veröffentlichen :)
Rizier123
1
Ausgezeichnete Post. Ich habe die Grundkonzepte von mod_rewrite sehr schnell verstanden!
Breez
6

Alternativen zu mod_rewrite

Viele grundlegende virtuelle URL-Schemata können ohne Verwendung von RewriteRules erreicht werden. Mit Apache können PHP-Skripte ohne .phpErweiterung und mit einem virtuellen PATH_INFOArgument aufgerufen werden .

  1. Benutze den PATH_INFO , Luke

    Heutzutage AcceptPathInfo Onist oft standardmäßig aktiviert. Damit können .phpandere Ressourcen-URLs grundsätzlich ein virtuelles Argument enthalten:

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

    Dies /virtual/pathzeigt sich nun in PHP, $_SERVER["PATH_INFO"]wo Sie zusätzliche Argumente verarbeiten können, wie Sie möchten.

    Dies ist nicht so bequem wie Apache getrennte Eingangspfadsegmente aufweist , in $1, $2, $3und sie als deutliche vorbei $_GETVariablen PHP. Es emuliert lediglich "hübsche URLs" mit weniger Konfigurationsaufwand.

  2. Aktivieren Sie MultiViews , um die .phpErweiterung auszublenden

    Die einfachste Option, um auch .php"Dateierweiterungen" in URLs zu vermeiden, ist Folgendes:

    Options +MultiViews
    

    Dies hat Apache aufgrund des übereinstimmenden Basisnamens article.phpfür HTTP-Anforderungen ausgewählt /article. Und dies funktioniert gut zusammen mit der oben genannten PATH_INFO-Funktion. Sie können also einfach URLs wie verwenden http://example.com/article/virtual/title. Dies ist sinnvoll, wenn Sie eine herkömmliche Webanwendung mit mehreren PHP-Aufrufpunkten / Skripten haben.

    Beachten Sie, dass MultiViews einen anderen / umfassenderen Zweck haben. Dies führt zu einer sehr geringen Leistungseinbuße, da Apache immer nach anderen Dateien mit übereinstimmenden Basisnamen sucht. Es ist eigentlich für gemeint ' Content-Negotiation , so Browser die beste Alternative unter den zur Verfügung stehenden Ressourcen (wie erhalten article.en.php, article.fr.php, article.jp.mp4).

  3. SetType oder SetHandler für erweiterungslose .phpSkripte

    Ein gezielterer Ansatz, um das Mitführen von .phpSuffixen in URLs zu vermeiden, besteht darin , den PHP-Handler für andere Dateischemata zu konfigurieren . Die einfachste Option ist das Überschreiben des Standard-MIME / Handler-Typs über .htaccess:

    DefaultType application/x-httpd-php
    

    Auf diese Weise können Sie Ihr article.phpSkript einfach in "einfach" article(ohne Erweiterung) umbenennen und es dennoch als PHP-Skript verarbeiten lassen.

    Dies kann nun einige Auswirkungen auf Sicherheit und Leistung haben, da alle Dateien ohne Erweiterung jetzt über PHP geleitet werden. Daher können Sie dieses Verhalten alternativ nur für einzelne Dateien festlegen:

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

    Dies hängt etwas von Ihrem Server-Setup und der verwendeten PHP-SAPI ab. Übliche Alternativen sind ForceType application/x-httpd-phpoder AddHandler php5-script.

    Beachten Sie erneut, dass sich solche Einstellungen von einem .htaccessauf Unterordner übertragen. Sie sollten die Skriptausführung ( SetHandler Noneund / Options -Execoder php_flag engine offusw.) für statische Ressourcen und Uploads / Verzeichnisse usw. immer deaktivieren .

  4. Andere Apache-Umschreibeschemata

    Unter seinen zahlreichen Optionen bietet Apache mod_aliasFunktionen, die manchmal genauso gut mod_rewritefunktionieren wie die RewriteRules. Beachten Sie, dass die meisten davon in einem <VirtualHost>Abschnitt eingerichtet werden müssen, jedoch nicht in .htaccessKonfigurationsdateien pro Verzeichnis .

    • ScriptAliasMatchist in erster Linie für CGI-Skripte, sollte aber auch für PHP funktionieren. Es erlaubt Regexps wie jedes andere RewriteRule. Tatsächlich ist es vielleicht die robusteste Option, einen Catch-All-Front-Controller zu konfigurieren.

    • Und eine Ebene Aliashilft auch bei ein paar einfachen Umschreibungsschemata.

    • Sogar eine einfache ErrorDocumentAnweisung könnte verwendet werden, um ein PHP-Skript virtuelle Pfade verarbeiten zu lassen. Beachten Sie, dass dies eine klobige Problemumgehung ist, jedoch alles andere als GET-Anforderungen verbietet und das error.log per Definition überflutet.

    Weitere Tipps finden Sie unter http://httpd.apache.org/docs/2.2/urlmapping.html .

Mario
quelle