Connect with us

Cześć, czego szukasz?

Internet Maker

Przyjazne adresy mod_rewrite

Przyjazne adresy URL wyglądają jak nazwy statycznych plików HTML, np. lorem.html, ipsum.html. W istocie są to odwołania do skryptów PHP, które bardzo często zawierają zmienne URL, np. index.php?id=13&tresc=artykul.

Artykuł opisuje, w jaki sposób przyjazne URL-e zaimplementować wykorzystując moduł serwera Apache mod_rewrite. Dodatkowo w otrzymanym rozwiązaniu adresy odwołujące się bezpośrednio do skryptów PHP zostają wyeliminowane. Jedynymi poprawnymi adresami są adresy przyjazne.

Instalacja modułu mod_rewrite

Instalacja modułu {stala}mod_rewrite{/stala} sprowadza się do zmian w konfiguracji serwera Apache. Instalowanie dodatkowych pakietów oprogramowania nie jest konieczne.

W pliku {stala}httpd.conf{/stala} zawartym w folderze {stala}c:\\Program files\\Apache Group\\Apache2\\conf{/stala} należy znaleźć dyrektywę {stala}Direcotry{/stala}:

Pomiędzy dwoma znacznikami {html}{/html} oraz {html}{/html} wprowadzamy dyrektywy:


   Options Indexes FollowSymLinks
   Order allow,deny
   Allow from all
   RewriteEngine on
   AllowOverride All

Ponadto w linijce:

#LoadModule rewrite_module modules/mod_rewrite.so

należy usunąć znak komentarza {stala}#{/stala}:

LoadModule rewrite_module modules/mod_rewrite.so

Ostatnim krokiem jest restart serwera Apache.

Przykład pierwszy: translacja adresu

Moduł {stala}mod_rewrite{/stala} wykonuje translacje adresów URL. Przeglądarka wysyła żądanie dotyczące pliku o nazwie adres.html. Moduł {stala}mod_rewrite{/stala} powoduje, że serwer Apache w odpowiedzi na żądanie o plik adres{stala}.html {/stala}wyśle plik {stala}index.php{/stala}. Na serwerze nie ma pliku o nazwie {stala}adres.html{/stala}.

Uruchomienie przykładu rozpoczynamy od przygotowania skryptu PHP o nazwie {stala}index.php{/stala}:


Witaj\';
?>

Jedynym zadaniem skryptu {stala}index.php{/stala} jest wydrukowanie komunikatu powitalnego.

Następnie w tym samym folderze tworzymy plik o nazwie {stala}.htaccess{/stala}. W pliku tym umieszczamy dwie dyrektywy konfiguracyjne {stala}RewriteEngine{/stala} oraz {stala}RewriteRule{/stala}:

RewriteEngine on
RewriteRule adres.html index.php

Pierwsza z nich włącza działanie modułu {stala}mod_rewrite{/stala}, a druga ustala wykonywaną translację. Podana reguła powoduje, że żądanie HTTP:

GET /adres.html HTTP/1.1

będzie obsługiwane identycznie, jak żądanie:

GET /index.php HTTP/1.1

W odpowiedzi na żądanie o plik index.html serwer Apache wyśle plik{stala} index.php {/stala}(dokładniej: kod HTML wygenerowany przez skrypt index.php).

W celu sprawdzenia działania powyższego rozwiązania należy uruchomić przeglądarkę i odnaleźć plik index.php. Ujrzymy wtedy stronę taką, jak na rys. 1.

Teraz w polu Adres przeglądarki wprowadzamy – w miejsce{stala} index.php{/stala} – nazwę pliku {stala}adres.html{/stala}. Przeglądarka wyświetli ten sam dokument, co poprzednio. Ilustruje to rys. 2.

Zwróćmy uwagę na dwa szczegóły. Po pierwsze plik {stala}.htaccess{/stala} nie jest widoczny w przeglądarce (rys. 3). Odpowiada za to wpis:


   Order allow,deny
   Deny from all

w pliku konfiguracyjnym serwera Apache {stala}httpd.conf{/stala}. Zauważymy, że ta sama strona WWW przedstawiona na rys. 1 oraz 2 jest dostępna pod dwoma różnymi adresami:{stala}index.php{/stala} oraz {stala}adres.htm{/stala}.

Wyrażenia regularne w dyrektywie RewriteRule

Dyrektywa {stala}RewriteRule{/stala} wykorzystuje wyrażenia regularne. W zapisie:

RewriteRule adres.html index.php

wyrażeniem regularnym jest nazwa pliku adres.html. Wyrażenie to będzie pasowało m.in. do adresów:

adres/html
adresXhtml
nowy/adres.html
nowy/adres/html
moj/nowy/adresXhtml
moj/nowy/adres-html/strona
moj/nowy/adres-html/strona/www

Po wpisaniu dowolnego z powyższych adresów w przeglądarce, ujrzymy stronę z rys. 1, co ilustruje rys. 4.

Adres wprowadzony w przeglądarce, np. {stala}nowy/adres/html{/stala}, jest dopasowywany do wyrażenia regularnego {stala}adres.html{/stala} podanego w dyrektywie {stala}Rewrite-Rule{/stala}. Ponieważ w wyrażeniu regularnym {stala}adres.html{/stala} kropka oznacza dowolny znak, więc fragment {stala}adres/html{/stala} pasuje do wyrażenia regularnego. W odpowiedzi na żądanie

GET /nowy/adres/html HTTP/1.1

Przykład drugi: dokładne dopasowanie nazwy pliku

Wyrażenie regularne{stala}adres.html{/stala} użyte w pierwszym przykładzie powoduje, że ta sama strona WWW jest dostępna pod nieskończoną liczbą adresów. Jeśli chcemy, by poprawnym adresem był wyłącznie napis {stala}adres.html{/stala}, należy użyć wyrażenia regularnego {stala}^adres\\.html${/stala}:

RewriteEngine on
RewriteRule ^adres\.html$ index.php

Przykład trzeci: wykluczanie adresu index.php

W celu wykluczenia adresu {stala}index.php{/stala} wykorzystujemy zmienną {stala}REQUEST_URI{/stala}, która jest dostępna wewnątrz skryptu PHP.

Plik {stala}.htacces{/stala} pozostawiamy niezmieniony:

RewriteEngine on
RewriteRule ^adres\.html$ index.php

zaś w pliku {stala}index.php{/stala} najpierw pobieramy zmienną {stala}REQUEST_URI{/stala}:

$adr = $_SERVER[\'REQUEST_URI\'];

Następnie usuwamy z niej wszelkie niedopuszczalne znaki:

$adr = preg_replace(
   \'/[^a-zA-Z0-9_\-\/.]/\',
   \'\',
   $adr
);

Po czym usuwamy nazwę folderu, w którym znajduje się skrypt:

$f = dirname($_SERVER[\'PHP_SELF\']) . \'/\';
$adr = preg_replace(
   \'/^\' . preg_quote($f, \'/\') . \'/\',
   \'\',
   $adr
);

Otrzymana zmienna {stala}$adr{/stala} zawiera adres, który został użyty do odwiedzenia strony. Na jej podstawie możemy wyświetlić treść lub komunikat o błędzie:

if ($adr == \'adres.html\') {
   echo \'

Witaj

\'; } else { echo \'Niepoprawny adres\'; }

W przykładzie tym jedynym poprawnym adresem jest {stala}adres.html{/stala}. W przypadku użycia adresu index.php (lub jakiegokolwiek adresu innego niż {stala}adres.html{/stala}) wyświetlany będzie komunikat Niepoprawny adres.

W wyrażeniu tym odwrócony ukośnik \ powoduje, że kropka ma znaczenie dosłowne (tzn. pasuje wyłącznie do kropki, a nie do dowolnego znaku), zaś kotwice ^ (początek wyrażenia) oraz $ (koniec wyrażenia) wykluczają dodanie czegokolwiek przed słowem adres lub po rozszerzeniu html.

W ten sposób strona będzie dostępna wyłącznie pod dwoma adresami {stala}adres.html{/stala} oraz {stala}index. php{/stala}. Ilustruje to rys. 5.

Przykład czwarty: ustalanie zmiennych URL

Adresy URL mogą zawierać zmienne, dołączone po znaku zapytania, np.:

index.php?imie=Jan&nazwisko=Nowak&wiek=57

W takim przypadku wyrażenie regularne użyte w dyrektywie {stala}RewriteRule{/stala} może stosować przechwytywanie. Jeśli w pliku {stala}.htaccess{/stala} umieścimy dyrektywę:

RewriteEngine on
RewriteRule ^adres-(.+)\.html$ index.php?id=

wówczas adres:

adres-lorem.html

będzie traktowany tak jak adres:

index.php?id=lorem

Podobnie adresy:

adres-a.html
adres-ipsum.html
adres-nieco-inny.html

zostaną potraktowane tak jak adresy:

index.php?id=a
index.php?id=ipsum
index.php?id=nieco-inny

Nawiasy okrągłe użyte w wyrażeniu:

^adres-(.+)\.html$

przechwytują dopasowany fragment. Fragment ten jest użyty w dalszej części dyrektywy {stala}RewriteRule{/stala} jako {stala}$1{/stala}:

index.php?id=

W skrypcie PHP badamy zmienną {stala}$_GET[‘id\’]{/stala}. Zawiera ona informacje potrzebne do ustalenia treści witryny:



Niestety w rozwiązaniu takim poprawnymi adresami są zarówno:

adres-a.html
adres-ipsum.html
adres-nieco-inny.html
jak i:
index.php?id=a
index.php?id=ipsum
index.php?id=nieco-inny

Przykład piąty: eliminacja adresów o rozszerzeniu .php

W celu wyeliminowania adresów o rozszerzeniu {stala}.php{/stala} z poprzedniego rozwiązania stosujemy zmienną {stala}REQUEST_URI{/stala}. Najpierw w pliku {stala}.htaccess{/stala} ustalamy regułę translacji:

RewriteEngine on
RewriteRule ^adres-.+\.html$ index.php

Zwróćmy uwagę, że reguła ta nie wykorzystuje przechwytywania.

W skrypcie PHP, w identyczny sposób, tak jak w przykładzie trzecim, ustalamy adres pobieranego dokumentu:

$adr = $_SERVER[\'REQUEST_URI\'];
 
$adr = preg_replace(
   \'/[^a-zA-Z0-9_\-\/.]/\',
   \'\',
   $adr
);
 
$f = dirname($_SERVER[\'PHP_SELF\']) . \'/\';
 
$adr = preg_replace(
   \'/^\' . preg_quote($f, \'/\') . \'/\',
   \'\',
   $adr
);

Następnie adres zawarty w zmiennej {stala}$adr{/stala} dopasowujemy do wyrażenia regularnego:

^adres-(.+)\.html$

Tym razem stosujemy przechwytywanie. Przechwycony fragment dostępny w zmiennej {stala}$m[1]{/stala} pozwala na ustalenie treści witryny:



W powyższym rozwiązaniu poprawnymi adresami są wyłącznie adresy zakończone rozszerzeniem {stala}.html{/stala}, np.:

adres-a.html
adres-lorem-ipsum.html

Wszelkie inne adresy, w szczególności adresy zakończone rozszerzeniem {stala}.php{/stala}, są niepoprawne i nie będą działały. Zwróćmy uwagę, że adresy zawierające znak zapytania i zmienne URL nie są w ogóle wykorzystywane. Cała aplikacja stosuje wyłącznie przyjazne URL-e o rozszerzeniu {stala}.html{stala}, co w znacznym stopniu uprości zarządzanie przestrzenią adresową.

Przykład szósty: strona z menu stosująca zmienne URL

Wykorzystajmy opisane rozwiązania do implementacji przyjaznych URL-i na stronie zawierającej menu. Rys. 6 przedstawia witrynę z piosenkami. Wybranie tytułu z lewego menu powoduje załadowanie tekstu piosenki po prawej stronie.

Strona wykorzystuje pliki tekstowe. Tekst każdej piosenki jest zapisany w osobnym pliku tekstowym. Dodatkowy plik o nazwie {stala}00lista.log{/stala} zawiera zestawienie wszystkich piosenek:

Krasnoludki|krasnoludki.txt|krasnoludki.html
Stary niedźwiedź|stary_niedzwiedz.txt|niedzwiedz.html
Ta Dorotka|ta_dorotka.txt|dorotka.html
...

Separatorem w pliku jest znak |. Kolejne kolumny to tytuł piosenki, nazwa pliku tekstowego z treścią piosenki oraz przyjazny URL.

Na przykład tekst piosenki zatytułowanej Stary niedźwiedź jest zawarty w pliku {stala}stary_niedzwiedz.txt{/stala}. Piosenka ta będzie dostępna pod adresem {stala}niedziwiedz.html{/stala}.

W pliku {stala}.htaccess{/stala} przedstawionym na listingu 1 ustalamy reguły translacji adresów (dyrektywa {stala}RewriteRule{/stala}) oraz adres strony głównej (dyrektywa {stala}DirectoryIndex{/stala}).

DirectoryIndex index.php?id=chodzi-lisek.html
RewriteEngine on
RewriteRule ^(.+\.html)$  index.php?id=

Skrypt {stala}index.php{/stala} jest przedstawiony na listingu 2. Na podstawie zmiennej {stala}$_GET[\’id\’]{/stala} ustalamy treść, która będzie widoczna na stronie.

assign(\'tekst\', $tekst);

}

$s->assign(\'menu\', $d[2]);
$s->assign(\'akcja\', $akcja);
$s->display(\'sz.tpl\');

?>

W rozwiązaniu tym poprawnymi adresami są:

  • adres pusty (po wejściu do folderu z przykładem ujrzymy pierwszą piosenkę; odpowiada za to dyrektywa {stala}DirectoryIndex{/stala}),
  • przyjazne adresy URL postaci {stala}niedzwiedz.html{/stala}, {stala}praczki.html {/stala}(ich dokładna postać wynika z zawartości pliku {stala}00lista.log{/stala}),
  • adresy stosujące zmienne URL, np.{stala} index.php?id=niedzwiedz.html{/stala}, {stala}index.php?id=praczki.html{/stala}.

Przykład siódmy: eliminacja adresów .php?id= na stronie z jednym menu

Ostatni przykład demonstruje eliminację adresów odwołujących się do skryptu {stala}index.php{/stala} w przykładzie z piosenkami. Podane poniżej rozwiązanie wykorzystuje zmienną {stala}REQUEST_URI{/stala}.

W pliku {stala}.htaccess{/stala} ustalamy reguły translacji, tak by dokumentem domyślnym w folderze (dyrektywa {stala}DirectoryIndex{/stala}) był skrypt index.php. Ponadto przyjazne URL-e (np. niedzwiedz.html, praczki. html) przekierowujemy dyrektywą RewriteRule również do skryptu index.php. Treść pliku {stala}.htaccess{/stala} jest przedstawiona na listingu 3.

DirectoryIndex index.php
RewriteEngine on
RewriteRule ^[a-zA-Z0-9_\-]+\.html$  index.php

W skrypcie {stala}index.php{/stala} w zmiennej {stala}$adr{/stala} ustalamy adres bieżąco obsługiwanego żądania HTTP. Otrzymany adres może być pusty (gdy wchodzimy do folderu) lub może być przyjaznym adresem piosenki (np. {stala}niedzwiedz.html{/stala}). Instrukcja {stala}if{/stala} wybiera jeden z przypadków. Skrypt {stala}index.php{/stala} jest przedstawiony na listingu 4.

assign(\'tekst\', $tekst);
}

$s->assign(\'akcja\', $akcja);
$s->assign(\'menu\', $d[2]);
$s->display(\'sz.tpl\');

?>

W otrzymanym rozwiązaniu poprawnymi adresami będą:

  • adres pusty,
  • przyjazne adresy URL zawarte w pliku {stala}00lista.log{/stala}.

Adresy, które zawierają nazwę skryptu index.php nie są w ogóle stosowane.

Może cię też zainteresować

Internet Maker

Po przeczytaniu poprzednich części publikacji wiesz już jak zainstalować Apache oraz doinstalować do niego PHP. Duet ten nie jest jednak wystarczający dla spełnienia podstawowych potrzeb tworzenia współczesnych aplikacji...

Internet Maker

Z pierwszej części naszego przewodnika dowiedziałeś się, jak uruchomić serwer WWW. W tym artykule dodamy do Apache2 możliwość obsługi skryptów PHP.

Internet Maker

Jeżeli wykupiłeś niedawno serwer VPS lub masz własny serwer dedykowany, najprawdopodobniej będziesz chciał uruchomić na nim serwer WWW. Jeżeli nie wiesz, w jaki sposób zabrać się do tej operacji,...

Internet Maker

Istnieją różne sztuczki, o których wiele osób słyszało, ale nie każdy je stosuje. Jeżeli prowadzisz stronę internetową i masz dostęp do pliku .htaccess na serwerze Apache, co obecnie jest już standardem,...