W firmie, w której pracuję, zajmuję się m. in. utrzymaniem portalu, który jest osadzony na kilku subdomenach określających poszczególne regiony Polski. Na podstawie tej informacji użytkownik widzi na stronie tylko wiadomości, które są związane z wybraną przez niego częścią kraju. W dzisiejszym wpisie chciałbym pokazać Wam, jak zasymulować takie zachowanie na serwerze lokalnym.
Problem.
Rozważmy następujący przykład: projektujemy ogólnoświatowy portal, który ma za zadanie prześcignąć pod względem popularności Google i Facebooka razem wziętych. Plany bardzo ambitne, aczkolwiek naszym głównym celem będzie umożliwienie użytkownikowi wyboru kontynentu na którym się znajduje – dostanie on wtedy materiały dotyczące tylko tej części świata. Nazwiemy naszą witrynę bardzo ambitnie – będzie to międzynarodowa korporacja Example, a strona główna portalu znajdzie się pod, a jakże, domeną example.com. Subdomeny, jakie nas interesują, to:
europe.example.com
asia.example.com
northamerica.example.com
southamerica.example.com
africa.example.com
australia.example.com
Przypuśćmy, że Antarktydę i Arktykę pominiemy, bo nie są one zbyt medialne. ;]
Ze względu na to, że chcemy utrzymać maksymalną spójność serwisu zarówno pod względem logicznym jak i fizycznym nie możemy sobie pozwolić na odniesienie tych domen do różnych katalogów – wszystko ma być podpięte pod jeden kod i na podstawie odpowiednich instrukcji po stronie serwera przekazywany parametr informujący o wybranym kontynencie. Zobaczmy więc, co da się w tej kwestii zrobić.
Rozwiązanie.
Tym, którzy nie wiedzą, jak tworzy się vhosty polecam jeden z moich wcześniejszych wpisów, gdzie wyjaśniłem dokładnie, krok po kroku, jak podpiąć jedną domenę pod jeden katalog. W tym wpisie skupię się tylko na informacjach, jak do utworzonego już wirtualnego hosta dołączyć inne domeny tak, aby wskazywały w to samo miejsce co oryginalny adres.
W ramach przypomnienia pozwolę sobie wstawić kod vhosta z wspomnianego wyżej wpisu:
<VirtualHost *:80> DocumentRoot [ścieżka] ServerName example.com </VirtualHost>
Widzimy, że nazwę domeny określa dyrektywa ServerName. Aby określić pozostałe domeny będziemy potrzebowali oddzielnej dyrektywy – jest nią ServerAlias. Jego działanie polega właśnie na „podłączeniu” podanej listy domen i takim samym wskazaniu na ścieżkę zawartą w dyrektywie DocumentRoot jak oryginalna domena. Dokumentacja serwera Apache tłumaczy całość następująco:
ServerAlias Directive
Description: Alternate names for a host used when matching requests to name-virtual hosts
Syntax: ServerAlias hostname [hostname] …
Context: virtual host
Status: Core
Module: coreThe ServerAlias directive sets the alternate names for a host, for use with name-based virtual hosts.
<VirtualHost *>
ServerName server.domain.com
ServerAlias server server2.domain.com server2
# …
</VirtualHost>
Jak widzimy, dyrektywa ServerAlias akceptuje listę nazw domen oddzielonych spacjami, które mają stanowić aliasy dla głównej. Zróbmy więc tak, jak nam nakazali developerzy serwera Apache. Nasza deklaracja vhosta wzbogaci się więc o jedną linijkę:
<VirtualHost *:80> DocumentRoot [ścieżka] ServerName example.com ServerAlias europe.example.com asia.example.com northamerica.example.com southamerica.example.com africa.example.com australia.example.com </VirtualHost>
Kod wynikowy jest mało czytelny, dlatego lepiej jest zapisać aliasy w postaci osobnych wpisów [tak też można ;]]:
<VirtualHost *:80> DocumentRoot [ścieżka] ServerName example.com ServerAlias europe.example.com ServerAlias asia.example.com ServerAlias northamerica.example.com ServerAlias southamerica.example.com ServerAlias africa.example.com ServerAlias australia.example.com </VirtualHost>
Oczywiście w tym momencie nie zadziała to jeszcze , ponieważ rzeczone domeny nie istnieją w pliku hosts. Dopiszmy zatem odpowiednie dane do tego pliku:
127.0.0.1 europe.example.com 127.0.0.1 asia.example.com 127.0.0.1 northamerica.example.com 127.0.0.1 southamerica.example.com 127.0.0.1 africa.example.com 127.0.0.1 australia.example.com
Teraz istnieją zarówno wpisy w deklaracji vhosta jak i w tablicy hosts systemu operacyjnego. Restartujemy Apache i możemy się połowicznie ucieszyć – wpisanie w pasku adresu każdej subdomeny kieruje nas do naszego serwisu. Dlaczego połowicznie? Ponieważ nasz skrypt jeszcze nie wie, jak „wyłuskać” informację o kontynencie. Ta część jest jednak trywialnie prosta – wykorzystamy tablicę $_SERVER dobrze znaną wszystkim z języka PHP. Zawiera ona w sobie indeks SERVER_NAME, którego wartość zostanie ustawiona na domenę, z której został wywołany nasz skrypt. Wystarczy więc wyciągnąć żądaną informację za pomocą prostego kodu [oczywiście można też skorzystać z wyrażenia regularnego, kwestia gustu ;]]:
// sample domain: europe.example.com
$pieces = explode('.', $_SERVER['SERVER_NAME']);
// equals to array('europe', 'example', 'com')
$continent = $pieces[0];
I zmusić skrypt do generowania zawartości odpowiedniej dla tej części świata. Prawda, że proste?
Podsumowanie.
Powyższe informacje można też zastosować w przypadku publicznego serwera dostępnego w Internecie. Jedyne, co musimy zrobić to zmienić adres IP na odpowiedni – zamiast tradycyjnego, lokalnego 127.0.0.1. Mam nadzieję, że rozjaśniło Wam to możliwości, jakie możemy uzyskać za pomocą kilku linijek w kilku plikach. ;] Żeby zamknąć temat należałoby jeszcze pokazać możliwości oferowane przez zastosowanie wildcardów w nazwie domeny, ale to już chyba materiał na kolejny artykuł [na pewno ukaże się w przyszłości ;]]. Pozdrawiam i do zobaczenia w niedzielę w Linkdumpie… numer 22!
Warto przeczytać.
Trwa ładowanie…
Odkrywcze to nie było ;) Ale może w końcu dam się przekonać do opisywania bardziej trywialnych spraw..
A powiedz mi, co można odkrywczego tutaj napisać? Przecież każdy problem, jaki tu opisałem jest prosty – jak już się zna rozwiązanie.
Przy okazji – nie nazwałbym tego problemu w ten sposób. Jest Prosty, i owszem, ale nie trywialny, bo do jego rozwiązania potrzebna jest wiedza – problemy trywialne rozwiązujesz poprzez zastosowanie już poznanych umiejętności.
Idea polega na tym, że „kiedyś” miałem problem, bo nie wiedziałem, jak sobie z tym poradzić. Skoro ja miałem problem, to zapewne taki sam problem będą miały tysiące ludzi po mnie. Dlatego dokładam swoją cegiełkę, żeby ktoś w przyszłości nie musiał się męczyć.