Dziś przedstawię Wam jak w łatwy sposób stworzyć ładne url'e we własnej aplikacji. Wielu początkujących programistów tworzy cały mechanizm ładnych url'i w całości oparty na mod-rewrite i pliku htaccess. Niestety takie podejście jest mało elastyczne i na dłuższą metę uciążliwe. Pokażę Wam inną metodę, gdzie cały mechanizm przetwarzania linków zawarty jest w kodzie php. Chcę od razu zaznaczyć, iż nie będzie tu żadnej super hiper obiektowości, rutingu i innych super hiper bajerów. Artykuł ma na celu pokazać jak prosto zrobić ładne linki i poznać podstawy tej konstrukcji.
Założenia wstępne
Na początku omówię w jaki sposób będzie kontrolowana nasza testowa aplikacja. Będzie się ona składała z modułów, zaś każdy moduł będzie miał akcje. Przykładowo możemy mieć moduł aktualności (news). Moduł ten udostępnia akcję listy aktualności (list) oraz akcję wyświetlenia konkretnej aktualności (show).
Teraz przyjmijmy, że nazwa modułu znajdować się będzie w parametrze module a akcja w parametrze action. Przykładowy standardowy link wyglądałby mniej więcej tak: index.php?module=jakismodul&action=jakasakcja
Dla naszego modułu aktualności i akcji listowania byłoby to więc tak: index.php?module=news&action=list zaś dla wyświetlenia konkretnej aktualności index.php?module=news&action=show&name=nazwanewsa&id=5 - dla konkretnej aktualności założyłem, iż potrzebna będzie jeszcze nazwa oraz id.
Mamy już linki ale jak sami widzimy są to nadal jeszcze te straszne brzydkie linki. Chcielibyśmy mieć je w ładnej postaci. Przyjmijmy więc, że nasze linki będą wyglądały tak jakismodul/jakasakcja/jakisparametr1/jakaswartosc2/jakisparametr2/jakaswartosc2. Dla naszego modułu aktualności byłoby to więc news/list oraz news/show/name/nazwanewsa/id/5
Przekierowanie adresów
Jak już mówiłem, cały mechanizm będzie oparty na php. Żeby jednak taki url jakismodul/jakasakcja/jakisparametr1/jakaswartosc2/jakisparametr2/jakaswartosc2 trafił do skryptu php, musimy go tam przekierować. W tym celu posłużę się plikiem .htaccess - wiem, mówiłem, że nie będzie potrzebny... W zasadzie to mówiłem, że nie będę tam określał reguł ładnych url'i
A w tym pliku zrobimy jedynie jedno przekierowanie i nic więcej - no bez tego się nie da. Tak więc należy stworzyć plik .htaccess o następującej treści:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/$1 [L]
Taki zapis spowoduje przekierowanie do skryptu index.php wszelkich odwołań do zasobów naszej aplikacji, których fizycznie nie ma na dysku. No a przecież czegoś takiego na dysku jakismodul/jakasakcja/jakisparametr1/jakaswartosc2/jakisparametr2/jakaswartosc2 raczej mieć nie będziemy
. No i to tyle jeśli chodzi o plik .htaccess i mod-rewrite - żadnych cudnych łamańców, których do końca nigdy nie rozumiemy i przy każdej nawet drobnej modyfikacji wyrywamy sobie włosy z głowy.
Dekodowanie adresu
Ok, to mamy już przekierowanie. Teraz trzeba taki ładny adresik przetworzyć. Nasz jakismodul/jakasakcja/jakisparametr1/jakaswartosc2/jakisparametr2/jakaswartosc2 znajdować się będzie zazwyczaj w $_SERVER['PATH_INFO']. Należy go więc stamtąd wydobyć, podzielić na podstawie "/" i przypisać wszystko do $_GET. Nie będę się tu rozpisywał co i jak tylko pokażę kod:
<?php
$pathInfo = trim($_SERVER['PATH_INFO'], '/'); //usuwamy znak / z końca
if (empty($pathInfo)) { //pusta ścieżka
return true;
}
$arr = explode('/',$pathInfo); //rozbijamy naszą ścieżkę na podstawie /
$count = count($arr);
//pierwsze dwa elementy to moduł i akcja
$_GET['module'] = $arr[0];
$_GET['action'] = isset($arr[1]) ? $arr[1] : ''; //tu małe zabezpieczenie, gdyby ktoś zapomniał podać akcji
//następne elementy to nazwy parametru i parametr i tak co dwa
for ($i=2; $i < $count;$i+=2){
$_n = $arr[$i]; //nazwa parametru
$_v = isset($arr[$i+1]) ? $arr[$i+1] : ''; //wartość parametru
$_GET[$_n] = $_v;
}?>
I już. W wyniku takiego kodu, nasz link jakismodul/jakasakcja/jakisparametr1/jakaswartosc2/jakisparametr2/jakaswartosc2 zostanie prawidłowo zapisany w tablicy $_GET skąd możemy się już standardowo odwoływać do poszczególnych elementów, np: $_GET['module'], $_GET['action']...
Kodowanie adresu
Pozostało nam jeszcze tworzyć linki w naszej aplikacji. W paczce do ściągnięcia znajduje się klasa, która posiada metodę Url(). Metoda ta tworzy nam linki. Wystarczy ją tylko wywołać, np: Url('module=jakismodul&action=jakasakcja&par=war') - taki kod zwróci nam link jakismodul/jakasakcja/par/war1. A o to kod:
<?php
public function Url($path = null){
if (empty($path)) //pusta ścieżka
$pars = array();
else
$pars = explode('&', $path);
$params = array();
foreach ($pars as $_param){
$_arP = explode('=',$_param,2); //par=war dzielimy na par i war
$params[$_arP[0]] = isset($_arP[1]) ? $_arP[1] : '';
}
$strRet = '';
if (!empty($params)){
foreach ($params as $_key => $_val){
if ($_key == 'module' || $_key == 'action')
$_key = '';
else
$_key.='/';
$strRet.="$_key$_val/";
}
}
return $this->baseUrl.htmlspecialchars($strRet);
}
?>
I tu nasuwa sie pytanie A po co przepuszczać to jeszcze przez jakąś funkcję? Czy nie można od razu wpisać sobie link taki jak chcemy? Odpowiedź: oczywiście, że można. Ale lepiej tego nie robić z bardzo prostego powodu - przepuszczanie tego przez funkcję gwarantuje nam jednolity mechanizm tworzenia linków - ustawiając jakismodul/jakasakcja zawsze otrzymamy ten sam link. No bo może się okazać, że kiedyś stwierdzicie, że dla modułu X linki mają wyglądać inaczej niż dla modułu Y. I co wtedy? Musicie ręcznie zamieniać wszystkie wstawki z modułem X. A gdyby to wszystko przechodzi przez jedną funkcję to jedyne co musicie zrobić to zmienić to i owo w tej jednej funkcji.
W paczce do ściągnięcia, rozszerzyłem właśnie trochę klasę i dopisałem inne tworzenie linków dla modułu news i akcji show. Teraz link do aktualności będzie wyglądał tak: jakas-nazwa,5.html pomimo, że wywołanie nadal wygląda tak: module=news&action=show&name=jakas-nazwa&id=5 - jedyne co musiałem zrobić to zmienić to i owo w jednej funkcji.
Podsumowanie
Zalety
- Dowolna (dynamiczna) liczba parametrów. Przy całościowym rozwiązaniu .htaccess nie można było określić dowolnej liczby parametrów
- Nieograniczone pole do popisu w wymyślaniu różnych kombinacji linków
- Możliwe modułowe podejście do sprawy: każdy moduł może wnieść swój własny routing i nie trzeba nic zmieniać w plikach globalnych aplikacji. Oczywiście możliwe jest to dopiero przy odpowiednio napisanym mechaniźmie. W przykładzie co Wam udostępniam oczywiście tego nie ma
Wady
Taki mechanizm stosuję od bardzo dawna. Uratował mi skórę gdy jeszcze kiedyś robiłem wszystko w htaccess i w pewnym momencie stanąłem na coraz to bardziej zagmatwanych regółkach. Podobny mechanizm stosowany jest chyba w większości popularnych frameworkach. Mówię tu oczywiście o zarządzaniu ładnymi linkami z poziomu php a nie o dokładnie takim samym kodzie co tu pokazałem.
Paczka z przykładową "aplikacją" i klasą do pobrania jak zwykle w dziale download. Polecam jej ściągnięcie, przejrzenie i odpalenie gdyż pomoże wszystkim tym, którzy nie do końca zrozumieli ten mechanizm.