Joomla@jogger.pl

 

18

kwietnia

2010

Problemy z UTF-8

Gdy zajmujemy się wdrażaniem rozszerzeń dla Joomla!, które są używane do wyświetlania tekstów w różnych językach może pojawić się problem z kodowaniem znaków lub błędnym obliczaniem pozycji znaków w tekście. Wszystkiemu winne są funkcje PHP służące do operowania na ciągach znaków.

W czym tkwi problem ?

Standardowe funkcje PHP takie jak np. substr, stripos nie są przystosowane do operowania na ciągach znaków w których znak może być reprezentowany jako więcej niż jeden bajt. W UTF-8 niektóre znaki są reprezentowane właśnie w taki sposób. Stąd powstało rozszerzenie dla PHP - Multibyte String - jego cechą charakterystyczną są funkcje z prefiksem "mb_". Co jednak jeżeli przygotowujemy rozszerzenie dla szerszego grona użytkowników z których nie każdy posiada zainstalowane u siebie takie rozszerzenie ?

JString

Rozwiązaniem problemu w takiej sytuacji jest klasa JString - jest ona swoistą nakładką na bibliotekę PHP UTF-8, która wchodzi w skład standardowych bibliotek dostarczanych razem z Joomla!.

Po zaimportowaniu klasy JString:

jimport('joomla.utilities.string');

możemy swobodnie korzystać z funkcji operujących na ciągach znaków, które poradzą sobie z UTF-8.

Pełna lista metod tej klasy znajduje się na tej stronie. Nie ma sensu ich tutaj kolejno opisywać gdyż są to po prostu odpowiedniki funkcji znanych z PHP. Jedyną niestandardową metodą jest transcode, która bazuje na rozszerzeniu iconv i pozwala na konwersję ciągu znaków z jednego kodowania na inne (w tym wypadku z UTF-8 na ISO-8859-2):

JString::transcode('UTF-8', 'ISO-8859-2', $text);

Wszystkie metody klasy JString są statyczne więc przykładowo wywołanie metody substr ogranicza się do zapisu:

JString::substr($text, 0);

Dzięki funkcjonalnościom tej klasy unikniemy sytuacji w której użytkownik z Grecji żali się nam, że nasz moduł wyświetlający skróty artykułów zamiast znaków jego alfabetu wyświetla znaki zapytania :)

 
 

11

kwietnia

2010

JBrowser

Dosyć często widuję w kodzie różnego rodzaju rozwiązań dla Joomla!, że jego twórcy próbują odkrywać koło na nowo - tak jest np. w wypadku detekcji przeglądarek. Tak jakby mało kto sobie zdawał sprawę z tego, że framework na którym bazuje Joomla! udostępnia całkiem sensowne rozwiązanie jakim jest klasa JBrowser.

Napisałem, że JBrowser to całkiem sensowne rozwiązanie, ponieważ ma oczywiście kilka wad - z moich testów wynika, że np. nie rozróżnia ona Chrome i Safari, a Safari w iPhone jest traktowane tak samo jak jego desktopowe odpowiedniki - wszystkie trzy przeglądarki są rozpoznawane jako "konqueror". Natomiast świetnie sobie radzi z najważniejszym zagadnieniem jakim jest detekcja różnych wersji IE, bo to w zasadzie główne zastosowanie detekcji przeglądarek (poza detekcją przeglądarek mobilnych). Podobny problem tyczy się listy wspieranych przez przeglądarkę udogodnień - jako, że klasa JBrowser była stworzona jakiś czas temu to nie poinformuje nas, że nowsze wersje Opery wspierają format SVG. Ale te problemy da się oczywiście wyeliminować dzięki dość szerokiej gamie metod oferowanych przez tą klasę.

Tworzenie obiektu klasy JBrowser

Aby rozpocząć pracę z klasą JBrowser musimy najpierw ją zaimportować, gdyż nie wchodzi ona w skład klas standardowo używanych przez rozszerzenia Joomla!. Aby to zrobić umieszczamy w naszym kodzie linijkę:

jimport('joomla.environment.browser');

Obiekty tej klasy możemy tworzyć przez standardowy konstruktor, lub z użyciem metody getInstance, osobiście polecam ten drugi sposób, chyba, że mamy jakiś powód dla którego musimy uzyskać niemodyfikowany wcześniej obiekt klasy JBrowser - wtedy lepiej skorzystać ze standardowego konstruktora.

$browser = JBrowser::getInstance();

Zarówno konstruktor jak i metoda getInstance pobierają dwa argumenty - ciąg user agent oraz zawartość nagłówka HTTP_ACCEPT. Oba te argumenty są oczywiście opcjonalne i mają wpływ na pozostałe składowe obiektu.

Jeżeli chcemy określi wspomniane dwa parametry już w czasie istnienia obiektu to możemy skorzystać z funkcji match, która działa tak samo jak getInstance z podanymi dwoma argumentami:

$browser->match("ciąg user agent", "ciąg HTTP_ACCEPT");

Tablice _features, _quirks i _robots

Obiekt klasy JBrowser zawiera trzy interesujące tablice:

I oczywiście mamy też kilka metod związanych z tymi tablicami. Możemy sprawdzić czy dane rozwiązanie jest wspierane przez przeglądarkę poprzez metodę getFeature:

$browser->getFeature('svg');

Jeżeli dodatkowo wykryjemy, że np. mamy do czynienia z Operą w nowszej wersji to wpierw możemy jej ustawić wsparcie dla SVG poprzez metodę setFeature:

$browser->setFeature ('svg');

Domyślna wartość drugiego argumentu tej metody to true, stąd go nie podaję.

Tak samo wygląda sytuacja z obsługą tablicy _quirks - mamy metody getQuirk i setQuirk, które pobierają argumenty w identycznej ilości i typie. Dodatkowo mamy do dyspozycji metody hasFeature i hasQuirk, które sprawdzają czy dana pozycja znajduje się w danej tablicy.

Aby stwierdzić czy aktualna przeglądarka odwiedzająca naszą witrynę jest botem jednej z wyszukiwarek wystarczy wywołać metodę isRobot:

if($browser->isRobot()) {
    // kod wykonywany gdy przeglądarka jest botem
}

Tutaj polecam też zapoznanie się z listą dostępną na http://www.user-agents.org/ i ewentualne uzupełnienie standardowej listy o dodatkowe pozycje by lepiej wykrywać boty wyszukiwarek.

Detekcja platformy i przeglądarki

Oczywiście głównym wątkiem związanym z klasą JBrowser jest sama detekcja rodzaju przeglądarki - związane z tym jest kilka metod, pierwszą z nich jest getAgentString, która zwraca nam cały ciąg user agent:

$user_agent = $browser->getAgentString();

I tą metodę będziemy wykorzystywać do detekcji wszelkich przeglądarek nierozpoznawanych standardowo przez klasę JBrowser. Przykładowo dla detekcji iPhone wykonamy kod:

$is_iphone = false;

if(preg_match('/iPhone/',$browser->getAgentString())){
    $is_iphone = true;
}

Aby poznać nazwę przeglądarki i platformy użytkownika korzystamy z metod getBrowser i getPlatform:

echo 'Przeglądarka:' . $browser->getBrowser(). '<br />';
echo 'OS:' . $browser->getPlatform();

Możemy też uzyskać informacje o wersji protokołu HTTP:

$browser->getHTTPProtocol();

Oraz dokładne informacje o wersji przeglądarki:

echo $browser->getMajor() . '<br />';
echo $browser->getMinor() . '<br />';
echo $browser->getVersion();

W wypadku IE 8.0 uzyskamy po uruchomieniu powyższego kodu następujące trzy linijki:

8
0
8.0

Inne metody klasy JBrowser

Wracając jeszcze do przykładu z iPhone - zamiast korzystać z dodatkowej zmiennej $is_iphone, możemy to zrobić bardziej elegancko, poprzez metody setBrowser i isBrowser:

if(preg_match('/iPhone/',$browser->getAgentString())){
    $browser->setBrowser('iPhone');
}

Natomiast późniejszego rozpoznania iPhone dokonamy poprzez:

if($browser->isBrowser('iPhone')){
    // kod wykonywany tylko na iPhone
}

Na koniec pozostała nam jeszcze metoda isSSLConnection, która sprawdza czy bieżące połączenie jest połączeniem szyfrowanym - dzięki temu możemy wyświetlić na stronie stosowny komunikat gdy wiemy, że na danej stronie połączenie powinno być szyfrowane a nie jest.

 
 

Miniblog