Małe, ale użyteczne

grudzień 16th, 2008

Tak to jest - człowiek całe życie się uczy a i tak głupi umiera ;)

PHPem zajmuję się już ładnych parę lat (6 albo 7 - nie mogę się doliczyć) a dopiero ostatnio dowiedziałem się o dwóch ciekawostkach, którymi chętnie się z Wami podzielę.

dla zwolenników wcięć i ogólnie wymyślnego formatowania…

Czy wiedzieliście o tym, że w wywołaniu funkcji oraz w przy tworzeniu tablicy (array()), można na końcu listy zostawić nadmiarowy przecinek?! Czyli zadziała np. mojafunkcja($a, $b,); Przydatna sprawa gdy lubicie umieszczać każdy element tablicy w nowym wierszu - nie trzeba przejmować się czy dodać/usunąć przecinek przy przestawianiu wierszy…

dla tych, co nie lubią wymyślnego formatowania…

Jeżeli nie lubisz wymyślnego wcinania wierszy, formatowania i wyrównywania, dla Ciebie jest druga sztuczka. Otórz przełącznik -w w wersji PHP dla lini poleceń, powoduje, że plik nie jest wykonywany a jedynie wypluwany przez php na wyjście… bez komentarzy i białych znaków. Jeżeli więc chcesz zmniejszyć plik do minimum przed wysłaniem na serwer, użyj php.exe -w mojplik.php > mojplik_c.php. Gotowe. Ostatnie swoje dzieło zmniejszyłem ze 120kB do 54kB….

i na koniec mała niespodzianka

Na koniec dodam, że mam dla Was małą niespodziankę - projekt, który prowadzę jako open source - hostowany jest na Google Code. Jeszcze chwila i podam Wam adres. Teraz powiem tylko tyle, że znacznie ułatwia pracę przy tworzeniu wszelkich dokumentów tekstowych (np. CSS/JavaScript/HTML/PHP itd). Potrafi w locie przetwarzać pliki i tworzyć z nich jeden (albo wiele - zależy od potrzeby) plików wynikowych. Wyobrażacie sobie zmienne i operacje matematyczne w CSS?

Pozdrawiam :)

Łatwiejsze debugowanie z FirePHP

wrzesień 17th, 2008

Problem…

Często debugując kod wypisujemy wartość jakiejś zmiennej do treści strony. Takie podejście ma tę wadę, że te wstawki trzeba usunąć z finalnej wersji. Czasem też format zwracanych danych uniemożliwia nam swobodne dodawanie własnego tekstu (XML, JSon no i oczywiście generowane dynamicznie grafiki). Do tego dochodzi praca z Ajaksem - wyników pobranych przez XmlHTTPRequest nie widzimy…

… rozwiązany

Skoro więc nie możemy przesłać dodatkowych komunikatów w wyniku, to może wykorzystać nagłówki HTTP? Jak się okazuje, jest to nie tylko możliwe, ale otrzymujemy gotowe rozwiązanie w postaci dodatku do Firefoksa - FirePHP i biblioteki PHP. Strona projektu - firephp.org. Na stronie FirePHP dostępne są informacje, jak zintegrować bibliotekę z wieloma znanymi frameworkami (CakePHP, CodeIgniter, Drupal, Kohana, ExpressionEngine, PRADO, Symfony, TYPO3, Zend Framework).

Jak to działa na serwerze?

Najpierw w kodzie wykorzystujemy bibliotekę FirePHP (wymagane PHP 5). Do dyspozycji mamy całą klasę FirePHP lub bardzo wygodną funkcję fb(). Najprostsze wywołanie to fb(’Hello World’); ale można też bardziej skomplikowanie (np. wypluć całą tablicę lub obiekt) - użycie funkcji fb(). Całość informacji jakie podamy przy kolejnych wywołaniach funkcji fb(); jest przesyłana w formacie JSon w szeregu nagłówków HTTP X-FirePHP-Data-

Jak to działa w przeglądarce?

Teraz trzeba przesłane dane wyświetlić w jakiś sensowny i czytelny sposób. To właśnie robi dodatek FirePHP do Firefoksa. Trzeba pamiętać, że FirePHP wymaga innego dodatku - Firebug. Gdy w odpowiedzi serwer przyśle nagłówki X-FirePHP-Data-, FirePHP połączy ich wartość w całość a zinterpretowany wynik wyświetli w konsoli Firebug.
Konsola Firebug z wynikami FirePHP

Zalety

Podstawową zaletą jest to, że dane potrzebne do debugowania nie muszą być osadzone w treści odpowiedzi. Dodatkowo, są prezentowane w czytelny sposób w jednym miejscu. Bardzo pomocne jest to, że dane debugowe można dołączyć do danych, które “gryzą się” z różnymi wstawkami (np. dane binarne, obrazki, XML, JSON etc.). Nawet jeżeli dane nie zostaną przesłane w nagłówkach strony (a np. w nagłówkach przesłanych w odpowiedzi pobranej z wykorzystaniem XMLHttpRequest lub w nagłówkach przysłanych z obrazkiem osadzonym na stronie) to i tak wynik zobaczymy w konsoli. No i ostatnie - nawet jeżeli zapomnimy usunąć wpisy debugowe, to i tak pozostaną one niewidoczne dla nie wtajemniczonych.

Wady

Nie widzę… ;)

Ciekawe co dalej…

Dostępny jest patch do Apache Mod Rewrite, wysyłający do FirePHP rewrite log. Niestety patch został napisany przez niedoświadczonego programistę C i jest w stadium proof-of-concept. Miejmy nadzieję, że projekt się rozwinie.

Z informacji na stronie projektu wynika, że FirePHP może być także użyty w połączeniu z ASP, Pythonem czy środowiskiem Jaxer.

Na stronie w dosyć szczegółowy sposób opisano jak formułować dane wysyłane do FirePHP, nic więc nie stoi na przeszkodzie, aby znaleźć nowe zastosowania dla tego rozszerzenia.

Serwer w PHP

wrzesień 14th, 2008

Dla wszystkich jest oczywiste, że PHP działa jako element serwera WWW. Jednak PHP może samo w sobie działać jako prosty serwer (nie koniecznie HTTP). Dla takiego rozwiązania najlepiej wykorzystać wersję CLI PHP (Command Line Interface)

Dlaczego serwer w PHP?

W jednym z ostatnich projektów, byłem zmuszony “wynieść” część funkcjonalności systemu z serwera linuksowego (PHP, Apache, MySQL) na inny komputer, działający pod kontrolą systemu Windows. Podstawowym zagadnieniem w tym momencie stała się komunikacja między głównym systemem, a tą wydzieloną cząstką. Po rozważeniu kilku możliwości, zdecydowałem się napisać prosty serwer z którym można połączyć się przez TCP/IP, wydać polecenie i odczytać wynik.

Jak to ma działać?

Zasada działania jest prosta - skrypt PHP działający pod Windows (nazwijmy go “Sonda”) nasłuchuje na porcie 9876, akceptuje przychodzące połączenia i wymaga autoryzacji od klienta. Po poprawnej autoryzacji możliwe jest wysłanie polecenia i odebranie wyników. Na samym końcu następuje wylogowanie i rozłączenie.

Kod źródłowy


set_time_limit(0);
$sckMain = socket_create(AF_INET, SOCK_STREAM, 0) or die();
socket_bind($sckMain, '192.168.1.101', 9876) or die();
socket_listen($sckMain) or die();
$oaClients = array();
while(true){
$sckaRead = array();
$sckaRead[0] = $sckMain;
foreach($oaClients as $x => $oClient){
if($oClient -> bClosed == true){
unset($oaClients[$x]);
}else{
$sckaRead[] = $oClient -> sckSocket;
}
}
socket_select($sckaRead, $null = null, $null = null, 0);
if(in_array($sckMain, $sckaRead)){
$sckNewClient = socket_accept($sckMain);
$oaClients[] = new clientHandler($sckNewClient);
}
foreach($oaClients as $oClient){
if(in_array($oClient -> sckSocket, $sckaRead)){
$oClient -> handle();
}
}
}
socket_close($sckMain);
class clientHandler{
var $bClosed = false;
var $sckSocket = '';
var $bAuthenticated = false;
function clientHandler($sckSocket){
$this -> sckSocket = $sckSocket;
$this -> send('HELLO');
}
function handle(){
$sCommand = $this -> read();
list($sExecute, $sParameters) = explode(' ', $sCommand, 2);
if($sCommand != ''){
if($this -> bAuthenticated == true){
if($sCommand == 'logout'){
$this -> disconnect();
}elseif($sExecute == 'echo'){
$this -> send($sParameters);
}elseif($sExecute == 'time'){
$this -> send(date('Y-m-d H:i:s'));
}else{
$this -> send('unknown command');
}
}elseif($sExecute == 'login'){
if($sParameters == 'powiedz-przyjacielu-i-wejdz'){
$this -> bAuthenticated = true;
$this -> send('login ok');
}else{
$this -> send('login error');
$this -> disconnect();
}
}else{
$this -> send('authenticate first');
}
}
}
function send($sMessage){
socket_write($this -> sckSocket, $sMessage . "\r\n" . chr(0));
}
function read(){
return trim(@socket_read($this -> sckSocket, 1024));
}
function disconnect(){
$this -> send('bye');
$this -> bClosed = true;
socket_close($this -> sckSocket);
}
}

Analiza

Aby można było nawiązać wiele połączeń jednocześnie, stworzymy jedno “główne” gniazdo (ang. socket) przyjmujące nowe połączenia i przekazujące je do nowych gniazd obsługujących połączenia. Zaczynamy więc:


$sckMain = socket_create(AF_INET, SOCK_STREAM, 0) or die();
socket_bind($sckMain, '192.168.1.101', 9876) or die();
socket_listen($sckMain) or die();

socket_create() tworzy nowe gniazdo, socket_bind() łączy je z portem 9876 i adresem IP 192.168.1.101, socket_listen() powoduje, że gniazdo zaczyna nasłuchiwać. Dodatkowo będziemy potrzebowali tablicy obiektów ($oaClients) obsługujących poszczególne połączenia.

Całość obsługi zamykamy w nieskończonej pętli (while(true)). Głównym jej elementem jest funkcja socket_select(). Jej opis w manualu PHP jest dosyć enigmatyczny (”Runs the select() system call on the given arrays of sockets with a specified timeout”). W praktyce wygląda to następująco: socket_select() przyjmuje jako trzy pierwsze wartości tablice gniazd (arrays of sockets) (a dokładnie rzecz ujmując funkcja przyjmuje parametry przez referencję). Funkcja monitoruje stany gniazd i w momencie gdy ulegnie zmianie status któregoś z gniazd kończy swoje działanie. Ważne jest to, że funkcja modyfikuje przekazane tablice tak, aby zawierały w sobie tylko te gniazda, które zmieniły swój status. Gniazda w pierwszej tablicy będą monitorowane pod kątem dostępności danych (a dokładnie, czy czytanie z tego gniazda nie zablokuje programu). Jako pozostałe parametry podamy NULL, gdyż w tej chwili interesuje nas tylko czytanie z gniazd.

Przed wywołaniem socket_select() musimy więc przygotować sobie tablicę gniazd do monitorowania:


$sckaRead = array();
$sckaRead[0] = $sckMain;
foreach($oaClients as $x => $oClient){
if($oClient -> bClosed == true){
unset($oaClients[$x]);
}else{
$sckaRead[] = $oClient -> sckSocket;
}
}

Jako pierwszy element monitorowanej tablicy dodajemy główne gniazdo (aby sprawdzić, czy nowe połączenie nie czeka na akceptację). W pętli przeszukujemy tablicę obiektów obsługujących połączenia. Jeżeli obiekt zamknął połączenie, usuwamy go z tablicy (unset). Jeżeli nie - dodajemy gniazdo do monitorowanej tablicy.


if(in_array($sckMain, $sckaRead)){
$sckNewClient = socket_accept($sckMain);
$oaClients[] = new clientHandler($sckNewClient);
}
foreach($oaClients as $oClient){
if(in_array($oClient -> sckSocket, $sckaRead)){
$oClient -> handle();
}
}

Po wywołaniu socket_select() sprawdzamy, czy w tablicy $sckaRead znajduje się główne gniazdo. Jeżeli tak, oznacza to, że nowe połączenie oczekuje na akceptację. Wtedy wywołujemy funkcję socket_accept() która przyjmuje połączenie i zwraca nowe gniazdo obsługujące to połączenie. Tworzymy nowy obiekt klasy clientHandler i dodajemy go do tablicy klientów. W kolejnej pętli sprawdzamy czy gniazdo poszczególnych połączeń znajduje się w tablicy gniazd z których możemy czytać. Jeżeli znajduje się - wywołujemy metodę handle() obiektu. Zadaniem tej metody jest przeczytanie “polecenia” z gniazda i odpowiedź na nie.

Klasa clientHandler jest dosyć prosta. Jej główną metodą jest handle() która czyta polecenie z gniazda, wykonuje je i zwraca wynik do klienta. Całość klasy nie wymaga chyba większego komentarza, dlatego jej analizę pozostawiam Wam.

Na koniec - zagadka

Na zakończenie tego króciutkiego wpisu zagadka: Dlaczego musiałem wynieść część funkcjonalności na inny komputer i co w oryginalnym projekcie robi program “Sonda”?

Szaf(k)a gra!

marzec 30th, 2008

Mam już na koncie całkiem sporo projektów - dużych i małych i tych napisanych “do szuflady”. Każdy staram się wykonać jak najlepiej, ale zawsze jest tak, że projekt albo “mi leży” albo “mi nie leży”. Najbardziej lubię projekty, które wychodzą poza środowisko serwera web i wchodzą w interakcję z otoczeniem mniej lub bardziej “fizycznym”.

Najnowszym takim projektem - cały czas we wczesnej fazie dev ;) - jest domowa skrzynka muzyczna sterowana przez web.

Jak to działa?

Sercem jest stary komputer z prockiem AMD Duron 900 MHz ustawiony w szafce w kuchni, żeby w pokoju była cisza. Do niego podłączone są głośniki ustawione już w pokoju. Całość podłączona jest do Sieci, dzięki czemu mogę sterować muzyką przez komórkę z Operą Mini, a w przypływie ochoty mogę posłuchać radia internetowego (np. Groove Salad).

Jak to jest zrobione?

Całkiem prosto. Oto lista potrzebnych rzeczy i softu:

  • komputer - 1 sztuka
  • kabel skrętka - w zależności od potrzeb, w moim przypadku 15 m
  • przedłużacz audio (mały jack) - w zależności od potrzeb
  • system operacyjny - Linux (ja użyłem dystrybucji Debian)
  • mpd (music player daemon) - soft grający, działa jako demon, nie ma interfejsu i sterowany jest przez sieć
  • mpc (konsolowy soft sterujący mpd)
  • mplayer - do odtwarzania stacji radiowych
  • serwer WWW (Apache) z obsługą PHP
  • konto na no-ip.org

Krok I

- instalujemy na komputerze Debiana (lub co tam wolicie), do tego mpd i mpc. I tutaj mała uwaga - dostępna przez apt-get wersja jest nieco stara i ma bug powodujący, że po zatrzymaniu ogdrywania (np. pauza) nie można wznowić odgrywania. Dlatego należy całość skompilować ze źródeł. Strona projektu: musicpd.org

Krok II

- komputer wynosimy tam, gdzie będzie najmniej przeszkadzał, podłączamy do sieci, podłączamy głośniki. Rejestrujemy się na no-ip.com i instalujemy klienta no-ip.com na maszynie

Krok III

- sterować możemy z konsoli, używając klienta mpc. Nie o to jednak chodziło. Ja interfejs zbudowałem w oparciu o PHP. Od strony użytkownika jest to przeglądarkowe klikadło wykorzystujące Ajax (jquery.com - świetnie działa w Operze Mini). Jeżeli zaś chodzi o komunikację z mpd - połączenie z portem 6600 localhosta. MPD ma własny, dość prosty protokół. Do sterowania playerem przygotowałem prostą klasę:


<?php
class ncmpdcommander{
var $fpStream;

function ncmpdcommander($sServer, $iPort){
$this -> fpStream = fsockopen($sServer, $iPort);
//stream_set_blocking($this -> fpStream, 0);
$sResoponse = fread($this -> fpStream, 1024);
}

function disconnect(){
fclose($this -> fpStream);
}

function doCommand($sCommand){
fwrite($this -> fpStream, $sCommand . "\n");

while(trim($sLine) != 'OK'){
$sLine = fgets($this -> fpStream, 512);
if(trim($sLine) != 'OK'){
$sResponse .= $sLine;
}
}
return $sResponse;
}

function playbackNext(){
$this -> doCommand('next');
}
function playbackPrev(){
$this -> doCommand('previous');
}
function playbackStop(){
$this -> doCommand('stop');
}
function playbackPlay(){
$this -> doCommand('play');
}
function playbackPause(){
$this -> doCommand('pause');
}

function getTitle(){
$sStatus = $this -> doCommand('currentsong');
preg_match('!file: (.+)!', $sStatus, $shFound);
$sTitle = $shFound[1];
preg_match('!([^/]+)\.mp3$!', $sTitle, $shFound);
$sTitle = $shFound[1];
$sTitle = preg_replace('!^[0-9 _-]+!', '', $sTitle);
$sTitle = str_replace('_', ' ', $sTitle);

return $sTitle;
}

function getPlaylist(){
$sPlaylist = $this -> doCommand('playlist');
$saPl = explode("\n", $sPlaylist);
foreach($saPl as $sItem){
list($iNum, $sTitle) = explode(':', $sItem, 2);
$saPlaylist[$iNum] = $sTitle;
}
return $saPlaylist;
}

function volumeUp(){
$this -> doCommand('volume +10');
}
function volumeDown(){
$this -> doCommand('volume -10');
}
}

?>

Samo wykorzystanie klasy jest już banalne:

<?php
require_once('ncmpdcommander.class.php');

$oCmd = new ncmpdcommander('localhost', 6600);
switch($_GET['cmd']){
case 'next':
$oCmd -> playbackNext();
break;
case 'prev':
$oCmd -> playbackPrev();
break;
case 'stop':
$oCmd -> playbackStop();
break;
case 'pause':
$oCmd -> playbackPause();
break;
case 'play':
$oCmd -> playbackPlay();
break;

case 'get-title':
echo $oCmd -> getTitle();
break;

case 'volume-up':
$oCmd -> volumeUp();
break;

case 'volume-down':
$oCmd -> volumeDown();
break;
}

$oCmd -> disconnect();
?>

To już koniec

Nie opisałem całości w szczegółach, mam jednak nadzieję, że ten opis zainspiruje Was do przygotowania czegoś podobnego. A może już coś takiego macie? Piszcie w komentarzach o Waszych projektach wychodzących poza przeglądarkę!

Pozdrawiam i do następnego wpisu!

Ten w okularach to ja 8-)

luty 11th, 2008

Niestety, nie mam ostatnio zbyt dużo czasu na pisanie bloga. Pracy nad kilkoma już projektami nie ubywa a wciąż pojawiają się nowe. Zapewniam Was jednak, że blog nie umarł - nadal o nim pamiętam, zatwierdzam komentarze i w miarę możliwości kończę czekające na publikację artykuły.
W życiu zawodowym pojawiło się kolejne wyzwanie: CeBIT 2008. Firma MASTER TELECOM jako jedna z około 30 polskich firm (wszystkich wystawców ma być ok 5500) będzie miała przyjemność przedstawić swoją ofertę na tych największych targach IT. W Hanowerze przedstawimy trzy nasze projekty:

Zapraszam więc na nasze stanowisko na targach CeBIT w dniach 4 - 6 marca 2008. Hala 9, stanowisko D05:

Mapa

mapa_b.png

MASTER TELECOM na CeBIT

Gdy już traficie na nasze stoisko, pamiętajcie: ten w okularach to ja 8-)

Bo komputer winien posłuszeństwo swemu panu

grudzień 3rd, 2007

Chciałbym zachęcić Was do podzielenia się waszymi przyzwyczajeniami i zwyczajami które wyrobiliście sobie podczas programowania. Chodzi mi o wasze warsztaty - jakich narzędzi (edytorów, menedżerów plików etc) używacie na co dzień, i
bez jakich programów nie wyobrażacie sobie wygodnego programowania. Ja sam używam Vim’a. Na tę okazję przygotowałem stronę z krótkim opisem moich ulubionych pluginów, kolorów i sztuczek. Ta strona to dopiero początek. Cały czas będę ją rozwijał i dodam opisy kolejnych programów. Zapraszam Was do zapoznania się ze stroną Vim the editor i do komentowania oraz chwalenia się ustawieniami, programami i narzędziami których używacie.

Dobra komunikacja

listopad 13th, 2007

Ostatnie miesiące to przede wszystkim wytężona praca nad nowym projektem, który wczoraj miał swoją premierę. Ten projekt to połączenie oprogramowania CRM z Contact Center w modelu ASP (Application Service Provider). Ten projekt to serwisowa.pl.

serwisowa.pl to nie tylko oprogramowanie pozwalające zarządzać bazą danych klientów i ich sprzętu, ale także system wychodzący poza internet i integrujący w sobie kilka kanałów komunikacji. Podstawowym kanałem jest telefon. Każde połączenie telefoniczne klienta z usługodawcą jest w sposób przezroczysty dla obu stron odnotowywane w systemie. Dzięki temu, jeszcze przed odebraniem połączenia, konsultant ma możliwość sprawdzenia, który klient dzwoni (klienci są identyfikowani numerem karty klienta) i sprawdzenia dotychczasowej histori kontaktów. Jeżeli dostawca wybrał opcję rejestrowania połączeń, klient jest informowany o tym przed połączeniem a rozmowa jest rejestrowana i udostępniana do odsłuchania zarówno dostawcy usług jak i klientowi. Gdy nie ma możliwości połączenia z dostawcą, klient może pozostawić wiadomość w poczcie głosowej.

Połączenie telefoniczne to tylko jedna z możliwości odebrania zgłoszenia od klienta. Dostępny jest także formularz zgłoszeniowy. O każdym nowym zgłoszeniu, dostawca może być informowany za pomocą wiadomości SMS i e-mail.

Przedstawione opcje, to dopiero początek. Kolejne wersje systemu przyniosą przede wszystkim zwiększenie ilości dostępnych kanałów komunikacyjnych, oraz API pozwalające zintegrować serwisowa.pl z innymi systemami. Wkrótce postaram się przybliżyć możliwości integracji, oraz kilka zastosowanych rozwiązań technicznych. Teraz jednak zapraszam do zapoznania się z naszym nowym systemem: serwisowa.pl

serwisowa.pl

Domena z www - nie twórzmy niepotrzebnych ograniczeń

wrzesień 16th, 2007

Problem

Po wpisaniu w Google zapytania jak wybrać domenę, otrzymamy w przybliżeniu 1,320,000 wyników. Jak widać, jest dość popularne zagadnienie. Każdy, kto zakłada własną stronę, może dowiedzień się jak wybrać piękną, unikalną domenę, sugerującą korzyści, jakość produktu, łatwo wymawianą, łatwą do zapamiętania… bla bla bla. Część z tych artykułów ociera się już o bełkot, choć można przeczytać także coś wartościowego.

Dziwi mnie jednak, dlaczego tak wielu administratorów stron (adminów, webmasterów i im podobnych) nie zauważa problemu subdomeny www? Bardzo często spotykam się z sytuacją, gdy jedynym działającym adresem strony jest www.example.org, natomiast example.org nie wskazuje na żaden serwer, albo - co gorsze - wskazuje na stronę firmy hostingowej.

Dziwi mnie niesamowicie to, że wiele firm walczy o jak najkrótsze nazwy, nieraz odkupując domeny za duże pieniądze. Po czym cały efekt jest psuty przez nieudolnego admina/webmastera etc, bo do ślicznej, trzyliterowej domeny trzeba dopisać kolejne 4 znaki - www. Złego wizerunku strony dopełnia fakt, że w gros przypadków nie ma żadnego uzasadnienia w wymuszaniu na użytkownikach dopisywania www.

Osobiście wpisując adresy stron, niemal zawsze pomijam www. Często niestety kończy się to koniecznością ponownego wpisania adresu - tym razem z www. Irytuje mnie to bardziej niż “strona przygotowana dla IE 5¼”. Szczególnie, że rozwiązanie problemu jest niesamowicie banalne, a zaniechanie - w mojej opinii - wynika jedynie z ignorancji adminów.

Rozwiązanie I (dobre, z wadami) - dajemy wybór internautom

Dosyć dobrym rozwiązaniem jest takie skonfigurowanie sewera www, aby dla obu adresów (example.org i www.example.org) zwracał tę samą stronę. W Apache można np. skonfigurować dwa wirtualne hosty wskazujące na to samo położenie dokumentów - DocumentRoot.

Dzięki takiemu rozwiązaniu, obojętnie czy odwiedzający wpisze www.example.org czy example.org - zawsze zobaczy stronę której szuka.

Wady rozwiązania I

Internauta jest zdezorientowany

Mniej doświadczeni internauci (np. ci, którzy na e mówią “Internet”) mogą czuć sie zdezorientowani, a nawet zagrożeni tym, że jakaś strona ma adres bez www na początku.

Możliwe rozwiązania: wykorzystać Rozwiązanie II lub zignorować problem ;)

Przeglądarka jest zdezorientowana

Należy pamiętać o tym, że przeglądarka odsyła ciasteczka tylko do tych domen, do których powinna je odesłać. Jeżeli więc w PHP ustawiamy ciasteczko w ten sposób:


setcookie('kruche', 'z_cukrem');

to nie dziwmy się, że użytkownik który np. zalogował się na example.org/login/, nie będzie zalogowany na www.example.org/.

Możliwe rozwiązania: ustawiajmy ciasteczka korzystając z opcjonalnych parametrów setcookie:

bool setcookie ( string $name [, string $value [, int $expire [, string $path [, string $domain [, bool $secure [, bool $httponly]]]]]])

Czyli możemy napisać tak:

setcookie('kruche', 'z_cukrem', time() + 60 * 60 * 24 * 31, '/', '.example.org');

ciasteczko będzie widoczne dla wszystkich subdomen naszego serwisu.

Takie podejście do ciasteczek jest bardzo ważne. Znam serwis, który działa pod dwoma adresami: example.org i www.example.org. Można w tym serwisie dokonać płatności za zamówienie za pośrednictwem jednego z systemów płatności online. Jednak powrót z systemu transakcyjnego następuje zawsze na adres www.example.org. Wiadomo jaki jest efekt: gdy loguję się na example.org - zamiast potwierdzenia płatności, otrzymuję ekran logowania…

Innym problemem jest zapamiętywanie haseł i wartości wpisanych w formularzach przez przeglądarki. Wartości te są także przypisywane do domen. Jeżeli zapamiętam hasło na example.org/login/, to nie będzie ono proponowane przez przeglądarkę na www.example.org/login/

Możliwe rozwiązania: Rozwiązanie II

serwer jest zdezorientowany

Przy korzystaniu z dwóch wirtualnych hostów, w zależności od konfiguracji serwera, możemy mieć problem np. ze statystykami (odzielne statystyki dla www.example.org i example.org) lub ze skonfigurowaniem SSL. Niektóre roboty i wyszukiwarki mogą traktować adresy www.example.org i example.org jako niezależne strony (choć zdaje się, że Google już sobie z tym poradziło).

Możliwe rozwiązanie: Rozwiązanie II

Rozwiązanie II (dobre) - odbieramy wybór internautom

W tym rozwiązaniu należy dać wybór internautom, przez skonfigurowanie serwera tak, aby działały oba adresy (www.example.org i example.org) - tak jak w Rozwiązaniu I - a następnie odebrać wybór przez ustawienie przekierowania na jednym z adresów. Takie rozwiązanie możemy zrealizować na dwa sposoby:

Apache i mod_rewrite

Używamy mod_rewrite w Apache aby przekierować użytkownika z example.org na www.example.org. Można to zrobić np. tak:

<VirtualHost 127.0.0.1>
ServerName example.org
DocumentRoot /var/www/i/co/tam/jeszcze_chcecie
RewriteEngine On
RewriteRule ^/(.*)?$ http://www.example.org/$1?%{QUERY_STRING} [R=301,L]
</VirtualHost>

Moje ulubione rozwiązanie. Jest o tyle dobre, że przekieruje użytkownika bez utraty ścieżki i parametrów przekazanych metodą GET. Wady: dane przekazane metodą POST zostaną utracone.

PHP i header()

Jeżeli nie macie możliwości modyfikowania konfiguracji Apache, podobne rozwiązanie można uzyskać korzystając z PHP i funkcji header():

if($_SERVER['HTTP_HOST'] == 'example.org'){
header("Location: http://www.example.org{$_SERVER['REQUEST_URI']}");
die();
}

i po problemie!

Jak widać, można bez problemu skonfigurować serwer tak, aby działały obie domeny - www.example.org lub example.org. Cała trudność polega jedynie na zauważeniu problemu. W zależności od potrzeb możemy skorzystać z któregoś z rozwiązań. W obu jednak trzeba pamiętać o tym, że serwery DNS muszą zwracać IP serwera dla obu domen.

Apel dnia ;)

Nie narzucajmy sztucznych i niepotrzebnych ograniczeń!

Takim niepotrzebnym ograniczeniem jest właśnie wymaganie wpisywania www lub to o którym pisał kiedyś Robert Drózd: Za krótkie - źle, za długie - też źle.

2^8 dzień roku

wrzesień 13th, 2007

W 28 dniu roku, wszystkim programistom życzę wszystkiego najlepszego z okazji Dnia Programisty. Ciekawy jestem, jak go obchodzicie…

Systemy komunikacji

czerwiec 5th, 2007

Wpis z pierwszego kwietnia był oczywiście żartem, ale tylko w części. Prawdą w nim jest to, że pożegnałem się ze swoim dotychczasowym pracodawcą i nie pracuję już nad systemami SIECI T2.

Teraz, wraz z grupą profesjonalistów pracuję nad nowymi, nowatorskimi systemami, także związanymi z komunikacją IP. Pierwsze wdrożenia i sukcesy już za nami, a praca nad nowymi produktami trwa w najlepsze!

Wszysktich zainteresowanych zapraszam:

teleakademia.pl


statystyki