Odniesienie: mod rewrite, przepisywanie URL i "ładne linki" wyjaśnione

"ładne linki" to często poszukiwany temat, ale rzadko jest w pełni wyjaśniony. mod_rewrite jest jednym ze sposobów na tworzenie "ładnych linków" , ale jest to skomplikowane i jego składnia jest bardzo zwięzła, trudna do wygrobienia, a dokumentacja zakłada pewien poziom biegłości w HTTP. Czy ktoś może wyjaśnić w prosty sposób, jak działają "ładne linki" i jak można wykorzystać mod_rewrite do ich tworzenia?

Inne popularne nazwy, aliasy, terminy dla czystych adresów URL: RESTful Url, User-friendly Url, SEO-friendly Url, Slugging, Adresy URL MVC (prawdopodobnie błędna nazwa)

Author: Taryn, 2013-12-13

4 answers

Aby zrozumieć, co robi mod_rewrite, musisz najpierw zrozumieć, jak działa serwer WWW. Serwer WWW odpowiada na żądania HTTP. Żądanie HTTP na jego najbardziej podstawowym poziomie wygląda tak:

GET /foo/bar.html HTTP/1.1

Jest to proste żądanie przeglądarki do serwera www z żądaniem adresu URL /foo/bar.html od tego. Ważne jest, aby podkreślić, że nie żąda pliku , żąda tylko jakiegoś arbitralnego adresu URL. Wniosek może również wyglądać następująco to:

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

Jest to tak samo ważne żądanie adresu URL i nie ma to oczywiście nic wspólnego z plikami.

Serwer WWW jest aplikacją nasłuchującą na porcie, akceptującą żądania HTTP przychodzące na ten port i zwracającą odpowiedź. Serwer WWW jest całkowicie darmowy, aby odpowiedzieć na każde żądanie w dowolny sposób, który uzna za odpowiedni/w jakikolwiek sposób skonfigurowałeś go, aby odpowiedzieć. Ta odpowiedź nie jest plikiem, jest to odpowiedź HTTP, która może, ale nie musi mieć nic wspólnego z pliki fizyczne na dowolnym dysku. Serwer WWW nie musi być Apache, istnieje wiele innych serwerów WWW, które są tylko programami, które działają uporczywie i są dołączone do portu, który odpowiada na żądania HTTP. Sam możesz napisać. Ten akapit miał na celu oderwanie Cię od wszelkich przekonań, że adresy URL są bezpośrednio równe plikom, co jest naprawdę ważne, aby zrozumieć. :)

Domyślną konfiguracją większości serwerów internetowych jest wyszukiwanie pliku pasującego do adresu URL na dysku twardym. Jeśli katalog głównydokumentu serwera jest ustawiony na, powiedzmy, /var/www, może sprawdzić, czy plik /var/www/foo/bar.html istnieje i służyć mu, jeśli tak. Jeśli plik kończy się na ".php " wywoła interpreter PHP i , a następnie zwróci wynik. Wszystkie te skojarzenia są w pełni konfigurowalne; plik nie musi kończyć się na ".php " aby serwer WWW mógł go uruchomić przez interpreter PHP, A adres URL nie musi pasować do żadnego konkretnego pliku na dysku, aby coś się stało.

Mod_rewrite jest sposobem na przepisać wewnętrzną obsługę żądań. Gdy serwer WWW otrzyma żądanie adresu URL /foo/bar, możesz przepisać ten adres URL do czegoś innego, zanim serwer WWW będzie szukał pliku na dysku, aby go dopasować. Prosty przykład:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

Ta reguła mówi gdy żądanie pasuje do "/ foo / bar", przepisz je na "/ foo / baz". żądanie zostanie potraktowane tak, jakby /foo/baz zamiast tego zostało poproszone. Może być stosowany do różnych efektów, dla przykład:

RewriteRule (.*) $1.html

Ta reguła pasuje do wszystkiego (.*) i przechwytuje to ((..)), a następnie przepisuje to, aby dołączyć ".html". Innymi słowy, jeśli /foo/bar był żądanym adresem URL, zostanie on potraktowany tak, jakby /foo/bar.html został poproszony. Zobacz http://regular-expressions.info aby uzyskać więcej informacji na temat dopasowywania, przechwytywania i zastępowania wyrażeń regularnych.

Inna często spotykana zasada jest taka:

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

To znowu pasuje do wszystkiego i przepisuje to na indeks plików.php z pierwotnie żądanym adresem URL dołączonym w parametrze zapytania url. Tzn. w przypadku wszelkich próśb prosimy o spis plików.php jest wykonywane i ten plik będzie miał dostęp do oryginalnego żądania w $_GET['url'], więc może z nim zrobić wszystko, co chce.

Przede wszystkim umieszczasz te reguły przepisywania w pliku konfiguracyjnym serwera www. Apache pozwala również * umieścić je w pliku o nazwie .htaccess wewnątrz katalogu głównego dokumentu (tj. obok Twojego .php plików).

* If dozwolone przez podstawowy plik konfiguracyjny Apache; jest opcjonalne, ale często włączone.

Co robi mod_rewrite a nie

Mod_rewrite nie magicznie sprawia, że wszystkie adresy URL są "ładne". To powszechne nieporozumienie. Jeśli masz ten link w swojej witrynie internetowej:

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

Nic mod_rewrite nie może zrobić, aby to było piękne. Aby zrobić z tego ładny link, musisz:

  1. Zmień link do ładnego linka:

    <a href="/my/pretty/link">
    
  2. Użyj mod_rewrite na serwerze, aby obsłużyć żądanie do adresu URL /my/pretty/link za pomocą jednej z metod opisanych powyżej.

(można by użyć mod_substitute w połączeniu do przekształcania wychodzących stron HTML i zawartych w nich linków. Chociaż jest to zwykle więcej wysiłku niż tylko aktualizacja zasobów HTML.)

Jest wiele możliwości mod_rewrite i bardzo złożonych reguł dopasowania, które możesz stworzyć, w tym łączenie kilku poprawek, proxy żądania do zupełnie innej usługi lub maszyny, zwracanie określonych kodów statusu HTTP jako odpowiedzi, przekierowywanie żądań itp. Jest bardzo potężny i może być używany do wielkiego dobra, jeśli rozumiesz podstawowy mechanizm odpowiedzi na żądania HTTP. To sprawia, że Nie automatycznie upiększa twoje linki.

Zobacz oficjalna dokumentacja dla wszystkich możliwych FLAG i opcji.

 90
Author: deceze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 16:03:30

Aby rozwinąć odpowiedź deceze , chciałem podać kilka przykładów i wyjaśnienie niektórych innych funkcji mod_rewrite.

Wszystkie poniższe przykłady zakładają, że w swoim pliku .htaccess umieściłeś już RewriteEngine On.

Przepisać Przykład

Weźmy ten przykład:

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

Reguła jest podzielona na 4 sekcje:

  1. RewriteRule - uruchamia regułę przepisywania
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ - to się nazywa wzór, jednak odnoszę się tylko do to jako lewa strona reguły-co chcesz przepisać z
  3. blog/index.php?id=$1&title=$2 - nazywa się podstawienie, lub prawa strona reguły przepisywania-co chcesz przepisać do
  4. [NC,L,QSA] są flagami reguły przepisywania, oddzielonymi przecinkiem, które wyjaśnię więcej w dalszej części

Powyższa przeróbka pozwoli Ci połączyć się z czymś takim jak /blog/1/foo/ i faktycznie załaduje się /blog/index.php?id=1&title=foo.

Lewa strona reguły

  • ^ wskazuje początek nazwy strony-więc przepisuje example.com/blog/..., ale nie example.com/foo/blog/...
  • każdy zbiór (…) nawiasów reprezentuje Wyrażenie regularne, które możemy uchwycić jako zmienną po prawej stronie reguły. W tym przykładzie:
    • pierwszy zestaw nawiasów - ([0-9]+) - pasuje do ciągu znaków o długości co najmniej 1 znaku i tylko z wartościami liczbowymi (np. 0-9). Można to odnieść do $1 po prawej stronie reguły
    • drugi zestaw nawiasów pasuje ciąg znaków o długości co najmniej 1 znaku, zawierający tylko znaki alfanumeryczne (A-Z, A-Z lub 0-9) lub - lub + (Uwaga {[24] } jest zabezpieczony odwrotnym ukośnikiem, ponieważ bez niego będzie to wykonywane jako znak powtarzania regex ). Można to odnieść do $2 po prawej stronie reguły
  • ? oznacza, że poprzedzający znak jest opcjonalny, więc w tym przypadku zarówno /blog/1/foo/, jak i /blog/1/foo przepisywałyby to samo miejsce
  • $ wskazuje, że jest to koniec łańcucha, który chcemy dopasować

Flagi

Są to opcje, które są dodawane w nawiasach kwadratowych na końcu reguły przepisywania, aby określić pewne warunki. Po raz kolejny, istnieje wiele różnych flag, które można przeczytać w dokumentacja , ale przejdę przez niektóre z bardziej popularnych FLAG:

NC

Znacznik no case oznacza, że reguła przepisywania jest niewrażliwa na wielkość liter, więc dla przykładowej reguły powyżej oznaczałoby to, że zarówno /blog/1/foo/, jak i /BLOG/1/foo/ (lub dowolna jego odmiana) byłyby dopasowane.

L

Ostatnia flaga wskazuje, że jest to ostatnia reguła, która powinna zostać przetworzona. Oznacza to, że wtedy i tylko wtedy, gdy ta reguła jest zgodna, żadne dalsze reguły nie będą oceniane podczas bieżącego przetwarzania przepisywania. Jeśli reguła nie pasuje, wszystkie inne reguły zostaną wypróbowane w kolejności jak zwykle. Jeśli nie ustawisz znacznika L, wszystkie poniższe reguły zostaną zastosowane do przepisanego adresu URL potem.

END

Od wersji Apache 2.4 można również używać flagi [END]. Reguła dopasowania z nią spowoduje całkowite zakończenie dalszego przetwarzania aliasów/przepisywania. (Podczas gdy znacznik [L] może często wywołać drugą rundę, na przykład podczas przepisywania do lub z podkatalogów.)

QSA

Znacznik append ciągu zapytania pozwala nam przekazać dodatkowe zmienne do podanego adresu URL, który zostanie dodany do oryginalnych parametrów get. Dla naszego przykładu oznacza to, że coś jak /blog/1/foo/?comments=15 załaduje /blog/index.php?id=1&title=foo&comments=15

R

Ta flaga nie jest tą, której użyłem w powyższym przykładzie, ale jest tą, o której myślę, że warto wspomnieć. Umożliwia to określenie przekierowania http z opcją włączenia kodu stanu (np. R=301). Na przykład, jeśli chcesz zrobić przekierowanie 301 na /myblog / to / blog/, po prostu napisz regułę coś takiego:

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

Przepisz Warunki

Warunki przepisywania sprawiają, że przepisywanie jest jeszcze bardziej wydajne, umożliwiając możesz określić poprawki dla bardziej konkretnych sytuacji. Istnieje wiele warunków, o których można przeczytać w dokumentacja , ale dotknę kilku typowych przykładów i wyjaśnię je:

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

Jest to bardzo powszechna praktyka, która rozszerzy Twoją domenę o www. (jeśli jeszcze jej nie ma) i wykona przekierowanie 301. Na przykład ładowanie http://example.com/blog/ przekierowałoby Cię do 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/$1 [L]

Jest to nieco mniej powszechne, ale jest dobrym przykładem reguły nie wykonuje się tego, jeśli nazwa pliku jest katalogiem lub plikiem istniejącym na serwerze.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] wykona przepisywanie tylko dla plików z rozszerzeniem jpg, jpeg, gif lub png (wielkość liter jest niewrażliwa).
  • %{REQUEST_FILENAME} !-f sprawdzi, czy plik istnieje na bieżącym serwerze i wykona przepisanie tylko wtedy, gdy nie
  • %{REQUEST_FILENAME} !-d sprawdzi, czy plik istnieje na bieżącym serwerze i wykona przepisanie tylko wtedy, gdy nie
  • przepisanie będzie próba załadowania tego samego pliku na inną domenę
 69
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:09

Referencje

Stack Overflow ma wiele innych wspaniałych zasobów na początek:

I regex przyjazny dla początkujących nawet:

Często używane placeholdery

  • .* pasuje do wszystkiego, nawet pustego łańcucha. Nie chcesz używać tego wzoru wszędzie, ale często w ostatniej zasadzie awaryjnej.
  • {[28] } jest częściej używany dla segmentów ścieżek. Pasuje do wszystkiego poza ukośnikiem.
  • \d+ pasuje Tylko do ciągów liczbowych.
  • \w+ pasuje do znaków alfanumerycznych. To skrót od [A-Za-z0-9_].
  • [\w\-]+ dla "slug" -segmenty ścieżki stylu, z użyciem liter, cyfr, kreski - i _
  • [\w\-.,]+ dodaje kropki i przecinki. Preferuje ucieczkę \- w znakach […].
  • \. oznacza dosłowny okres. W przeciwnym wypadku . poza […] jest symbolem zastępczym dla dowolnego symbolu.

Każdy z tych elementów zastępczych jest zwykle zawinięty w (…) nawiasy jako grupa przechwytywania. I cały wzór często w znacznikach ^………$ początek + koniec. Cytowanie "wzorców" jest opcjonalnie.

RewriteRules

Poniższe przykłady są zorientowane na PHP i nieco bardziej przyrostowe, łatwiejsze do dostosowania do podobnych przypadków. Są to tylko podsumowania, często link do większej ilości wariantów lub szczegółowych pytań i odpowiedzi.

  • Mapowanie statyczne
    /contact, /about

    Skrócenie kilku nazw stron do wewnętrznych schematów plików jest najprostsze:

     RewriteRule ^contact$  templ/contact.html
     RewriteRule ^about$    about.php
    
  • Identyfikatory numeryczne
    /object/123

    Wprowadzenie skrótów takich jak http://example.com/article/531 do istniejących skryptów PHP jest również łatwe. Liczba może być po prostu zamieniona na parametr $_GET:

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

    Możesz łatwo rozszerzyć tę regułę, aby zezwolić na /article/title-string placeholdery:
     RewriteRule ^article/([\w-]+)$    article-show.php?title=$1
     #                       └────────────────────────────────┘
    

    Zauważ, że Twój skrypt musi być w stanie (lub dostosować) mapować te tytuły z powrotem do database-ids. Sam Rewriter nie potrafi tworzyć ani odgadywać informacji z powietrza.

  • Ślimaki z przedrostkami numerycznymi
    /readable/123-plus-title

    Dlatego często zobaczysz mieszane /article/529-title-slug ścieżki używane w praktyce:

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

    Teraz możesz po prostu pominąć przekazywanie title=$2 tak czy siak, ponieważ twój skrypt i tak będzie bazował na database-id. -title-slug stał się arbitralną dekoracją URL.

  • Jednorodność z listami alternatywnymi
    /foo/… /bar/… /baz/…

    Jeśli masz podobne reguły dla wielu ścieżek stron wirtualnych, możesz dopasować i skompaktować je z | listami alternatywnymi. I ponownie po prostu przypisać je do wewnętrznych parametrów GET:

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

    Możesz podzielić je na pojedyncze RewriteRule jeśli to będzie zbyt skomplikowane.

  • Wysyłanie powiązanych adresów URL do różnych backendów
    /date/SWITCH/backend

    A więcej praktycznym zastosowaniem list alternatywnych jest mapowanie ścieżek żądań do odrębnych skryptów. Na przykład, aby zapewnić jednolite adresy URL dla starszej i nowszej aplikacji internetowej na podstawie dat:

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

    To po prostu remaps 2009-2011 posty na jednym skrypcie, a wszystkie inne lata pośrednio do innego Handlera. Zwróć uwagę na bardziej szczegółową regułę, która pojawi się najpierw . Każdy skrypt może używać różnych GET params.

  • Inne ograniczniki niż tylko / ukośniki ścieżek
    /user-123-name

    Najczęściej widzisz RewriteRules do symulacji wirtualnej struktury katalogów. Ale nie jesteś zmuszany do bycia nierzeczywistym. Możesz również użyć myślników - do segmentacji lub struktury.

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

    Dla również wspólnych /wiki:section:Page_Name schemat:

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

    Czasami w tej samej regule jest odpowiednie, aby na przemian między /-ogranicznikami i : lub .. Lub mieć dwa RewriteRules ponownie mapować warianty na różne Skrypty.

  • Opcjonalny trailing / slash
    /dir = /dir/

    Wybierając ścieżki w stylu katalogów, możesz uczynić je osiągalnymi z i bez końcowego /

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

    Teraz to obsługuje zarówno http://example.com/blog/123 jak i /blog/123/. Oraz /?$ podejście jest łatwe do dodania do dowolnego innego RewriteRule.

  • Elastyczne segmenty dla ścieżek wirtualnych
    .*/.*/.*/.*

    Większość reguł, które napotkasz, mapuje ograniczony zestaw segmentów ścieżki zasobów do poszczególnych parametrów GET. Niektóre skrypty obsługują jednak zmienną liczbę opcji . Silnik wyrażeń regularnych Apache nie pozwala na wybór dowolnej liczby z nich. Ale możesz łatwo rozszerzyć go na blok reguł:

     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
     #              └─────┴─────┴───────────────────┴────┴────┘
    

    Jeśli potrzebujesz do pięciu segmentów ścieżki, skopiuj ten schemat do pięciu reguł. Można oczywiście użyć bardziej szczegółowe [^/]+ placeholder każdy. Tutaj kolejność nie jest tak ważna, jak żadne się nie nakładają. Więc posiadanie najczęściej używanych ścieżek jest w porządku.

    Alternatywnie możesz użyć parametrów tablicy PHPS poprzez ?p[]=$1&p[]=$2&p[]=3 query string tutaj-jeśli twój skrypt tylko preferuje ich wstępnie podzielony. (Chociaż częściej używa się reguły catch-all i pozwala samemu skryptowi rozwinąć segmenty z REQUEST_URI.)

    Zobacz także: jak przekształcić segmenty ścieżki URL w Zapytanie ciąg pary klucz-wartość?

  • Opcjonalne segmenty
    prefix/opt?/.*

    Powszechną odmianą jest posiadanie opcjonalnych przedrostków w ramach reguły. Zwykle ma to sens, jeśli masz statyczne ciągi lub więcej ograniczonych elementów zastępczych wokół:

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

    Teraz bardziej skomplikowany wzór (?:/([^/])+)? tam po prostu zawija nie przechwytywanie (?:…) grupa, i czyni go opcjonalnym )?. Zawarte placeholder ([^/]+) będzie wzorzec podstawienia $2, ale być pusty, jeśli nie ma Środkowej ścieżki /…/.

  • Uchwyć resztę
    /prefix/123-capture/…/*/…whatever…

    Jak wspomniano wcześniej, nie często chcesz zbyt ogólnych wzorców przepisywania. Czasami jednak sensowne jest łączenie statycznych i specyficznych porównań z .*.

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

    Ta opcja umożliwia dowolne /…/…/… segmenty ścieżki. Co oczywiście wymaga, aby skrypt obsługi je rozdzielił, a variabl-ify wyodrębnione parametry siebie (czyli to, co robi Web-"MVC" Framework).

  • Following file "rozszerzenia"
    /old/path.HTML

    Adresy URL tak naprawdę nie mają rozszerzeń plików. O to właśnie chodzi w tym całym odwołaniu (=adresy URL są wirtualnymi lokalizatorami, niekoniecznie bezpośrednim obrazem systemu plików). Jeśli jednak wcześniej mapowałeś plik 1:1, możesz stworzyć prostsze zasady:

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

    Inne powszechne zastosowania czy przemapowanie przestarzałych ścieżek .html do nowszych programów obsługi .php, lub po prostu aliasowanie nazw katalogów tylko dla pojedynczych (rzeczywistych/rzeczywistych) plików.

  • Ping-Pong (przekierowuje i przepisuje w unisonie)
    /ugly.html ←→ /pretty

    Więc w pewnym momencie przepisujesz swoje strony HTML, aby zawierały tylko ładne linki, jak zarysował deceze. W międzyczasie nadal będziesz otrzymywać zapytania o stare ścieżki, czasami nawet z zakładek. Jako obejście , możesz wyświetlać/ustanawiać przeglądarki nowe adresy URL.

    Ta wspólna sztuczka polega na wysyłaniu przekierowania 30x/lokalizacja , gdy przychodzący adres URL podąża za przestarzałym/brzydkim schematem nazewnictwa. Przeglądarki będą następnie rerequest nowy/ładny URL, który następnie jest przepisywany (tylko wewnętrznie) do oryginalnej lub nowej lokalizacji.

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

    Zauważ, jak ten przykład po prostu używa [END] zamiast [L] do bezpiecznego zastępowania. Na starsze wersje Apache 2.2 Można używać innych obejść, oprócz remapowania zapytanie parametry ciągu na przykład: przekierowanie ugly do pretty URL, zremapowanie z powrotem do ugly path, bez nieskończonych pętli

  • Spacje we wzorach
    /this+that+

    To nie jest tak ładne w paskach adresów przeglądarki, ale można używać spacji w adresach URL. Do przepisywania wzorców należy użyć spacji odwrotnego ukośnika-ucieczki \␣. Else just " - quote the cały wzór lub podstawienie:

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

    Klienci serializują adresy URL za pomocą + lub %20 dla spacji. Jednak w RewriteRules są one interpretowane literalnymi znakami dla wszystkich względnych segmentów ścieżki.

częste duplikaty:

.htaccess pułapki

Weź to z przymrużeniem oka. Nie każda porada może być uogólniona do wszystkich kontekstów. To tylko proste podsumowanie znanych i kilku nieoczywistych potknięć bloki:
  • Włącz mod_rewrite i .htaccess

    Aby faktycznie używać RewriteRules w plikach konfiguracyjnych dla poszczególnych katalogów, musisz:

    • Sprawdź czy twój serwer ma AllowOverride All włączone . W przeciwnym razie dyrektywy per-directory .htaccess zostaną zignorowane, a RewriteRules nie będą działać.

    • Oczywiście mieć mod_rewrite włączone w sekcji httpd.conf Moduły.

    • Przedpisz każdą listę reguł z RewriteEngine On nadal. Podczas gdy mod_rewrite jest domyślnie aktywny w sekcjach <VirtualHost> i <Directory> , pliki per-directory .htaccess wymagają indywidualnego wezwania.

  • Czołowy ukośnik ^/ nie pasuje

    Nie powinieneś zaczynać .htaccess przepisywania wzorców z ^/ normalnie:

     RewriteRule ^/article/\d+$  …
                  ↑
    

    Jest to często widoczne w starych samouczkach. I to było poprawne dla ancient Apache 1.wersje X. Obecnie ścieżki żądania są wygodnie w pełni katalog-względny in .htaccess RewriteRules. Po prostu zostaw główną /.

    · zauważ, że główny Ukośnik jest nadal poprawny w sekcjach <VirtualHost>. Dlatego często widzisz to ^/? opcjonalnie dla parytetu reguły.
    * Lub gdy używasz RewriteCond %{REQUEST_URI} nadal pasowałbyś do wiodącego /.
    * Zobacz też Webmaster.SE: kiedy jest potrzebny ukośnik wiodący ( / ) we wzorcach mod_rewrite?

  • <IfModule *> owijki odejdź!

    Prawdopodobnie widziałeś to w wielu przykładach:

    <IfModule mod_rewrite.c>
       Rewrite… 
    </IfModule>
    
    • to ma sens w <VirtualHost> sekcjach - jeśli została połączona z inną opcją awaryjną, taką jak ScriptAliasMatch. (Ale nikt nigdy tego nie robi).
    • i jest powszechnie rozpowszechniany dla domyślnych .htaccess zestawów reguł z wieloma projektami open source. Tam jest po prostu oznaczony jako awaryjny i utrzymuje "brzydkie" adresy URL jako domyślne.

    Jakkolwiek ty nie chcesz to zazwyczaj w twoich własnych plikach .htaccess.

    • po pierwsze, mod_rewrite nie wyłącza się losowo. (Gdyby tak było, mielibyście większe problemy).
    • gdyby naprawdę był wyłączony, Twój Rewriter i tak by nie zadziałał.
    • ma na celu zapobieganie błędom HTTP 500. To, co zwykle osiąga, to zaszczycenie użytkowników błędami HTTP 404. (Nie tyle bardziej przyjazne dla użytkownika, jeśli się nad tym zastanowić.)
    • praktycznie to tylko wyłącza bardziej użyteczne wpisy dziennika lub wiadomości z powiadomieniami serwera. Byłabyś nie mądrzejsza dlaczego Twoje Przepisywacze nigdy nie działają.
    To, co wydaje się kuszące jako uogólnione zabezpieczenie, często okazuje się w praktyce przeszkodą.
  • Nie używaj RewriteBase chyba że jest to konieczne

    Wiele przykładów kopiuj + wklej zawiera dyrektywę RewriteBase /. Co i tak jest domyślną wartością domyślną. Więc nie potrzebujesz tego. On obejście dla fantazyjnych schematów przepisywania VirtualHost i błędnych ścieżek DOCUMENT_ROOT dla niektórych współdzielonych hosterów.

    Sensowne jest używanie poszczególnych aplikacji internetowych w głębszych podkatalogach. W takich przypadkach może skrócić wzorce RewriteRule. Ogólnie najlepiej jest preferować względne specyfikatory ścieżek w zestawach reguł dla poszczególnych katalogów.

    Zobacz także jak działa RewriteBase .htaccess

  • Wyłączanie MultiViews gdy ścieżki wirtualne nakładka

    Przepisywanie adresów URL jest używane głównie do obsługi wirtualnych ścieżek przychodzących. Zazwyczaj masz tylko jeden skrypt dyspozytora (index.php) lub kilka indywidualnych programów obsługi (articles.php, blog.php, wiki.php, ...). Ten ostatni może kolidować z podobnymi wirtualnymi ścieżkami zapisu.

    Żądanie dla /article/123 może na przykład mapować do article.php z /123 path_info w domyśle. Albo będziesz musiał strzec swoich zasad, wtedy z pospolitym RewriteCond !-f+!-d, i / lub wyłączyć obsługę PATH_INFO, a może po prostu wyłączyć Options -MultiViews.

    Co nie znaczy, że zawsze musisz . Negocjacja treści jest tylko automatyzmem dla zasobów wirtualnych.

  • Porządkowanie jest ważne

    Zobacz wszystko, co chcieliście wiedzieć o mod_rewrite jeśli jeszcze tego nie zrobiłeś. Łączenie wielu RewriteRules często prowadzi do interakcji. To nie jest coś, aby zapobiec zwyczajowo na [L] flaga, ale schemat uściśniesz raz zorientowanego. Możesz zapisywać wirtualne ścieżki z jednej reguły do drugiej, dopóki nie osiągnie ona rzeczywistego mechanizmu obsługi celu.

    Nadal będziesz często chcieć mieć najbardziej szczegółowe reguły (stały ciąg /forum/… wzorce, lub bardziej restrykcyjne placeholdery [^/.]+) w wczesnych regułach. Ogólne slurp-wszystkie zasady (.*) lepiej zostawić później. (Wyjątkiem jest RewriteCond -f/-d strażnik jako główny blok.)

  • Arkusze stylów i obrazy przestają działać

    Kiedy wprowadzasz struktury wirtualnych katalogów {[150] } wpływa to na względne odwołania do zasobów w HTML(takie jak <img src=mouse.png>). Które można rozwiązać poprzez:

    • tylko przy użyciu referencji server-absolute href="/old.html" lub src="/logo.png"
    • często po prostu dodając <base href="/index"> do sekcji HTML <head>. To w sposób dorozumiany odtwarza względne odniesienia do tego, czym były wcześniej.

    You could alternatywnie wykonaj dalsze Przepisywarki, aby ponownie znaleźć .css lub .png ścieżki do ich oryginalnych lokalizacji. Ale to jest zarówno niepotrzebne, lub powoduje dodatkowe przekierowania i utrudnia buforowanie.

    Zobacz także: CSS, JS i obrazy nie wyświetlają się z ładnym adresem url

  • RewriteConds mask one RewriteRule

    Powszechną błędną interpretacją jest to, że RewriteCond blokuje wiele RewriteRules (ponieważ są one wizualnie rozmieszczone razem):

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

    Które domyślnie nie działa. Możesz połączyć je używając flagi [S=2]. Inaczej będziesz musiał je powtórzyć. Chociaż czasami można stworzyć" odwróconą " podstawową regułę, aby [zakończyć] przetwarzanie przepisywania wcześnie.

  • QUERY_STRING]}

    Nie można dopasować RewriteRule index.php\?x=y, ponieważ mod_rewrite porównuje tylko ścieżki względne domyślnie. Można je jednak dopasować osobno poprzez:

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

    Zobacz również Jak mogę dopasować zmienne ciągu zapytania z mod_rewrite?

  • .htaccess vs. <VirtualHost>

    Jeśli używasz RewriteRules w pliku konfiguracyjnym dla poszczególnych katalogów, to martwienie się o wydajność wyrażeń regularnych jest bezcelowe. Apache zachowuje skompilowane wzorce PCRE dłuższe niż proces PHP ze wspólnym frameworkiem routingu. W przypadku witryn o dużym natężeniu ruchu należy jednak wziąć pod uwagę przenoszenie zestawów reguł do konfiguracji serwera vhost, po ich sprawdzone w walce.

    W tym przypadku preferuj opcjonalny prefiks separatora katalogów ^/?. Pozwala to na swobodne przenoszenie RewriteRules pomiędzy PerDir a serwerem pliki konfiguracyjne.

  • Kiedy coś nie działa

    Nie martw się.
    • Porównaj access.log i error.log

      Często można dowiedzieć się, jak przepisujący źle się zachowuje, patrząc na twoje error.log i access.log. Skoreluj czasy dostępu aby zobaczyć, która ścieżka żądania została pierwotnie wprowadzona i której ścieżki / pliku Apache nie mógł rozwiązać (błąd 404/500).

      To nie mówi, który RewriteRule jest winowajcą. Ale niedostępne ścieżki końcowe, takie jak {167]}, mogą zdradzić, gdzie można je dalej sprawdzić. W przeciwnym razie wyłącz reguły, dopóki nie uzyskasz przewidywalnych ścieżek.

    • Włącz przepisywanie tekstu

      Zobacz Apache RewriteLog docs. Do debugowania można go włączyć w vhost sekcje:

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

      Daje to szczegółowe podsumowanie sposobu modyfikowania ścieżek przychodzących żądań przez każdą regułę:

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

      Który pomaga zawęzić zbyt ogólne reguły i wyrażenia regularne.

      Zobacz też:
      · .htaccess nie działa (mod_rewrite)
      * Wskazówki dotyczące debugowania .htaccess rewrite rules

    • Zanim zadasz własne pytanie

      Jak zapewne wiesz, przepełnienie stosu jest bardzo nadaje się do zadawania pytań na mod_rewrite. Zrób je on-topic w tym wcześniejszych badań i prób (uniknąć zbędnych odpowiedzi), wykazać podstawowe regex {190]} zrozumienie i:

      • Dołącz pełne przykłady wejściowych adresów URL, fałszywie przepisanych ścieżek docelowych, prawdziwej struktury katalogów.
      • kompletny zestaw RewriteRule, ale również wyodrębnij domniemaną wadliwą.
      • wersje Apache i PHP, Typ OS, system plików, DOCUMENT_ROOT i środowisko PHPs $_SERVER, jeśli chodzi o niedopasowanie parametrów.
      • fragment twojego access.log i error.log, aby zweryfikować, do czego służą istniejące zasady. Jeszcze lepiej, rewrite.log podsumowanie.

      To daje szybsze i dokładniejsze odpowiedzi i czyni je bardziej użytecznymi dla innych.

  • Skomentuj swój .htaccess

    Jeśli skopiujesz skądś przykłady, zadbaj o to, aby dołączyć # comment and origin link. Choć to tylko złe maniery, aby pominąć przypisywanie, to często naprawdę boli konserwacji później. Udokumentuj dowolny kod lub źródło samouczka. W szczególności, podczas gdy nieweryfikowalne należy tym bardziej zainteresowani nie traktowaniem ich jak magicznych czarnych skrzynek.

  • To nie"SEO" -adresy URL

    Zastrzeżenie: tylko pet peeve. często słyszysz ładne Schematy przepisywania adresów URL określane jako linki "SEO" lub coś w tym stylu. Chociaż jest to przydatne do googlowania przykładów, jest to data błędna nazwa.

    Żadna z nowoczesnych wyszukiwarek nie jest tak naprawdę niepokojona przez .html i .php w segmentach ścieżek, lub ?id=123 ciągi zapytań o to. Wyszukiwarki starych, takich jak AltaVista, czy uniknąć indeksowania stron internetowych z potencjalnie niejednoznacznych ścieżek dostępu. Współczesne crawlery często pragną nawet głębokich zasobów internetowych.

    Do tworzenia stron internetowych należy używać" ładnych " adresów URL przyjazny dla użytkownika.

    1. mając czytelne i oczywiste Schematy zasobów.
    2. zapewnienie, że adresy URL są długotrwałe (AKA permalinks).
    3. zapewnienie możliwości wykrycia przez /common/tree/nesting.

    Nie rezygnuj jednak z unikalnych wymagań dla konformizmu.

Narzędzia

Istnieją różne narzędzia online do generowania RewriteRules dla większości get-parameterish Url:

W większości tylko wyjście [^/]+ ogólne placeholdery, ale prawdopodobnie wystarcza na banalne strony.

 35
Author: mario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:30

Alternatywy dla mod_rewrite

Wiele podstawowych wirtualnych schematów URL można osiągnąć bez użycia RewriteRules. Apache umożliwia wywoływanie skryptów PHP bez rozszerzenia .php i z wirtualnym argumentem PATH_INFO.

  1. Użyj PATH_INFO , Luke

    Obecnie AcceptPathInfo On często jest domyślnie włączona. W przeciwieństwie do innych adresów URL, nie można używać wirtualnego argumentu.]}

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

    Teraz to /virtual/path pojawia się w PHP jako $_SERVER["PATH_INFO"] gdzie możesz poradzić sobie z dowolnymi dodatkowymi argumentami, jak chcesz.

    Nie jest to tak wygodne, jak posiadanie oddzielnych segmentów ścieżki wejściowej Apache do $1, $2, $3 i przekazywanie ich jako odrębnych zmiennych $_GET do PHP. Po prostu emuluje "ładne adresy URL" przy mniejszym wysiłku konfiguracji.

  2. Włącz MultiViews aby ukryć rozszerzenie .php

    Najprostszą opcją, aby również unikać .php "rozszerzeń plików" w adresach URL jest enabling:

    Options +MultiViews
    

    To ma Apache select article.php dla żądań HTTP na /article ze względu na pasującą nazwę bazową. I to działa dobrze razem z wyżej wymienioną funkcją PATH_INFO. Więc możesz po prostu używać adresów URL, takich jak http://example.com/article/virtual/title. Co ma sens, jeśli masz tradycyjną aplikację internetową z wieloma punktami wywoływania/skryptami PHP.

    Zauważ, że MultiViews ma inny / szerszy cel. Wiąże się to z bardzo drobną karą za wydajność, ponieważ Apache zawsze szuka inne pliki o pasujących nazwach podstawowych. W rzeczywistości jest przeznaczony do content-Negotiation, więc przeglądarki otrzymują najlepszą alternatywę wśród dostępnych zasobów (takich jak article.en.php, article.fr.php, article.jp.mp4).

  3. SetType lub SetHandler dla skryptów bez rozszerzeń .php

    Bardziej ukierunkowanym podejściem, aby uniknąć przenoszenia przyrostków .php w adresach URL, jest konfiguracja obsługi PHP dla innych schematów plików. Najprostszą opcją jest nadpisanie domyślnego typu MIME/handler poprzez .htaccess:

    DefaultType application/x-httpd-php
    

    W ten sposób możesz po prostu zmienić nazwę skryptu article.php NA just article (bez rozszerzenia), ale nadal przetwarzać go jako skrypt PHP.

    Teraz może to mieć wpływ na bezpieczeństwo i wydajność, ponieważ wszystkie pliki bez rozszerzeń byłyby teraz przesyłane przez PHP. Dlatego można alternatywnie ustawić to zachowanie tylko dla pojedynczych plików:

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

    Jest to w pewnym stopniu zależne od konfiguracji serwera i używanego PHP SAPI. Typowe alternatywy obejmują ForceType application/x-httpd-php lub AddHandler php5-script.

    Ponownie zwróć uwagę, że takie ustawienia propagują się z jednego .htaccess do podfolderów. Zawsze należy wyłączyć wykonywanie skryptu (SetHandler None i Options -Exec lub php_flag engine off itd.) dla zasobów statycznych, oraz upload / katalogów itp.

  4. Inne programy przepisywania Apache

    Wśród wielu opcji, Apache zapewnia mod_alias funkcje - które czasami działają tak samo dobrze jak RewriteRules mod_rewrite. Należy pamiętać, że większość z nich musi być ustawiona w sekcji <VirtualHost> jednak nie w plikach konfiguracyjnych per-directory .htaccess.

    • ScriptAliasMatch jest przede wszystkim dla skryptów CGI, ale także powinien działać dla PHP. Pozwala na wyrażenie regularne tak jak każdy RewriteRule. W rzeczywistości jest to prawdopodobnie najbardziej solidna Opcja konfiguracji kontrolera przedniego catch-all.

    • I Równina Alias pomaga również w kilku prostych schematach przepisywania.

    • Nawet zwykły ErrorDocument dyrektywa może być użyta, aby skrypt PHP obsługuje ścieżki wirtualne. Zauważ, że jest to jednak kłopotliwe obejście, zabrania niczego poza żądaniami GET i zalewa błąd.dziennik z definicji.

    Zobacz http://httpd.apache.org/docs/2.2/urlmapping.html dla dalszych wskazówek.

 5
Author: mario,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:36