Dla pozycjonera mod_rewrite jest jednym z najważniejszych modłów serwera Apache w drodze do szczytowych pozycji. Umożliwia między innymi operacje na zmiennych środowiskowych, zmiennych serwera, nagłówkach HTTP jeszcze przed wczytaniem właściwej strony.
„Welcome to mod_rewrite, the Swiss Army Knife of URL manipulation! ”
http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html
Do czego może służyć moduł mod_rewrite?
- a) do stworzenia łatwych w zapamiętaniu linków
- rozpowszechnienie adresu wśród znajomych, linkowanie z innych stron
- do stworzenia zoptymalizowanych linków pod kątem SEO
- większe natężenie słów kluczowych w stosunku do długości adresu
- do intuicyjnej nawigacji w serwisie
- użytkownik widząc adres w pasku przeglądarki zyskuje wiedzę na temat treści podstrony oraz jej położenia w serwisie
- do poprawy bezpieczeństwa
- dzięki takim linkom zyskujemy ukrycie realnych odwołań w skrypcie a także możliwość wstępnego przefiltrowania danych wejściowych
- możemy filtrować także adresy ip, wartości USER_AGENT w celu zablokowania dostępu do strony niepożądanym osobom i robotom sieciowym
- do eliminacji duplicate content
- używając przekierowań możemy się pozbyć podstron zawierających tą samą treść
- do zmiany nazw generowanych dynamicznie obrazków i arkuszy css.
- do stworzenia własnych stron błędów
Powyższe zastosowania w realnym użyciu na przykładach.
Wstępnie załóżmy że dysponujemy ładnie graficzną, bogatą w treść stronę internetową opierającą swoją nawigację na tradycyjnych odwołaniach metodą GET o następujących schematach linków:
http://example.com/index.php?kataegoria=warszawa
http://example.com/index.php?kataegoria=warszawa&podkategoria=mieszkania
http://example.com/index.php?kataegoria=warszawa&podkategoria=mieszkania&art=ceny
http://example.com/index.php?kataegoria=warszawa&podkategoria=mieszkania&art=ceny&st=4
Tworząc reguły przepisywania w pliku .htaccess kierujemy się przeważnie zasadą "od największego do najmniejszego" czyli tak aby przetwarzać najpierw adresy zawierające najwięcej zmiennych GET. Tworząc nowy format linków musimy także odzwierciedlić to w naszym skrypcie.
Przykład pliku .htaccess
RewriteEngine On
# włączenie przepisywania linków
RewriteBase /
# niezbędne kiedy umieszczamy plik .htaccess w podkatalogach naszej domeny
RewriteRule ^/?([a-z]*)/([a-z]*)/([a-z]*)/([0-9]*)/$ index.php?kataegoria=$1&podkategoria=$2&art=$3&st=$4 [NC,L]
RewriteRule ^/?([a-z]*)/([a-z]*)/([a-z]*)/$ index.php?kataegoria=$1&podkategoria=$2&art=$3 [NC,L]
RewriteRule ^/?([a-z]*)/([a-z]*)/$ index.php?kataegoria=$1&podkategoria=$2 [NC,L]
RewriteRule ^/?([a-z]*)/$ index.php?kataegoria=$1 [NC,L]
# poniżej szersze wyjaśnienie reguł
# powinniśmy zawsze zostawiać pustą linię na końcu pliku .htaccess
Od kiedy umieścimy taki plik na serwerze możemy się odwoływać do naszej strony za pomocą następujących linków:
http://example.com/warszawa/
http://example.com/warszawa/mieszkania/
http://example.com/warszawa/mieszkania/ceny/
http://example.com/warszawa/mieszkania/ceny/4/
Pozostaje jeszcze wprowadzenie odpowiednich zmian w skrypcie (na przykład w menu) tak aby wyświetlane linki miały żądany format.
Przykład dla adresu
http://example.com/warszawa/mieszkania/ceny/4/:
<a href="<?echo '/'.$miasto.'/'.$nieruchomosc.'/'.$artykul.'/'.$id.'/'?>">Anchor</a>
Wyjaśnienie dyrektyw i reguł przepisywania.
RewriteEngine - włączenie przepisywania linków
RewriteBase - położenie pliku względem DOCUMENT_ROOT
RewriteRule - przepisywanie REQUEST_URI za pomocą podanego wzorca do podzapytania wewnętrznego
^/?([a-z]*)/([a-z]*)/$ - wzorzec do którego jest dopasowywane REQUEST_URI , zawarcie wyrażenia pomiędzy ^$ oznacza dopasowywanie całości REQUEST_URI, poszczególne części są przechwytywane przez podwyrażenia zawarte w nawiasach i przekazywane do kolejnych zmiennych $1, $2, $3, $4 $9 dzięki czemu możemy je umieścić w zapytaniu wewnętrznym
index.php?kataegoria=$1&podkategoria=$2 - zapytanie wewnętrzne, zrozumiałe przez serwer, zmienne $1 i $2 są zastępowane odpowiednimi przechwyconymi wartościami
[NC,L] - flagi, NC - wielkość liter przy dopasowywaniu REQUEST_URI nie ma znaczenia, L - last jeżeli nastąpi dopasowanie reguła zostanie wykonana jako ostatnia
[a-z]* - ciąg składający się z dowolnej ilości liter
[0-9]* - ciąg składający się z dowolnej ilości liczb
Leniwy użytkownik - przewidywanie błędów.
Często bywa tak że użytkownik zapomina o kończącym adres znaku "/" w przypadku realnych katalogów bez użycia mod_rewrite jest automatycznie dopisywany ale w naszym przypadku musimy zadbać o to sami dokładając kolejne reguły:
RewriteRule ^/?[a-z]*/[a-z]*$ /$0/ [R=301,L,NC]
RewriteRule ^/?([a-z]*)/([a-z]*)/$ index.php?kataegoria=$1&podkategoria=$2 [NC,L]
Taki schemat stosujemy także do pozostałych reguł, flaga R=301 oznacza przekierowanie 301 na odpowiednią podstronę.
Unikanie duplicate content na podstronach i subdomenach.
RewriteCond - służy do sprawdzania wartości zmiennej według podanego wzorca, jeżeli nastąpi dopasowanie zostanie wykonane RewriteRule występujące bezpośrednio po danym RewriteCond.
Powyższe reguły mają za zadanie sprawdzanie czy wywołany adres nie zawiera subdomeny www - jeżeli nie zawiera zostanie wykonane automatyczne przekierowanie na subdomenę www w przeciwnym wypadku takie przekierowanie zostanie pominięte. Druga reguła RewriteRule sprawdza czy nie został wywołany plik index.php, jeżeli tak to nastąpi
przekierowanie 301 na główny katalog domeny "/".
Dodatkowe dane.
Jeżli chcemy użyć dodatkowych danych w skrypcie możemy je przekazać za pomocą QUERY_STRING
np.:
http://example.com/warszawa/?dana=zmienna
-
RewriteCond %{QUERY_STRING} ^dana=([a-z]*)$ [NC]
RewriteRule ^/?([a-z]*)/([a-z]*)/$ index.php?kataegoria=$1&podkategoria=$2 [NC,L,QSA]
Zastosowanie takiego wpisu spowoduje doklejenie do wewnętrznego zapytania zmiennej dana jeżeli istnieje.
Dynamiczny css, dynamiczne obrazki.
http://example.com/warszawa10.jpeg
http://example.com/css10.css
RewriteRule ^/?style([0-9]*).css$ css.php?css=$1
RewriteRule ^/?token([0-9]*).jpeg$ image.php?id=$1
Powyższe reguły pozwalają na odwoływanie się do dynamicznie generowanych plików za pomocą "normalnych" nazw.
Realne pliki i katalogi a mod_rewrite.
RewriteCond %{REQUEST_FILNAME} !-d
RewriteCond %{REQUEST_FILNAME} !-f
Umieszczenie takich wyrażeń warunkowych przed regułą RewriteRule powoduje sprawdzenie czy nie następuje odwołanie do istniejącego pliku lub katalogu, w przypadku istnienia takiego pliku lub katalogu przepisywanie zostanie pominięte.
Niepożądani użytkownicy i roboty.
RewriteCond %{REMONTE_ADDR} ^12\.12\.12\.12$ [OR]
RewriteCond %{HTTP_USER_AGENT} yahoo [NC]
RewriteRule . error404.php [R,L]
Użycie takich warunków powoduje przeniesienie użytkownika o ip 12.12.12.12 lub user agent zawierającym ciąg "yahoo" na odpowiednią podstronę.
Własne strony błędów.
ErrorDocument 401 /error401.php
ErrorDocument 403 /error403.php
ErrorDocument 404 /error404.php
ErrorDocument 405 /error405.php
Dzięki takim wpisom możemy używać własnych odpowiednio przygotowanych stron błędów.
Ukrywanie rzeczywistych linków.
RewriteCond %{QUERY_STRING} kategoria=([a-z]*) [NC]
RewriteRule ^/?index.php$ /%1/? [R=301,L]
RewriteRule ^/?([a-z]*)/$ index.php?kataegoria=$1
Zastosowanie tego typu wpisu pozwala na ukrycie rzeczywistych linków w formacie ze zmiennymi typu GET.
Uwagi na temat stosowania mod_rewrite:
- używane wyrażenia regularne powinny być jak najbardziej ścisłe
- konfiguracja serwerów może się nieznacznie różnić, więc jednakowe reguły nie muszą koniecznie dziać na rożnych serwerach,
we wzorcach użyłem na początku "/?" co jest zbędne na większości serwerów
- przekierowania powinny się znajdować jak najbliżej początku pliku tak aby nie wykonywać zbędnych reguł
- własne strony błędów powinny zwracać odpowiednie nagłówki
- nie należy polegać na .htaccess jako metodzie zabezpieczania skryptów