Dokumentacja Kursy i specyfikacje

mod_rewrite

Korzystanie z wyrażen regularnych

Potęga mod_rewrite'a wiąże się z możliwością tworzenia zaawansowanych wzorców składni. Im bardziej zawiłe przepisanie tym bardziej złożone będzie wyrażenie regularne. Dlatego też, aby w pełni korzystać z możliwości mod_rewrite, musisz opanować wyrażenia regularne. Poniżej znajdziesz kilka przykładów, które bazują na rozwiniętych wyrażeniach.

RewriteEngine On
RewriteRule ^sklep/([0-9][0-9])/$ sklep.php?id=$1

Pierwszy parametr to nasza maska. Mówi ona – sprawdzany ciąg znaków zaczyna się od "sklep/" i po nim występują dwie cyfry, np: "sklep/23/". Okrągłe nawiasy służą do grupowania. Tekst dopasowany w nawiasach może być przekazany jako parametr do docelowego adresu. Czyli w rezultacie działania tej reguły nastąpi przepisanie:

sklep/23/   ->   sklep.php?id=23

Parę słów rozwinięcia:

  • znaki ^ oraz $ informują o dopasowywaniu od początku do końca tekstu źródłowego. Jeśli je pominiemy,  wyrażenie regularne będzie szukać wystąpienia tekstu w dowolnym miejscu tekstu.  Przykładowo:

    tekst: /produkty/promocja/koszulka/czerwona
    maska:  ^/promocja/$
    wynik: błąd – nie znaleziono szukanej treści. Według naszej maski podany na wejściu tekst powinie zawierać tylko  "/promocja/" i nic więcej.

    tekst: /produkty/promocja/koszulka/czerwona
    maska: /promocja/
    wynik: sukces – w szukanym tekście występuje fraza "/promocja/".
  • [0-9] – znak z podanego zakresu znaków,
  • (...) - nawiasy te służą grupowaniu. Wartość wyrażenia dopasowania w nawiasach jest przekazywana jako parametr – można ją wypisać używając $1 do $9

Kolejny przykład:

RewriteEngine On
RewriteRule ^artykul/([a-zA-Z]+)/$ /wyswietl.php?artykul=$1

Jest on bardzo podobny do poprzedniego. Tym razem w masce dopasowania sprawdzamy, czy tekst zaczyna się od frazy "artykul/", po którym spodziewamy się tytułu artykułu. W tym celu użyliśmy grupowania zakresu małych i dużych liter. Znak plusa informuje, że może wystąpić jedna lub wiele liter. Oto przykłady: tekst: /artykul/MalyTytul/
wynik: /wyswietl.php?artykul=MalyTytul tekst: /artykul/123/
wynik: błąd dopasowania (tytuł artykułu nie zawiera liter) Nawiązując do przykładu z pierwszego rozdziału, możemy stworzyć już regułę, która zrealizuje to przepisanie. Przypomnijmy: tekst: http://moja-strona.home.pl/nowosci/3487
oczekiwany wynik: http://moja-strona.home.pl/wyswietl.php?id=3487

RewriteEngine On
RewriteRule ^nowosci/([0-9]+)$ /wyswietl.php?id=$1

Dodawanie kończącego slasha

Patrząc na te przykłady możesz powiedzieć – wszystko dobrze, tylko co w przypadku, kiedy użytkownik wpisze adres bez kończącego go slasha? Mam robić osobne reguły dla każdego przypadku? Nie musisz. Pamiętaj, że po każdym wykonanym przepisaniu strona jest wywoływana ponownie, z nowym URLem. I co się z wiąże, ponownie są przetwarzane reguły mod_rewrite. Rozbudujmy więc ostatni przykład:

RewriteEngine On
RewriteRule ^artykul/([a-zA-Z]+)$ /artykul/$1/ [R]
RewriteRule ^artykul/([a-zA-Z]+)/$ /wyswietl.php?artykul=$1

Co się stanie po wywołaniu adresu "/artykul/DuzyTytul" ?

  1. Zostanie wykonana pierwsza reguła, która zamieni adres na postać "/artyklul/DuzyTytul/" oraz wykona przekierowanie na tą stronę (o tym mówi flaga R).
  2. Nowy adres nie zostanie już dopasowany do pierwszej reguły, więc serwer spróbuje go dopasować do kolejnej reguły - co zakończy się sukcesem.

Niepoprawne reguły powodujące zapętlenia są najczęstszym błędem.

Jak ustrzec się przed zapętleniem reguł?

Przede wszystkim należy pamiętać, że po przepisaniu adresu, następuje ponowne wywołanie strony - już z nowym adresem. Wtedy również ponownie zostają wykonane reguły zapisane w pliku .htaccess. Należy więc tak konstruować reguły, aby nie zaszedł przypadek, kiedy raz przepisany adres jest przepisywany ponownie przez tą samą regułę. 

RewriteEngine On
RewriteRule  (.*)  /pokaz.php/$1

Pierwszy przebieg: tekst: artykuly/478
wynik: /pokaz.php/artykuly/478 Drugi przebieg: tekst: /pokaz.php/artykuly/478
wynik: /pokaz.php/pokaz.php/artykul478 Jak widać, reguła ta będzie wykonywać się w nieskończoność. Oto poprawiona wersja, która opiera się na sprawdzeniu, czy przepisywany adres nie zawiera kropki.

RewriteEngine On
RewriteRule  ^([^.]*)$  /pokaz.php/$1

Pierwszy przebieg wygląda podobnie jak w poprzednim przykładzie, natomiast drugi zwróci błąd, gdyż przepisywany tekst zawiera już kropkę. Dlaczego wymuszamy przepisanie tekstu który nie zawiera kropki? W normalnym przypadku kropka pojawia się tylko w nazwie pliku - w tym przypadku jest to pokaz.php. Inną metodą jest użycie RewriteCond w celu sprawdzenia, czy adres nie zawiera rzeczywistego katalogu i nazwy pliku - jeśli tak, oznacza to, że posiadamy już adres w ostatecznej postaci.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule  (.*) /pokaz.php/$1

Oba dopasowania RewriteCond sprawdzają zawartość wywołanego adresu - pierwsze sprawdza, czy adres nie prowadzi do pliku (parametr -f), natomiast drugie czy nie jest to katalog (parametr -d). Po pierwszym przebiegu i wykonaniu reguły zmianna REQUEST_FILENAME będzie zawierać już nazwę pliku tj. pokaz.php