PHP Solutions 04 2007 PL

84

description

* osCommerce* Aplikacje www* CakePHP* Prado* Python kontra PHP* eZ Publish* RBAC* Agavi* PDF* PostNuke* Stałe łącza internetowe* Gotowe rozwiązania przeciwko zdrowemu rozsądkowi

Transcript of PHP Solutions 04 2007 PL

Page 1: PHP Solutions 04 2007 PL
Page 2: PHP Solutions 04 2007 PL
Page 3: PHP Solutions 04 2007 PL
Page 4: PHP Solutions 04 2007 PL

4 5

06 AKTUALNOŚCIKrzysztof Trynkiewicz

08 OPIS CDŁukasz Skowroński, Magdalena Maryańska

DLA POCZĄTKUJĄCYCH10 osCommerceMagdalena MaryańskaMagdalena w sposób prosty i przejrzysty pokaże Ci, jak zmienić do-myślny wygląd sklepu osCommerce. Po przeczytaniu tekstu wstawie-nie własnego banera, zmiana rozmiaru czy kolorystyki sklepu nie bę-dzie już żadnym problemem.

PRAKTYKA14 Aplikacje wwwŁukasz SkowrońskiŁukasz opisuje sposób wykorzystania buforowania aplikacji www. Dzięki temu zabiegowi zwiększysz wydajność swojej strony. Artykuł jest niezbędny każdemu programiście, gdyż napisanie dobrej aplikacji jest niemożliwe bez poruszenia tematyki wydajności.

TECHNIKA18 CakePHPPiotr GapińskiPiotr pokaże Ci zasady tworzenia i zarządzania znacznikami. Zapre-zentuje również sposoby ich wyświetlania jako tzw. chmury znaczni-ków. Wiedza na ten temat przyda się każdemu programiście.

SPIS TREŚCI

PHP Solutions jest wydawany przez Software-Wydawnictwo Sp. z o.o.

Dyrektor wydawniczy: Sylwia Pogroszewska

Redaktor naczelny: Patrycja Wądołowska [email protected]

Redaktor prowadzący: Dorota Pączka [email protected]

Korekta: Mateusz Lipiński [email protected]

Kierownik produkcji: Marta Kurpiewska [email protected]

Projekt okładki: Agnieszka Marchocka

Skład i łamanie: Robert Zadrożny [email protected]

Dział reklamy: [email protected]

Prenumerata: Marzena Dmowska [email protected]

Nakład: 6 000 egz.

Page 5: PHP Solutions 04 2007 PL

4 5

24 PradoMichał GajekMichał opisuje zasady tworzenia stron z użyciem frameworka PRADO. W tekście znajdziesz też sposób na zrobienie prostej aplikacji – księgi gości. Dzięki dużej liczbie gotowych komponentów wykorzystanie PRA-DO jest bardzo wygodne.

28 Python kontra PHPPiotr MalińskiPiotr opisuje opensourcowy projekt Python. Z pewnością znasz już ję-zyk PHP, służący do tworzenia stron, a teraz zapraszamy Cię do przyj-rzenia się innemu projektowi. Piotr prezentuje go w przyjemny do czy-tania sposób analizy w kontekście PHP.

BEZPIECZEŃSTWO36 eZ PublishJuliusz CałyniukJuliusz pokaże Ci, czym jest CMF oraz eZ Ecosystem. Poznasz również podstawy architektury eZ Publish i jej możliwości. Dzięki temu arty-kułowi dowiesz się, że eZ Publish znany jako system zarządzania tre-ścią możesz wykorzystać jako wzorzec projektowy. Artykuł pokazuje, że system dostarcza doskonałe możliwości integracyjne

40 RBACAdam ByrtekAdam pokaże Ci model RBAC i nauczy, jak przy jego użyciu zaprojek-tować elastyczny i rozszerzalny model kontroli dostępu. Dzięki opisa-nemu modelowi opartemu o role dowiesz się, jak łatwo administro-wać uprawnieniami. Artykuł opisuje, jak uniknąć zaszywania kontroli dostępu bezpośrednio w kodzie.

NARZĘDZIA

46 Agavi Łukasz DywickiŁukasz pokaże Ci, jakie możliwości posiada framework Agavi oraz jak możesz je wykorzystać. Prosto przeprowadzi Cię przez instalację, a następnie pokaże, jak utworzyć nowy projekt.

54 PDFTomasz KrawczykTomasz pokaże Ci, jak przygotować bibliotekę do pracy oraz utworzyć dokumenty PDF i wypełniać je. Musisz tylko wiedzieć, jak tworzyćo-biekty w PHP oraz dziedziczyć i pisać własne funkcje. Artykuł pokaże Ci, jak możesz używać tego najpopularniejszego formatu.

62 PostNukeMichał GackiMichał prezentuje zasady działania PostNuke. Jest to system zarzą-dzania treścią powstały na bazie starej wersji PHP-Nuke. Każdy po-czątkujący programista PHP po zapoznaniu się z artykułem będzie miał doskonałą podstawę do nauki o CMSach.

TESTY KONSUMENCKIE74 Stałe łącza internetowe

78 RECENZJE

79 FELIETONŁukasz SkowrońskiGotowe rozwiązania przeciwko zdrowemu rozsądkowi

Adres korespondencyjny:Software-Wydawnictwo Sp. z o.o., ul. Bokserska 1, 02-682 Warszawa, Polskatel. +48 22 887 13 35, fax +48 22 887 10 11www.phpsolmag.org [email protected]

Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy G DATA Software Sp. z o.o.

Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu nośnikach informacje i programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantuje także poprawnego działania programów shareware, freeware i public domain.

Uszkodzone podczas wysyłki płyty wymienia redakcja.

Wszystkie znaki firmowe zawarte w piśmie są własności odpowiednich firm zostały użyte wyłącznie w celach informacyjnych.

Redakcja używa systemu automatycznego składu

Do tworzenia wykresów i diagramów wykorzystano program firmy

Osoby zainteresowane współpracą prosimy o kontakt:[email protected]

Druk: ArtDruk

Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie CD-ROM dostarczonej razem z pismem.

Sprzedaż aktualnych lub archiwalnych numerów pisma po innej cenie niż wydrukowana na okładce – bez zgody wydawcy – jest działaniem na jego szkodę i skutkuje odpowiedzialnością sądową.

Pismo ukazuje się w następujących wersjach językowych:

polskiej , francuskiej

Page 6: PHP Solutions 04 2007 PL

xxxxxxxxxxx

Aktualności

6 xxxxxxxxxxxxxxx

Aktualności

7

10 podstawowych zasad prowadzenia projektów open sourceW życiu niemal każdego dewelopera przy-chodzi wreszcie moment, w którym uświa-damia sobie, że większość jego wiedzy została zdobyta dzięki projektom open source oraz darmowym tutorialom. Wtedy też często zapada decyzja o zaangażo-waniu się w rozwój gotowych rozwią-zań o ogólnodostępnym kodzie - czy to w ramach wdzięczności, czy też z potrze-by zaistnienia w społeczności. Bywa także, że dobre pomysły z fazy planowania prze-chodzą do fazy realizacji, tworząc równo-cześnie wokół siebie sieć community mem-bers. Tobias Schlitt, certyfikowany przez Zend programista, brał udział w tego typu przedsięwzięciach. Efektem wielu lat pracy jest opisany na jego blogu zbiór dziesięciu trafnych porad, które być może, po prze-czytaniu przygaszą lekko zapał począt-kujących deweloperów, ale równocześnie gładko wprowadzą w realia prowadze-nia projektu open source. Jeśli planuje-my dorzucić nasze trzy grosze do wspólnej puli open source, to warto najpierw zapo-znać się z jego doświadczeniami.http://schlitt.info/applications/blog/index.php?/archives/541-10-golden-rules-for-starting-with-open-source.html

XML do PHPCzysty HTML powoli odchodzi w niepa-mięć. Wprawdzie niedawno powołano zespół mający pracować jeszcze nad udo-skonaleniem wersji 4 tego języka, jednak wiadomo, dokąd zazwyczaj zmierza webde-velopment. Pierwszym, świeższym podej-ściem do tematu ustandaryzowania znacz-ników był xHTML. Teraz na popularności zyskuje XML – nadaje się bowiem także do przechowywania danych oraz komunikacji przy pomocy różnych protokołów. Jeśli więc jeszcze nie stosowaliśmy XML w naszych projektach, prawie na pewno będziemy do tego zmuszeni. Gdy już zajdzie taka potrze-ba, należy wiedzieć, jak parsować dane z formatu XML do PHP. Z pomocą przycho-dzi pakiet XJConf for PHP, domyślnie napi-sany dla użytkowników Javy i zaadaptowa-ny do PHP. Oferuje on parsowanie dowol-nych plików XML, zwracając dane w posta-ci dowolnych typów zmiennych PHP (za-równo prostych, jak obiektów). Przystęp-na licencja LGPL gwarantuje, że rozwiąza-nie można bez problemu stosować w pro-jektach komercyjnych. Pakiet dostępny jest zarówno jako archiwum do pobrania z poniższej strony, jak również w ramach repozytorium PEAR. Chociaż XML staje się bardzo popularny, ilość dobrych parse-rów dla PHP jest niewielka. Naturalnie, sam PHP zawiera funkcje pomocne przy parso-waniu takich dokumentów, które zostały dodatkowo napisane całkowicie od nowa w PHP5 (w oparciu o libxml2), jednak użycie ich w praktyce wymaga czasu. Warto więc zapoznać się z opisanym projektem.http://php.xjconf.nethttp://pl2.php.net/xmlhttp://devzone.zend.com/node/view/id/1713

Trac – otwieramy własny projekt opensource

Czy wreszcie nadszedł Twój czas na zajęcie miejsca wśród społeczno-ści deweloperskiej? Jeśli odpowiedź

brzmi tak i zamierzasz dokonać tego przez udostępnienie kodu jednego ze swoich pro-jektów, to na pewno dojdziesz do wniosku, że w praktyce uruchamiasz kolejny projekt.

Dobry pomysł i jego realizacja to bowiem nie wszystko, co gwarantuje, że użytkownicy będą wdzięczni. Jeśli prezentujemy nasz pro-dukt, to musimy pokazać go jak najlepiej. W praktyce oznacza to, że potrzebujemy nowej witryny do obsługi naszego projektu openso-urce.

Witryna ta musi być przejrzysta, łatwa w edytowaniu (w końcu nasz projekt powinien rozwijać się prężnie) i zawierać typowe mo-duły: dział download z podziałem na wersje, FAQ, forum dla użytkowników, system ra-portowania błędów, system wprowadzania nowych pomysłów i udoskonaleń, wyszuki-warkę oraz dokumentację.

Jak widać, udostępnienie naszego kodu wymaga niejednokrotnie napisania znacznie większej jego ilości (oprogramować trzeba jeszcze stronę).

Z pomocą przychodzi Trac – darmowy sys-tem opensource w stylu Wiki, który oferuje wsparcie dla wyżej wymienionych działów i świetnie zdaje egzamin, jeśli zależy nam na szybkim udostępnieniu kodu w dobrym sty-lu – nasz czas będziemy mogli poświęcić na rozwój faktycznego projektu.

Trac oferuje także podział na kategorie w wielu działach – na przykład w tzw. Road-Map, która stanowi plan rozwoju naszego projektu. Możemy w niej umieszczać kolejne zadania i przypisywać je do określonych wer-sji aplikacji, co bardzo pomaga w zarządzaniu projektem.

Lista projektów, które korzystają z Trac jest już bardzo długa – ma ponad 100 pozy-cji i szybko rośnie. Sam skrypt zawiera w so-bie schludny layout, zaś jego atutem jest szyb-kość działania. Jeśli zamierzamy udostępnić nasz kod światu, Trac bardzo ułatwi nam to zadanie.

http://trac.edgewall.org

Page 7: PHP Solutions 04 2007 PL

xxxxxxxxxxx

Aktualności

6 xxxxxxxxxxxxxxx

Aktualności

7

Resources w sesji? Czemu nie!Wszyscy dobrze wiemy, jak wielkim mankamen-tem jest niemożność używania różnego typu danych w zmiennych sesyjnych. Przykładem może być choćby identyfikator połączenia z bazą danych. Jeśli przekażemy go do sesji, otrzymamy ciąg niewiele mówiących znaków, a w przypad-ku PHP5, otrzymamy informację o błędzie. Pro-blem polega na tym, że dane sesyjne przechowy-wane są najczęściej w plikach tekstowych, podle-gają więc konwersji na ciąg znaków. Jakkolwiek problemem nie jest wtedy zapisanie zmiennych typu string, tablic, czy obiektów, natomiast sytu-acja z innymi typami jest już patowa – w przy-padku połączenia MySQL, nie mamy szans na osiągnięcie zamierzonego celu. Przynajmniej teoretycznie, bowiem w praktyce możemy zse-rializować dane połączenia, a potem je odtwo-rzyć. Sprytny sposób rozwiązania tego problemu zaprezentował Damien Seguy. Dodatkowo, pod poniższym adresem przeczytamy, jak skompre-sować tego typu dane, by zaoszczędzić na trans-ferze. Dla zaawansowanych programistów lektu-ra obowiązkowa.http://www.nexen.net/articles/dossier/16932-the_month_of_php_functions_:_home_made_serialisation.php

Nowy zarząd PEARGrupa PEAR przechodzi zmiany. Wybra-ny został bowiem nowy zarząd, a co za tym idzie, nowe cele. W chwili pisania aktualności, nie była znana jeszcze dokładna obsada trzy-nastu wolnych stanowisk. Znane natomiast były postulaty osób mających je zająć. Ogól-nie nie są one zbyt rewolucyjne, wyjątkiem jest wiadomość, umieszczona w notkach na blogach deweloperów, na temat PEAR2 (do-stępnego tylko dla PHP5). Więcej informacji na ten temat można znaleźć na blogach:http://blog.agoraproduction.com/index.php?/archives/35-PEAR-Group-Elec-tions-tomorow!-Vote-for-me!-D.htmlhttp://blog.joshuaeichorn.com/archives/2007/04/19/pear-elections-begin-tomorrow

Stubbles – nowy framework dla PHP 5Nowe możliwości OOP w PHP5 znajdują odzwierciedlenie w coraz większej ilości powsta-jących frameworków. Już teraz jest ich tak wiele, że z pewnością każdy znajdzie odpowiedni pro-jekt dla siebie. Oczywiście, opieranie się na fra-meworkach ma większy sens tylko w przypad-ku, gdy w pełni odpowiadają naszym wyma-ganiom. W praktyce podpatrujemy rozwiąza-nia, które następnie możemy implementować w naszych własnych, autorskich rozwiązaniach. Pisany pod kątem PHP 5.2 framework Stubbles szczyci się prostą i przejrzystą implementacją wzorców projektowych na bazie OOP. Próbuje on także wprowadzić kilka pożytecznych funk-cjonalności rodem z Javy przy pomocy dodatku stubReflection. Z tego powodu, projekt ten jest szczególnie wart uwagi programistów „przesia-dających” się z języka Java na PHP. Framework rozwijany jest przez trzech głównych dewelope-rów i kilka innych osób, które tworzyły już projekty open-source (m.in. pakiety PAT opisane we wcze-śniejszym wydaniu aktualności).http://www.stubbles.orghttp://www.stubbles.org/archives

Konkurencja dla Wordpress?

Szybciej niż serwisów społecznościowych Web 2.0 przybywa już tylko blogów. W Internecie mnożą się oferty serwisów, któ-

re za darmo oferują możliwość założenia własne-go dziennika. Ciężko określić, który z nich wie-dzie prym, bowiem niemal każdy serwis społecz-nościowy ma wbudowaną możliwość blogowania dla użytkowników i jest zintegrowany z dodatko-wymi funkcjonalnościami – przykładem może być YouTube czy MySpace. Pewne jest natomiast, że dla dewelopera PHP takie rozwiązanie nie jest najlepsze – jako programiści, często potrzebuje-my dodatkowych funkcjonalności, a co za tym idzie – dostępu do interpretera PHP. Tego, z oczy-wistych względów, nie uświadczymy w przypad-ku darmowych serwisów typu Blogger. Przy po-szukiwaniu gotowych aplikacji pozwalających na założenie własnego bloga niewątpliwie najpierw trafimy na Wordpress. System ten jest bardzo po-pularny, rozwinięty i oferuje szeroką gamę dodat-ków dla zaawansowanych użytkowników. Moż-na rzec, że konkurencja nie ma nawet możliwo-ści przebicia się. W praktyce, zaawansowani użyt-kownicy coraz częściej wybierają rozwiązania ty-pu Jogger – wpisów do takiego pamiętnika można dokonywać bezpośrednio z poziomu komunika-tora sieci Jabber (XMPP). Warto jednak przyjrzeć się także innym rozwiązaniom, bowiem z czasem Wordpress także może ulec, jak to zwykle bywa, przerostowi formy nad treścią (jak np. phpBB w opinii wielu użytkowników). Alternatywą może być Serendipity. Co oferuje? Na dobry początek ponad 120 dodatków. System szablonów oparto o Smarty (obecnie jest ich kilkadziesiąt), zastoso-

wano system automatycznego sprawdzania obec-ności nowych wersji na oficjalnej witrynie. Do dys-pozycji mamy także edytor WYSIWYG, komen-tarze, wielokrotnie zagnieżdżane kategorie, ob-sługę wielu języków, wbudowaną bazę mediów, wątki RSS, filtry antyspamowe oraz to, co mo-że się bardzo przydać – system importowania i eksportowania wpisów, obsługujący m.in. Word-press. Całość może działać na bazach MySQL, MySQLi, PostgreSQL lub SQLite. Przy pomocy dzielonych zasobów, możemy z jednej instalacji poprowadzić wiele blogów. Lista użytkowników systemu podawana jest w tysiącach, co gwaran-tuje, że zawsze możemy liczyć na pomoc społecz-ności oraz dobrze opracowaną dokumentację. Sys-tem ten dostępny jest na licencji BSD i ma zadatki na poważnego rywala Wordpress.

http://wordpress.orghttp://www.s9y.orghttp://blogger.comhttp://jabberstudio.org

Page 8: PHP Solutions 04 2007 PL

04/20078 www.phpsolmag.org 9

Opis CD

MySQL (film instruktażowy)Specjalnie dla czytelników PHP Solutions przygotowaliśmy krótką serię filmów, których tematyka oscyluje wokół MySQL. W pięciu krótkich filmach przekażemy Ci wiedzę dotyczącą in-stalacji i administracji serwerem MySQL. Jeżeli wcześniej nie miałeś styczności z tymi zagadnieniami, powinieneś obejrzeć ten materiał.

W pierwszym filmie zajmiemy się instalacją serwera My-SQL oraz dodatkowo zainstalujemy serwer Apache z PHP i PHPMyAdmin. W efekcie otrzymamy serwer gotowy do na-uki i do pracy.

W następnych filmach zajmiemy się administracją naszej ba-zy danych spod linii komend jak i PHPMyAdmin-a. Dowiesz się, jak tworzyć nowych użytkowników ze zróżnicowanymi prawa-mi dostępu oraz tworzyć kopie zapasowe Twoich danych. Obie te umiejętności są niezbędne do swobodnej i bezpiecznej pracy z MySQL.

W dwóch kolejnych filmach zajmiemy się przykładowym opro-gramowaniem, które pomoże Ci w projektowaniu (DBDesigner) i zarządzaniu bazą danych (AquaDataStudio). Takie programy mo-gą ułatwić Ci korzystanie z MySQL. Na pewno są ciekawą alterna-tywą dla tradycyjnych metod.

Na koniec zajmiemy się interesującym zagadnieniem reseto-wania hasła root-a dla serwera MySQL. Jest to bardzo przydatna umiejętność, która nieraz może uratować Cię przed utratą danych na skutek reinstalacji serwera.

OsCommerce (animacja)Na płycie CD dołączonej do tego numeru magazynu umieszczo-ne zostały pliki potrzebne do uruchomienia i odpowiedniego działania sklepu osCommerce (wersja 1.03 PL).

Pliki zostały odpowiednio zmodyfikowane w celu uzyska-nia nowego wyglądu - w sposób szczegółowo opisany w artyku-le (osCommerce Nowy wygląd krok po kroku, Magdalena Ma-ryańska).

Ponadto na płycie znajduje się animowana instrukcja instalacji oraz konfiguracji sklepu.

W filmie pokazano krok po kroku, jak samodzielnie zainstalo-wać sklep na serwerze. Animacja składa się z trzech części - pre-zentacja pokazująca instalację poprzedzona jest informacjami o wymaganiach oraz przygotowaniach potrzebnych do zainstalowa-nia sklepu.

Druga część pokazuje wszystkie kolejne etapy instalacji oraz wskazuje potrzebne zmiany w plikach na serwerze.

Część trzecia natomiast przedstawia ustawienia zainstalo-wanego sklepu oraz sposoby ich modyfikacji - w tym opis pa-nelu administracyjnego, zarządzanie kontami, zmiany poszcze-gólnych wartości, edycję strony głównej, opis najważniejszych działów oraz prezentację dodawania cech do produktów.

Page 9: PHP Solutions 04 2007 PL

04/20078 www.phpsolmag.org 9

Redakcja nie udziela pomocy technicznej w instalowaniu

i użytkowaniu programów zamieszczonych na płytach

CD-ROM dostarczonych razem z pismem.

Jeśli nie możesz odczytać zawartości płyty CD, a nie

jest ona uszkodzona mechanicznie, sprawdź ją na co

najmniej dwóch napędach CD. W razie problemów

z płytą, prosimy pisać pod adres: [email protected]

Page 10: PHP Solutions 04 2007 PL

04/2007

Dla początkujących

10

osCommerce

www.phpsolmag.org 11

Mimo utrudnień – pamiętając o tym, że wygląd jest równie ważny w sprze-daży internetowej jak funkcjonalność

– warto poświęcić trochę czasu na opracowanie własnej, ciekawszej formy. W artykule tym po-każemy, że nie jest to takie trudne, zwłaszcza kie-dy wiadomo, gdzie należy szukać danych infor-macji. Obrazki Rysunek 1. oraz Rysunek 2. po-kazują wygląd sklepu przed i po wprowadzeniu zmian (przeglądarka Internet Explorer, rozdziel-czość ekranu 1024x768).

Zmieniamy szerokośćsklepu i kolor tłaPlik center_shop.php (katalog includes/languages/polish) zawiera następujące ustawienia:

• wyśrodkowanie sklepu (domyślnie włą-czone),

• szerokość (domyślnie ustawioną na 780 px),• wyświetlanie tła wokół sklepu (domyślnie

włączone),• kolor tła wokół sklepu (domyślnie ciemno-

szary),• kolor tła dla zawartości sklepu (domyślnie

biały),

• dodatkowy margines dookoła sklepu (do-myślnie brak),

• wyświetlanie logo osCommerce jako górny baner.

Oprócz wymienionych, znajdują się tam rów-nież ustawienia dotyczące wyświetlania obraz-ka (logo osCommerce) wraz z linkiem na stro-nie głównej. Poprzez modyfikację odpowied-nich sekcji tego pliku, możliwa jest zmiana domyślnego loga na własne (wraz z linkiem) . Wygląd strony głównej łatwiej jest jednak edy-tować za pomocą panelu administracyjnego.

W naszym przykładzie zmieniona została wartość CENTER_SHOP_WIDTH (szerokość sklepu) na 1002 i CENTER_SHOP_BACK-GROUND_COLOR_OUT na #CDC7D8 (ko-lor tła wokół sklepu). Ustawiliśmy również war-tość HEADER_IMG_LINK_ON na 0, żeby nie wyświetlać loga osCommerce w banerze.

Plik header.phpPlik header.php (katalog includes) zawiera definicje głównych tabel sklepu. Pierwsza z nich to „otocz-ka” wokół sklepu, druga to sklep „właściwy”. Żeby zlikwidować dodatkowy margines wokół sklepu, ustawiamy wartości CELLSPACING, CELLPAD-DING oraz BORDER w dwóch pierwszych tabe-lach na 0. W pliku tym zawarte są również infor-macje o górnej części sklepu: banerze, górnych iko-nach oraz pasku znajdującym się pod ikonami. Bę-dziemy je modyfikować w dalszej części artykułu.

Plik stylesheet.cssZnaczna część wyglądu sklepu określona jest przez plik stylesheet.css (katalog główny). Mo-dyfikując go możemy np. zmienić kolor tła ca-łej strony (będzie ono jednak widoczne tylko w trakcie ładowania się strony, a następnie zosta-nie przysłonięte przez kolor tła pierwszej tabeli, która obejmuje 100% strony). Kolor tła strony określa wartość background w klasie BODY.

Wstawiamy własny baner oraz ikony górne Zmieniając wpis w pliku center_shop.php usunę-liśmy już logo osCommerce wyświetlające się ja-ko górny baner. Teraz umieścimy w tym miejscu nasz własny baner oraz zamienimy 3 górne do-myślne ikony na własne. W pliku header.php kolej-na (trzecia) tabela wyznacza obszar zarezerwowa-ny na baner oraz ikon, a jej wygląd określa klasa he-ader w pliku stylesheet.css. Modyfikujemy tę klasę odnajdując w pliku stylesheet.css wpis TR.header (wygląd wiersza w tabeli) i umieszczając w nim dane odpowiedzialne za odpowiednią wysokość oraz wyświetlenie baneru jako tła. Po wprowadze-niu zmian nasza klasa wygląda tak:

TR.header {

background: url('baner.png') no-repeat;

height: 160px;

}

W naszym przykładzie jako tło wstawiliśmy plik baner.png (umieszczony w katalogu głów-nym) o wysokości 160 px .

IkonyW prawym dolnym rogu baneru wyświetlają się trzy domyślne ikony sklepu: Moje konto, Zawar-tość koszyka oraz Zamówienie. Możemy je usunąć lub podmienić własnymi obrazkami. Aby pod-mienić ikony na własne, należy skopiować własne pliki graficzne jako: header_account.gif (Moje kon-to), header_cart.gif (Zawartość koszyka) oraz he-ader_checkout.gif (Zamówienie) do katalogu ima-

osCommerce

Wiele osób uważa domyślny wygląd sklepu osCommerce za mało interesujący. Niestety modyfikacja pliku CSS w tym przypadku nie wystarczy, ponieważ elementy odpowiedzialne za wygląd sklepu rozmieszczone są także w kilku innych miejscach. Dodatkowo pracę nad wyglądem utrudnia fakt, że układ sklepu osCommerce oparty został na wielu zagnieżdżonych tabelach.

Dowiesz się...• Pokażemy, jak zmienić domyślny wygląd sklepu

osCommerce – wyjaśnimy, w jaki sposób moż-na wstawić własny baner, ikony oraz przyciski, a także, jak zmienić rozmiary i kolorystykę skle-pu oraz usunąć niepotrzebne elementy.

• Opiszemy, które pliki umożliwią nam wprowa-dzenie zmian oraz jakie rezultaty osiągniemy modyfikując poszczególne wpisy.

Powinieneś wiedzieć...• Należy posiadać umiejętność zainstalowania

sklepu osCommerce.• Wymagana jest również podstawowa znajo-

mość CSS oraz PHP.

Poziom trudności

Nowy wygląd krok po kroku

Page 11: PHP Solutions 04 2007 PL

04/2007

Dla początkujących

10

osCommerce

www.phpsolmag.org 11

ges (w katalogu głównym) w miejsce istniejących. Opisy pojawiające się po najechaniu na poszcze-gólne ikony można zmienić w pliku polish.php (katalog includes/languages) przypisując zmien-nym: HEADER_TITLE_MY_ACCOUNT, HEADER_TITLE_CART_CONTENTS oraz HEADER_TITLE_CHECKOUT własne treści. Aby natomiast całkiem usunąć gór-ne ikony, należy w pliku header.php odnaleźć i usu-nąć (lub ująć w komentarz) linijkę jak na Listingu 1. oraz dodatkowo usunąć następujący fragment ko-du (Listing 2.). W ten sposób zostanie usunięta jed-na kolumna tabeli odpowiedzialnej za górny baner oraz fragment wyświetlający ikony.

Zmieniamy kolorystykę sklepuPod banerem, domyślnie znajduje się szary pa-sek, na którym umieszczono z lewej strony ścież-kę informującą o bieżącej lokalizacji, a z prawej dodatkowe linki odpowiadające trzem opisa-nym powyżej górnym ikonom. Pasek ten two-rzy kolejna tabela zawarta w pliku header.php, jeśli więc chcemy go zlikwidować musimy usu-nąć z pliku tę tabelę. Jej wygląd opisuje klasa headerNavigation . Aby zmienić kolor paska odnajdujemy w pliku stylesheet.css wpis TD.he-aderNavigation i zmieniamy wartość backgro-und (kolor tła). Wartość color określa w tym przypadku tylko kolor elementów pomiędzy linkami, takich jak >> czy |. Żeby zmienić ko-lor linków na pasku zmieniamy wpisy w klasie A.headerNavigation (kolor linków na pasku) oraz A.headerNavigation:hover (kolor linków na pasku po najechaniu). Należy jednak pamię-tać, że linki tej klasy znajdują się również na nie-których belkach ramek (tam, gdzie występują lin-ki zamiast napisów, np. w ramce Produkty pole-cane), więc ich kolor również zostanie zmienio-ny. Drugi pasek znajduje się u dołu sklepu. Tabe-la, która go tworzy znajduje się w pliku footer.php (katalog includes). Pierwsza zdefiniowana tabela w tym pliku to właśnie nasz dolny pasek – może-my ją usunąć, jeśli chcemy całkowicie zrezygno-wać z paska. Za wygląd tej tabeli odpowiada w pliku stylesheet.css klasa footer. Zmieniamy ko-lor paska oraz umieszczonych na nim napisów (data oraz ilość odwiedzin) modyfikując w pliku style.css wpis TD.footer. Druga tabela w pliku fo-oter.php wyświetla zawartość zmiennej FOOTER_TEXT_BODY określoną w pliku polish.php (katalog includes/languages/) – czyli ostatni napis na stro-nie, umieszczony pod dolnym paskiem (infor-macje o prawach autorskich osCommerce).

RamkiW sklepie osCommerce większość informa-cji rozmieszczona jest w ramkach tzw. boxach. Każda ramka posiada u góry „belkę” z nazwą danej ramki (Kategorie, Producenci, Promo-cje itd.), ma też określone obramowanie oraz wypełnienie. Tekst znajdujący się w ramkach określa klasa boxText. Modyfikując tę kla-sę w pliku stylesheet.css możemy określić ko-lor, rozmiar oraz krój czcionki dla napisów w boxach. Kolor linków (domyślnie czarny) mo-

Rysunek 1. Domyślny wygląd sklepu osCommerce

Rysunek 2. Wygląd sklepu po dokonaniu zmian

Page 12: PHP Solutions 04 2007 PL

04/2007

Dla początkujących

12

żemy zmienić w pliku stylesheet.css (klasa A), należy jednak pamiętać, że ustawienia, jakie tu wprowadzimy będą dotyczyły wszystkich linków w sklepie. Kolor tła dla ramek określa klasa infoBoxContents, a kolor obramowania znajduje się w klasie infoBox. Aby zmienić wygląd napisów na „belkach” modyfikujemy wpisy TD.infoBoxHeading w pliku styleshe-et.css – można zmienić rozmiar, kolor i czcion-kę napisu. „Belka” nad każdą ramką składa się z 3 plików graficznych: corner_left.gif, cor-ner_right.gif oraz corner_left_right.gif, a na nie-których znajduje się jeszcze dodatkowo mała strzałka – arraw_right.gif. Wszystkie te pliki znajdują się w katalogu images/infobox/. Mo-żemy wykonać własne obrazki i zamienić ni-mi istniejące; w naszym przykładzie przerobi-liśmy te pliki zmieniając ich kolor z zielonego na czerwony.

PrzyciskiDomyślne przyciski w osCommerce, to zaokrą-glone niebieskie prostokąty na białym tle, z bia-łym napisem oraz ikonką. Ich pliki znajdują się w katalogu includes/languages/polish/images/buttons – możemy je przerobić lub zamienić na własne. W naszym przykładzie zmieniliśmy tylko ich ko-lor z niebieskiego na czerwony, który bardziej pa-suje do wybranej przez nas kolorystyki.

Usuwamy, co niepotrzebneNa podstronach, w części środkowej, wyświe-tlają się domyślnie małe obrazki (Rysunek 3.), które nie wszystkim jednak mogą się po-dobać. Jeśli chcemy z nich zrezygnować, mu-simy usunąć wszystkie pliki *.gif, których na-zwa zaczyna się od table_background, z kata-logu images (w katalogu głównym).

Co nowego? i Witaj Nieznajomy!W domyślnej konfiguracji sklepu, na stro-nie głównej, pojawia się napis Co nowego? – możemy go usunąć lub zmienić w pliku in-dex.php z katalogu includes/languages/polish modyfikując wpis:

define('HEADING_TITLE', 'Co nowego?');

Napis ten wyświetla się ciemnoszarą, pogru-bioną czcionką o rozmiarze 20px – tak samo jak nazwa i cena w szczegółach produktu (okre-śla je ta sama klasa). Możemy zmienić te usta-wienia, modyfikując w pliku stylesheet.css wpis TD.pageHeading, DIV.pageHeading. Kolejnym napisem umieszczonym na stronie głównej jest Witaj Nieznajomy! – możemy go zmienić we wspomnianym już wcześniej pliku polish.php (katalog includes/languages). Przeglądając ten plik znajdziemy wiele domyślnie używanych opisów. Zawiera on m.in. tytuł strony oraz tekst powitalny, za który odpowiada linijka:

define('TEXT_GREETING_GUEST',

'Witaj <span class="greetUser">

Nieznajomy!</span> Czy chcesz się

<a href="%s"><u>zalogować</u></a>?

A może jeszcze nie masz u nas konta i

<a href="%s"><u>chciałbyś założyć

</u></a>?');

Obrazek na stronie głównejStronę główną możemy edytować korzystając z panelu administracji (Administracja –> Sklep: Za-wartość –> Boczne menu –> Sklep –> Edycja strony głównej). Za pomocą edytora możemy umieścić również własny tekst oraz obrazki. Wprowadzo-ne zmiany zostaną zapisane w pliku mainpage.php (katalog includes/languages/polish). Plik ten może-my również modyfikować „ręcznie” – możliwość ta przydaje się zwłaszcza, jeśli chcemy mieć więk-szą kontrolę nad wprowadzaną treścią.

PodsumowanieW tym artykule pokazaliśmy jak można samodziel-nie dopasować wygląd sklepu osCommerce do wła-snych potrzeb. Niestety panel administracyjny skle-pu nie oferuje zbyt wielu możliwości w zakresie do-stosowywania wyglądu. Przydatne są opcje zmia-ny rozmiarów obrazków wyświetlanych jako mi-niaturki czy nagłówki (Administracja –> Sklep: Za-wartość –> Boczne menu –>Konfiguracja –> Obraz-ki) . Możemy również określić liczbę produktów (Konfiguracja –> Wartości maksymalne) wyświetla-nych na stronie głównej (nowości) oraz w poszcze-gólnych ramkach (Bestsellery, Promocje, Nowe recen-zje itd.), czy też zrezygnować z wyświetlania ramki Produkty polecane (Konfiguracja –> Produkty poleca-ne). Żeby jednak bardziej znacząco wpłynąć na wy-gląd sklepu, musimy zagłębić się w zawartość pli-ków. Wiedząc, gdzie rozmieszczone są poszcze-gólne elementy odpowiedzialne za wygląd, można zmodyfikować domyślny szablon według własnych preferencji. Pomocne, w osiągnięciu zamierzonego efektu, mogą okazać się dodatkowe materiały, za-mieszczone na stronach których adresy znajdują się w ramce W Sieci.

MAGDALENA MARYAŃSKAAutorka pracuje w firmie a3a jako projektant stron internetowych.Kontakt: [email protected]

Listing 1. Likwidacja górnych ikon..

echo '<a href="' . tep_href_link(FILENAME_ACCOUNT, '', 'SSL') . '">' . tep_image(

DIR_WS_IMAGES . 'header_account.gif', HEADER_TITLE_MY_ACCOUNT)

. '</a>&nbsp;&nbsp;<a href="' . tep_href_link(FILENAME_SHOPPING_CART)

. '">' . tep_image(DIR_WS_IMAGES . 'header_cart.gif',

HEADER_TITLE_CART_CONTENTS) . '</a>&nbsp;&nbsp;<a href="' . tep_href_link(

FILENAME_CHECKOUT_SHIPPING, '', 'SSL') . '">' . tep_image(DIR_WS_IMAGES

. 'header_checkout.gif', HEADER_TITLE_CHECKOUT) . '</a>';

Listing 2. Linijka kodu, którą należy usunąć.

<?php if (HEADER_IMG_LINK_ON=='1') { ?>

<td valign="middle"><?php echo '<a href="' . tep_href_link(FILENAME_DEFAULT) . '">

' . tep_image(DIR_WS_IMAGES . 'oscommerce.gif', 'osCommerce')

. '</a>'; ?></td><?php

} else {

?>

<td valign="middle">

<?php echo tep_image(

DIR_WS_IMAGES . HEADER_IMG_PIC, HEADER_IMG_ALT)

. '<BR>'; ?></td>

<?php } ?>

Rysunek 3. Jedna z domyślnych ikonek wyświetlanych w tle

W Sieci

• Główna strona osCommerce – informacje, skrypty, skórki oraz wiele różnych dodatków http://www.oscommerce.com• Polskie forum poświęcone osCommerce – porady, dyskusje, moduły i dodatki http://www.oscommerce.pl• Generator przycisków osCommerce. – http://generator.oscpremium.com• Tabela kolorów dla stron www – http://algorytmy.pl/doc/xhtml/index.php?id=0108• Kursy CSS: http://webmade.org/kursy-online/kurs-css.php ; http://www.kurshtml.boo.pl/• Edytory HTML/CSS: http://dobreprogramy.com/index.php?dz=2&t=135&id=321• MED (wersja angielska lub niemiecka) – http://www.pfersdorff.de/de/downloadwin.html

Page 13: PHP Solutions 04 2007 PL
Page 14: PHP Solutions 04 2007 PL

Praktyka

4/200714

Aplikacje www

www.phpsolmag.org 15

Wraz ze wzrostem doświadczenia za-czynamy zastanawiać się nie nad tym, jak coś napisać, ale jak zrobić to

optymalnie. Chcemy mieć pewność, że aplikacja będzie działać szybko nawet przy dużym obciąże-niu i tutaj właśnie przychodzi nam z pomocą bufo-rowanie. W artykule tym zajmiemy się buforowa-niem w pliku informacji, które nie muszą być ge-nerowane za każdym razem oraz buforowaniem stron internetowych we współpracy z wyjątkami. To tylko dwa przykłady zastosowania buforowa-nia, ale warto je znać. Zapraszam do lektury.

Buforowanie dynamicznej strony www w plikuWyobraźmy sobie, że mamy serwis napisany przy pomocy PHP i MySQL. Za każdym razem wszystkie podstrony są generowane dynamicznie. Serwer musi więc przetworzyć kod PHP, połączyć się z bazą danych, wygenerować stronę oraz ją wy-świetlić. Możemy sobie zadać pytanie, co działoby się, gdyby serwer musiał jednocześnie wygenero-wać tysiąc takich stron? Prawdopodobnie każda z osób łączących się z naszą stroną musiałaby dłuż-szą chwilę odczekać, a jak wiadomo, nikt nie lubi tracić czasu. Z tego powodu któryś z odwiedzają-cych mógłby w ogóle zrezygnować z wejścia na na-szą stronę. Tutaj właśnie przychodzi nam z pomo-cą buforowanie, ponieważ możemy dzięki niemu zapisać raz wygenerowaną stronę w pliku, który będzie naszym buforem i w zależności od potrze-

by uaktualniać go po zmianach lub po upłynię-ciu określonej ilości czasu. Przy dużym obciąże-niu serwera na pewno będzie można odczuć róż-nicę. Tego typu rozwiązanie zda również egzamin w przypadku, gdy nasza baza danych znajduje się na innym serwerze, ponieważ dane z bazy mogą zostać zbuforowane np. w XML-owym pliku. Za-oszczędzimy wtedy czas potrzebny na połączenie do bazy danych i przesłanie informacji, a dodatko-wo czas na sformatowanie wyników, bo przecież wszystko może już być przechowywane w odpo-wiedniej postaci w naszym pliku.

Zaczniemy od stworzenia bardzo prostej strony internetowej, na której przykładzie bę-dziemy ćwiczyć. Rzecz jasna nie będziemy zaj-mowali się jej wyglądem, bo przecież nie to jest naszym celem. Zrezygnujemy też z wykorzy-stania w tym przykładzie bazy danych, choć w praktyce metoda ta w tego typu zastosowaniach przydaje się najbardziej. Nasza strona właściwie będzie składać się tylko z jednego dynamiczne-go elementu, którym będzie wyświetlenie go-dziny wraz z minutami (Listing 1.).

Podany kod będzie wyświetlać na stronie go-dzinę jej otwarcia. Treść naszej strony będzie ge-nerowana za każdym razem przez skrypt PHP. Łatwo możemy zauważyć, że przez 60 sekund strona zawsze będzie przybierać tę samą postać, po co ma być więc ponownie generowana, jeżeli jej zawartość nie uległa zmianie? Lepiej byłoby, gdyby strona przez ten czas pozostała statyczna. Do tego celu użyjemy pliku, w którym będzie-my zapisywać statyczną stronę i zmieniać ją, co minutę. Pomimo że w naszym przypadku czas dostępu do pliku może przewyższyć czas wyge-nerowania strony, to wydaje mi się, że dzięki swojej prostocie każdy zrozumie intencję i bez

problemu będzie mógł zastosować tę metodę w bardziej rozbudowanych projektach, w których zyski z takiego postępowania będą widoczne. Rozszerzymy teraz nasz skrypt do postaci wi-docznej na Listingu 2.

Jak widać, skrypt rozrósł się tylko odrobinę. W pierwszej kolejności deklarujemy w nim nazwę naszego pliku. Następnie sprawdzamy czy po-dany plik istnieje oraz czy nie został on utworzo-ny na tyle dawno, że wymagana jest jego aktuali-zacja. W naszym przypadku czas przedawnienia został ustawiony na 60 sekund. Jeżeli oba warun-ki zostaną spełnione to naszą stronę wyświetlamy odczytując ją z pliku i dodając komunikat, tylko dla własnej wygody, że strona została wczytana z pliku. Natomiast, jeżeli warunki nie zostaną speł-nione deklarujemy nazwę dla pliku tymczasowe-go, w którym będziemy przechowywać bufor do czasu jego zapisania w pliku temp.cache. Nazwa tymczasowa zostaje zróżnicowana poprzez do-danie do nazwy identyfikatora procesu, który jest unikalny w danym momencie. O ile w tym przy-padku nie jest to aż tak bardzo ważne, to w mo-mencie, gdy warunkiem uaktualnienia pliku by-łyby np. zmiany wprowadzone przez użytkowni-ków byłoby już ważne, gdyż zaszłoby ryzyko za-pisywania danych do jednego pliku jednocześnie. Następnie otwieramy nasz plik do zapisu – jeże-li nie istnieje zostanie utworzony, co zajdzie wła-śnie w naszym przypadku, a po tym za pomo-cą polecenia funkcji ob_start() zaczynamy bu-forowanie informacji wyświetlanych na stronie. Wszystko, co od tej pory miałoby zostać wyświe-

Aplikacje www

Wydajność aplikacji jest zagadnieniem, które kiedyś musi pojawić się w życiu każdego programisty. Napisanie dobrej aplikacji bez zastanawiania się nad jej wydajnością jest niemożliwe i wskazuje na brak profesjonalizmu.

Dowiesz się...• Jak wykorzystywać buforowanie do zwiększe-

nia wydajności strony oraz do eleganckiego ob-sługiwania błędów.

Powinieneś wiedzieć...• Powinieneś znać PHP5,• Wymagana jest znajomość zasad programo-

wania obiektowego i podstaw HTML i MySQL.

Poziom trudności

Buforowanie

Listing 1. Strona internetowa generowana od nowa przy każdym jej otworzeniu

<HTML>

<BODY>

Aktualna godzina to: &nbsp;

<?php echo date("H:i"); ?>

</BODY>

</HTML>

Page 15: PHP Solutions 04 2007 PL

Praktyka

4/200714

Aplikacje www

www.phpsolmag.org 15

tlone, zostanie przechowane w buforze. Cały kod HTML oraz PHP nie zostanie wyświetlony. Po za-ładowaniu strony do bufora chcielibyśmy zapisać ją do pliku. W tym celu sprawdzamy, czy posia-damy uchwyt do otwartego pliku tymczasowego. Jeżeli warunek jest spełniony, całą treść z bufora zapisujemy za pomocą funkcji ob_get_contents() do naszej zmiennej, a następnie zapisujemy ją do naszego pliku tymczasowego, któremu po chwili zmieniamy nazwę na temp.cache. Pozostało nam już tylko wyświetlenie strony, co czynimy dzięki funkcji ob_end_flush(). W ten oto właśnie sposób utworzyliśmy plik, w którym przechowywana jest nasza strona w postaci statycznej, wywoływa-na dynamicznie tylko w przypadku potrzeby.

Wyobraźmy sobie teraz, że mielibyśmy wy-korzystać ten mechanizm do wyświetlania stro-ny, której proces wygenerowania wykorzystuje dużo pamięci i procesora. Przykładem takiego przypadku może być strona oparta o bazę da-nych, która musi odczytać informacje, prze-tworzyć je, a dopiero później wyświetlić wyni-ki tej operacji. Jeżeli wiemy, że treści te nie mu-szą być za każdym razem przetwarzane, zdecy-dowanie lepiej stworzyć stronę statyczną niż za każdym razem ją generować.

Buforowanie strony internetowej w parze z wyjątkamiInnym zastosowaniem dla buforowania mo-że być następująca sytuacja. Załóżmy, że nasz skrypt dla strony www pobiera dodatkowe in-formacje z zewnątrz (tzn. z bazy danych, pli-ku, zmiennych superglobalnych) i po wczyta-niu pewnej części strony następuje jakiś błąd. Cała strona zostaje w takim wypadku rozsypa-na, a jej konstrukcja ulega uszkodzeniu i nasz “odwiedzający” zamiast przeglądać spodziewa-ną treść otrzymuje kilka błędów z bazy danych. Niestety, nie jest to ładny widok. Na szczeście, buforowanie w połączeniu z obsługą wyjątków może nas od tego ustrzec i wyświetlić wcześniej przygotowaną stronę z informacją o błędzie.

Zaczniemy od zapoznania z klasą Exception (Listing 3.), po której będziemy następnie dzie-dziczyć, tworząc naszą klasę.

Jak widzimy, klasa Exception większość me-tod odpowiadających za nasz komunikat o wy-jątku ma zadeklarowane jako final, przez co nie możemy ich przedefiniować w klasie dziedzi-czącej. Jedyną metodą, którą możemy zmienić, jest __toString() i to właśnie za pomocą niej zmienimy formę naszego komunikatu. Zrobi-my to podczas deklaracji naszej klasy PageError, która dziedziczy po Exception – Listing 4.

W naszej deklaracji, dodaliśmy dodatkowo metodę template, w której będziemy przecho-wywać szablon naszej strony będącej komuni-katem. Dzięki takiemu podejściu łatwiej będzie nam edytować późniejszy wygląd strony. Następ-nie wywołujemy naszą funkcję template() z ar-gumentem $this->getMessage() w metodzie __toString(), dzięki czemu w wyniku pojawie-nia się wyjątku zostanie wyświetlona nasza strona

Listing 2. Strona internetowa z zaimplementowanym buforowaniem – generowana raz na 60 sekund (przez resztę czasu pozostaje statyczna)

<?php

$file_name="temp.cache";

if(file_exists($file_name) && (filemtime($file_name)+60)>time()){

include($file_name);

echo '<BR/> Godzina pobrana z Pliku';

exit();

}

$file_tmp=$file_name.'.'.getmypid();

$file_handle=fopen($file_tmp,"w");

ob_start();

?>

<HTML>

<BODY>

Aktualna godzina:&nbsp;<?php echo date("H:i"); ?>

</BODY>

</HTML>

<?php

if($file_handle){

$page_content=ob_get_contents();

fwrite($file_handle, $page_content);

fclose($file_handle);

if(file_exists($file_name)){ unlink($file_name); }

rename($file_tmp,$file_name);

}

ob_end_flush();

?>

Listing 3. Klasa Exception – niepełna deklaracja

class Exception{

protected $message = 'Unknown exception';

protected $code = 0;

protected $file;

protected $line;

private $trace;

private $string;

function __construct (string $message=NULL, int $code=0){

if (func_num_args(){ $this->message=$message; }

$this->code = $code;

$this->file=__FILE__;

$this->line=__LINE__;

$this->trace=debug_backtrace();

$this->string=StringFormat($this);

}

final function getMessage(){ return $this->message; }

final function getCode(){ return $this->code; }

final function getFile(){ return $this->file; }

final function getTrace(){ return $this->trace; }

function __toString(){ return $this->string; }

...

}

z odpowiednio sformatowanym komunikatem o błędzie. W naszym przypadku informacja ta bę-dzie się ograniczać jedynie do napisu podawane-go przy rzuceniu wyjątku. Możemy też dodać inne informacje odpowiednio zmieniając funk-cję template i przyjmowane przez nią argumen-ty. Dodatkowo można wykorzystać informacje o kodzie błędu pliku, w którym powstał problem wraz z podaniem konkretnej linii. Z założenia

użytkownik strony powinien wiedzieć, jak naj-mniej na temat powstałego problemu, więc najle-piej wyświetlić mu tylko przygotowany komuni-kat. Dobrym pomysłem może być np. spowodo-wanie, aby pozostałe informacje były wysyłane na adres e-mail administratora strony. Wszystko to już tylko kwestia własnej inwencji twórczej. Na-szą klasę umieszczamy w oddzielnym pliku, któ-ry nazwiemy class_page_error.php.

Page 16: PHP Solutions 04 2007 PL

Praktyka

4/200716

Nadszedł czas na napisanie głównego skryp-tu naszej strony. Zakładamy, że zadaniem tej strony jest wyświetlenie odpowiednio sforma-towanej zawartości jednej z tabel naszej bazy danych. Nie będziemy zastanawiać się nad tym, co jest w tej bazie oraz jak to ma być obudowa-ne naszą stroną – pomijamy walory estetyczne oraz ewentualne stronicowanie zawartości. Ca-łość będzie zawarta w blokach try i catch. Kod jest widoczny na Listingu 5.

Przeanalizujemy teraz nasz skrypt. Zaczęliśmy od deklaracji funkcji show_error(), której zada-niem jest wyczyszczenie bufora oraz rzucenie wy-jątku. Moglibyśmy z niej zrezygnować, ale ponie-waż korzystamy z niej kilka razy, lepiej jest korzy-stać z funkcji niż kopiować kod. Następnie poja-wia się blok try, w którym generowana jest na-sza strona. Następuje wystartowanie bufora, a na-stępnie próba połączenia do serwera bazy danych i próba wybrania bazy. Jeżeli któreś z odwołań do bazy zakończy się niepowodzeniem zostanie wy-wołana funkcja show_error(), co oznacza rzuce-nie wyjątku i wygenerowanie wcześniej przygo-towanej strony o błędzie. Jeżeli wszystko prze-biegnie pomyślnie, strona jest generowana dalej, a następnie zostaje wyświetlona poprzez opróż-nienie bufora.

Jest to bardziej eleganckie podejście do tego samego tematu. Istnieje jeszcze inny sposób wy-świetlenia tej samej strony, jedyna różnica tkwi w sposobie implementacji. Otóż zamiast tworzyć swoją klasę możemy skorzystać z klasy Exception. Nie musimy wtedy deklarować klasy, ale kod jest też mniej czytelny i trudniejszy w edycji. Przy-kład ten widoczny jest na Listingu 6.

Jak widzimy, różnica wydaje się nieduża, ale tylko dlatego, że mamy do czynienia z bardzo prostym przykładem. Jasno możemy stwierdzić, że poprzedni kod był znacznie bardziej skalowal-ny. W poprzednim przykładzie moglibyśmy za-deklarować naszą metodę template jako abs-trakcyjną i dziedziczyć po naszej klasie PageEr-ror, aby tworzyć całą gamę podstron błędów. W obecnym przypadku nie możemy tego zrobić. Na tej podstawie widać, że poprzedni kod jest znacznie mniej elastyczny, ale dla prostych przy-kładów możemy go wykorzystać. Połączenie obu omówionych metod buforowania, może dać jesz-cze lepsze efekty. Należy też pamiętać, że nie mu-simy buforować od razu całej strony, ale możemy objąć buforowaniem np. tylko dynamiczne ele-menty lub też tylko te narażone na błędy. Wszyst-ko to jest już kwestią indywidualnego podejścia.

Mam nadzieje, że poznane techniki, pozwolą wam tworzyć jeszcze wydajniejsze witryny in-ternetowe, którymi naprawdę będziecie mogli się pochwalić nie tylko ze względu na wygląd, ale i wydajność.

Listing 4. Deklaracja klasy PageError

class PageError extends Exception {

public function construct($message){ parent::__construct($message); }

public function __toString(){ return $this->template($this->getMessage()); }

protected function template ($only_message){

return '<html><body>'.$only_message.'</body></html>';

}

}

Listing 5. Strona wykorzystująca buforowanie oraz wyjątki

<?php

include_once('class_page_error.php');

function show_error($message){

ob_end_clean();

throw new PageError($message);

}

try{

ob_start();

?>

<HTML>

<BODY>

<?php

if(!$db= @mysql_connect('localhost','user','password')){

show_error('Błąd połączenia do bazy danych.');

}

if(!@mysql_select_db('database_name')){

show_error('Błąd podczas wybierania bazy danych.');

}

if(!$request=mysql_query('select * from my_table',$db)){

show_error('Błąd podczas wybierania bazy danych.');

}

?>

<TABLE><TR><TD>key</TD><TD>value</TD></TR>

<?php

while($row=mysql_fetch_assoc($request)){

foreach ($row as $key => $value){

echo “<tr><td>$key</td><td>$value</td></tr>”;

}

}

?>

</TABLE>

</BODY>

</HTML>

<?php

ob_end_flush();

}

catch(PageError $e){

echo $e;

}

?>

Listing 6. Strona wykorzystująca buforowanie oraz wyjątki – mniej elegancka wersja

<?php

function show_error($message){

ob_end_clean();

throw new Exception($message);

}

try{ // ten sam kod co w Listingu 5.

...

}

catch(Exception $e){ echo '<html><body>'.$e->getMessage().'</body></html>'; }

?>

ŁUKASZ SKOWROŃSKIAutor jest studentem III roku informatyki na Uniwer-sytecie w Białymstoku.Kontakt z autorem: [email protected]

Page 17: PHP Solutions 04 2007 PL
Page 18: PHP Solutions 04 2007 PL

04/2007

Technika

18

CakePHP

www.phpsolmag.org 19

Sposób wyróżnienia poszczególnych fraz nie jest przypadkowy, gdyż niesie ze sobą dodatkowe informacje. Przyj-

mijmy, że znaczniki-linki są uszeregowane alfabetycznie, natomiast wielkość i pogrubie-nie fontu jest zależne od popularności dane-go znacznika. Dzięki takiemu zabiegowi moż-liwe jest intuicyjne wyszukiwanie danych za-równo według alfabetu jak i popularności (Ry-sunek 1.). Wizualne efekty jakie możemy za-stosować to:

• Wielkość czcionki;• Kolor;• Styl;• Porządek, w jakim wyrazy są umieszczone

na liście.

Każdy z powyższych efektów możne przeka-zywać dodatkowe informacje np.:

• Wielkość czcionki może być skorelowana z liczebnością;

• Kolor z czasem aktualizacji danych;• Kolejność wyrazów w liście może wynikać

z ważnością danych.

Tag cloud po raz pierwszy został zastosowa-ny do nawigacji w serwisie flickr.com (serwis umożliwiający gromadzenie, udostępnianie

i zarządzanie zdjęciami). Pomysł się przyjął i obecnie „chmurki” można znaleźć w bardzo wielu serwisach umożliwiających zarządza-nie treścią.

ZnacznikiStosowanie znaczników (ang. tags) powiąza-nych z danymi udostępnianymi w serwisie jest bardzo popularnym sposobem zarządzania tre-ścią. Dzięki temu, że znaczniki są pewnego ro-dzaju etykietami, możliwe staje się grupowanie danych. Na przykład zdjęciom z wakacji nad

morzem możemy nadać znaczniki „wakacje”, „morze”, „molo”, „zachód słońca” itp. Oczywi-ście możliwe jest nadawanie wielu znaczników do tego samego zdjęcia.

Takie podejście do gromadzenia i katalogo-wania danych ma zasadniczą zaletę - wyszu-kiwanie jest szybkie i intuicyjne. Niestety sto-sowanie znaczników ma także swoje wady. Przede wszystkim za każdym razem znaczni-ki mogą być nazywane nieco odmiennie („za-chód-słońca”, „Zachód Słońca!”, „zachodzące słońce” itp.) i mogą mieć rożne znaczenie dla różnych osób przez co nie uda nam się dotrzeć do odpowiednich danych. Rozwiązaniem tych problemów może być tzw. normalizacja lub wybór znaczników z pewnej ograniczonej pu-li. Normalizacja to proces ujednolicania. Dzię-ki niemu wyrazy o podobnym znaczeniu, ale różnej pisowni będą mogły być zarządzane w ten sam sposób. W najprostszym przypadku

CakePHP

Tag cloud (w dosłownym tłumaczeniu „chmura znaczników”) to specyficzny sposób prezentowania danych, polegający na wizualnym wyróżnianiu (np. kolorem) pewnego rodzaju listy haseł.

Dowiesz się...• Poznasz zasady tworzenia i zarządzania znacz-

nikami oraz sposoby ich wyświetlania jako tzw. „chmury znaczników”.

Powinieneś wiedzieć...• Wymagana jest podstawowa znajomość fra-

meworku CakePHP;• Przydatna będzie znajomość języka SQL i umie-

jętność administrowania bazą danych MySQL.

Poziom trudności

Tags i Tags clouds – znaczniki

Rysunek 1. Przykładowa chmura znaczników (serwis flickr.com)

Page 19: PHP Solutions 04 2007 PL

04/2007

Technika

18

CakePHP

www.phpsolmag.org 19

normalizacja polega na usunięciu polskich li-ter, znaków interpunkcyjnych i spójników. Po takim zabiegu ze znaczników „zachód-słońca” oraz „Zachód Słońca!” otrzymamy np. znacz-nik „zachodslonca”. Metoda ta niestety nie sprawdza się w bardziej złożonych przypad-kach („zachodzące słońce”), ale odpowiednio zaawansowany algorytm normalizacji mógł-

by przecież ujednolicać znaczniki bazując na np. odmianie wyrazów. Jest to dosyć skompli-kowane zadanie, czasochłonne i w większości przypadków po prostu zbędne.

Zdecydowanie skuteczniejsza od normaliza-cji jest metoda ograniczonego wyboru znaczni-ków. Wybierając hasła z gotowej listy, nie nara-żamy się na kłopoty wynikające z błędnej (nie-

standardowej) pisowni. Ograniczeniem w tym przypadku jest sama lista, która może nie za-wierać haseł oddających charakter danych. Na-wet jeżeli proces aktualizacji listy o nowe wy-razy będzie przebiegał sprawnie, to możemy stanąć przed koniecznością ponownego przy-pisywania znaczników do danych. Jeżeli do li-sty dodamy nowy znacznik, to z pewnością bę-dziemy chcieli go przypisać także do danych, które już wcześniej były katalogowane.

Zarządzanie znacznikamiW internecie dominują dwa sposoby zarzą-dzania znacznikami (techniki przypisywania znaczników do danych). Różnica między ni-mi polega na tym, że w formularzu widoczne są wszystkie lub tylko nowe znaczniki. W pierw-szym przypadku istnieje możliwość natychmia-stowej, prostej edycji i w razie potrzeby usunię-cia wszystkich znaczników jednocześnie. W drugim przypadku, nowe znaczniki są dołącza-ne do danych, a ich usunięcie wymaga dodatko-wych zabiegów (najczęściej każdy ze znaczni-ków musi być usunięty oddzielnie).

Ze sposobem zarządzania znacznikami wią-że się sposób ich prezentacji oraz konstrukcji adresu www. Znaczniki, które były poddawa-ne normalizacji mogą być wyświetlane w posta-ci surowej (ang. raw) lub znormalizowanej. Nie-które serwisy pozostawiają wybór sposobu pre-zentacji użytkownikowi, który najczęściej wi-dzi „swoje” znaczniki w takiej postaci, w jakiej je wprowadził do systemu (raw). Inni użytkow-nicy te same znaczniki widzą w postaci znorma-lizowanej. Prezentacja znaczników przechowy-wanych jako lista haseł odbywa się najczęściej za pomocą numeru identyfikującego konkret-ną pozycję w liście (ID znacznika).

Sposób prezentacji znaczników ma istotny wpływ na konstrukcję adresu www. Intuicyjny i łatwy do zapamiętania adres będzie dodatkowo zachęcał użytkowników do odwiedzenia serwi-su. Wystarczy porównać poniższe adresy:

• http://www.serwer.pl/tags/friends/;• http://www.serwer.pl/albumy.php?start=0&

kategoria=1.

HABTM a nazwy tabelCakePHP wymaga, by nazwa dodatko-wej tabeli pasowała do wzorca [liczba _mnoga _ model _ 1] _ [liczba _ mnoga _model _ 2], przy czym modele danych mu-szą by w kolejności alfabetycznej. Dla mo-deli Message i Tag nazwa tabeli będzie mia-ła postać: messages_tags, dla Message i UserTag: messages _ user _ tags. Klu-cze obce w tabeli muszą pasować do wzor-ca [liczba _ pojedyncza _ model] _ id . W naszym przypadku będzie to odpowied-nio message _ id oraz tag _ id . CakePHP w wersji 1.xx nie umożliwia automatycznej obsługi rozszerzonych relacji między tabela-mi (tzn. nie ma możliwości obsługi innych ko-lumn niż tych, które zawierają klucze obce).

Listing 1. Struktury danych wykorzystane do przechowywania informacji o znacznikach (tags) powiązanych z wiadomościami (messages)

mysql> desc messages;

+------------+------------------+------+-----+---------+----------------+

| Field | Type | Null | Key | Default | Extra |

+------------+------------------+------+-----+---------+----------------+

| id | int(10) unsigned | NO | PRI | NULL | auto_increment |

| title | varchar(60) | YES | | NULL | |

| content | text | YES | | NULL | |

| created_at | datetime | YES | | NULL | |

+------------+------------------+------+-----+---------+----------------+

4 rows in set (0,05 sec)

mysql> desc tags;

+---------+-------------+------+-----+---------+----------------+

| Field | Type | Null | Key | Default | Extra |

+---------+-------------+------+-----+---------+----------------+

| id | int(10) | NO | PRI | NULL | auto_increment |

| raw | varchar(60) | YES | | NULL | |

| name | varchar(60) | YES | | NULL | |

+---------+-------------+------+-----+---------+----------------+

3 rows in set (0,03 sec)

mysql> desc messages_tags;

+-------------+---------+------+-----+---------+----------------+

| Field | Type | Null | Key | Default | Extra |

+-------------+---------+------+-----+---------+----------------+

| id | int(10) | NO | PRI | NULL | auto_increment |

| message_id | int(10) | NO | | 0 | |

| tag_id | int(10) | NO | | 0 | |

+------------ +---------+------+-----+---------+----------------+

3 rows in set (0,02 sec)

Listing 2. Relacje między modelami danych Tag oraz Message

class Tag extends AppModel {

...

var $hasAndBelongsToMany = array(

'Messages' => array(

'className' => 'Message',

'fields' => 'Message.id,Message.title',

'order' => 'Message.created_at'

)

);

}

class Message extends AppModel {

...

var $hasAndBelongsToMany = array(

'Tags' => array(

'className' => 'Tag',

'order'=>'Tags.name ASC'

)

);

}

Page 20: PHP Solutions 04 2007 PL

04/2007

Technika

20

Pierwszy z powyższych adresów www za-wiera w sobie wyjaśnienie: link prowadzi do strony zawierającej dane powiązane z ha-słem friends (pol. przyjaciele). Już na podsta-wie tych informacji możemy określić, czy je-steśmy zainteresowani odwiedzeniem ser-wisu czy też nie. Drugi adres www jest po-zbawiony takich informacji. CakePHP do-myślnie obsługuje intuicyjne adresy www i w naszym przykładzie wykorzystamy tą właściwość.

Jak to się robi w CakePHPTworzenie chmury znaczników zaczniemy od zaprojektowania struktur umożliwiają-cych przechowywanie wiadomości i znacz-ników oraz relacji między nimi. Musimy pa-miętać, że każdy znacznik może być przypi-sany do wielu wiadomości oraz że każda wia-domość może mieć dowolną liczbę znaczni-ków (lub nie mieć ich wcale). Taką relację między danymi określa się jako m:m (wiele do wielu), a w CakePHP jako hasAndBelong-sToMany (HABTM).

Utworzymy tablicę messages (wiadomości), tags (znaczniki) oraz tablicę messages_tags. Ta ostatnia tablica będzie zawierała informacje o tym, które wiersze tabel messages i tags łączą się ze sobą (z tego powodu taka tabela nazywana jest czasem „przesiadką”).

Przykładowe struktury danych znajdują się na Listingu 1. (tabela tags zawiera dwie kolum-ny raw i name, w których będą przechowy-wane nazwy znaczników przed i po norma-lizacji).

Relacje między poszczególnymi modela-mi danych zostały przedstawione na Listin-gu 2. Od strony modelu danych Tag będą wi-doczne tylko kolumny messages.id oraz messa-ges.title, a wiadomości będą posortowane we-dług daty utworzenia messages.created_at. Od strony modelu danych Message będą widocz-ne wszystkie kolumny tabeli tags, które do-datkowo będą posortowane w porządku al-fabetycznym.

Wprowadzanie danychZapisywanie danych z uwzględnieniem relacji HABTM jest nieco bardziej skomplikowane niż dla pozostałych relacji. W CakePHP zapisywa-nie jest wykonywane w kontekście modelu da-nych tzn. każdy model może zapisywać dane tylko do „swojej” tabeli. Relacja HABTM skła-da się aż z trzech tabel i z tego powodu zapis jest przeprowadzany „na raty”. Najpierw mu-simy zapisać (utworzyć) wiadomość (model da-nych Message), a dopiero w następnej kolejności dołączyć do niej znaczniki (model danych Tag). Ponowny zapis wiadomości uzupełniony o po-wiązania ze znacznikami (numery ID znaczni-ków) spowoduje automatyczną aktualizację ta-beli messages_tags.

Załóżmy, że w bazie danych już znajdu-je się wiadomość, do której chcemy dołączyć

Listing 3. Zapisywanie wiadomosci wraz z informacją o znaczniku (powiazanie HABTM)

var $uses = array('Tag','Message');

$tag_name = $this->data['Message']['tag'];

$existing = $this->Tag->findByName($tag_name);

if (!empty(existing)) {

$tag = $existing[$this->Tag->name][$this->Tag->primaryKey];

} else {

$this->data[$this->Tag->name]['raw'] = trim($tag_name);

$this->data[$this->Tag->name]['name'] = preg_replace('/[^a-z0-9]/', '', low($tag_

name));

$this->Tag->recursive = -1; // zapisz tylko dane modelu Tag

$this->Tag->save($this->data);

$tag = $this->Tag->id;

}

Listing 4. Przykładowy formularz umożliwiający wprowadzanie informacji (wiadomość i powiązane znaczniki rozdzielone przecinkami)

<h2>Nowa wiadomość</h2>

<table><tr>

<td>Tytuł:</td><td><?php echo $html->input('Message/title'); ?></td>

</tr>

<tr>

<td>Znaczniki powiązane z wiadomością</td>

<td><?php echo $html->input('Tag/tag'); ?></td>

</tr>

<tr><td colspan="2">

<?php echo $html->textarea('Message/content'); ?>

<?php echo $html->hidden('Message/id' , array('value'=>'0')); ?>

<?php echo $html->submit('Zapisz'); ?>

</td>

</tr>

</table>

Listing 5. Metoda saveTags() tworząca listę identyfikatorów (ID) na podstawie nazw znaczników rozdzielonych przecinkami

class Tag extends AppModel {

...

function saveTags($string = null) {

$return = array();

if($string) {

$array = explode(',', $string);

foreach($array as $tag) {

if(!empty($tag)) {

$this->data[$this->name]['raw'] = trim($tag);

$this->data[$this->name]['name'] = preg_replace('/[^a-z0-9]/', '',

low($tag));

$this->recursive = -1;

$existing = $this->find("name = '{$this->data[$this->name]['name']}'");

if(!empty($existing)) {

$return[] = $existing[$this->name][$this->primaryKey];

} else {

$this->id = null;

if($this->save($this->data)) {

$return[] = $this->id;

}

}

}

}

}

return $return;

}

?>

Page 21: PHP Solutions 04 2007 PL
Page 22: PHP Solutions 04 2007 PL

04/2007

Technika

22

CakePHP

www.phpsolmag.org 23

znaczniki. W pierwszym kroku upewniamy się, że znacznik, który ma zostać przypisany do wiadomości już istnieje i zapamiętujemy jego numer ID.

Jeżeli znacznik jeszcze nie istnieje, to mu-simy go utworzyć i poddać normalizacji. W naszym przykładzie usuwamy wszyst-kie znaki nie należące do alfabetu łacińskie-go i nie będące cyframi arabskimi. Patrz Li-sting 3.

Numer ID znacznika otrzymany w jed-nym z powyższych kroków posłuży jako po-wiązanie między modelem danych Message i Tag. Odczytujemy strukturę danych z żąda-nego wiersza tabeli messages, umieszczamy w niej numer ID znacznika (lub tablicę znaczni-ków) i ponownie zapisujemy zmodyfikowa-ny rekord. Istotne jest by powiązanie wpro-wadzić jako zagnieżdżoną tablicę asocjacyjną o nazwie zgodnej z relacją HABTM, która zo-stała zdefiniowana w modelu danych Message (tablica ['Tags']['Tags']).

$this->data = $this->Message->read

(null, $this->data['Message']['id']);

$this->data['Tags']['Tags'] = $tag;

$this->Message->Save($this->data);

Powyższy przykład dotyczy przypisania do wiadomości tylko jednego znacznika. Jeżeli chcemy przypisywać większą liczbę znacz-ników, to musimy założyć, że będą one wprowadzane do formularza jako ciąg wy-razów rozdzielonych przecinkami (Listing 4.) i zapisywane za pomocą metody Tag->saveTags() przedstawionej na Listingu 5. W takim przypadku oczywiście zamiast jednego numeru ID znacznika w zmiennej $this->data['Tags']['Tags'] musi się zna-leźć tablica zawierająca wszystkie ID znacz-ników, które mają być przypisane do wiado-mości.

Chmura znacznikówWreszcie możemy zweryfikować zapisane da-ne korzystając z metody $this->Message->read() (Listing 6.) i zabrać się za tworze-nie chmury znaczników. Chmura taka, to nic innego jak specyficzna lista wartości, w któ-rej zakodujemy informacje o popularności poszczególnych znaczników. CakePHP do-myślnie nie zawiera funkcji, która podsumu-je nam wykorzystanie znaczników. Musimy posłużyć się kodem SQL (Listing 7.), który zwróci listę zawierającą m.in. nazwę znacz-nika i liczbę wiadomości, do których został przypisany. Listę taką wystarczy wyświetlić wyróżniając wielkością czcionki odpowied-nie hasła.

Oczywiście jest bardzo wiele sposobów wy-świetlania chmury znaczników jednak nie wszystkie dają pożądany efekt. Najczęstszym błędem popełnianym przez programistów jest bezpośrednie mapowanie popularności znacz-

Listing 6. Kod weryfikujący zawartości tabeli messages

$message = $this->Message->read(null, $this->data['Message']['id']);

$this->set('message', $message);

print_r($message);

// wynik

Array

(

[Message] => Array

(

[id] => 1

[title] => Cake Model Associations

[content] => Time saving, easy, and powerful.

[created_at] => 2006-04-15 09:33:24

)

[Tags] => Array

(

[0] => Array

(

[id] => 1

[raw] => CakePHP

[name] => cakephp

)

)

)

Listing 7. Metoda popular() tworząca listę znaczników posortowaną według liczby wiadomości do których zostały przypisane

class Tag extends AppModel {

...

function popular($limit = 10) {

return $this->query("select Tag.id, Tag.name, count(MT.message_id) count

from tags Tag inner join messages_tags MT on MT.tag_id=Tag.id

inner join messages Message on MT.message_id=Message.id

group by Tag.id order by Tag.name limit $limit ");

}

}

Listing 8. Przeskalowanie wilekości czcionek przed wyświetleniem chmury znacznkiów

// minimalna i maksymalna wielkość czcionki

$minfsize = 8;

$maxfsize = 40;

$dstfsize = $maxfsize - $minfsize;

// minimalna i maksymalna popularność znaczników

$minmax = array();

foreach($tags as $no => $tag) { $minmax[$no] = $tag[0]['count']; }

asort($minmax);

$mincnt = $minmax[0];

$maxcnt = $minmax[sizeof($minmax)-1];

$dstcnt = $maxcnt + 1 - mincnt;

foreach ($tags as $tag) {

// skalowanie wielkości napisu

$cnt = $tag[0]['count'];

$fsize = $minfsize + $dstfsiz * ($cnt - $mincnt)/$dstcnt;

echo $html->link($tag['name'],

'/tags/'.$tag['raw'],

array('style'=>'font-size:'.$fsize.'px;'));

echo '&nbsp;';

}

Page 23: PHP Solutions 04 2007 PL

04/2007

Technika

22

CakePHP

www.phpsolmag.org 23

ników na wielkość czcionki, którą znacznik bę-dzie wyróżniony.

foreach ($tags as $tag) {

echo $html->link($tag['name'],

'/tags/'.$tag['raw'],

array('style'=>'font-size:'.

$tag[0]['count'].'px;'));

echo '&nbsp;';

}

Taki sposób postępowania stwarza problemy przy wyświetlaniu listy, w której poszczegól-ne wartości znacznie od siebie odbiegają. Ła-two sobie wyobrazić, jak będzie wyglądała na-sza „chmurka”, gdy ze znacznikiem wyróżnio-nym czcionką 100 pikseli będzie sąsiadował znacznik narysowany czcionką o wysokości 1 piksela (Rysunek 2). Konieczne jest więc prze-skalowanie wielkości czcionek przed wyświe-tleniem chmury znaczników (Listing 8.).

Jeżeli zastosujemy skalowanie liniowe, to wyświetlony wynik znowu nie spełni naszych oczekiwań. Liniowy rozkład charakteryzuje się tym, iż niewielkim zmianom popularności bę-dą towarzyszyły niewielkie zmiany wielkości czcionki. W skrajnym przypadku, gdy popular-ność znaczników będzie na zbliżonym pozio-mie, otrzymamy listę zawierającą pozycje róż-niące się od siebie o np. 1 piksel (Rysunek 3). Taka lista z pewnością nie będzie przydatna. Do przeskalowania danych będziemy potrzebowa-li funkcji, która pozwoli uwypuklić niewielkie zmiany między poszczególnymi znacznikami. W tym celu do skalowania wielkości czcion-ki wykorzystamy popularność znaczników w funkcji logarytmu dziesiętnego (Listing 9.). Do-piero taki sposób tworzenia chmury znaczni-ków da pożądany efekt (Rysunek 4).

PodsumowanieStosowanie chmur znaczników wymusza ko-nieczność takiego ich zorganizowania, by od-powiadały potrzebom użytkowników. Trudno mówić o przydatności listy zawierającej np. kil-kaset pozycji ze wszystkimi hasłami, jakie użyt-kownicy serwisu nadali dostępnym artykułom. Bardzo trudno dostrzec zmiany w tak rozbudo-wanej liście i z punktu widzenia użytkownika będzie ona statyczna (za każdym razem, gdy odwiedzi serwis będzie miał wrażenie, że lista nie uległa zmianie). Korzystniejsze jest wyświe-tlanie listy np. kilkunastu najpopularniejszych haseł. Lista taka prawdopodobnie będzie zmie-niała się dosyć często, co może spowodować, że użytkownicy serwisu będą mieli możliwość do-tarcia do danych, które dotychczas pomijali.

PIOTR GAPIŃSKIAutor w wolnych chwilach zajmuje się programo-waniem w różnych językach (głównie Rebol, Ruby, PHP i AmigaE). Adres do korespondencji: [email protected]

Rysunek 4. Chmura znaczników, w której wielkość czcionki jest skalowana względem popularności znaczników w funkcji logarytmu dziesiętnego

Listing 9. Widok CakePHP tworzący chmurę znaczników przeskalowaną za pomocą funkcji logarytmicznej

<h2>Chmura znaczników</h2>

<div>

<?php if(!empty($tags)): ?>

// minimalna i maksymalna wielkość czcionki

$minfsize = 8;

$maxfsize = 40;

$dstfsize = $maxfsize - $minfsize;

// minimalna i maksymalna popularność znaczników

$minmax = array();

foreach($tags as $no => $tag) { $minmax[$no] = $tag[0]['count']; }

asort($minmax);

$minlog = log($minmax[0]);

$maxlog = log($minmax[sizeof($minmax)-1]);

$dstlog = $maxlog - minlog;

if ($dstlog == 0) $dstlog = 1;

foreach ($tags as $tag) {

// skalowanie wielkości napisu

$cnt = $tag[0]['count'];

$fsize = $minfsize + $dstfsize * (log($cnt) - $minlog)/$dstlog;

echo $html->link($tag['name'],

'/tags/'.$tag['raw'],

array('style'=>'font-size:'.$fsize.'px;'));

echo '&nbsp;';

}

?>

</div>

Rysunek 3. Chmura znaczników, w której wielkość czcionki jest skalowana liniowo względem popularności znaczników

Rysunek 2. Chmura znaczników, w której popularność znaczników przekłada się bezpośrednio na wielkość czcionki

Page 24: PHP Solutions 04 2007 PL

04/2007

Technika

24

Prado

Jednak w przeciwieństwie do P4A, PRA-DO oferuje znacznie szerszy zestaw kom-ponentów oraz, co ważniejsze, obsługę sza-

blonów. Dzięki szablonom mamy w zasadzie pełną kontrolę nad generowaną stroną, w pli-ku możemy np. przeplatać kod HTML z kom-ponentami PRADO.

Szablon, komponenty i obsługa zdarzeń, czyli HelloWorldDzięki plikowi szablonu (rozszerzenie takiego pliku to .page), możemy łatwo wstawiać kom-ponenty w określone miejsca kodu HTML. Kod wygląda niezwykle podobnie do zwykłego tagu XHTML, czyli dość schematycznie

<com:TypKomponentu parametr1=

”wartosc1” parametr2=”wartosc2” />

Przykładowo, aby utworzyć przycisk nale-ży napisać <com:TButton Text=”Przycisk

1” />.Obsługa kliknięcia wymaga stworzenia

skryptu php, który będzie „reagował” na różne zdarzenia występujące na danej stronie, np. na kliknięcie. Dlatego, aby poznać działanie PRA-DO napiszemy najprostszy możliwy przykład – przycisk z obsługą kliknięcia.

Nasza pierwsza aplikacja będzie składała się z trzech plików – index.php, Home.page i Ho-

me.php. Dwa ostatnie pliki muszą znaleźć się w katalogu \protected\pages (Rysunek 1.).

Musimy pamiętać, że katalogi assets (do niego trafiają zasoby udostępniane użytkow-nikowi przez komponenty np. obrazki, arku-sze styli CSS itp.) oraz \protected\runtime (w nim zapisywane są tymczasowo dane do-tyczące aplikacji, np. stan aplikacji i kompo-nentów) muszą być dostępne do zapisu dla serwera (muszą mieć nadane odpowiednie prawa).

Plik index.php jest jedynym plikiem do-stępnym bezpośrednio dla użytkownika stro-ny. Plik ten składa się przynajmniej z trzech linii, zawierających odpowiednie polecenia, czyli: komendy dołączenia biblioteki PRADO, stworzenia nowej instancji aplikacji i jej uru-chomienia.

require_once('sciezka/do/prado.php');

//dołączenie biblioteki

$application=new Tapplication;

//nowa instancja aplikacji

$application->run();

//uruchomienie aplikacji

Plik home.page – to szablon dla strony głów-nej aplikacji. W naszej aplikacji, w sekcji BO-DY kodu HTML napiszemy następujące trzy linie (odpowiedzialne za stworzenie formula-rza i przycisku):

<com:TForm>

<com:TButton Text=

"Kliknij tutaj" OnClick="buttonClicked" />

</com:TForm>

Plik home.php – plik z implementacją klasy Home, w nim znajdzie się kod odpowiedzial-ny za obsługę kliknięcia przycisku (funkcja buttonClicked).

class Home extends TPage {

public function buttonClicked(

$sender,$param)

{//funkcja ta zostanie wywołana

po kliknięciu przycisku $sender->

Text="Kliknąłeś przycisk

"; //ustaw nową wartość Text,

czyli etykiety przycisku

W wersji PRADO 3.1.0 (w chwili pisania artykułu jest to jeszcze wersja alpha) au-torzy wprowadzili bibliotekę ActiveCon-trols, która zawiera zamienniki większo-ści podstawowych, występujących w PRA-DO, elementów, jedyna różnica polega na tym, że do ich obsługi używana jest tech-nologia AJAX, zamiast przeładowywania całej strony. Wystarczy, że w pliku szablo-nu zamiast TButton napiszemy TActive-Button oraz w pliku z implementacją klasy Home dodamy linię Prado::using ('System.Web.UI.ActiveControls.*');, która jest od-powiedzialna za załadowanie biblioteki Ac-tiveControls.

Księga GościNapiszemy teraz niezwykle prostą księgę go-ści, używającą technologii AJAX do przesyła-

Prado

W artykule zajmiemy się frameworkiem dla języka PHP o nazwie PRADO (ang. PHP Rapid Application Development Object-oriented). Podobnie jak w opisywanym wcześniej PHP 4 Applications, tak i w tym przypadku, pisanie stron i aplikacji ułatwione jest dzięki dużej liczbie gotowych komponentów oraz obsłudze zdarzeń.

Dowiesz się...• Poznasz zasady tworzenia stron z użyciem fra-

meworka PRADO.• Dowiesz się, jak stworzyć prostą aplikację -

księgę gości.

Powinieneś wiedzieć...• Powinieneś znać podstawy PHP oraz programo-

wania obiektowego.

Poziom trudności

PHP Framework

Instalacja PRADOInstalacja PRADO sprowadza się do pobra-nia spod adresu http://www.pradosoft.com/download/ odpowiedniej wersji frameworku (prezentowane w artykule skrypty testowane były na wersji 3.1.0a.r1626) oraz rozpakowa-niu plików do katalogu dostępnego z sieci. Do poprawnej pracy PRADO wymagany jest inter-preter języka PHP w wersji 5.1.0 lub wyższej.

Page 25: PHP Solutions 04 2007 PL

04/2007

Technika

24

Prado

nia danych oraz pliku XML do przechowywa-nia wpisów.

Zacznijmy od stworzenia struktury katalo-gów i plików (będzie identyczna jak w przypad-ku HelloWorld, z tą różnicą, że mamy podkata-log App_Code w katalogu protected).

SzablonNajpierw musimy stworzyć plik szablonu – bę-dzie to standardowy plik HTML. W jego treści stworzymy sekcję div, w której wyświetlane bę-dą wpisy.

<div id="messages">

Ładowanie ...

<com:TPlaceHolder ID=

"messageList" />

</div>

W przykładzie zamieszczonym na płycie CD, w treści dokumentu znajduje się arkusz sty-lów, którego ze względu na rozmiar nie będę tutaj prezentował.

Skoro gotowe jest już miejsce, w którym wpisy będą wyświetlane, musimy dać możli-wość dodawania wpisów.

W tym celu utworzymy kolejną sekcję div, tym razem jej id to newEntryBox. Wewnątrz utworzymy komponent TForm (<com:TForm> ... </com:TForm>) - to właśnie ten formularz będzie odpowiedzialny za przesłanie wpisu użytkownika do księgi.

Wewnątrz sekcji utworzymy również trzy komponenty – dwa typu TActiveText-Box (nick i message) oraz jeden typu TActi-veButton.

Pierwsze z nich będą służyły do wpisania nicka i wiadomości (treści wpisu), zaś trzeci, przycisk, będzie służył do ich wysłania. Kod powinien wyglądać tak:

<com:TActiveTextBox id="nick" />

<com:TActiveTextBox TextMode=

"MultiLine" id="message" />

<com:TActiveButton Text="Dodaj wpis" id=

"addEntry" OnClick="addEntry" />

W drugim z komponentów TActiveTextBox ustawiliśmy parametr TextMode=”MultiLine” dzięki czemu zezwala on na wpisanie wielu linii tekstu (zamiast jednej).

W przykładzie dołączonym do płyty poszcze-gólne komponenty zostały rozmieszczone w ko-mórkach tabeli. Ze względu na czytelność przy-kładu, nie zamieściłem tu pełnego kodu, a jedy-nie szkielet aplikacji.

Mamy już możliwość dodawania wpisu, przydałoby się jeszcze odświeżać wpisy co ja-kiś czas np. co 15 sekund. W tym celu doda-my jeszcze jeden komponent – TimeTriggered-Callback. Już sama jego nazwa sugeruje do czego służy.

Komponent ten co podaną ilość czasu wy-wołuje podaną funkcję (oczywiście używając technologii AJAX).

Atrybuty, których użyjemy to Interval – odstępy czasu między kolejnymi wywołania-mi funkcji, oraz OnCallback – nazwa funkcji z klasy Home do wywołania.

Dodatkowo, atrybut StartTimerOnLoad ustawimy na true, dzięki czemu odliczanie

czasu zacznie się zaraz po załadowaniu stro-ny. Ostateczny kod powinien wyglądać mniej więcej tak:

<com:TTimeTriggeredCallback OnCallback=

"refresh" Interval="15"

StartTimerOnLoad=

"true" />.

Klasa HomeTradycyjnie, musimy stworzyć klasę Home (dzie-dziczącą po TPage), w której znajdzie się obsłu-ga kliknięcia przycisku oraz funkcja odświeża-jąca listę wpisów.

Funkcja dodająca wpis (o nazwie AddEntry) jest dosyć prosta.

Tworzymy w niej obiekt klasy GuestBook (klasę tę niedługo zaimplementujemy, będzie ona odpowiedzialna za obsługę pliku XML zawierającego wpisy), wywołujemy funk-cję dodającą wpis, ukrywamy obiekty służą-ce do dodawania wpisów oraz odświeżamyna

Rysunek 1. Struktura katalogów dla pierwszej aplikacji

Rysunek 2. Efekt końcowy naszych prac

R E K L A M A

Page 26: PHP Solutions 04 2007 PL

04/2007

Technika

26

stronie. Treść funkcji addEntry($sender,$param) przedstawia się więc następująco:

$entry = new GuestBook ();

$entry->AddMessage

($this->message->Text,

$this->nick->Text);

$this->Page->CallbackClient->

puff("newEntryBox", "");

$this->refresh("", "");

//wywołujemy z pustymi parametrami

Musimy jeszcze zaimplementować funkcję refresh. Wewnątrz niej utworzymy obiekt GuestBook, wywołamy metodę GetMessages, a następnie w pętli odczytamy i zaprezentuje-my dane dotyczące każdego wpisu.

Za chwilę zaimplementujemy klasę Gu-estBook (znajdzie się ona w pliku \protected\App_Code\GuestBook.php), aby tego doko-nać musimy poinformować PRADO, że-by dołączył ten plik do aplikacji. W tym ce-lu wywołamy polecenie Prado:using('Applica-tion.App_Code.*'); Linię tę musimy umieścić na samym początku Home.php. Jak widać, ja-ko podmoduł modułu Application podajemy nazwę katalogu.

Obsługa XML w PRADOPRADO umożliwia nam niezwykle prostą obsługę plików XML, a wszystko za sprawą TXMLDocument i TXMLElement. Techniki

użycia obu tych klas nauczymy się na przy-kładzie, czyli pisząc klasę GuestBook.

Na początku, w pliku \protected\App_Code\GuestBook.php definiujemy nazwę pliku XML, w którym przechowywane będą wpisy (musimy pamiętać, aby nadać upraw-nienia pozwalające na zapis do tego pliku), w naszym przykładzie będzie to DEFINE( "StorageFile", dirname(__FILE__) . "./../en-tries.xml" );

Tak więc plik entires.xml znajdzie się w katalogu \protected. Nasza klasa Guest-Book będzie posiadać jedną zmienną - $doc, do której przypiszemy obiekt TXMLDocu-ment. Jego utworzeniem zajmiemy się w konstruktorze klasy, tutaj też załadujemy zawartość entries.xml (pod warunkiem, że plik istnieje):

$this->doc = new TxmlDocument

('1.0', 'utf-8');

if (file_exists(StorageFile))

//jeśli plik istnieje,

załaduj dokument

$this->doc->loadFromFile( StorageFile );

$this->doc->TagName = "guestbook";

// nazwa głównego elementu (root)

dokumentu

Kolejnym zdaniem będzie funkcja dodająca wpis – w niej też nauczymy się, jak tworzyć element, ustawiać jego atrybuty i wartość:

$elem = new TxmlElement(array());

//utwórz element

$elem->TagName = "entry";

// nazwij go "entry"

$elem->setAttribute("nick", $nick);

// dodaj atrybut o nazwie nick i

zawartości nicka podanego

przez użytkownika

$elem->setValue($message);

//w wartości elementu ustaw wiadomość

Teraz pozostało nam już tylko dodanie nowe-go elementu do dokumentu XML oraz zapis dokumentu do pliku:

$this->doc->elements->

add ( $elem ); //dodaj element

$this->doc->saveToFile

( StorageFile ); //zapisz plik

Ostatnią wymaganą operacją jest napisanie funkcji pobierającej z dokumentu wszystkie elementy o nazwie entry:

function GetMessages()

{ //zwraca liste elementow jako TList

return $this->doc->

getElementsByTagName("entry");

}

Nasza księga gości jest już gotowa do użycia!

PodsumowanieNauczyliśmy się, jak wygląda szkielet aplikacji używającej PRADO, jak tworzyć szablony, re-agować na zdarzenia z umieszczonych kompo-nentów, wreszcie, jak stworzyć aplikację używa-jącą AJAX nie pisząc ani jednej linii kodu w ję-zyku JavaScript.

Osoby znające nieco narzędzia do tworzenia aplikacji dla Windows (takie jak Borland® Del-phi® czy Microsoft VisualStudio .NET) na pew-no zauważyły, że duża część pomysłów zreali-zowanych w PRADO jest „zapożyczona” z bi-bliotek dla Microsoft Windows, co wielu pro-gramistom ułatwa życie.

Warta uwagi jest dokumentacja, dostępna pod adresem http://www.pradosoft.com/docs/manual/.

Zawiera ona bogaty opis klas i ich metod. Godne uwagi są również przykłady dołączo-ne do PRADO, m.in. blog napisany w opar-ciu o SQLite.

Księga gości stworzona w tym artykule nie wyróżnia się w żaden sposób od innych skryp-tów, jednak była doskonałym wprowadzeniem do funkcjonalności PRADO.

MICHAŁ GAJEKAutor jest programistą – amatorem, od kilku lat piszącym również w języku PHP.Kontakt z autorem: [email protected]

Listing 1. Metoda refresh klasy Home

public function refresh($sender, $param)

{

$entry = new GuestBook ();

// pobierz wpisy

$msgs = $entry->GetMessages();

$code = "";

if (!empty($msgs)){

//w pętli odczytuj po jednej wiadomości

for ($i = 0; $i < $msgs->Count; $i++){

// formatuj wiadomości

(generowanie kodu XHTML) $code .= "<b>".$msgs[$i]-> getAttribute('nick').

"</b><br />\n";

$code .= "<span class=\"msg\">".$msgs[$i]->getValue()."</span><hr /><br />";

}

}

// prześlij zawartość do

<div id = "messages" >

$this->Page->CallbackClient->update("messages", $code);

}

Page 27: PHP Solutions 04 2007 PL
Page 28: PHP Solutions 04 2007 PL

04/2007

Technikę

28

Python kontra PHP

www.phpsolmag.org 29

W królestwo PHP zaczynają wkra-czać inne języki oferując kon-kurencyjne rozwiązania, które

to omówimy w tym artykule. Cytując wiki-pedię Python jest interpretowanym, interak-tywnym językiem programowania stworzo-nym przez Guido van Rossuma w 1990 ro-ku. Rozwijany jest jako projekt Open Source, zarządzany przez niedochodową Python So-ftware Foundation. PHP to wykonywany po stronie serwera skryptowy język programo-wania służący do generowania stron inter-netowych. Python tak samo jak Ruby sam z siebie nie jest przystosowany do tworzenia stron www, jako że jest to język uniwersal-ny od początku swojego istnienia. PHP nato-miast od początku tworzony był jako język do tworzenia stron www. W niniejszym ar-tykule skupimy się nie tyle na porównaniu języków, ale frameworków napisanych w Py-thonie i PHP.

Różnice i podobieństwaOba języki mają wiele wspólnego, ponieważ są:

• Interpretowalnymi językami wysokiego poziomu z dynamicznym systemem ty-pów;

• Rozwijane jako projekty OpenSource;• Posiadają duże społeczności;• Łatwe w nauce (w porównaniu do np. Javy);• Łatwe do rozszerzenia poprzez C/C++;

• Działają na wielu platformach i architek-turach.

Mimo podobieństw są to dwa różne języki. Zbiór różnic przedstawia Tabela 1.

Nie ulega wątpliwości, że PHP jest popular-ny i ma bardzo dużą społeczność, również w Polsce. Znalezienie pomocy, czy to w postaci opublikowanych materiałów, czy też w posta-ci forum dyskusyjnego to nie problem. Rów-nież praktycznie każdy darmowy, tani ho-sting będzie zawierał w ofercie obsługę skryp-tów PHP.

Python ma mniejszą społeczność, w Pol-sce jest raczej mało popularny, lecz w skali światowej społeczność jest dość duża i sku-piona wokół mniejszej ilości serwisów i orga-nizacji. W kwestii hostingu umożliwiające-go obsługę aplikacji Zope, Django czy Pylons nie będziemy mieć licznego grona kandyda-tów, lecz jakość usług będzie wysoka (np. WebFaction). Skrypty PHP wystarczy umie-ścić na serwerze, korzystając np. z klien-ta FTP. W przypadku aplikacji wspomnia-nych frameworków praktycznie nieodzow-ny będzie dostęp do shella oraz odpowied-nia konfiguracja serwera www. Framewor-ki Pythonowe nie nadają się więc jako „Mo-ja pierwsza strona”.

Kolejnym punktem, który warto poruszyć to wsteczna zgodność Pythona. Aplikacja pi-sana pod Pythonem 2.5 będzie w stanie dzia-łać pod Pythonem 2.3. Potencjalne zmiany w kodzie ograniczą się do zmian nazw modu-łów czy sposobu ich użytkowania (chyba że użyjemy „starszej” nazwy modułu). W przy-padku PHP jest jeden problem. PHP5 udo-stępniło programistom wiele dobrych roz-

wiązań, które zostały wykorzystane w wie-lu projektach.

Niestety na większości kont hostingowych wciąż dominuje PHP4. Wydanie PHP6 jesz-cze bardziej spotęguje to zjawisko, a progra-miści oprócz wykonania swojej pracy będą musieli co chwilę uwzględniać wersję PHP, pod którą ma działać ich aplikacja.

Python dla programisty PHPProgramista PHP dość szybko może połapać się w konkurencyjnym języku, choć będzie musiał przyzwyczaić się do pewnych różnic. Pierwszą jest brak średnika na końcu linii, drugą grupowanie kodu za pomocą wcięć. Pę-tla for w PHP wygląda znajomo:

<?PHP

for($i=1;$i <=5;$i++)

{

print $i.'<br />';

}

?>

W Pythonie wyglądać może tak:

for i in range(1,6):

print i

Nieco większą różnicą jest brak tablic zna-nych z PHP, a obecność list, tupli i dzienni-ków. Pierwsze dwa typy uznać można za tabli-ce numeryczne, a dzienniki za tablice asocja-cyjne. Oto przykład:

dziennik = {'klucz': 'wartosc'}

print dziennik['klucz']

lista = ['element1', 'element2']

print lista[1]

print lista[0]

tupla = ['element tupli1', 'element

tupli2']

for i in tupla:

print i

Python kontra PHP

Trend web 2.0 przyniósł ze sobą nie tylko nowe podejście do tworzenia stron internetowych, ale również nowe technologie i narzędzia. Wielu z nas słyszało lub miało kontakt z Ruby on Rails, a użytkownicy portalu grono.net korzystali z aplikacji napisanej w Django.

Dowiesz się...• Zapoznasz się z nowymi narzędziami do two-

rzenia stron www.

Powinieneś wiedzieć...• Podstawowa znajomość PHP i wzorca MVC.

Poziom trudności

czyli węże i słonie

Page 29: PHP Solutions 04 2007 PL

04/2007

Technikę

28

Python kontra PHP

www.phpsolmag.org 29

Nowością będzie przestrzeń nazw i importo-wanie modułów. W przypadku PHP w skryp-cie mamy dostęp do wszystkich funkcji i klas danej instalacji PHP. W przypadku Pythona by uzyskać dostęp np. do klas obsługujących pliki ZIP musimy zaimportować odpowied-ni moduł:

import zipfile

z = zipfile.ZipFile("plik.zip", "r")

for plik in z.namelist():

print 'Plik: ', plik,

bajty = z.read(plik)

print 'ma', len(bajty), 'bajtow'

Wydajność i skalowalnośćOba języki są interpretowane (do wykonania skryptu używa się interpretera), lecz PHP nie jest kompilowany do bajtkodu i zapisywany do wielokrotnego użytku. Każde żądanie wy-słane do serwera spowoduje zinterpretowanie i wykonanie kodu w locie. W przypadku Py-thona kompilacja do bajtkodu jest automa-tyczna, natomiast użytkownicy PHP muszą skorzystać z kompilatorów nie wchodzących w skład domyślnej dystrybucji PHP, takich jak Xcache, eaccelerator, APC czy produktów firmy Zend. W bezpośrednim starciu bez za-biegów optymalizacyjnych Python wygra, lecz odpowiednio skonfigurowane PHP nie będzie miało się czego wstydzić.

Python i niektóre jego frameworki mo-gą działać wielowątkowo, co jest wydajniej-sze od zwykłego trybu pracy PHP, jako że ta-ki tryb pracy zużywa mniej zasobów. Rów-nież w przypadku Django czy Pylons może-my skorzystać z różnych sposobów hostowa-

nia aplikacji – dla Apache mamy mod_python i mod_fcgid, dla Lighttpd, Cherokee czy Nginx możemy wykorzystać protokół FastC-GI lub SCGI.

Za chwilę poznamy bliżej framework Django. W jego przypadku dodanie keszowania dla całe-go projektu, to dodanie jednego wiersza w usta-wieniach, a do keszowania możemy użyć m.in. memcache – wydajnego systemu bazującego na pamięci RAM.

Stosując Pythona do tworzenia dynamicz-nych stron www, na pewno nie stracimy na wy-dajności gotowych aplikacji, a nawet dość często nawet zyskamy.

Frameworki PythonaW Pythonie znajdziemy kilka (a nie kil-kadziesiąt i więcej) frameworków do two-rzenia stron www, które można wykorzy-stać. Prym wiedzie Django i Pylons, a trze-ci – TurboGears znajduje się obecnie w fa-zie przejściowej między starą i stabilną se-rią 1.X a przygotowywaną serią 2.X zgodną z WSGI. Dobrze znane od dawna Zope i Plo-ne też ewoluują, lecz to Pylons i Django pod sztandarem nowoczesności i web 2.0 ataku-ją układ LAMP.

Django to framework dla „profesjonalistów z terminami”, jak głosi jego motto. Jest to dobrze zintegrowany zestaw własnych komponentów takich jak ORM wysokiego poziomu, system szablonów czy mapper adresów URL. Pylons to framework bazujący na integracji „najlep-szych ze swojego rodzaju” rozwiązań.

Wykorzystuje on istniejące podzespoły jak również umożliwia łatwą ich wymianę, tak więc nie jesteśmy ograniczani do np. jedne-

go systemu szablonów. Krótkie porównanie przedstawia Tabela 2.

Oba frameworki są bardzo dobrymi rozwią-zaniami. Django jest frameworkiem najlepiej pasującym do aplikacji typu CMS. Pylons ma podejście „zrób to sam” i króluje w przypad-kach, gdy wymagamy elastyczności i stawiamy nietypowe wymagania.

Portale takie jak Grono.net i lawrence.com wykonane są w Django – i są dużymi serwisa-mi internetowymi. Poradnikzdrowie.pl to ser-wis napisany w Pylons zintegrowany z RedDo-tem (istniejącą wcześniej strukturą serwisów właściciela). Serwisy te dobrze obrazują różni-ce między Django a Pylons.

WSGIWSGI czyli Web Server Gateway Interface to standard interfejsu aplikacji napisanej w Py-thonie do porozumiewania się z serwerami. Stworzono standard interfejsu, który obec-nie stosowany jest przez wiele pythonowych aplikacji, głównie frameworków i aplikacji sieciowych.

Przestrzeganie standardu ułatwiło współ-pracę wielu aplikacji ze sobą i z serwera-mi – pojawiło się pojęcie middleware, czyli skryptu o określonym interfejsie, modyfiku-jącym żądanie bądź odpowiedź wysyłaną do lub z serwera.

Dany skrypt middleware może być bez mo-dyfikacji stosowany w każdym frameworku, zgodnym z wytycznymi WSGI, co stanowi ogromne pole do rozbudowy narzędzi tego typu o nowe możliwości. Przykładem jest tu framework Pylons stawiający na WSGI. Sam nie posiada ani systemu użytkowników, ani

Tabela 1. Różnice pomiędzy językami PHP i Python

PHP Python

Składnia bazująca na C i Perlu Wcięcia stosowane do grupowania kodu

Instrukcje swith i do... while Przestrzenie nazw

Brak przestrzeni nazw Wszystko jest referencją

Nawiasy klamrowe stosowane do grupowania kodu Wielowątkowość

Większa społeczność i popularność Dużo typów wysokiego poziomu

Język głównie do tworzenia dynamicznych stron Język ogólnego użytku

Stabilny, lecz gwałtowniej rozwijany (PHP4 – PHP5) Wstecznie zgodny, stabilny i dojrzały. Standaryzacja rozwiązań

Kompilatory dostępne jako rozszerzenia (APC, Xcache, eaccelerator, zend) Automatyczne kompilowanie do bajtkodu

Tabela 2. Porównanie frameworków Pythona

Django Pylons

Dobrze zintegrowane własne komponenty Integruje najlepsze istniejące komponenty i umożliwia ich łatwą wymianę

Łatwy w nauce, świetnie udokumentowany Niespójna i mniej liczna dokumentacja (każdy komponent ma dokumenta-cję na swojej stronie). Wymaga więcej czasu na naukę i konfigurację kom-ponentów

ORM wysokiego poziomu obsługujący MySQL, SQLite i PostgreSQL (Oracle od wersji 1.0)

Zalecane stosowanie ORMa SQLAlchemy – większe możliwości i łatwiejsza praca na istniejących tabelach, lecz trudniejszy w nauce.

Większa społeczność, zastosowany w wielu projektach Aplikacja może działać wielowątkowo

Generyczne widoki, Automatyczny panel admina, system użytkowników i uprawnień

Wiele pomocników JavaSript, Ajax (w tym Scriptaculous)

Page 30: PHP Solutions 04 2007 PL

04/2007

Technikę

30

Python kontra PHP

www.phpsolmag.org 31

obsługi openID, ale middleware, takie jak np. AuthKit, bezproblemowo dodają te funkcjo-nalności do frameworka. Chęć przestrzega-nia specyfikacji jest w społeczności tak du-ża, że trzeci duży framework – TurboGears zawiesił rozwój dotychczasowego niezgodne-go z WSGI drzewa 1.X tworząc zarazem roz-wojową obecnie gałąź 2.X, zgodną z WSGI. Dla programistów rozwijających framewor-ka oznacza to przepisanie wielu modułów TurboGears.

W PHP standaryzacja rozwiązań kuleje. Na-wet na poziomie nazw funkcji trafimy na róż-ne style nazewnictwa. W kategorii komponen-tów sprawę nieco wyjaśnia PEAR, lecz czy Co-deIgniter, Symfony lub Zend Framework bez-boleśnie integrują API pakietów PEAR? Nie-stety nie.

Zend Framework i ezComponents jako zbiór luźniejszych komponentów, które łatwiej wy-korzystywać w innych frameworkach, dają na-dzieję, lecz na tak daleko posuniętą standary-zację jak w przypadku Pythona nie mamy na razie co liczyć.

Django kontra CodeIgniter i spółkaZajmiemy się teraz porównaniem obu frame-worków, jak i drogi tworzenia aplikacji z ich użyciem (CodeIgniter opisany został w nume-rze 2/2007 phpSolutions). Django wykorzystuje wzorzec MVC , lecz w porównaniu z CI wpro-wadza kilka zmian. Pierwszą z nich jest nazwa – MTV czyli Model-Template-View. W Django model określa strukturę tabeli (logikę bazoda-nową ogólnie), widok zawiera logikę aplikacji, a szablon wygląd. Kolejna różnica dotyczy sa-mego modelu. W przypadku CodeIgnitera mo-del zawierał definicje różnych operacji na ba-zie danych, takich jak pobieranie ostatnich newsów, kasowanie i aktualizowanie wpisów. W Django model definiuje strukturę tabeli, a operacje wykonujemy w widokach za pomo-cą ORMa.

Przykładowy projekt DjangoZaprezentuję teraz prosty projekt Django – blog z systemem newsów obrazujący sposób tworze-nia projektów Django.

InstalacjaOstatnią wydaną wersją Django jest wersja 0.96. Pobieramy archiwum z frameworkiem ze strony projektu i rozpakowujemy. Otwieramy konsolę i przechodzimy do katalogu z kodem Django. Wydajemy polecenie:

python setup.py install

Django wymaga kilku dodatkowych bibliotek Pythona:

• Do obsługi SQLite Django używa pysqlite;• Postgres: psycopg;• MySQL: mysql-python.

Tworzenie aplikacji w DjangoTworzenie projektu. Projekt składa się z aplika-cji, np. CMS z różnych modułów. By stworzyć projekt wystarczy wydać polecenie:

django-admin.py startproject NAZWA_PROJEKTU

django-admin.py startproject blog

Stworzone zostaną podstawowe pliki projek-tu, możemy nawet uruchomić serwer Django dla tego projektu.

Uruchamianie serwera DjangoZ konsoli po przejściu do katalogu projektu wy-konaj polecenie:

python manage.py runserver 8080

Komenda ta uruchomi deweloperski serwer Django. Będzie on dostępny pod adresem http://localhost:8080/.

Konfiguracja projektu – bazy danychDjango jest silnie powiązane z bazami danych i do dalszych operacji będzie nam potrzeb-na dostępna baza danych (sqlite3, mysql lub postgresql). Edytujemy settings.py i ustawia-my SQLite jako naszą bazę danych: patrz Li-sting 1.

Teraz zatrzymujemy serwer Django i syn-chronizujemy bazę danych. Po dodaniu nowej aplikacji, bądź danych do bazy danych nowe-go projektu, musimy te dane zsynchronizować. Służy do tego polecenie:

python manage.py syncdb

W przypadku rozpoczynania pracy z bazą da-nych Django zapyta nas też o dane głównego admina projektu.

Tworzenie aplikacjiBy stworzyć aplikację wystarczy wykonać pole-cenie z katalogu projektu:

python manage.py startapp

NAZWA_APLIKACJI

python manage.py startapp news

Listing 1. Podłączenie bazy danych do naszego CMSa

DATABASE_ENGINE =

'sqlite3' # 'postgresql', 'mysql', 'sqlite3' lub 'ado_mssql'.

DATABASE_NAME =

'bazka.db' # nazwa bazy danych lub ścieżka dla bazy sqlite3

DATABASE_USER =

'' # użytkownik bazy, puste dla sqlite3

DATABASE_PASSWORD =

'' # hasło użytkownika, puste dla sqlite3

DATABASE_HOST =

'' # host do bazy danych, puste localhost

DATABASE_PORT =

'' # Podaj port jeżeli niestandardowy, puste dla sqlite3.

następnie zmieniamy język i strefę czasową:

TIME_ZONE = 'Europe/Warsaw'

LANGUAGE_CODE = 'pl'

Listing 2. Model aplikacji wiadomości

from django.db import models

class News(models.Model):

news_title = models.CharField(

maxlength=255, verbose_name='Tytuł')

news_text = models.TextField(

verbose_name='Treść')

news_date = models.DateTimeField(

auto_now_add = True, blank=

True, verbose_name='Data dodania')

class Meta:

verbose_name = "Wiadomość"

verbose_name_plural = "Wiadomości"

class Admin:

list_display = ('news_title', 'news_date')

list_filter = ['news_date']

search_fields = ['news_title', 'news_text']

date_hierarchy = 'news_date'

def __str__(self):

return self.news_title

Page 31: PHP Solutions 04 2007 PL

04/2007

Technikę

30

Python kontra PHP

www.phpsolmag.org 31

Co stworzy katalog aplikacji wraz z plikami:

news/

__init__.py

models.py

views.py

Zbiór models.py zawiera modele naszej aplika-cji. Kod modelu dla naszej przykładowej apli-kacji przedstawia Listing 2.

Każdy model, klasa dziedziczy z django.db.models.models, przez co może-my zdefiniować strukturę poszczególnych tabel. Pole CharField i TextField służą do prze-chowywania tekstu, DateTimeField daty. Te-raz edytujemy settings.py projektu. Do IN-STALLED_APPS dodajemy naszą aplikację (NAZWA_PROJEKTU.NAZWA_APLIKA-CJI), czyli blog.news. Zapisujemy i synchroni-zujemy bazę danych.

Panel AdminaBy włączyć panel administracyjny wykonu-jemy:

• Do INSTALLED_APPS w settings.py doda-jemy django.contrib.admin;

• Synchronizujemy bazę danych;• Edytujemy urls.py i usuwamy komentarz

(#) z wiersza: (r'̂ admin/', include('django.contrib.

admin.urls')),

Panel Admina dostępny jest pod adresem http://localhost:8080/admin/ i umożliwia zarządzanie aplikacją – dodawanie, usu-wanie i edytowanie wpisów wraz z opcja-mi pomocniczymi jak listowanie i wyszu-kiwanie.

Interfejs użytkownikaMamy gotowy panel administratora wiado-mości, lecz nie mamy jeszcze interfejsu od strony użytkownika. Zaczynamy od zapro-jektowania adresów URL. urls.py zawierają listę powiązanych adresów URL z akcjami wywoływanymi w przypadku dopasowania URLa. Format:

(wyrażenie regularne, funkcja pythona

do wykonania [, opcjonalnie katalog])

urls.py powinien wyglądać tak: Listing 3.W wielu frameworkach MVC, w tym miej-

scu, musielibyśmy napisać kontrolery (wido-ki w Django) wykonujące określone czynno-ści. Lecz Django posiada coś takiego, jak Gene-ryczne Widoki, czyli predefiniowane akcje ta-kie jak: pokaż określony wpis, listuj wpisy ze stronicowaniem i inne. W powyższym kodzie urls.py użyliśmy generycznego django.views.generic.list_detail.object_list – li-sty wpisów ze stronicowaniem. Teraz musi-my tylko stworzyć szablony.

Szablony

• W katalogu projektu utwórz katalog templates (na szablony) i site _ media (na pliki statyczne);

• Dodaj 'templates' (nazwę katalogu na sza-blony) w settings.py do TEMPLATE _

DIRS. TEMPLATE_DIRS = (

'templates',

)

Edytuj plik urls.py i dodaj regułę:

(r'^site_media/(.*)$', 'django.views.static

.serve',

{'document_root': '/ŚCIEŻKA/DO/site_

media'}),

Teraz wystarczy, że stworzymy szablo-ny. Skorzystamy z darmowego szablonu. Załóżmy, że zawiera on XHTML zawie-ra katalog images oraz pliki: default.css i index.html.

• Katalog i plik css kopiujemy do /site _

media a index.html do /templates ;• Edytujemy plik index.html i zastępujemy

przykładową treść tagiem: {% block content %}{% endblock %};

• Znajdujemy <link rel="stylesheet"

type="text/css" href="default.css" />;• Zamieniamy na <link rel="stylesheet"

type="text/css" href="/site _ media/

default.css" /> ;• Tworzymy plik /templates/news _

list.html z kodem: Listing 4.

Listing 3. Dopasowanie adresów URL w urls.py

from django.conf.urls.defaults import *

from blog.news.models import *

urlpatterns = patterns('',

(r'^admin/', include(

'django.contrib.admin.urls')),

(r'^/?$', 'django.views.generic.

list_detail.object_list', {

'queryset':News.objects.all().

order_by('-id'), 'paginate_by':10,

'allow_empty':True, 'template_name':

'news_list.html'}),

(r'^/(?P<page>[0-9]+)$',

'django.views.generic.list_detail.object_list',

{'queryset':News.objects.all().order_by('-id'),

'paginate_by':10, 'allow_empty':True,

'template_name':'news_list.html'}),

)

Listing 4. Przykładowy plik news_list.html

{% extends "index.html" %}

{% block content %}

{% if object_list %}

{% for new in object_list %}

<h3>{{ new.news_title }}</h3>

<p>{{ new.news_text }}... {{

new.news_date|truncatewords:"1" }}</p>

{% endfor %}

{% if has_previous %}

<div style="text-align:center;">

<a href="/?page={{ previous }}">

<b>Nowsze Wiadomości</b></a></div>

{% endif %}

{% if has_next %}

<div style="text-align:center;">

<a href="/?page={{ next }}">

<b>Starsze Wiadomości</b></a></div>

{% endif %}

{% else %}

Brak wiadomości

{% endif %}

{% endblock %}

Page 32: PHP Solutions 04 2007 PL

04/2007

Technikę

32

Python kontra PHP

Otwieramy główną stronę swojej aplika-cji w przeglądarce, wpisując adres http://localhost:8080/. Efekt przedstawiono na Ry-sunku 2.

Trochę wyjaśnień, otóż zaczęliśmy od poda-nia w settings.py nazwy katalogu na szablony, następnie w urls.py podaliśmy regułę obsługu-jącą pliki statyczne pod serwerem deweloper-skim (w warunkach produkcyjnych to serwer www tym się zajmuje). Pliki statyczne to gra-fiki, pliki JS czy css, jak i inne, do których chce-my mieć dostęp z poziomu aplikacji Django. Ko-lejną czynnością było przystosowanie szablonu HTML. Przypomnijmy sobie regułę serwującą statyczne pliki:

(r'^site_media/(.*)$', 'django.views.static

.serve',

{'document_root': '/ŚCIEŻKA/DO/site_

media'}),

r'^site _ media/(.*)$' – oznacza, iż wszystkie pliki statyczne dostępne są przez /site_media/plik_ statyczny, tak więc musie-liśmy zmienić odnośnik do pliku CSS. Ko-lejnym etapem było zastąpienie przykłado-wej treści przez tag bloku. Następnie stwo-rzyliśmy drugi szablon dziedziczący in-dex.html:

{% extends "index.html" %}

Szablony Django obsługują dziedziczenie – news_list.html dziedziczy index.html, czyli wy-

świetla zawartość tego szablonu. Oprócz dzie-dziczenia skorzystaliśmy z drugiego ważnego elementu – bloków. W news_list.html podali-śmy zawartość dla bloku content:

{% block content %}

tutaj zawartość

{% endblock %}

W efekcie wypełniliśmy index.html określoną przez nas zawartością – listą newsów. Oczy-wiście możemy stworzyć identyczną aplika-cję w PHP, lecz kluczowym czynnikiem jest tutaj szybkość tworzenia. Django jest bardzo dobrym narzędziem, gdyż jego komponenty umożliwiają bardzo wydajne tworzenie wyso-kiej jakości aplikacji. W porównaniu do takie-go samego programu wykonanego w CodeIgni-terze różnice są następujące:

• Nie tworzymy tabeli w bazie danych, robi to framework (dbając m.in. o indeksy);

• Mamy gotowy Panel Admina do zarządza-nia aplikacjami;

• Generyczne Widoki znacznie ułatwiają tworzenie interfejsu od strony użytkowni-ka;

• Model opisuje tabele bazy danych, a nie operacje na nich – w przypadku CI bez struktury tabel trudno byłoby je odtwo-rzyć bazując na kodzie modeli (brak wy-cieku informacji poza projekt);

• Walidacja na poziomie mapowania URLi poprzez wyrażenia regularne i na pozio-

mie modelu poprzez wysokopoziomowe typy pól.

Smaczki DjangoPrezentowana przed chwilą aplikacja, nie pokazała wszystkich możliwości framewor-ka. Poznanie ich wymaga bardziej dokładne-go poznania tego narzędzia, lecz poniżej opi-szę kilka innych przydatnych komponentów Django.

ORM DjangoORM mapuje strukturę bazy danych – po-szczególnych tabel na obiekty. W Django obsłu-ga ORMa jest bardzo prosta, a sam komponent jest mocno rozbudowany. Propel dostępny dla PHP niestety nie może pochwalić się tak czy-stym i przyjemnym interfejsem.

Listing 5. przedstawia model dla systemu blogów złożony z trzech tabel. Blog – nazwa i opis blogów, Author – Nazwisko i email auto-rów. Entry – wpis dla danego bloga.

Zaprezentowany na listingu model prezen-tuje obsługę powiązanych tabel – Entry ma pole authors zależne od Author i pole blog za-leżne od Blogs. Proste zależności wiele-do-jednego określane są przez pola typu Foreign-Key, zawierające jako parametr nazwę mode-lu. Tak więc dany wpis (Entry) przypisany jest do konkretnego autora i bloga. Django oferu-je również obsługę zależności wiele-do-wielu czyli np. gdyby taka zależność dotyczyła pola blog, to dany wpis (Entry) mógłby być przy-pisany do wielu blogów. Listing 6. przedsta-wia operacje na rekordach wykonywane po-przez ORM.

System uprawnień i użytkownikówDjango oferuje również system użytkowni-ków, grup oraz uprawnień. Przy synchroniza-cji bazy danych mogłeś zauważyć, że dla każ-dego modelu (klasy) tworzone są domyślnie trzy „znaczniki” uprawnień: dodawanie, edy-cja i usuwanie obiektu danego modelu. Można też tworzyć własne. W Panelu administracji w łatwy sposób możemy tworzyć grupy, zbiory uprawnień jak również nadawać poszczegól-nym użytkownikom uprawnienia i przypisy-wać ich do istniejących grup. Wykorzystanie tego systemu w praktyce jest bardzo łatwe, ja-ko że w widoku bieżący użytkownik reprezen-towany jest przez obiekt request.user. Najlepiej obrazuje to Listing 7. zawierający kod proste-go widoku.

MiddlewareMiddleware to pojęcie związane z WSGI, obecnym również w Django. Middleware może globalnie wpływać na żądania wysy-łane do widoków, jak i na ich odpowiedzi. Do czego można zastosować middleware? Np. do śledzenia aktywności użytkowników na stronie – każde żądanie dowolnej strony

Rysunek 2. Widok strony głównej wiadomości

Rysunek 1. Panel Admin w akcji

Page 33: PHP Solutions 04 2007 PL

04/2007

Technikę

32

Python kontra PHP

naszej aplikacji może wykonać kod middle-ware, aktualizujący listę użytkowników Na Stronie. Może też posłużyć do modyfikacji nagłówków, czy zmiany działania serwisu w określonych warunkach (np. obsługa ope-nID w Pylons).

Maper adresów URLJak już mogliśmy zauważyć w Django (w Py-lons również) adresy URL są mapowane, co w PHP jest niespotykane. Za pomocą wyra-żeń regularnych określamy URL i przypi-sujemy mu widok, jaki ma zostać wykona-ny. URLe, które nie zostaną dopasowane do żadnego wyrażenia nie istnieją (zwrócony zo-stanie kod 404). Wymaga to od programisty znajomości podstaw wyrażeń regularnych. W efekcie dostajemy przyjazne wyszukiwar-kom odnośniki oraz w przypadku zastosowa-nia poprawnych formuł – walidację na pozio-mie mapowania odnośników (nie trzeba tego robić w widoku). Mapowane adresy URL to nie przepisany Query String, który również istnieje i może być stosowany w wyjątkowych okolicznościach (zaleca się stosowanie mapo-wanych odnośników).

Zedo.pl – Dlaczego Django?Zedo.pl to nowo powstały portal społeczno-ściowy, w którym użytkownicy dzielą się komponentami do telefonów komórkowych, takimi jak tapety i w przyszłości motywy czy dzwonki. Pierwotnie właściciel chciał, by ser-wis był wykonany w znanej mu technologii – PHP i MySQL, lecz gdy zapoznałem go z Django i jego możliwościami zgodził się na to rozwiązanie. Dlaczego wybrałem Django? Ze względu na szybkość i przyjemność tworze-nia kodu aplikacji. Główne problemy, jakie dostrzegłem po zapoznaniu się ze specyfika-cją portalu to:

• Rozbudowany system użytkowników wraz z „użytkownikami online”, rozbudo-wanymi profilami z komentarzami, przy-jaciółmi itp.;

• Walidacja formularzy, w szczególności do-dawanie tapet (walidacja i skalowanie pli-ków);

• Powiązane między sobą tabele (Komór-ki z przypisaną rozdzielczością – tapeta o określonej rozdzielczości) i filtrowanie da-nych z powiązanych tabel.

Nie jest to nic, czego nie można zrobić w PHP, ale tutaj liczy się czas programisty i wysiłek ja-ki należy włożyć, by uzyskać założony efekt. Django zawiera dobry system użytkowników i uprawnień oraz rozbudowany, elastyczny sys-tem walidacji i obsługi formularzy, dzięki te-mu dość łatwo rozwiązać możliwe problemy:

• Skrypt Middleware w przypadku zalogo-wanego użytkownika, co 5 minut aktuali-zuje jego obecność na stronie, wykorzystu-jąc cookie z zapisanym znacznikiem czasu, do określania czy i kiedy zaktualizować wpis w bazie danych;

• Do walidacji wysyłanych tapet, oprócz walidacji rozszerzenia wykorzystany zo-stał PIL do walidacji rozmiaru i typu MI-ME (wykrywa łączone pliki typu grafika-+PHP);

• System użytkowników został rozszerzony o zależne tabele zapewniające funkcjonal-ność profilu użytkownika.

Nietypowe rozwiązaniaPython to język ogólnego przeznaczenia, istnie-je więc wiele komponentów, które nie były two-

R E K L A M A

Page 34: PHP Solutions 04 2007 PL

04/2007

Technikę

34

rzone z myślą o stronach www, co nie oznacza, że nie możemy ich wykorzystać. Chcąc zro-bić bazę danych wyników analiz chromato-graficznych – wystarczy skorzystać z bibliote-ki pyCDF i zapisać wyniki w formacie CDF. Je-żeli chcemy generować złożone wykresy z tych analiz, lub z innych danych, problem nasz roz-wiąże matplotlib. Generowaniem raportów, pli-ków PDF czy prostych wykresów zajmie się re-portlab, a skanowaniem przesyłanych załącz-ników, pod kątem obecności wirusów, pyCla-mAV. Odpowiednikiem GD z PHP będzie PIL o równie bogatej, jeżeli nie większej funkcjo-nalności.

Programowanie sieciowePython w swojej bibliotece standardowej po-siada szereg modułów przydatnych przy pro-gramowaniu sieciowym. Moduł socket, jak sa-ma nazwa wskazuje, daje nam możliwość ope-rowania na gniazdach. Moduły wyższego po-ziomu jak urllib, telnetlib, imaplib czy ftplib zapewniają obsługę poszczególnych protoko-łów. Nie jest to nic nadzwyczajnego. Wymaga-jących zapewne zainteresuje coś innego – fra-mework sieciowy Twisted, wspierający TCP, UDP, SSL/TLS, multicast czy protokoły takie jak HTTP, NNTP, IMAP, SSH, IRC, FTP. Fra-mework ten umożliwia pisanie asynchronicz-nych klientów i serwerów różnego typu.

Test Driven DevelopmentTesty jednostkowe i ciągła kontrola rozwija-nej aplikacji w przypadku dużych projektów jest nieodzowna. Również w Pythonie znaj-dziemy narzędzia do przeprowadzania ta-kich testów. Dostępnych jest kilka rozwiązań jak: unittest, pymock, nose, nosy czy py.test. Py-lons, swój system testów jednostkowych oparł o nose, a Django o doctest i unittest, dodając dodatkowo własny system do testowania ele-mentów kodu powiązanego z bazą danych (fi-xtures). Można również stosować aplikacje ta-kie jak Selenium.

PodsumowaniePowyższy artykuł miał za zadanie przybliżyć programistom PHP alternatywne rozwiąza-nia, jakie można wykorzystać przy tworzeniu stron internetowych. Zarówno PHP, jak i Py-thon, mają swoje wady i zalety, lecz oba języki dobrze sprawdzają się w powierzonych im za-daniach. Jeżeli chcesz poznać nowy język o sze-rokich możliwościach, nie odchodząc zarazem od tworzenia stron www to, moim zdaniem, Py-thon będzie dobrym wyborem.

PIOTR MALIŃŚKIAutor jest studentem Politechniki Warszawskiej na kierunku Technologia Chemiczna. Od 4 lat zaj-muje się tworzeniem aplikacji w PHP, jak też od niedawna aplikacji o Pythonie. Kontakt z autorem: [email protected]

W Sieci:

• http://www.python.org – strona Pythona;• http://www.ipersec.com/index.php?q=en/bench_ea_vs_apc – porównanie wydajności róż-

nych enkoderów bajtkodu PHP;• http://www.python.org/dev/peps/pep-0333/ – opis WSGI;• http://wiki.rubyonrails.com/rails/pages/Framework+Performance – porównanie wydajności

Symfony, Ruby on Rails i Django;• http://twistedmatrix.com/trac/ – strona frameworka Twisted;• http://www.djangoproject.com – strona Django;• http://www.pylonshq.com – strona Pylons;• http://www.python.rk.edu.pl/ – polska dokumentacja Django i Pylons• http://docs.pythonweb.org/ – wiki Pylons

Listing 5. Model systemu blogów

class Blog(models.Model):

name = models.CharField(maxlength=100)

tagline = models.TextField()

def __str__(self):

return self.name

class Author(models.Model):

name = models.CharField(maxlength=50)

email = models.URLField()

def __str__(self):

return self.name

class Entry(models.Model):

blog = models.ForeignKey(Blog)

headline = models.CharField(maxlength=255)

body_text = models.TextField()

pub_date = models.DateTimeField()

authors = models.ManyToManyField(Author)

def __str__(self):

return self.headline

Listing 6. Przykładowe operacje ORMa django

# Dodanie wpisu

b = Blog(name= 'Blog Andrzeja', tagline=

'Najnowsze wieści z pola')

b.save()

#edycja

b.name='Blog Zbyszka'

b.save()

# pobranie wszystkich blogów

blogi = Blog.objects.all()

# pobranie 5 blogów

blogi = Blog.objects.all()[:5]

# filtrowanie i sortowanie wyników

wpisy = Entry.objects.filter(

pub_date__year=2005).order_by(

'-pub_date', 'headline')

Listing 7. Przykładowy widok wykorzystujący system użytkowników i uprawnień

def moj_widok(request):

if request.user.is_authenticated():

# zalogowany

else:

# niezalogowany

if request.user.is_staff and

request.user.has_perm(

'news.add_news'):

# zalogowany,

z odpowiednimi uprawnieniamibv

Page 35: PHP Solutions 04 2007 PL

v

Pren

umer

ata

PRO

Wię

cej i

nfor

mac

ji: patrycja.wadolowska@

software.com.pl

tel.:

022

887

-13-

45

v

Page 36: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

36

eZ Publish

www.phpsolmag.org 37

Bazując na wbudowanych możliwo-ściach systemu możemy go dodatko-wo rozbudować, dostosowując do po-

trzeb konkretnego wdrożenia. Enterprise Open Source CMS, jak nazywany jest eZ Pu-blish, to:

• Oprogramowanie klasy Enterprise, czyli system pozwalający na bezpieczne wyko-rzystanie w dużych projektach produkcyj-nych, daje odbiorcy:• pełną gamę wbudowanych funkcjonal-

ności do zarządzania informacją;• pełne wsparcie producenta;

• Open Source udostępnia w pełni kod źró-dłowy, a dodatkowo jest:• ukierunkowany na standardy siecio-

we;• umożliwia rozbudowę i integrację z

innymi systemami.

Jeden login do wielu systemówJednym z podstawowych elementów inte-gracji systemów informatycznych jest moż-liwość zastosowania jednolitego systemu au-toryzacji użytkowników, poprzez integrację kont. Pojedyncze dane dostępowe użytkowni-ka (zwykle login i hasło) mogą być wykorzy-stane do autoryzacji w kilku systemach infor-matycznych.

Metody autoryzacji użytkowników w eZ PublisheZ Publish posiada trzy wbudowane metody au-toryzacji użytkowników. Opierają się one na:

• kontach zarejestrowanych w systemie;• informacjach przechowywanych w pli-

kach tekstowych;• integracji z LDAP.

Dodatkowo możliwe jest stworzenie własnego rozszerzenia obsługującego autoryzację. Meto-da autoryzacji ustawiana jest przez administratora na poziomie plików konfiguracyjnych systemu. W jednym z nich, settings/site.ini, gromadzącym pod-stawowe ustawienia znajduje się następujący wpis:

[UserSettings]

LoginHandler[]=standard

Aby umożliwić autoryzację opartą na pliku tek-stowym, należy nadpisać domyślną konfigura-cję (Ramka 1.) w następujący sposób:

[UserSettings]

LoginHandler[]=standard

LoginHandler[]=textfile

eZ Publish

eZ Publish jest znany przede wszystkim jako system zarządzania treścią (ang. content management system – CMS), może być również z powodzeniem wykorzystany jako wzorzec projektowy (ang. content management framework – CMF).

Dowiesz się...• Prezentujemy, czym jest CMF oraz eZ Ecosys-

tem.• Poznasz podstawy architektury eZ Publish oraz

jej możliwości.

Powinieneś wiedzieć...• Powinieneś wiedzieć, czym jest CMS.• Powinieneś wiedzieć, jak działają systemy web-

based.

Poziom trudności

Intergracja różnych systemów autoryzacji użytkowników

Rysunek 1. Grupa użytkowników o różnych typach uprawnień

Page 37: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

36

eZ Publish

www.phpsolmag.org 37

Taka modyfikacja oznacza, że autoryzacja nadal opiera się na standardowym mechanizmie eZ Publish. Jeżeli jednak operacja logowania nie zakończy się powodzeniem, system będzie pró-bował wykorzystać dodatkowy mechanizm, aby sprawdzić uprawnienia użytkownika.

Konta użytkowników w eZ PublishDomyślna metoda autoryzacji oparta jest na syste-mie kont użytkowników, zarejestrowanych w eZ Publish. Ich struktura opiera się na grupach użyt-kowników oraz kontach zarejestrowanych przez administratora lub samodzielnie przez użytkow-nika końcowego. Konto użytkownika zawiera przede wszystkim dane identyfikacyjne, czyli:

• nazwę użytkownika (login);• hasło;• adres e-mail.

Dodatkowo może zawierać inne informacje związane z osobą lub jej profilem. Przykłado-wo, zgromadzić można: imię, nazwisko, ad-res, sygnaturę, zdjęcie i inne dane. Rejestracja samodzielna (dokonywana przez użytkownika końcowego) może podlegać autoryzacji. Stosuje się wtedy mechanizm przesyłania potwierdze-nia pocztą elektroniczną na podany adres, a na-stępnie, po zatwierdzeniu poprawności (kliknię-cie specjalnie spreparowanego odnośnika w wia-domości), konto zostaje aktywowane. Aktywne konto użytkownika służy do autoryzacji tożsa-mości przed każdorazowym rozpoczęciem pra-cy w systemie.

Pliki tekstoweMetoda przechowywania danych o użytkow-nikach w pliku tekstowym bliska jest mecha-nizmom znanym z systemów operacyjnych ro-dziny Linux.

Aby skorzystać z autoryzacji opartej na infor-macjach przechowanych w pliku tekstowym,

konieczne jest odpowiednie skonfigurowanie systemu, czyli zamieszczenie odpowiedniego wpisu w pliku settings/site.ini:

[UserSettings]

LoginHandler[]=standard

LoginHandler[]=textfile

Dodatkowo możemy zachować informacje na temat struktury pliku tekstowego. Do tego ce-lu służy: settings/textfile.ini. Patrz Listing 1.

LDAPMetoda autoryzacji oparta na LDAP polega na integracji usług katalogowych z eZ Publish. Aby

Konfiguracja eZ PublishUstawienia konfiguracyjne eZ Publish przechowywane są w plikach tekstowych, zgromadzonych w ka-talogu settings/ systemu oraz jego podkatalogach. Pliki z rozszerzeniem .ini zawierają predefiniowa-ne ustawienia – domyślną konfigurację systemu. Konstrukcja pliku konfiguracyjnego jest bardzo prosta – składa się z bloków gromadzących pokrewne ustawienia oraz z par: “nazwa zmiennej” = “wartość zmiennej”. Przykładowo blok zawierający konfigurację bazy danych wygląda w następujący sposób:

[DatabaseSettings]

DatabaseImplementation=ezmysql

Server=localhost

User=root

Password=

Database=nextgen

Charset=

Socket=disabled

Transactions=enabled

Konfigurację domyślną można zastąpić własną, tworząc pliki o nazwie zgodnej z wzorcową (zwykle do-dawane są rozszerzenia .append.php) oraz umieszczając je w podkatalogach settings/. System spraw-dza ustawienia konfiguracyjne na kolejnych poziomach i ostatecznie bierze pod uwagę te o najwyższym priorytecie. Kolejność nadpisań od najmniej do najbardziej-istotnego pliku jest następująca:

/settings/site.ini

/settings/siteaccess/<identyfikator-serwisu>/site.ini.append.php

/settings/override/site.ini.append.php

<identyfikator-serwisu> to ciąg znaków, który związany jest z konkretnym interfejsem dostępo-wym lub serwisem WWW. Przykładowo: Zapis ogólny: http://www.domena.com/<identyfikator-ser-wisu> Może mieć formę:

• http://www.domena.com/pl – serwis WWW w polskiej wersji językowej;• http://www.domena.com/en – serwis WWW w angielskiej wersji językowej;• http://www.domena.com/administrator – panel administracyjny;

Dla każdego z tych interfejsów możliwe jest stworzenie niezależnej konfiguracji.

Listing 2. Zawartość pliku settings/ldap.ini

[LDAPSettings]

LDAPEnabled=true

LDAPServer=ldap.example.com

LDAPPort=389

LDAPBaseDn=ou—users,dn--example,dn--com

LDAPSearchScope=sub

# ustawienie zamiany ciągu znaków w “--” na "="

# dla zmiennych LDAPBaseDn or LDAPSearchFilters

LDAPEqualSign=--

# ustawienia filtrowania wyników

LDAPSearchFilters[]

# identyfikator użytkownika

LDAPLoginAttribute=uid

# przykładowa konfiguracja powiązania użytkowników w grupy

LDAPUserGroupType=id

LDAPUserGroup=12

LDAPUserGroupAttributeType=name

LDAPUserGroupAttribute=pracownicy

LDAPFirstNameAttribute=givenname

LDAPLastNameAttribute=sn

LDAPEmailAttribute=mail

Listing 1. Zawartość pliku settings/textfile.ini

[TextFileSettings]

TextFileEnabled=true

# nazwa pliku

FileName=konta.txt

# polożenie pliku

FilePath=var/storage/konta

# separator danych

FileFieldSeparator=;

# domyślna grupa użytkowników

DefaultUserGroupType=name

DefaultUserGroup=Editors

# kolejność kolumn

LoginAttribute=3

PasswordAttribute=4

FirstNameAttribute=1

LastNameAttribute=2

EmailAttribute=5

Page 38: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

38

eZ Publish

www.phpsolmag.org 39

Listing 3. Fragment pliku cronjobs/ldapusermanage.php

Listing 4. Szablon klasy obsługującej nowy typ autoryzacji użytkowników w eZ Publish

<?php

/* ... */

// pobranie tablicy użytkowników zapisanych

// w bazie danych eZ Publish

$db =& eZDB::instance();

$query = "SELECT contentobject_id, login

FROM ezcontentobject, ezuser

WHERE remote_id like 'LDAP%'

AND ezcontentobject.id=contentobject_id";

$LDAPUsers = $db->arrayQuery( $query );

// odczytanie ustawień konfiguracyjnych dla LDAP

$ini =& eZINI::instance();

$LDAPIni =& eZINI::instance( 'ldap.ini' );

$LDAPVersion = $LDAPIni->variable(

'LDAPSettings', 'LDAPVersion' );

$LDAPServer = $LDAPIni->variable(

'LDAPSettings', 'LDAPServer' );

$LDAPHost = $LDAPServer;

$LDAPPort = $LDAPIni->variable(

'LDAPSettings', 'LDAPPort' );

$LDAPBaseDN = $LDAPIni->variable(

'LDAPSettings', 'LDAPBaseDn' );

$LDAPBindUser = $LDAPIni->variable(

'LDAPSettings', 'LDAPBindUser' );

$LDAPBindPassword = $LDAPIni->variable(

'LDAPSettings', 'LDAPBindPassword' );

/* ... */

// nawiązanie połączenia z serwerem LDAP

$ds = ldap_connect( $LDAPHost, $LDAPPort );

if ( $ds )

{

ldap_set_option(

$ds, LDAP_OPT_PROTOCOL_VERSION, $LDAPVersion );

if ( $LDAPBindUser == '' )

{

<?php

include_once(

"kernel/classes/datatypes/ezuser/ezusersetting.php" );

include_once(

"kernel/classes/datatypes/ezuser/ezuser.php" );

include_once(

'lib/ezutils/classes/ezini.php' );

class eZMyLoginHandlerUser extends eZUser

{

// konstruktor

function eZDedykowanaAutoryzacjaUser()

{

$r = ldap_bind( $ds );

}

else

{

$r = ldap_bind(

$ds, $LDAPBindUser, $LDAPBindPassword );

}

if ( !$r )

{

eZDebug::writeError( 'Cannot bind in to LDAP server',

'ldapusermanage.php' );

return false;

}

ldap_set_option( $ds, LDAP_OPT_SIZELIMIT, 0 );

ldap_set_option( $ds, LDAP_OPT_TIMELIMIT, 0 );

}

else

{

eZDebug::writeError( 'Cannot initialize connection

for LDAP server', 'ldapusermanage.php' );

return false;

}

// aktualizacja kont użytkowników

$db->begin();

foreach ( array_keys ( $LDAPUsers ) as $key )

{

/* ... */

}

$db->commit();

if ( !$isQuiet )

$cli->output( "All LDAP users have been updated!" );

?>

}

// funkcja obsługująca logowanie użytkownika

function &loginUser(

$login, $password, $authenticationMatch = false )

{

// zwrócenie obiektu eZUser w przypadku powodzenia

return $user;

// lub false po niepowodzeniu logowania

// return false;

}

}

?>

skorzystać z tej metody, należy posiadać odpo-wiednio skonfigurowane środowisko serwera. Przede wszystkim konieczny jest dostęp do usłu-gi katalogowej z serwera www oraz moduł LDAP dla PHP (opcja --with-ldap[=DIR]). Blok, za-wierający ustawienia związane z użytkowni-

kami w pliku settings/site.ini, powinien zostać zmodyfikowany w następujący sposób:

[UserSettings]

LoginHandler[]=standard

LoginHandler[]=LDAP

Kolejnym ważnym krokiem jest dostosowanie konfiguracji związanej bezpośrednio z usługą. Do tego celu wykorzystywany jest plik settings/ldap.ini (Listing 2.).

Ponieważ eZ Publish tworzy duplikaty kont użytkowników, potrzebne jest cykliczne prze-

Page 39: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

38

eZ Publish

www.phpsolmag.org 39

prowadzanie aktualizacji ich ustawień. Do te-go celu wykorzystywany jest moduł zadań cy-klicznych – cron.

Zadania cykliczne można podzielić na sek-cje i wykonywać je w tle, w różnych odstępach czasu.

Synchronizacja kont użytkownikówDo aktualizacji kont użytkowników ba-zy danych eZ Publish, na podstawie za-pisów z LDAP, służy skrypt: cronjobs/

ldapusermanage.php.Oto fragment zawierający najciekawsze czę-

ści kodu obrazuje Listing 3.

Autoryzacja użytkowników w eZ Publish na podstawie kont w LDAPDo autoryzacji użytkowników, których kon-ta zapisane zostały w katalogu LDAP, słu-ży skrypt: /kernel/classes/datatypes/ezuser/ezldapuser.php.

Dedykowany system autoryzacjiPoza wymienionymi wyżej trzema predefi-niowanymi przez producenta metodami au-toryzacji, możliwe jest stworzenie własnego mechanizmu i zintegrowanie go z eZ Publish. Aby stworzyć rozszerzenie dedykowana au-toryzacja należy przygotować skrypt PHP

kernel/classes/datatypes/ezuser/ezdedykowana-autoryzacjauser.php.

Listing 4. przedstawia szablonową konstruk-cję klasy. Nowa klasa dziedziczy po eZUser i wy-maga nadpisania funkcji logowania.

Dla potrzeb konfiguracji rozszerzenia stworzyć można dodatkowy plik z ustawie-niami settings/dedykowanaautoryzacja.ini. Je-go konstrukcja oraz zawartość może być po-dobna do przedstawionej wyżej – przypa-dek konfiguracji bazującej na zawartości pli-ku tekstowego.

Przed rozpoczęciem korzystania z rozsze-rzenia konieczne jest odpowiednie skonfiguro-wanie systemu. W pliku settings/site.ini, należy umieścić wpis:

[UserSettings]

LoginHandler[]=standard

LoginHandler[]=DedykowanaAutoryzacja

PodsumowanieJak widać, możliwości systemu eZ Publish po-zwalają przede wszystkim na wykorzystanie wbudowanych mechanizmów, a dzięki temu na zaoszczędzenie czasu niezbędnego do im-plementacji potrzebnych rozwiązań. System nie jest jednak zamknięty. W sytuacji, gdy po-trzebujemy stworzyć dedykowane rozwiąza-nie, możemy rozszerzyć domyślną funkcjonal-ność systemu.

Przykład metod autoryzacyjnych stosowa-nych w eZ Publish pokazuje wyraźnie, że sys-tem ten dostarcza doskonałe możliwości inte-gracyjne.

Jako system otwarty, może być idealnym kandydatem na łącznika aplikacji w trakcie budowania portalu korporacyjnego. Udostęp-nienie funkcjonalności pojedynczego logowania to tylko jeden z punktów jego wykorzystania. Integracji mogą podlegać również inne mecha-nizmy związane z gromadzeniem i udostęp-nianiem danych.

Zadania cykliczne w eZ PublisheZ Publish udostępnia mechanizm wykony-wania zadań działających systematycznie w tle. Konfiguracja zadań przechowywana jest w pliku settings/cronjobs.ini, a aktywowanie zadań polega na uruchomieniu skryptu run-cronfobs.php przez PHP działające w trybie CLI. Istnieje również możliwość zintegrowa-nia zadań z systemowym mechanizmem crontab. Do tego celu można wykorzystać plik ezpublish.cron.

Rysunek 3. Ekran logowania użytkownika do publicznego serwisu WWW. Dostęp przez adres typu: http://www.domena.com/pl

Rysunek 2. Ekran logowania użytkownika do panelu administracyjnego. Dostęp przez adres typu: http://www.domena.com/administrator

JULIUSZ CAŁYNIUKAutor zajmuje się zarządzaniem projektami w We-bStyle. Od 7 lat związany z oprogramowaniem dla platformy LAMP.Kontakt z autorem: [email protected]

Page 40: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

40

RBAC

www.phpsolmag.org 41

W artykule omówimy pokrótce teo-retyczny model kontroli dostępu, opartej o role w konfrontacji z in-

nymi powszechnie stosowanymi rozwiązania-mi, a następnie zaproponujemy przykładową implementację kontroli dostępu w aplikacji we-bowej, stosującej wzorzec kontrolera strony.

ProblemPrzy tworzeniu praktycznie każdej aplikacji, wy-korzystywanej przez więcej niż jednego użyt-kownika, trzeba zmierzyć się z problemami kon-troli dostępu. Jeden z nich to uwierzytelnianie, a więc weryfikacja tożsamości podmiotu. Drugi to autoryzacja, czyli sprawdzanie, czy dany pod-miot ma dostęp do zasobów, o które prosi.

W aplikacjach webowych uwierzytelnianie odbywa się na ogół poprzez podanie loginu i hasła. Implementacja ekranu logowania, to te-mat opisywany już wielokrotnie, więc na po-trzeby tego tekstu założymy, że mechanizm uwierzytelniania jest już gotowy i skupimy się na bardziej złożonym problemie autoryzacji. Powszechną praktyką, stosowaną przez twór-ców aplikacji webowych (nawet jeśli nie są te-go świadomi), jest zdefiniowanie trzech pod-stawowych poziomów dostępu:

• Anonimowy użytkownik to taki, który nie przeszedł procesu uwierzytelnienia.

Na ogół ma dostęp jedynie do ekranu logo-wania (system intranetowy) lub może ko-rzystać z pewnych podstawowych funkcji (system internetowy);

• Zalogowany użytkownik to taki, który po-myślnie przeszedł proces uwierzytelnie-nia. Konta użytkowników są na ogół two-rzone przez administratora (system intra-netowy) lub ich samych, na przykład po weryfikacji mailowej (system interneto-wy);

• Administrator to specjalny użytkow-nik, który ma pełną kontrolę nad syste-mem. Często (choć nie zawsze) korzysta w tym celu z odrębnego panelu admini-stratora.

Takie rozwiązanie sprawdza się całkiem nieźle w prostych scenariuszach, gdy wszy-scy użytkownicy są równorzędni, a admini-stratorów jest niewielu i mają władzę abso-lutną. To założenie można śmiało przyjąć w przypadku wielu aplikacji internetowych, może stąd wynika jego powszechność. Jed-nak rzadko kiedy, tak prosty model okazu-je się wystarczający dla intranetowych sys-temów o strategicznym znaczeniu, modelu-jących logikę biznesową firmy. W takiej sy-tuacji oczywiste jest, że szef powinien mieć inny poziom dostępu niż szeregowy pracow-nik, ten jeszcze inny niż podwykonawca, a dział techniczny inne uprawnienia niż dział obsługi klienta.

Rozwiązanie, które często stosowane jest w takich sytuacjach, polega na sztywnym okre-śleniu klas użytkowników, a następnie ogra-

niczeniu dostępu do pewnych obszarów czy funkcji jedynie dla wybranych klas, poprzez zapisanie warunków bezpośrednio w kodzie. Na przykład w systemach śledzenia błędów często rozróżniani są zgłaszający (mogący two-rzyć nowe zgłoszenia), programiści (mogący dodatkowo modyfikować stan zgłoszeń) i me-nedżerowie (mogący generować raporty i ze-stawienia).

W przypadku systemu, w którym zadania są jasno zdefiniowane i niezmienne w czasie (jak wspomniany już system śledzenia błędów) ta-kie rozwiązanie może się sprawdzić. Jednak zastosowanie tego podejścia w dużym syste-mie biznesowym, rozwijanym w warunkach ciągle zmieniających się wymagań, częstych reorganizacji i zmian strategii firmy ma licz-ne wady.

Po pierwsze, cała logika kontroli dostępu za-pisywana jest bezpośrednio w kodzie, jej mo-dyfikacja wymaga ingerencji u źródła. Weryfi-kacja, dbanie o jej spójność i bezpieczeństwo jest mocno utrudnione. Co więcej, audyt wy-maga wiedzy programistycznej i znajomości architektury systemu. Logika kontroli dostępu rozrzucona jest w różnych miejscach kodu, co utrudnia tworzenie nowych klas użytkowni-ków czy implementację nowych modułów sys-temu, zwiększa też prawdopodobieństwo po-myłek. W końcu nie ma możliwości wdroże-nia w oparciu o te same źródła kilku instancji systemu, z których każda ma inaczej zdefinio-waną logikę kontroli dostępu. Warto pamiętać także o tym, że każda zmiana w kodzie wyma-ga testów, co więcej, na serwerze produkcyj-nym pojawi się nie od razu, a dopiero po wyda-niu nowej wersji aplikacji.

Jak widać, w takiej sytuacji cała odpowie-dzialność za zarządzanie dostępem spada na programistów, podczas gdy powinna spoczy-

RBAC

Tworząc aplikacje webowe, szczególnie te bardziej skomplikowane, realizujące złożoną logikę biznesową, bardzo często spotykamy się z problemem kontroli dostępu. Każdy system, pracujący na danych o kluczowym znaczeniu, powinien mieć możliwość ograniczania dostępu do nich dla różnych użytkowników.

Dowiesz się...• Zaprezentujemy model RBAC i pokażemy, jak

przy jego użyciu zaprojektować elastyczny i rozszerzalny moduł kontroli dostępu.

Powinieneś wiedzieć...• Wskazana jest znajomość architektury MVC i

wzorca dekoratora;• Podstawowa wiedza z zakresu kontroli dostępu.

Poziom trudności

Kontrola dostępu w aplikacjach webowych

Rysunek 1. Model RBAC

������� ���� ��������������� ���� ���� ����

Page 41: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

40

RBAC

www.phpsolmag.org 41

wać na administratorze systemu, czy osobie odpowiedzialnej za bezpieczeństwo informa-cji w firmie.

Takie rozwiązanie, choć często stosowane, narzuca wiele ograniczeń, które mogą oka-zać się nie do przyjęcia. W dalszej części ar-tykułu zaproponujemy alternatywne rozwią-zanie, dzięki któremu można uniknąć więk-szości powyższych problemów. Opiszemy prosty, a zarazem bardzo elastyczny model RBAC i zaprezentujemy jego przykładową implementację.

Model RBACKontrola dostępu oparta o role (ang. Role-Ba-sed Access Control, w skrócie RBAC), to teo-retyczny model kontroli dostępu, od lat po-wszechnie stosowany w aplikacjach bizneso-wych, będący alternatywą dla tradycyjnych modeli MAC i DAC. Co ciekawe, formalizacji doczekał się dopiero w publikacji z roku 1992 (odnośnik do niej dostępny jest w materiałach do artykułu), gdy był już szeroko stosowany w praktyce.

Podstawowym pojęciem w RBAC jest, jak łatwo się domyślić, rola, opisująca pewną funkcję czy stanowisko w organizacji. Kolej-nym ważnym obiektem są uprawnienia, re-prezentujące operacje udostępniane przez system. Uprawnienia przypisywane są do ról, określając tym samym ich prawa. Z ko-lei podmiotem określa się każdego użytkow-nika aplikacji, a także zewnętrzny system ko-rzystający z jej usług. Podmiot może posia-dać wiele ról, odpowiadających jego pozycji w strukturze organizacji. Zależności pomiędzy poszczególnymi pojęciami modelu RBAC ilu-struje Rysunek 1.

Niezwykle istotną własnością modelu RBAC jest to, że podmiot otrzymuje upraw-nienia wyłącznie poprzez role, które posia-da. Innymi słowy, z punktu widzenia kontroli dostępu, istotne jest jedynie stanowisko użyt-kownika, a nie jego tożsamość. Ta prosta wła-sność sprawia, że struktura uprawnień staje się dużo bardziej przejrzysta i łatwiejsza w ad-ministracji.

Warto zaznaczyć, że uprawnienia powinny opisywać operacje na poziomie logiki bizneso-wej, a nie prawa zapisu lub odczytu, do nisko-poziomowych zasobów (jak pliki czy tabele w bazie danych). Innymi słowy zarówno role, jak i uprawnienia powinny być definiowane w języ-ku konkretnej organizacji, na podstawie wcze-śniejszej analizy.

Na koniec warto wspomnieć o pewnej bar-dzo dobrej praktyce kontroli dostępu, dotyczą-cej nie tylko modelu RBAC. Nazywana jest za-sadą najmniejszych uprawnień (ang. Principle of Least Privilege) i mówi o tym, że użytkownik nie powinien posiadać większych uprawnień, niż to wymagane do wykonywania swoich obo-wiązków. Warto pamiętać o tym przy admini-stracji uprawnieniami i rolami.

Przykład implementacjiOmówiliśmy pokrótce podstawy teoretycz-ne, spróbujmy więc zaimplementować RBAC w przykładowej aplikacji webowej. Wyjdzie-my od analizy przypadków użycia, która uła-twi określenie potrzebnych ról i uprawnień. Następnie, korzystając ze wzorca dekoratora (opisanego m.in. w artykule „Dekorator: wzo-rzec projektowy na każdą bolączkę” z nume-ru 4/2006, dostępnego do ściągnięcia na stro-nie PHP Solutions), zaprojektujemy i zaimple-mentujemy klasy, odpowiadające za kontrolę dostępu w przykładowej architekturze stosują-cej kontroler strony.

Skupimy się na najbardziej interesują-cych z punktu widzenia niniejszego artyku-łu aspektach, nie zajmując się chociażby spo-

sobem dostępu do bazy danych czy przebie-giem procesu logowania. Przykład celowo nie jest związany z żadnym konkretnym frame-workiem (choć opiera się na architekturze stosowanej w wielu z nich), aby pokazać ogól-ność rozwiązania.

Przypadki użyciaRozważmy typowy system obsługi zgłoszeń (ang. trouble tickets), którego głównym zada-niem jest usprawnienie kontaktu z klientami. Po analizie dziedziny mógłby powstać diagram przypadków użycia taki, jak na Rysunku 2. (mocno uproszczony dla celów przykładu). Po-może on nam zdefiniować role i uprawnienia.

Jak wiadomo, role opisują funkcje, jakie w organizacji pełnią użytkownicy (mówiąc bar-

Rysunek 2. Diagram przypadków użycia

������

����������

��������

���������������������

������������������

�������������������

���������������������

������������������

Rysunek 3. Diagram kontrolerów

�������������

����������

������������

�����������������������

������������������

��������������

������������

�����������������������

�����������������

�����������������

���������������

����������������

������������������

������������������

�����������������

�������������������

������������������

Page 42: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

42

dziej ogólnie, podmioty). Jeśli korzystamy z diagramu przypadków użycia, dobrymi kan-dydatami na role są aktorzy (choć nie zawsze musi to być relacja jeden-na-jeden). W opisa-nym przykładzie możemy wyróżnić następu-jące role:

• Klient: osoba korzystająca z systemu, aby zgłosić swój problem i śledzić jego stan;

• Konsultant: pracownik odpowiadający za obsługę zgłoszeń klientów;

• Menedżer: osoba nadzorująca pracę kon-sultantów.

Kolejnym krokiem jest określenie upraw-nień, najmniejszego i niepodzielnego kwantu, umożliwiającego kontrolę dostępu w modelu RBAC. Role zawsze można zmienić, jednak odpowiedni dobór ,,rozdzielczości” upraw-nień, to ważna decyzja projektowa. Od tego zależy, jak łatwe i elastyczne będzie definiowa-nie ról, i jak precyzyjna kontrola dostępu bę-dzie możliwa.

Także w tym przypadku można oprzeć się na przypadkach użycia, często jednak okazu-

je się, że uprawnienia powinny być nieco bar-dziej szczegółowe i niskopoziomowe. Wtedy jeden przypadek użycia można rozbić na kilka uprawnień.

Implementacja kontroli dostępu staje się znacznie łatwiejsza, jeśli uprawnienia mają swoje odpowiedniki w samym systemie. Dla-tego w przykładzie opisanym poniżej zastosu-jemy kontrolę uprawnień w warstwie kontro-lera, a uprawnienia utożsamimy ze zdarzenia-mi kontrolera (a same kontrolery zaprojektuje-my tak, aby ich zdarzenia odpowiadały upraw-nieniom).

KontroleryProjektując architekturę aplikacji webowej, najprawdopodobniej skorzystamy z jakie-goś rodzaju kontrolera, obsługującego żąda-nia HTTP. Jeśli wszystkie żądania przecho-dzą przez kontroler, wybór uprawnień i im-plementacja kontroli dostępu staje się prosta i przejrzysta.

Załóżmy, że stosujemy wzorzec Page Con-troler (choć podobny sposób rozumowania można także zastosować dla Front Control-

lera), a każdy kontroler to osobny plik PHP, obsługujący żądanie dla danego URL. Do-datkowo zakładamy, że kontroler otrzymuje jako parametr żądania nazwę zdarzenia, któ-re ma obsłużyć. Wszystkie kontrolery dzie-dziczą po wspólnej abstrakcyjnej nadklasie i implementują metody onAction(), gdzie ac-tion to nazwa zdarzenia, które obsługuje da-na metoda.

W uproszczonym przykładzie projektowa-nego systemu obsługi zgłoszeń, podstawowy-mi pojęciami są zgłoszenia i raporty, a więc to dla nich utworzymy kontrolery. Projektu-jąc zdarzenia najlepiej wyjść od przypadków użycia, choć często okazuje się, że zdarze-nia powinny być bardziej szczegółowe. Do-brym przykładem są tu tzw. przypadki użycia CRUD (ang. Create, Read, Update, Delete), łą-czące operacje tworzenia obiektu, jego modyfi-kacji i usuwania (a więc trzech osobnych zda-rzeń) w jeden przypadek użycia ,,zarządzanie obiektem”.

Przykładowy diagram kontrolerów dla nasze-go systemu obsługi zgłoszeń znajduje się na Ry-sunku 3.

Rysunek 4. Diagram dekoratorów kontrolera

�������������

����������

������������

�����������������������

������������������

�������������������

������������

�����������������������

������������������

��������������

������������

�����������������������

�����������������������

������������

�������

�����������������������������������������������������������

�������������������

Rysunek 5. Diagram sekwencji kontroli dostępu

����� ������������������������ ��������������� ��������

���

���

������������

���

�������������

������������������������������

������������������������������

����������������������

Page 43: PHP Solutions 04 2007 PL
Page 44: PHP Solutions 04 2007 PL

04/2007

Bezpieczeństwo

44

Jak łatwo się już domyślić, w aplikacji webo-wej o takiej architekturze, dobrym kandydatem na uprawnienie (w rozumieniu modelu RBAC) będzie para $(kontroler, zdarzenie)$. Przema-wia za tym kilka faktów:

• Kontrolę uprawnień możemy przeprowa-dzić na poziomie kontrolera, wtedy staje się ona przezroczysta dla programisty, co

ułatwia pracę, ale także ogranicza możli-we dziury w bezpieczeństwie wynikające z przeoczeń;

• Taki wybór uprawnień sprawia, że me-chanizm kontroli dostępu staje się rozsze-rzalny wraz z rozbudową systemu, a na-rzut związany z jego utrzymaniem i ak-tualizacją jest minimalny (nowe upraw-nienia mogą być nawet rozpoznawane

automatycznie, za pomocą refleksji klas kontrolerów);

• Równoważność uprawnień i zdarzeń kontrolera ułatwia komunikację w ze-spole, nie ma potrzeby tworzenia i doku-mentowania nowego pojęcia. Sprawę do-datkowo ułatwia fakt, że oba pochodzą od przypadków użycia, a te bezpośred-nio powiązane są z aktorami (a więc i ro-lami).

Tabela 1. zawiera podsumowanie przypad-ków użycia, odpowiadających im zdarzeń i uprawnień w projektowanym przez nas sys-temie.

W dalszej części artykułu zaproponujemy implementację przezroczystej dla kontrolera kontroli dostępu, przy założeniu, że uprawnie-niami są zdarzenia kontrolera.

Dekorowanie kontroleraSkoro uprawnienia są jednoznaczne z prawami dostępu do zdarzeń kontrolera, a każde żądanie musi przejść przez kontroler, dobrym miejscem na implementację kontroli dostępu jest właśnie klasa kontrolera.

Oczywiście można zapisać odpowiednie warunki w kodzie nadklasy, po której dzie-dziczą kontrolery (albo utworzyć klasę po niej dziedziczącą), jednak nie jest to zbyt eleganckie rozwiązanie. Obsługa żądań i kontrola dostępu to dwa różne zadania, któ-re nie powinny być łączone. W takich sytu-acjach dobrym pomysłem jest skorzystanie z wzorca dekoratora, który pozwala na dyna-miczne zwiększanie zakresu odpowiedzial-ności obiektu.

Rysunek 4. zawiera zmodyfikowany schemat klas kontrolerów, rozbudowany o abstrakcyjny dekorator i dziedziczący po nim dekorator prze-prowadzający kontrolę uprawnień.

Na Listingu 1. znajduje się kod dekorato-ra, realizującego interfejs kontrolera, który w konstruktorze otrzymuje obiekt do udekoro-wania i przekierowuje do niego wszystkie me-tody interfejsu.

Warto zauważyć, że klasa jest zdefiniowana jako abstrakcyjna mimo, że nie posiada żad-nych abstrakcyjnych metod. Po prostu two-rzenie obiektów tej klasy nie ma żadnego sen-su, istnieje tylko po to, aby konkretne dekora-tory dziedziczące po niej, nie musiały za każ-dym razem implementować mechanizmu de-koracji.

Na Listingu 2. znajduje się kod dekoratora przeprowadzającego kontrolę dostępu przed przekazaniem sterowania do metody realizu-jącej zdarzenie. Zakładamy, że w konstruk-torze został przekazany profil opisujący ak-tualnie zalogowanego użytkownika. Meto-da hasPermission() profilu sprawdza (prze-glądając wszystkie role), czy użytkownik ma uprawnienia do danego kontrolera i zdarze-nia. Jeśli nie, dekorator wyrzuca wyjątek i nie

Listing 1. Dekorator kontrolera

abstract class ControllerDecorator implements Controller

{

protected $decoratedController;

function __construct(Controller $decoratedController)

{

$this->decoratedController = $decoratedController;

}

function getEventName()

{

return $this->decoratedController->getEventName();

}

function getName()

{

return $this->decoratedController->getName();

}

function run()

{

return $this->decoratedController->run();

}

}

Listing 2. Dekorator kontroli dostępu

class ControllerRbacDecorator extends ControllerDecorator

{

private $profile;

public function __construct(Controller $decoratedController, Profile $profile)

{

$this->profile = $profile;

parent::__construct($decoratedController);

}

function run()

{

if (!$this->profile->hasPermission($this->getName(), $this->getEventName())) {

throw new Exception("Brak uprawnień");

}

return $this->decoratedController->run();

}

}

Page 45: PHP Solutions 04 2007 PL

RBAC

www.phpsolmag.org 45

przekazuje sterowania do dekorowanego kon-trolera. Utworzenie i wywołanie udekorowa-nego kontrolera przebiega w następujący spo-sób (zakładając, że mamy referencję do profi-lu użytkownika):

$controller = new ControllerRbacDe

corator(new

TicketsController(),

$profile);

try {

$controller->run();

} catch (Exception $e) {

echo "Błąd: ". $e->getMessage();

}

Nie są wymagane żadne zmiany w samych kla-sach kontrolera, za kontrolę dostępu odpowia-da tylko dekorator.

Jak to działaNa koniec warto przeanalizować diagram se-kwencji przedstawiony na Rysunku 5., przed-stawiający dynamiczny obraz procesu kontro-li dostępu.

Przeglądarka użytkownika wysyła żądanie HTTP, które serwer kieruje do odpowiednie-go kontrolera, wywoływana jest jego metoda run(). Kontroler został udekorowany, więc dekorator najpierw pobiera nazwę dekoro-wanego kontrolera oraz zdarzenia, które zo-stało wywołane przez użytkownika. Następ-nie profil proszony jest o sprawdzenie, czy aktualnie zalogowany użytkownik ma upraw-nienia do danego kontrolera i zdarzenia (i czy jest w ogóle zalogowany). To, jak działa i kie-dy tworzony jest profil, nie wchodzi w zakres niniejszego artykułu. Warto jednak wspo-mnieć, że profil powinien obsługiwać logowa-nie, wylogowanie i przechowywanie informa-cji o użytkowniku w sesji, a także powinien przekierowywać niezalogowanego użytkow-nika do kontrolera logowania (który oczywi-ście nie może być dekorowany kontrolą dostę-pu). Profil, sprawdzając uprawnienia, powi-nien opierać się na liście ról bieżącego użyt-kownika. Jeśli posiada on dane uprawnienie, kontrola przekazywana jest do udekorowane-go kontrolera, który z kolei wywołuje metodę obsługującą dane zdarzenie. Jeśli nie, wyrzu-cany jest wyjątek, który oczywiście powinien zostać odpowiednio obsłużony.

Jak widać dzięki założeniu, że wszystkie żąda-nia muszą przejść przez kontroler i dzięki użyciu

wzorca dekoratora, udało się w prosty sposób za-implementować przezroczysty dla programisty i rozszerzalny moduł kontroli dostępu.

Dzięki zastosowaniu modelu RBAC logi-ka kontroli dostępu nie jest zapisana bezpo-średnio w kodzie, a w dynamicznych zależno-ściach między podmiotami, rolami i upraw-nieniami. Dzięki temu cała struktura jest bar-dzo przejrzysta, łatwa w administracji i mo-że być modyfikowana przez osoby nie będące programistami. Co więcej, polityka bezpie-czeństwa może różnić się między kilkoma in-stalacjami systemu.

Możliwe ulepszeniaZaprezentowany powyżej szkic implementa-cji nie jest jedynym możliwym, można go roz-winąć i ulepszyć na wiele sposobów, oto kil-ka z nich:

• Przydatny będzie panel administracyjny, po-zwalający na zarządzanie rolami, przypisy-wanie uprawnień do ról i ról do użytkowni-ków. Oczywiście dostęp do takiego modu-łu także można, i należy chronić za pomocą opisanego mechanizmu kontroli dostępu;

• Główną wadą kontroli dostępu na pozio-mie kontrolera jest to, że jest ściśle zwią-zana z żądaniami HTTP i warstwą kon-trolera. Jeśli system posiada bogaty mo-del domeny, wykorzystywany przez wię-cej niż jedną aplikację, warto rozważyć kontrolę dostępu w warstwie domeny. W takiej sytuacji teoretyczne podstawy po-zostają bez zmian, ale zmienia się znacze-nie uprawnień i implementacja kontroli dostępu;

• Można zmodyfikować szablony tak, aby deaktywować czy nawet usuwać odnośni-ki do operacji, do których bieżący użyt-kownik nie ma dostępu;

• Łatwo napisać skrypt, który automa-tycznie zaktualizuje tabelę uprawnień na podstawie analizy kodu kontrole-rów. Dzięki temu nie trzeba pamiętać o uzupełnianiu tabeli uprawnień w bazie wraz z rozwojem systemu. Taki skrypt może po prostu szukać w plikach źró-dłowych wzorców, odpowiadających me-todom kontrolera (np. przy użyciu wyra-żeń regularnych), albo wykorzystać me-chanizm refleksji. Na podstawie zebra-nych danych można synchronizować ta-belę uprawnień.

W bardziej skomplikowanych projektach można rozważyć zastosowanie bardziej za-awansowanych aspektów modelu RBAC:

• Nietrudno dodać, bardzo przydatny w praktyce, mechanizm dziedzicze-nia uprawnień. Dzięki temu menedżer będzie mógł dziedziczyć z roli konsul-tanta, przejmując wszystkie uprawnie-nia roli dziedziczonej i uzupełniając je o uprawnienia specyficzne dla roli dzie-dziczącej (podobnie do mechanizmu dziedziczenia w programowaniu obiek-towym);

• Założyliśmy, że użytkownik po zalogo-waniu może korzystać ze wszystkich swoich ról i związanych z nimi upraw-nień. Alternatywnym i bardziej zgod-nym z modelem RBAC rozwiązaniem jest wymuszenie wyboru jednej z do-stępnych ról w momencie logowania. Wtedy powstaje sesja, łącząca użytkow-nika z aktywną rolą (nie mylić z mecha-nizmem sesji PHP);

• Można zaimplementować politykę se-paracji obowiązków (ang. Separation of Duties), mającą na celu ograniczenie za-grożeń wynikających z łączenia kilku ról przez jednego pracownika. Ta zasa-da mówi, że dla pewnego zbioru operacji (np. zlecenia przelewu i akceptacji prze-lewu) nie może istnieć osoba, która ma uprawnienia do wszystkich z nich.

Zachęcamy Czytelników do dalszych ekspery-mentów i dzielenia się swoimi pomysłami.

PodsumowanieStosując sprawdzony model kontroli dostępu opartej o role, udało nam się w łatwy sposób za-projektować prosty, elegancki i elastyczny me-chanizm kontroli dostępu. Uniknęliśmy za-szywania kontroli dostępu bezpośrednio w ko-dzie, pozwalając na dynamiczne przydzielanie uprawnień do ról, a zarazem ułatwiając admini-strację uprawnieniami.

W Sieci

• David Ferraiolo, Richard Kuhn. Role-Based Access Control, http://csrc.nist.gov/rbac/Role_Based_Access_Control-1992.html;

• Wikipedia: Role-Based Access Control, http://en.wikipedia.org/wiki/Role-Ba-sed_Access_Control.

ADAM BYRTEKAutor odpowiada za zespół programistyczny, zajmujący się rozwojem wewnętrznego systemu OSS/BSS dla ogólnopolskiego dostawcy internetu.Kontakt z autorem: [email protected]://adambyrtek.blogspot.com/

Tabela 1. Związek przypadków użycia, metod kontrolera i uprawnień

Przypadek użycia Metoda kontrolera Uprawnienie

Utworzenie zgłoszenia TicketsController::onCreate() (tickets, create)

Podgląd zgłoszenia TicketsController::onView() (tickets, view)

Zamknięcie zgłoszenia TicketsController::onClose() (tickets, close)

Dodanie komentarza TicketsController::onComment() (tickets, comment)

Generowanie raportu ReportsController::onGenerate() (reports, generate)

Page 46: PHP Solutions 04 2007 PL

Kwiecień 2007

Narzędzia

46

Celem developerów Agavi było i jest two-rzenie frameworka uniwersalnego, któ-ry nie ogranicza programisty poprzez

narzucenie mu mechanizmów, z których musi korzystać, nie ma zatem mechanizmów typu ORM, czy też scaffolding. Technologia obsługu-jąca widok jest dowolna (do wyboru php, xslt, smarty, phptal) podobnie jak sposób dostępu do bazy danych (m.in. pdo, adodb, creole). W wy-borze narzędzi mamy wolną rękę. Jeśli przy-zwyczaiłeś się do którejkolwiek z tych biblio-tek, nie musisz z niej rezygnować, framework wspiera ich obsługę.

Instalacja AgaviNajszybszym sposobem na instalację Agavi jest użycie kanału PEAR. Sposób ten wymaga wcze-śniejszego skonfigurowania PHP i instalacji pa-kietu PEAR.

pear config-set auto_discover 1

pear install --alldeps channel://

pear.agavi.org/agavi

Instalacja z opcją alldeps spowoduje zainstalo-wanie wszystkich, nawet opcjonalnych pakie-tów, tj. Propel, Creole.

Wyżej opisany sposób jest przewidziany dla stanowisk deweloperskich. Na serwerze napisa-na przez nas aplikacja wymaga tylko odpowied-

niego ustawienia dyrektywy include_path, tak by wskazywało na agavi i ewentualnie użyte przez nas biblioteki.

Tworzymy projektStworzenia akcji w Agavi wiąże się ze stworze-niem projektu. Po instalacji przez PEAR (patrz ramka Instalacja) mamy do dyspozycji polece-nie agavi, które umożliwia tworzenie modułów, akcji oraz widoków na podstawie predefiniowa-nych szablonów kodu, które można zmienić (folder agavi/buildtools/code_templates). Jest ono o tyle użyteczne, że zwalnia nas z ko-nieczności ręcznego kopiowania plików i zmie-niania nazw klas.

Aby stworzyć strukturę katalogów na potrze-by artykułu, wpisujemy w konsoli agavi project. Instalator zapyta nas o położenie projektu i po-

prosi o nazwy dla akcji systemowych tj. akcja lo-gowania, akcja do obsługi błędów 404, przykła-dowa akcja wymagająca autoryzacji, strona po-kazywana w przypadku, gdy wyłączymy mo-duł.

Strukturę katalogów nowostworzonego pro-jektu można zobaczyć na Rysunku 1.

Pierwsza akcjaZgodnie z paradygmatem MVC Agavi dzie-li aplikację na niezależne od siebie warstwy. Warstwę logiki biznesowej, którą reprezentu-ją kontrolery obiektów biznesowych, reprezen-towanych przez modele oraz warstwę logiki wi-doku.

Każda akcja w Agavi musi być przyporządko-wana do określonego modułu (jakiejś wydzielo-nej, logicznie spójnej części aplikacji) i rozsze-rzać klasę abstrakcyjną – AgaviAction.

Stwórzmy swoją pierwszą akcję, która bę-dzie wyświetlać formularz i dane wprowadzo-ne przy jego pomocy.

Poleceniem agavi module tworzymy nowy moduł o nazwie Welcome. Zostaniemy zapyta-ni również o akcje, jakie powinny zostać stwo-rzone. Pozostawiamy domyślną – Index. Po-

Agavi

Do tej pory w dużej mierze czytelnicy tego czasopisma byli zapoznawani z dziedziną problemu po to, by móc budować własne rozwiązania. Ten artykuł jest inny. Nie skupia się na istocie frameworków oraz szczegółach implementacji poszczególnych mechanizmów, ponieważ ma on pokazać możliwości frameworka Agavi.

Dowiesz się...l Po zapoznaniu się z tekstem czytelnik będzie w

stanie budować szybciej, prościej oraz wydaj-niej aplikacje internetowe w oparciu o frame-work Agavi.

Powinieneś wiedzieć...l Wymagana jest podstawowa znajomość PHP

oraz umysł otwarty na gotowe rozwiązania.

Poziom trudności

Pierwsze kroki

Listing 1. Pierwsza akcja do obsługi formularza

<?php

// Schemat nazwy akcji:

NazwaModułu_NazwaAkcjiAction

class Welcome_IndexAction extends ProjectBaseAction {

// obsługa żądania POST

public function executeWrite(

AgaviRequestDataHolder $rd) { return 'Success'; }

// obsługa żądania GET

public function getDefaultViewName() { return 'Input'; }

}

?>

Page 47: PHP Solutions 04 2007 PL

trzebne widoki, o które zapyta Agavi to Input oraz Success.

Otwieramy plik app/modules/Welcome/actions/IndexAction.class.php w celu zmiany wy-generowanej akcji. Domyślnie zawiera ona tyl-ko jedną metodę – getDefaultViewName(). Zmieniamy zwracaną wartość z 'Success' na 'In-put' oraz dodajemy metodę executeWrite z atrybutem AgaviRequestDataHolder zwraca-jącą 'Success'. Kod po wprowadzeniu modyfi-kacji powinien wyglądać tak, jak na Listingu 1. Warto zwrócić uwagę, że akcja rozszerza kla-sę ProjectBaseAction a nie AgaviAction. Ak-cja podstawowa dla projektu jest tworzona, by umieszczać w niej często powtarzające się ope-racje.

W chwili, gdy Agavi uruchamia akcję spraw-dza ją pod kątem zadeklarowanych metod. Metoda getDefaultViewName zwraca nazwę widoku, który będzie uruchomiony w przypad-ku żądania mającego na celu tylko odczyt da-nych np. HTTP GET. W metodzie tej nie po-winna znajdować się żadna logika. Gdy typ uru-chamianego widoku jest uzależniony od jakiejś zmiennej wskazana jest implementacja metody executeRead(AgaviRequestDataHolder), jak-kolwiek nie jest to miejsce, w którym powin-na znaleźć się logika biznesowa, ponieważ w tym celu jest zazwyczaj implementowana me-toda executeWrite(AgaviRequestDataHolder). Zachowanie kodu z Listingu 1. można stre-ścić zdaniem: w chwili, gdy otrzymasz żądanie POST uruchom widok Success, w przeciwnym wypadku uruchom widok Input.

Teraz przechodzimy do implementacji wido-ków. Klasy wygenerowane przez Agavi pozosta-wiamy bez zmian. Zmienimy tylko szablony.

Szablon dla widoku Input będzie zawierał po-le tekstowe i formularz – Listing 2. Po jego wy-

Rysunek 1. Struktura katalogów nowego projektu

Rysunek 2. Działająca akcja

R E K L A M A

Page 48: PHP Solutions 04 2007 PL

Kwiecień 2007

Narzędzia

48

słaniu pokażemy użytkownikowi stronę, na której wykorzystamy przesłaną wartość – Li-sting 3.

W szablonach pojawiają się zmienne, których w żaden sposób nie deklarowaliśmy w widoku. Są to obiekty zdefiniowane w konfiguracji me-chanizmu typów wyjściowych (ang. output ty-pes). Omówimy je w dalszej części artykułu. W tej chwili istotne są dwie, zdefiniowane domyśl-nej konfiguracji zmienne – rd, czyli obiekt klasy AgaviRequestDataHolder oraz ro – obiekt kla-sy AgaviRouting. Pierwszy jest pochodną kla-sy AgaviAttributeHolder i zawiera wszyst-kie dane wejściowe, z jakimi została urucho-miona akcja, natomiast drugi to element odpo-wiedzialny za mapowanie oraz generowanie ad-resów URL. Mechanizm routingu (ang. routes) jest jednym z bardziej istotnych w Agavi. Jest on odpowiedzialny za mapowanie adresów URL do akcji. Definicję wszystkich mapowań apli-kacji znajdziemy w pliku app/config/routes.xml. Warto zapamiętać, że kolejność definiowania poszczególnych mapowań ma znaczenie. I tak, pusty wzorzec dla mapowania zdefiniowanego na początku zawsze będzie pasował, do każdego adresu. Agavi przy tworzeniu nowego projektu domyślnie tworzy mapowanie, które przechwy-tuje wszystkie żądania, by wyświetlić stronę po-witalną. Usuwamy zatem pierwsze mapowanie i dodajemy na końcu własne, kierujące z adresu index.php/Welcome/Index (serwer http musi wi-dzieć katalog pub aplikacji) do dopiero co stwo-rzonej akcji. Jeśli chcemy używać danego mapo-wania do generowania adresu musimy określić wartość dla atrybutu name.

Konfiguracja po zmianach powinna wyglą-dać tak jak na Listingu 4. Po dokonaniu tych modyfikacji jesteśmy gotowi, by uruchomić akcję. Wpisujemy zatem w adresie przeglądar-ki adres, pod którym stworzyliśmy aplikację (miejsce, gdzie jest dostępny katalog pub aplika-cji) i dodajemy w adresie, po pliku wzorzec zde-finiowany w mapowaniu – /Welcome/Index.

Walidacja danychNieodłącznym elementem każdej aplikacji, nie tylko webowej, jest weryfikacja poprawności i spójności otrzymywanych danych. Walidacja poprawności obejmuje format i zakresy wpro-wadzonych wartości podczas, gdy walidacja pod kątem spójności wiąże się zwykle ze spraw-dzaniem, czy wprowadzone wartości są repre-zentowane w bazie danych. Agavi potrafi znacz-nie ułatwić pierwszy z tych procesów dostar-czając komplet klas i odpowiedni mechanizm do ich obsługi.

Definicja walidacji jest unikalna dla każdej akcji jakkolwiek jest możliwość elastycznego łączenia walidacji poprzez doczytywanie ko-lejnych plików (zresztą to się tyczy całej kon-figuracji Agavi) przy pomocy Xinclude. Wali-dację dla każdej akcji definiujemy przy pomo-cy XML-a w pliku validate/nazwa-akcji.xml. Na Listingu 5. znajduje się konfiguracja dla ak-

Listing 2. Szablon widoku WelcomeInput

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

</head>

<body>

<h1>Podaj imię</h1>

<form action="<?php echo $ro->gen('welcome'); ?>" method="post">

<label for="fe-name">Imię</label>

<input type="text" name="name" id="fe-name" />

<input type="submit" />

</form>

</body>

</html>

Listing 3. Szablon widoku WelcomeSuccess

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

</head>

<body>

<h1>Witaj <?php echo $rd->getParameter('name'); ?>!</h1>

</body>

</html>

Listing 4. Konfiguracja mechanizmu mapowania adresów

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<configurations>

<configuration>

<routes>

<route pattern="^/$" module="%actions.default_module%"

action="%actions.default_action%" />

<route pattern="^/Welcome/Index$" module="Welcome" action="Index"

name="welcome" />

</routes>

</configuration>

</configurations>

Obiekty predefiniowane, dostępne w szablonachAgavi daje możliwość określenia w konfiguracji typów wyjściowych (ang. output types) predefinio-wanych zmiennych.

• routing – instancja klasy AgaviRouting – elementu odpowiedzialnego za tworzenie i zarzą-dzanie adresami URL.

• request – instancja klasy pochodnej AgaviRequest – dostarcza informacji o obecnym żąda-niu np. w przypadku HTTP metodę dostępu, adres etc.

• user – instancja klasy AgaviUser – dostęp do zmiennych zapisanych w sesji• translation_manager – instancja klasy AgaviTranslationManager – zarządzanie tłumacze-

niami komunikatów, formatowaniem dat oraz liczb• request_data – wszystkie dane wejściowe jakie otrzymało Agavi• validation_manager – instancja klasy AgaviValidationManager – dostęp do błędów wali-

dacji.

Page 49: PHP Solutions 04 2007 PL
Page 50: PHP Solutions 04 2007 PL

Kwiecień 2007

Narzędzia

50

global_filters oraz dodajemy styl CSS w szablo-nie widoku WelcomeInput z Listingu 7.

Filtr, który włączyliśmy przed chwilą jest od-powiedzialny za integrowanie walidacji oraz wi-doku. Jest on wykonywany dopiero po wygene-rowaniu odpowiedzi i operuje na kodzie, tuż przed jego wysłaniem do przeglądarki. Stąd ma dostęp do wszystkich powstałych błędów i mo-że z powodzeniem wypełniać ponownie dany-mi formularz oraz wyróżniać te pola, których walidacja się nie powiodła. Domyślnie FPF do-daje do tych pól klasę error, tyczy się to rów-nież etykiet tekstowych (ang. labels) wskazują-cych na dane pole.

Po ponownym wprowadzeniu danych na-szym oczom ukaże się pokolorowane pole oraz czerwona etykieta tekstowa tak jak na Rysunku 3. Niestety w wersji Agavi 0.11 FPF nie wstawia komunikatów błędów obok etykiet tekstowych. Taką możliwość będzie dawał dopiero w wersji 1.0. Obsługę błędów bez dodatkowego kodu można zrealizować przy pomocy rozszerzonej implementacji FPF dostępnej do pobrania wraz z listingami do artykułu.

Klasy widokówWażnym elementem, który pozwala nam na bardzo dokładną separację kodu są klasy wido-ków. Do tej pory nie definiowaliśmy żadnych klas widoku – zrobiło to za nas Agavi. W kla-sie widoku powinna znaleźć się logika i opera-cje związane z prezentacją treści tj. pobranie ja-kiegoś rekordu z bazy danych, dorzucenie ja-kiejś dodatkowej zmiennej, która nie pochodzi od użytkownika.

Na Listingu 8. znajduje się klasa podobna do tej, którą wygenerował framework. Podobnie jak akcja, tak i klasa widoku musi rozszerzać odpo-wiednią klasę – w tym przypadku AgaviView. Metoda setupHtml jest zdefiniowana w wido-

Listing 5. Walidowanie danych dla akcji Index

<?xml version="1.0" encoding=" UTF-8" standalone="no"?>

<configurations>

<configuration>

<validators method="write">

<validator class="regex" name="name">

<!-- zmienne, które obejmuje walidacja -->

<arguments><argument>name</argument></arguments>

<!-- komunikaty błędów -->

<errors><error>Zły format danych</error></errors>

<!-- konfiguracja walidatora -->

<parameters><parameter name="pattern">/\w{2,7}/</parameter></parameters>

</validator>

</validators>

</configuration>

</configurations>

Listing 6. Metoda wykonywana w chwili niepowodzenia walidacji

//obsługa błędów w przypadku żądania POST

public function handleWriteError (AgaviRequestDataHolder $rd)

{

return 'Input';

}

Listing 7. Styl CSS do obsługi błędów walidacji

.error { color: maroon; }

input.error { background-color: #ffe0e0; }

Listing 8. Klasa widoku IndexInput

<?php

// Schemat nazwy akcji: NazwaModułu_NazwaAkcjiView

class Welcome_IndexInputView extends ProjectBaseView {

// Nazwa metody: executeNazwaTypuWynikowego

public function executeHtml(AgaviRequestDataHolder $rd) {

$this->setupHtml($rd);

// ustawienie zmiennej _title dostępnej z poziomu szablonu

$this->setAttribute('_title', 'Index Action');

}

}

?>

Listing 9. Najprostsza akcja logowania

<?php

class Default_LoginAction extends AgaviAction {

public function execute(AgaviRequestDataHolder $rd) {

$user = $this->getContext()->getUser();

$user->setAuthenticated(true);

return array('Welcome', 'IndexInput', $rd);

}

}

?>

Listing 10. Dokument XML z definicjami uprawnień

<?xml version="1.0"

encoding="UTF-8"

standalone="yes"?>

<configurations>

<configuration>

<roles>

<role name="member">

<permissions>

<permission>

welcome.index

</permission>

</permissions>

</role>

</roles>

</configuration>

</configurations>

cji Index. Sprawdzamy w niej, czy podane imię (zmienna name) jest w prawidłowym formacie przy użyciu wyrażeń regularnych.

W chwili, gdy proces walidacji wygeneru-je błędy Agavi domyślnie będzie usiłowywało uruchomić widok Error dla danej akcji. Można zmienić to zachowanie dodając do akcji metodę handleWriteError(AgaviRequestDataHolder

), która powinna zwracać nazwę widoku obsłu-gującego błąd. W naszym wypadku akcja ta bę-

dzie wyglądać tak, jak na Listingu 6. Po urucho-mieniu akcji i wprowadzeniu nieprawidłowych danych zobaczymy ponownie stronę z formula-rzem. Tu nasuwa się pytanie, co trzeba zrobić, by dorzucić do widoku WelcomeInput obsługę błędów? Tak naprawdę, niewiele. Po pierwsze włączamy FormPopulationFilter (w skrócie FPF) poprzez zmianę atrybutu enabled na true przy jego definicji (fragment filter name="

FormPopulationFilter") w pliku app/config/

Page 51: PHP Solutions 04 2007 PL
Page 52: PHP Solutions 04 2007 PL

Kwiecień 2007

Narzędzia

52

ku podstawowym projektu. Jeden widok może zawierać wiele metod execute* w zależności od formatów, jakie obsługuje dana akcja.

W szablonie mamy dostęp do zmien-nych, które ustawiliśmy w klasie widoku, za pośrednictwem tablicy $template (np. $template['zmienna']).

Obsługa sesji i autoryzacjaW Agavi sesja użytkownika jest reprezentowana przez instancję klasy AgaviUser, jest to pochod-na klasy AgaviAttributeHolder. Wszystkie atrybuty, które zostaną ustawione w tym obiek-cie będą dostępne w kolejnych akcjach.

Jednym z mechanizmów, które potrafią za-oszczędzić sporo czasu jest obsługa uwierzy-telniania i autoryzacji użytkowników. Obsługa pierwszej z usług jest włączona domyślnie. Jeśli któraś z naszych akcji wymaga uwierzytelnia-nia musimy nadpisać w niej metodę isSecure. Informuje ona framework, że zanim uruchomi akcję musi sprawdzić, czy użytkownik jest za-logowany, w przeciwnym wypadku zostanie on przekierowany do strony logowania. Gdy Agavi ignoruje metodę isSecure należy w pliku app/config/settings.xml znaleźć ustawienie use_se-curity i zmienić wartość na true, jeśli wartość jest inna.

Aby ocenić w pełni sprawność działania me-chanizmu musimy zaimplementować akcję lo-gowania, która odpowiednio zmodyfikuje in-stancję klasy AgaviSecurityUser. Przykłado-wa akcja znajduje się na Listingu 9. Nie zawie-ra ona jakichkolwiek operacji związanych z ba-zą danych, a tylko ustawia odpowiednią flagę, która powoduje, że Agavi dopuszcza użytkow-nika do uruchomienia akcji.

Jeśli tworzymy większą aplikację z biegiem czasu powstają grupy użytkowników, które mają różne uprawnienia, np w sklepie księgo-wy nie może dodawać produktów, sprzedawca nie może przeglądać statystyk sprzedaży i tak dalej. Każda grupa ma dostęp do określonych akcji. W Agavi możemy zrealizować to w bar-dzo prosty sposób. Po pierwsze – mówimy frameworkowi, by zaczął obsługiwać grupy użytkowników. Robimy to przez wyedytowa-nie pliku app/config/factories.xml, w znaczni-ku user zmieniamy wartość atrybutu class na AgaviRbacSecurityUser. Następnie w akcji nadpisujemy metodę getCredentials, tak by zwracała tablicę z listą uprawnień, które mu-si posiadać użytkownik by framework odpalił akcję. Po wykonaniu tej czynności tworzymy plik rbac_definitions.xml w folderze app/config z zawartością z Listingu 10. Następnie mo-dyfikujemy akcję logowania, tak by nadawała zalogowanemu użytkownikowi odpowiednie uprawnienie. Robimy to przez wykonanie me-tody grantRole na obiekcie AgaviUser.

Listing 11. Kompletny kod naszej akcji

<?php

// Schemat nazwy akcji: NazwaModułu_NazwaAkcjiAction

class Welcome_IndexAction extends ProjectBaseAction

{

// obsługa żądania POST

public function executeWrite(AgaviRequestDataHolder $rd)

{

return 'Success';

}

// obsługa żądania GET

public function getDefaultViewName() {

return 'Input';

}

// obsługa błędów w przypadku żądania POST

public function handleWriteError(AgaviRequestDataHolder $rd)

{

return 'Input';

}

// wymagamy autoryzacji

public function isSecure() {

return true;

}

// lista wymaganych uprawnień

public function getCredentials() {

return array('welcome.index');

}

}

?>

W Sieci:

• http://agavi.org/ - oficjalna strona projektu Agavi• http://wact.sourceforge.net/ - witryna jednego ze starszych frameworków dla PHP• http://cakephp.org/ - framework wzorowany na Ruby on Rails• http://symfony-project.com/ - framework wzorowany na Ruby on Rails, oparty na zmodyfiko-

wanym szkelecie Mojavi• http://framework.zend.com/ - framework tworzony przez firmę Zend• http://code-house.net/ - polskojęzyczna strona poświęcona między innymi Agavi

Rysunek 3. Walidatory oraz Form Population Filter w działaniu

ŁUKASZ DYWICKIKontakt z autorem: [email protected]

Page 53: PHP Solutions 04 2007 PL

Strona poświęcona językowi PHP. Skierowa-na głównie do webmasterów i twórców opro-gramowania.

www.strefaphp.net

Strona, na której znajdziesz profesjonalne sza-blony stron www. Ponadto prezentuje tutoriale, artykuły i porady dla webmasterów.

www.d4u.pl

Strona jest polską bazą tutoriali, zawierającą różnorodne teksty o tematyce informatycznej.

www.webtutorials.pl

Strona poświęcona językowi php. Można tu znaleźć m.in. artykuły oraz dział “download” oraz wypowiedzieć się na forum.

www.php.org.pl

Portal w całości poświęcony językowi PHP. Można tu znaleźć m.in. recenzje, artykuły oraz newsy poświęcone temu zagdnieniu.

www.php.pl

Strona zajmująca się różnymi zagadnieniami z działu IT. Prezentuje m.in. newsy, artykuły oraz pliki do ściągnięcia i forum.

www.huntersq2.boo.pl

Misją serwisu jest dostarczanie rzetelnych in-formacji z zakresu szeroko pojętej informatyki. Strona zawiera newsy m.in. z działów: progra-mowania, bezpieczeństwa oraz Internetu.

www.itnews.icx.pl

Główna strona firmy gdaq.pl multimedia zajmu-jącej się kreowaniem wizerunku firm poprzez projektowanie stron, hosting, e-marketing etc.

www.gdaq.pl

Strona zawierająca skrypty, newsy i artykuły dotyczące aplikacji CMS oraz forum poświęco-ne temu zagadnieniu.

www.trycms.org

Główna strona studentów Politechniki War-szawskiej.

www.polibuda.info

Serwis dla początkujących, jak i zaawansowa-nych webmasterów. Zawiera gotowe szablony stron oraz posegregowane skrypty PHP i Ja-vaScript.

www.szablonypro.com

To serwis branży IT, oferujący m.in. newsy, ar-tykuły, recenzje książek i magazynów oraz fo-rum. Strona obejmuje również patronat nad projektami IT.

www.webhat.pl

Page 54: PHP Solutions 04 2007 PL

04/2007

Narzędzia

54

Zaprojektuj i zbuduj swój własny dokument PDF

www.phpsolmag.org 55

Otóż PDF (ang. Portable Document For-mat) jest formatem plików, służą-cym do prezentacji danych teksto-

wych oraz graficznych, z zachowaniem wyso-kiej jakości i małego rozmiaru. Takie specjal-ne pliki można drukować, edytować (nie za-wsze), a co najważniejsze można je samemu bu-dować. Do odczytu plików PDF służą specjalne programy, które potrafią w odpowiedni sposób zaprezentować to, co w pliku zostało umiesz-czone. Najpopularniejszym czytnikiem plików PDF jest Adobe Acrobat Reader. Jest to darmo-wy program stworzony przez twórców PDF. Ist-nieje również wiele innych darmowych narzę-dzi do odczytu tychże plików, jednak Acrobat Reader, moim zdaniem, jest najlepszy. Tyle sło-wem wstępu o samym formacie.

To, co tygryski lubią najbardziejPrzejdźmy zatem do sedna problemu jakim jest tworzenie plików PDF. Firma Adobe Systems udostępnia odpłatnie narzędzia do tworzenia plików PDF. Ale kogo będzie interesował zakup programu, jeśli chce tylko użyć go raz?

W sieci znajduje się wiele programów darmo-wych, wyspecjalizowanych w tego typu zada-niach. Problematyczna jest natomiast ich funk-cjonalność. Innym sposobem generowania pli-ków PDF jest ich tworzenie z poziomu któregoś z języków programowania. Tutaj również ma-

my pewne pole do manewru w kwestii wyboru wyspecjalizowanej biblioteki dla danego języka, którym się aktualnie posługujemy.

Nas jednak interesuje, w tym przypadku, tyl-ko jeden język oraz tylko jedna biblioteka.

PHP + FPDFFPDF jest biblioteką, a konkretniej klasą PHP, która umożliwia generowanie dokumentów w formacie PDF. Literka F na początku nazwy oznacza, że jest ona darmowa (ang. Free) i może-my jej używać do swoich celów oraz modyfiko-wać w miarę potrzeb.

Klasa oferuje między innymi takie możliwo-ści jak:

• ustawienie sposobu formatowania strony (jej układ);

• nagłówki stron oraz stopki;• automatyczne łamanie stron (dodawanie

nowej strony, jeśli tekst z poprzedniej stro-ny się na niej nie mieści);

• łamanie zbyt długich linijek tekstu;• wstawianie obrazków w formatach JPEG

oraz PNG;• kolorowanie;• rysowanie linii;• manipulacja kursorem;• podpisywanie dokumentu;• oraz inne, których jest tyle, co metod udo-

stępnianych przez klasę. Spis wraz z obja-śnieniami znajduje się na końcu artykułu.

ZaczynamyZe strony domowej projektu ściągamy najnow-szą wersję klasy (najnowsza, w chwili pisania ar-

tykułu, to 1.53), następnie rozpakowujemy ar-chiwum (zip lub tgz). Po rozpakowaniu powin-niśmy otrzymać następujące pliki: FAQ.htm, fpdf.css, fpdf.php, histo.htm, install.txt oraz kata-logi: doc, font, tutorial.

To, co nas naprawdę interesuje, abyśmy mo-gli spokojnie korzystać z dobrodziejstw FPDF, to katalog font oraz pliki fpdf.css, fpdf.php. Po skopiowaniu ich do odpowiedniej lokalizacji, możemy przejść do tworzenia pierwszego do-kumentu.

Czas na odrobinę wyjaśnień. Linijka nr 2 po-woduje dołączenie pliku fpdf.php, wymaganego do poprawnego generowania dokumentów. Li-nijka 3 tworzy obiekt pdf, na którym będziemy właściwie operować.

Tworzenie każdego dokumentu PDF zaczyna się od dodania strony (linijka 4). Jeśli tego nie uczynimy generator „utworzy” nam dokument, lecz program później go odczytujący stwier-dzi, że jest on uszkodzony lub nie jest to PDF. Aby cokolwiek móc zacząć pisać w naszym do-kumencie jesteśmy zmuszeni wybrać czcionkę oraz określić jej właściwości takie jak styl oraz rozmiar. Linijka 5 przedstawia ustawianie po-grubionej czcionki Arial o rozmiarze 16. Moż-liwe jest również łączenie właściwości czcionek np. BUI ustawi nam czcionkę na pogrubioną, pochyloną i zarazem podkreśloną.

Samo pisanie jest możliwe dzięki trzem me-todom udostępnianym przez FPDF. Jedną z nich jest Cell(). Jest ona czymś więcej niż tyl-ko narzędziem do pisania. Jak widać w linijce 6 przyjmuje ona aż 3 argumenty (w rzeczywi-stości może przyjmować ich trochę więcej, ale o tym później). Metoda Cell(), tak napraw-dę, rysuje prostokąt (komórkę) i wypełnia go tekstem. Pierwszy argument określa szerokość owej komórki, drugi zaś wysokość i wreszcie trzeci to sam tekst. Ostatnia, bardzo istotna, linijka to zamknięcie dokumentu PDF. Służy do tego metoda Output(). Jeśli wywołamy ją w takiej postaci jak jest to przedstawione w li-nijce 7, to przeglądarka (w zależności od usta-

PDF

Odkąd firma Adobe Systems zaprezentowała i oddała do użycia format PDF, stał się on jednym z najpopularniejszych formatów dokumentów elektronicznych. Czym tak właściwie jest ten PDF?

Dowiesz się...• Jak przygotować bibliotekę do pracy• Jak tworzyć dokumenty PDF oraz jak je wypeł-

niać.

Powinieneś wiedzieć...• Jak tworzyć obiekty w PHP• Jak dziedziczyć oraz pisać własne funkcje.

Poziom trudności

Generowanie z poziomu PHP

Page 55: PHP Solutions 04 2007 PL

04/2007

Narzędzia

54

Zaprojektuj i zbuduj swój własny dokument PDF

www.phpsolmag.org 55

wień) otworzy nam taki dokument. Metodzie Output() możemy przekazać jeszcze 2 argu-menty np. Output(dokument.pdf, true), w ten sposób spowodujemy wymuszenie zapisania dokumentu na dysku lokalnym o nazwie doku-ment.pdf. Jest to dość przydatne.

Wynikiem działania kodu z Listingu 1. jest nic innego jak tylko dokument PDF o następu-jącym wyglądzie: patrz Rysunek 1.

Nasz dokument nie jest, jak na razie, zbyt roz-budowany. Na Rysunku 2. przedstawię bar-dziej urozmaicony przykład.

Jak widać dodałem troszkę elementów do na-szego PDF-a. Nowy kod nie różni się niczym nadzwyczajnym od poprzedniego. Ważną zmianą jest jedynie dodanie czterech wywołań metody Cell() z odpowiednimi argumentami. Fragment kodu formatującego komórkę:

$pdf->Cell(60,20,

"Czciona pochylona", 1, 1, "c")

Trzy pierwsze argumenty nie wymagają zbyt-niego wyjaśnienia. Natomiast kolejne 3 wyglą-dają dość interesująco. Wcześniej wspomnia-łem już, że metoda Cell() może przyjmować więcej niż 3 argumenty. Teraz słowo wyjaśnie-nia co do pozostałych. Pierwsza cyfra 1 mówi, aby narysować ramkę o rozmiarach 60 na 20 oraz, aby była ona widoczna. Jeśli argument ten ustawimy na 0, ramka pozostanie niewi-doczna. Kolejna 1-ka mówi, gdzie ustawić kur-sor, czyli na początek nowej linii. Wartość tego argumentu również może zostać ustawiona na zero, wtedy kursor zostanie ustawiony na pra-wo od ramki (jest to opcja domyślna). Ostat-ni argument opisuje, w jaki sposób ma zostać ustawiony tekst w stosunku do komórki (ram-ki). C oznacza, że ma zostać wycentrowany. Domyślną wartością (gdy żaden argument nie zostanie podany) jest L – wyrównaj do lewej, istnieje również wyrównanie do prawej – R .

„Chodź pomaluj mój świat”Klasa FPDF udostępnia nam możliwość ryso-wania. Nie jest to może funkcjonalność rozbu-dowana, ale można ją wykorzystać nawet przy tworzeniu dość skomplikowanych kształtów. I tak możemy rysować linie o różnych kolorach i grubościach, wypełniać kolorem opisane wcze-śniej komórki, kolorować tekst oraz ustanawiać kolor obrysu komórki. Zaprezentuję pokrótce w/w możliwości. Oto fragment kodu ustawia-jącego kolor tekstu:

$pdf->SetTextColor(255, 0, 0)

Powyższa linijka sprawi, że każdy tekst, jaki będziemy umieszczać w naszym dokumencie, będzie koloru czerwonego tak jak, ten pokaza-ny na Rysunku 3.

Metoda SetTextColor() pobiera 3 argumen-ty, które stanowią składowe RGB. W ten sposób możemy mieszać kolor czerwony, zielony i nie-

bieski w celu otrzymania interesującej nas bar-wy. Kolejną ważną opcją jest możliwość naryso-wana ramki komórki w wybranym kolorze:

$pdf->SetDrawColor(255, 0, 0);

$pdf->SetTextColor(255, 0, 0);

$pdf->Cell(50, 20, "Czerwony", 1)

Metoda SetDrawColor() służy do ustawia-nia koloru obramowań komórek oraz do ry-sowania pojedynczych linii. Stosując ją do na-rysowania ramki komórki należ pamiętać, że-by metodzie Cell() przekazać argument mó-wiący o wyświetleniu ramki. Inaczej nie zo-baczymy interesującego nas efektu: patrz Ry-sunek 4.

Kolejnym prezentowanym przeze mnie spo-sobem „upiększania” PDF-a jest wypełnianie komórek kolorem. W tym celu należy posłu-żyć się metodą SetFillColor() oraz przekazać jej argumenty w postaci składowych RGB. Nie-stety nie wystarczy tylko wywołać tej metody i rysując komórkę oczekiwać, że otrzymamy za-mierzony efekt. Metodzie Cell() należy jeszcze przekazać kolejny argument mówiący o tym, że ma użyć zdefiniowanego przed chwilą koloru wypełnienia. Całą tę procedurę wraz z efektem przedstawiam kod poniżej i Rysunek 5.:

$pdf->SetDrawColor(255, 0, 0);

$pdf->SetFillColor(255, 0, 0);

$pdf->Cell(50, 20, "Czerwony", 1, 0, "", 1)

Jak widać manipulowanie kolorami jest dość proste, ale efektowne. Aby osiągnąć ciekawe efekty nie trzeba wcale posiadać specjalnych umiejętności plastycznych.

Na sam deser przygotowałem przykład pre-zentujący, w jaki sposób należy posługiwać się metodą Line(), która umożliwia rysowanie pojedynczych linii. Oczywiście nic nie stoi na przeszkodzie, aby proste linie łączyć w bardziej złożone kształty.

Na pierwszy rzut oka konstrukcja wydaje się być trochę dziwna, ale odrobina wyjaśnienia z mojej strony i przykład stanie się jasny jak słoń-ce. W linijce pierwszej znajduje się metoda, któ-rą już wcześniej poznaliśmy przy rysowaniu obramowań komórek. W ten sposób ustawia-my kolor linii, który za chwilę będą rysowany. Właściwe rysowanie odbywa się wraz z wywo-łaniem metody Line(x1, y1, x2, y2). Przyjmu-je ona 4 argumenty. Pierwszy to współrzędna x1 początku linii, druga to współrzędna y1 po-czątku linii. Kolejne dwie to współrzędne x2 i y2 końca linii. Należy pamiętać, iż początkiem układu współrzędnych jest górny lewy róg ak-tualnej strony dokumentu. I po narysowaniu li-nii pozycja kursora nie zmienia się tylko pozo-staje w tym samym miejscu jak np. po zakoń-czeniu pisania za pomocą Cell(). W przypad-ku chęci wypisania czegoś pod daną linią należy ustawić odpowiednio kursor metodą SetXY(x, y) lub SetY(y) i SetX(x).

Wracając do naszego przykładu kolorem czerwonym zostały narysowane 3 linie. Ko-niec każdej linii jest początkiem następnej, ła-two więc domyśleć się, że rysowaną figurą bę-dzie trójkąt.

Kolejną figurą jaką narysowaliśmy również jest trójkąt z tą tylko różnicą, że boki tego trój-kąta są znacznie grubsze niż u poprzedniego oraz mają inny kolor. Grubość linii wynika z faktu wywołania metody SetLineWidth(x), gdzie x stanowi określenie grubości w milime-trach. Standardowo wartość ta wynosi 2 mm. No dobrze, mamy namalowane figury. Ale cze-goś tu w wyjaśnieniach jeszcze brakuje. Otóż w przykładzie użyłem metody Text(x, y,

string), która to pozwala na wypisanie tek-stu, którego początek będzie znajdować się w

Rysunek 1. Fragment wygenerowanego prostego PDF-a

Rysunek 2. Urozmaicony dokument PDF

�������������������

������������������

�����������������

��������������������������������

Rysunek 6. Efekt malowania liniami o określonych kolorach. Oraz wypisywanie tekstu w określonym miejscu dokumentu

������������������

������������

Rysunek 5. Efekt wyboru koloru wypełnienia wnętrza komóki oraz kolorowania jej obramowania

Rysunek 4. Efekt kolorowania tekstu i obramowania komórki

Rysunek 3. Efekt kolorowania tekstu

Page 56: PHP Solutions 04 2007 PL

04/2007

Narzędzia

56

punkcie x,y.Efekt takiego fragmentu kodu przedstawia

Rysunek 6.

Odnośniki i obrazkiDokumenty PDF niejednokrotnie zawierają różnego rodzaju obrazki (grafiki). Klasa FPDF również udostępnia nam taką możliwość. Słu-ży do tego metoda Image(plik, x, y, w, h). Posiada jeszcze dwa dodatkowe argumenty, ale o nich za chwilę.

X i Y oznacza początek obrazka względem początku aktualnej strony dokumentu, W i H jak duży ma być wyświetlany obrazek (width – szerokość i height – wysokość). Sam obrazek jest określony w argumencie plik. Warto w tym miejscu wspomnieć, że FPDF rozpoznaje for-maty JPEG, JPG, PNG. Wspomniałem już, że istnieją jeszcze 2 argumenty. Są one opcjonal-ne i określają typ obrazka (jeśli nie zostaną okre-ślone, to typ zostanie wyznaczony na podstawie rozszerzenia pliku) oraz odnośnik. Odnośnik to np. adres do strony www, na którą zostaniemy przekierowani, po kliknięciu odnośnika w po-staci obrazka.

Polecenie wczytania prostego obrazka bez określenia linii przedstawia poniższa linijka:

$pdf->Image(

"debian.jpg", 10, 10, 120, 120)

Komenda ta spowoduje wczytanie pliku o na-zwie debian.jpg. Lewy górny róg obrazka zosta-nie umieszczony w punkcie o współrzędnych (10,10), a jego szerokość i wysokość będą wy-nosiły 120.

Przy osadzaniu obrazków w PDF-ach należy również pamiętać, że pozycja kursora nie ulega zmianie i wymagana jest interwencja, tak jak to miało miejsce wcześniej.

Tytuł podrozdziału zawiera słowo „odnośni-ki”, więc również i o nich wypadałoby trosz-kę napisać. W przypadku FPDF odnośniki ma-ją dwojakie znaczenie. Mogą się odwoływać do elementów dokumentu np. do konkretnej stro-ny lub zasobów sieci Internet. Pierwszy typ od-nośników uzyskujemy manipulując metoda-mi AddLink() oraz SetLink(). Drugi typ spro-wadza się do wykorzystania jednej z 4 metod: Link(), Cell(), Write() oraz Image(). Pierw-sza metoda przyjmuje 5 argumentów i wyglą-da tak: Link(x, y, w, h, link). Pierwszych czte-

rech nie muszę chyba wyjaśniać, ostatni nato-miast jest właściwym linkiem do zasobu. Przy osadzaniu linków najczęściej wykorzystywa-ne są trzy pozostałe metody, które jako ostatni argument przyjmują właśnie określony link. Po-niżej znajduje się przykładowy kod pokazujący, jak dodać do dokumentu odnośnik:

$pdf->Write(5, "Zapraszam na strone

domowa projektu FPDF ");

$pdf->SetTextColor(0, 0, 255);

$pdf->Write(5, "www.fpdf.org",

"http://www.fpdf.org")

Wykorzystałem tutaj metodę Write(), która wypisuje żądany tekst. Pierwszym argumen-tem jest wielkość pisanego tekstu. Trzeci ar-gument, jak widzimy przy drugim wywołaniu Write(), stanowi określony przeze mnie link do strony domowej projektu FPDF. Wynik takiego działania możemy oglądać na Rysunku 8.

Klikając napis www.fpdf.org zostaniemy prze-niesieni na stronę domową projektu FPDF.

TabeleDokumenty PDF często służą do prezentacji wyników różnych badań, zestawień lub też wy-

kazu stanu magazynu. W takim przypadku da-ne reprezentowane są w postaci tabel – upo-rządkowanych zbiorów wierszy i kolumn.

FPDF umożliwia tworzenie i wypełnianie ta-bel. Sprytny czytelnik pomyśli, że pewnie two-rzy się je za pomocą metody Table() lub po-dobnej. Otóż nic bardziej mylnego. Tabele two-rzy się za pomocą narzędzia już wcześniej pre-zentowanego, jakim jest metoda Cell(). Pamię-tacie, że pozwala ona na rysowanie obramowań komórek? To właśnie dzięki tej funkcjonalno-ści jesteśmy w stanie osadzać tabele w PDF-ach. Kod w Listingu 3. prezentuje przykładową ta-belę wraz z wypełnionymi i pokolorowanymi komórkami. Jak widać nie ma tu zbyt wielkiej „magii”. Ale krótkie wyjaśnienie będzie na pew-no pomocne. W pierwszej kolejności dobrze by było, aby nasza tabela posiadała nagłówki. Ich tworzenie zawarte jest w trzech pierwszych li-nijkach. Czynność ta wykonywana jest w pę-tli. Komórki będą ustawione obok siebie – sty-kając się krawędziami. Ich zawartość będzie za-wierać napis Kolumna 1, Kolumna 2 itd. aż do Kolumna 5.

Omówmy teraz tworzenie wierszy. W tym ce-lu utworzenia wiersza tabeli wykorzystujemy dwie pętle – zewnętrzną oraz wewnętrzną. Pętla we-

Rysunek 7. Efekt wstawienia obrazka do dokumentu

Rysunek 8. Efekt zastosowania odnośnika do zasobu w Internecie

Rysunek 9. Efekt zastosowania wlasnoręcznie utworzonej czcionki

Listing 1. Kod prostego PDF-a

<?

require("fpdf.php");

$pdf=new FPDF();

$pdf->AddPage();

$pdf->SetFont("Arial","B",16);

$pdf->Cell(30,20,"Witaj w FPDF :)");

$pdf->Output();

?>

Page 57: PHP Solutions 04 2007 PL
Page 58: PHP Solutions 04 2007 PL

04/2007

Narzędzia

58

Listing 2. Fragment kodu prezentującego rysowanie liniami o pewnych kolorach oraz wstawianie tekstu w określone miejsce dokumentu

$pdf->SetDrawColor(255, 0, 0);

$pdf->Line(30, 10, 50, 10);

$pdf->Line(30, 10, 25, 50);

$pdf->Line(50, 10, 25, 50);

$pdf->SetFont("Arial", "", 12);

$pdf->Text(60, 40, "Taka dziwna figura");

$pdf->SetLineWidth(5);

$pdf->SetDrawColor(0, 255, 255);

$pdf->Line(30, 70, 30, 130);

$pdf->Line(30, 130, 80, 130);

$pdf->Line(80, 130, 30, 70);

$pdf->Text(90, 100, "Gruba figura");

Listing 3. Fragment kodu prezentujący tworzenie przykładowej tabeli oraz jej wypełnienie z kolorowaniem wierszy

for($i = 0; $i < 5; $i++) {

$l = $i + 1;

$pdf->Cell(35, 15, "Kolumna ".$l, 1);

}

$pdf->Ln();

$pdf->SetFont("Arial", "", 12);

for($k = 0; $k < 6; $k++) {

$wiersz = $k+1;

if(($wiersz%2) == 0) {

$pdf->SetFillColor(0, 255, 0);

for($j = 0; $j < 5; $j++) {

$pdf->Cell(35, 10, "Dana ".$j+$k+1, 1, 0, "", 1);

}

}

else {

$pdf->SetFillColor(0, 255, 255);

for($j = 0; $j < 5; $j++) {

$pdf->Cell(35, 10, "Dana ".$j+$k+1, 1, 0, "", 1);

}

}

$pdf->Ln();

}

Listing 4. Fragment kodu prezentujący wykorzystanie utworzonej czcionki

$pdf->AddFont("MojTimes", "", "mojtimes.php");

$pdf->SetFont("MojTimes", "", 14);

$pdf->Write(5, "Zapraszam na stronę domowa projektu FPDF ");

$pdf->SetTextColor(0, 0, 255);

$pdf->Write(5, "www.fpdf.org", "http://www.fpdf.org");

Listing 5. Fragment kodu prezentującego przetwa�anie danych z formularza

function wypiszImie($imie) {

$this->SetFont("Arial", "B", 14);

$this->SetTextColor(255, 0, 0);

$this->Cell(30, 10, "Imie", 0);

for($i = 0; $i < strlen($imie); $i++) {

$this->Cell(10, 10, " ".$imie[$i], 1);

}

$this->Ln();

$this->Ln();

}

wnętrzna (linijka 8) dba o to, aby została wykreślo-na odpowiednia ilość wierszy, czyli 6. Między linij-kami 10 i 19 odbywa się wypełnianie wierszy od-powiednią ilością komórek. Aby urozmaicić przy-kład postanowiłem pokolorować tworzone komór-ki w zależności od spełnianego warunku (parzysta, nieparzysta) – linijka 10. W linijce 22 znajduje się polecenie przejścia do nowej linii w celu rozpoczę-cia nowego wiersza z danymi. Jeśli tego byśmy nie uczynili, to 6 wierszy byłoby w jednej linijce wy-chodząc poza obręb dokumentu.

Do You speak polish?W FPDF mamy do dyspozycji określoną ilość czcionek. Co zrobić w przypadku, gdy chcemy użyć jakiejś niestandardowej lub też brakuje nam pewnej podstawowej czcionki o danym kodowa-niu znaków. W tym momencie z pomocą przy-chodzi nam metoda MakeFont(). Lecz zanim przystąpimy do tworzenia czcionki powinniśmy przygotować plik afm, który jest wymagany przez metodę MakeFont(). Uczynić możemy to dzięki programowi tt2pt1. Gdy już zaopatrzymy się w tt2pt1 wystarczy, że wpiszemy w linii poleceń:

ttf2pt1 -a c:\windows\fonts\

times.ttf mojtimes

Dzięki temu uzyskamy potrzebny plik moj-times.afm. Poniżej prezentuję kod skryptu PHP, który stworzy czcionkę mojtimes z pol-ską stroną kodową:

require('font/makefont/makefont.php');

MakeFont('times.ttf','mojtimes.afm',

'iso-8859-2')

Rysunek 11. Efekt przetworzonych danych z formularza

Rysunek 10. Efekt zastosowania wlasnoręcznie utworzonej czcionki

W Sieci

• http://www.fpdf.org – strona domowa projektu FPDF.

Page 59: PHP Solutions 04 2007 PL
Page 60: PHP Solutions 04 2007 PL

04/2007

Narzędzia

60

Jak widać na listingu, w pierwszej kolejności mu-simy wczytać kod metody MakeFont(), aby na-stępnie móc ją wywołać. Do prawidłowego dzia-łania metoda ta wymaga oryginalnej czcionki pliku, który wcześniej stworzyliśmy oraz usta-lenia trybu kodowania znaków (strony kodo-wej). W wyniku działania skryptu otrzyma-my dwa pliki mojtimes.z oraz mojtimes.php. Pa-

miętajmy, aby umieścić je w tym samym katalo-gu, co skrypt z nich korzystający lub w katalo-gu font wraz z definicją lokalizacji czcionek po-przez define(FPDF_FONTPATH, font/). Obo-jętnie, który z warunków spełnimy, możemy już przystąpić do korzystania z nowoutworzo-nej czcionki (Listing 4.). Na początek musimy zarejestrować czcionkę, najlepiej za pomocą me-

tody AddFont(). Pierwszym argumentem przyj-mowanym przez tę metodę jest nazwa, pod jaką będzie rozpoznawana w skrypcie nasza czcionka, drugi to styl (pogrubiony, pochylony, podkreślo-ny, zwykły) oraz ostatni – nazwa pliku PHP, któ-ry został wcześniej wygenerowany. Teraz może-my już za pomocą poznanego wcześniej polece-nia SetFont() ustawić nową czcionkę. Zwracam uwagę na pierwszy argument metody, który musi być taki sam jak nazwa, pod jaką czcionka zosta-ła wcześniej zarejestrowana. W ten sposób może-my już cieszyć się własną czcionką wraz z polski-mi znakami patrz Rysunek 9.

W miarę jedzenia apetyt rośnieMam nadzieję, że troszkę przybliżyłem czytel-nikowi wybrane możliwości pakietu FPDF.

Przyszedł czas na prezentację połączenia nie-których w/w funkcji w małą aplikację. Sposób działania programu polega na pobraniu, po-przez prosty formularz, danych od użytkowni-ka oraz przekazaniu ich do skryptu PHP, który wygeneruje na ich podstawie dokument PDF.

Rysunek 10. przedstawia wygląd formularza z przykładowymi danymi. W Listingu 5. przed-stawię fragment kodu formatowania przesła-nych danych (pełny kod został dołączony do artykułu).

Zdeklarowana funkcja przyjmuje parametr $imie, który wcześniej został przesłany za po-mocą metody POST. Następnie w pętli rysowa-na jest odpowiednia ilość komórek, poszczególne wypełniane są danym znakiem pochodzącym ze zmiennej $imie (linijki 5, 6). W ten napis został rozbity na poszczególne elementy, z których każ-dy „opakowany” jest przez komórkę. Efekt dzia-łania skryptu zaprezentowany został poniżej:

PodsumowanieJak widać na powyższym obrazku, dokument zawsze będzie generowany dynamicznie w za-leżności od otrzymanych danych. Używanie FPDF jest dobrym pomysłem na generowanie plików PDF w przypadku, gdy zawartość doku-mentu może się zmieniać.

Możliwości FPDF nie kończą się jednak na obsłudze formularzy. Bibliotekę tę możemy wykorzystać np. do prezentacji zawartości tabel zawartych w bazach danych. Jedynym ograni-czeniem jest tylko wyobraźnia.

Życzę powodzenia i dobrej zabawy, w eks-perymentowaniu z tworzeniem dokumentów PDF via PHP.

TOMASZ KRAWCZYKAutor jest studentem informatyki w Społecznej Wy-szej Szkole Przedsiębiorczości i Zarządzania w Ło-dzi. Obecnie jest w trakcie przygotowania do obro-ny pracy inżynierskiej. Interesuje się systemami operacyjnymi, różnymi językami programowania (w szczególności Java), algorytmami genetyczny-mi oraz tworzy różnego rodzaju oprogramowanie. Kontakt z autorem: [email protected]

Spis wszystkich metod udostępnianych przez FPDF:

• AcceptPageBreak – włącza lub wyłącza automatyczne łamanie strony;• AddFont – dodaje nową czcionkę;• AddLink – tworzy wewnętrzny odnośnik;• AddPage – dodaje nową stronę;• AliasNbPages – definuje alias dla liczby stron;• Cell – wypisuje ramkę tekstową;• Close – zamyka dokument;• Error – błąd krytyczny;• Footer – stopka strony;• FPDF – konstruktor;• GetStringWidth – oblicz szerokość tekstu;• GetX – zwraca współrzędną X kursora;• GetY – zwraca współrzędną Y kursora;• Header – nagłówek strony;• Image – wstawia obrazek;• Line – Kreśli linię;• Link – wstaw odnośnik;• Ln – koniec linii;• MultiCell – wypisuje wieloliniowy tekst;• Open – tworzy dokument;• Output – zapisz albo wyślij dokument;• PageNo – numer strony;• Rect – prostokąt;• SetAuthor – ustawia autora dokumentu;• SetAutoPageBreak – ustawia tryb automatycznego łamania stron;• SetCompression – włącza lub wyłącza kompresję;• SetCreator – ustawia źródło dokumentu;• SetDisplayMode – ustawia tryb wyświetlania;• SetDrawColor – ustawia kolor rysowania;• SetFillColor – ustawia kolor wypełnienia;• SetFont – ustaw czcionkę;• SetFontSize – ustawia rozmiar czcionki;• SetKeywords – przypisz słowa kluczowe do dokumentu;• SetLeftMargin – ustawia lewy margines;• SetLineWidth – ustawia grubość linii;• SetLink – ustawia cel wewnętrznego odnośnika;• SetMargins – ustawia marginesy;• SetRightMargin – ustawia prawy margines;• SetSubject – ustawia temat dokumentu;• SetTextColor – ustawia kolor tekstu;• SetTitle – ustaw tytuł dokumentu;• SetTopMargin – ustawia wielkość górnego marginesu;• SetX – ustawia bieżącą pozycję X kursora;• SetXY – ustawia pozycję kursora;• SetY – ustwia współrzędną Y kursora;• Text – wypisuje tekst;• Write – wypisuje tekst w określonej lokalizacji na stronie.

Tabela 1. Efekt utworzenia przykładowej tabeli wraz z wypełnieniem jej danych i kolorowaniem wierszy

Kolumna 1 Kolumna 2 Kolumna 3 Kolumna 4 Kolumna 5

1 1 1 1 1

2 2 2 2 2

3 3 3 3 3

4 4 4 4 4

5 5 5 5 5

6 6 6 6 6

Page 61: PHP Solutions 04 2007 PL
Page 62: PHP Solutions 04 2007 PL

4/2007

Narzędzia

62

PostNuke

63

Pierwsze wersje PostNuke utrzymywały kompatybilność z PHP–Nuke pod wzglę-dem API (ang. application programming

interface, w tym przypadku główny zbiór funkcji CMSa), a obecnie pozostałosci z tego CMSa pra-wie wcale nie ma, dlatego też nie możemy uru-chamiać modułów z PN (skrót od PostNuke) na PHP–Nuke i odwrotnie. PN zawsze zachowywał licencję GNU/GPL, co przywiodło mu więcej zwo-lenników niż PHP–Nuke. W przeciwieństwie do swojego przodka, który nadal jest aktulizowany, PN na bieżaco miał łatane dziury, a także był dużo bardziej efektownie udoskonalany (np. PHP–Nuke do dzisiaj nie ma instalatora). PostNuke jest do dzi-siaj jednym z najczęściej używanych CMSów, a nic nie zwiastuje, aby to się zmieniło – nowa wersja Po-stNuke jest już w budowie – co prawda trwa to już kilka lat, ale można pobrać już pierwsze wersje RC (ang. release candidate) i wszystko wskazuje na to, że wersję finalną zobaczymy już w tym roku.

Rozwój i CMSy na nim bazująceTak naprawdę ludzie zaczęli dostrzegać Postnuke już od wydania pierwszych wersji 0.7x. Wersje starsze, jak np. 0.716 byly bardzo wydajne, aczkolwiek nie miały w sobie nic odrózniającego się od konkuren-cyjnych systemów. Do teraz tych wersji używaja oso-by, które uważaja, iż wersje te są dla nich wystarcza-jące i nie obciążają zbytnio serwera. Często jednak

takie osoby "atakują" fora supportowe z pytaniem jak ktoś mógł włamać się im na stronę lub dlaczego nowsza wersja dotychczas używanego przez nich modułu nie działa. Zazwyczaj odpowiedź jest prosta – Dokonaj aktulizacji, jednak nie wszyscy po tym są szczęśliwi, ale o tym w dalszej części artykułu. Kon-tynuując – dużo nowego wniosła wersja 0.726, któ-ra mimo tego, że jest odradzana z powodu wielu luk w bezpieczeństwie, nadal ma ogromną ilość użyt-kowników. Była to chyba jedyna wersja, która była jeszcze w miarę szybka i funkcjonalna, ale wszyst-kiego – teoretycznie – mieć nie moża. PHP idzie do przodu, serwery mamy coraz lepsze i powoli ludzie przestawają myśleć o optymalizacji, co jest błedem. Kolejną wersją był przełomowy PostNuke 0.75 – ta wersja była dużym krokiem do przodu, miała nieco inną filozofię dotyczącą modułów, była bardziej spo-pularyzowana dzięki temu, że po kilku przeróbkach można było zrobić stronę całkiem wyróżniającą się od innych, ale problem był jeden – moduły miały kod HTML na zasadzie "kod w kodzie", czyli ich layout wbudowany był po prostu w funkcje echo (funkcja PHP wyświetlająca dany tekst). Dopiero w PostNuke 0.760 moduły zaczęły korzystać z syste-mu szablonów Smarty. Wersja ta jest najnowszą sta-bilną wersją, którą wzbogacono już o poprawki i łatki kolejno wydając paczki PN 0.761, 0.762, 0.763 (na dniach po wydaniu zauważono kolejne problemy), 0.764. Wersja 0.76x jest zarazem najwolniejszą wersją PN (najbardziej obciąża serwery). Z PostNu-ke także zostały stworzone forki. Najpopularniejsze z nich to MDPro (powstały z PN 0.726, zachowuje 80% kompatybilności z PN 0.75 oraz ok. 60% z PN 0.76x), enVolution, Xoops oraz Xaraya (obecna wer-sja praktycznie nie jest wcale kompatybilna z PN, jej

developerzy kompletnie przerobili silnik i z PostNu-ke w Xarayi zostało praktycznie tyle co nic). Zazwy-czaj po doinstalowaniu kilku modułów z PN np. do MDPro, można uruchomić nowe moduły dedyko-wane tylko pod PostNuke. Ważną rolę odrywa tu pnRender, ale o tym także później.

Ogólnie o PostNuke i jego standardowych modułachDo czego przyda nam się PostNuke i do jakiego typu stron go używać? PostNuke jest dość uniwer-salnym systemem CMS, dzięki temu, że możemy wyłaczyć bez żadnego problemu modułu (moduł to odpowiedni "podskrypt" korzystający z funkcji PN i swoich, bedący tylko konkretną częścią stro-ny; modułem są np. Newsy, Recenzje), których nie używamy. Mało tego – można także wyłaczyć wtyczki dla poszczególnych modułów, np. Komen-tarze dla Newsów, Ankiet. Takie zarządzanie mo-dułami, które oferuje ten CMS, jest jego ogromną zaletą. Instalacja modułów pobranych z internetu nie stanowi także problemów – wystarczy odpo-wiednio skopiować folder na serwer i zaktywować moduł w panelu administracyjnym jednym klik-nięciem myszki. Dla porównania np. dla polskiego jPortalu można doinstalować moduły (co i tak jest dużo bardziej uciążliwe niż w przypadku PN), ale o ich usuwaniu już nikt nie myślał. PN odrożnia jeszcze jedna rzecz – system wtyczek. Takie mo-duły jak komentarze są traktowane przez system jako wtyczki, które można podpiąć do dowolnych modułów – np. do modułu sklepu umożliwiając komentowanie jego produktów. Instalując jedną wtyczke sami wybieramy gdzie ma być ona używa-na. Przykładowo instalując wtyczke umożliwiającą używanie emotoikon możemy ją aktywować tylko dla forum lub dla forum, newsów, artykułów, czy też do wszystkich modułów. Tu nie trzeba nic kom-binować – wszystko "załatwiamy" dzięki zaledwie kilku kliknięcią myszą. Gdzie jednak w modułach uniwersalność PostNuke? Otóz polega to na tym, że możemy usunąć modułu, które są dla nas zbyt bar-dzo rozbudowane lub nieintuicyjne, albo posiadają-ce zbyt mała funkcjonalność. Wszystkie możemy

PostNuke

Od pewnego czasu webmasterzy przekroczyli próg statycznych stron WWW. Obecnie tworzy się dynamiczne strony najczęściej sięgając po język PHP. Nie każdy jednak musi być mistrzem PHP by stworzyć rozbudowany serwis – zawsze można sięgnąć po system zarządzania treścią, który nam w tym pomoże. Przedstawimy jeden z ciekawszych darmowych projektów – PostNuke.

Dowiesz się• Zaznajomienie się z działaniem PostNuke i jego

modułami• Nauczenie się konfiguracji systemu pod swoje po-

trzeby łącznie z instalacją dodatkowych modułów• Zapoznanie się z regułami uprawnień

Powinieneś wiedzieć• Należy znać podstawowe pojęcia, m.in: serwer,

PHP, baza danych• Należy znać podstawy administracji serwerem

i jego komponentami, np. tworzenie nowych baz danych

Poziom trudności

System zarządzania treścią

Page 63: PHP Solutions 04 2007 PL

4/2007

Narzędzia

62

PostNuke

63

zamienić na moduły alternatywne (oficjalne bądź nieoficjalne), których w internecie do pobrania setki i to za darmo. W dodatku nie trzeba daleko szukać – na stronach supportowych, których jest dość sporo (chociażby świetny polski support http://www.post–nuke.pl), wszystko znajduje się w dziale download dobrze posegregowane. Musimy jednak pamiętać, że nikt nie ponosi odpowiedzialności za używanie nieoficialnych modułów, gdyż niektóre z nich mogą być powodem włamań na stronę. Czy jednak PostNuke jest odpowiedni na wszystkie stro-ny? Oczywiście, że nie. Jest to CMS dedykowany średnim serwisom, ponieważ gdyby postawić na nim większy portal z odwiedzalnością powyżej kil-ku tysięcy unikalnych użytkowników dziennie, po-trzeba było by bardzo mocnego dedykowanego ser-wera – i jeszcze nie ma gwarancji na to, że w danym momencie nie padnie nam baza MySQL, gdyż nie-stety zapytania w PostNuke nie są zbyt mocno zop-tymalizowane. Czym możemy się ratować? System szablonów Xanthia i pnRender (czyli implementacja Smarty w PN) posiada możliwość cachowania i bu-forowania, gdzie nawet samo właczenie cachowania szablonów wpływa znacząco na prędkość serwisu. Pamiętajmy także o tym, aby nie zaśmiecać naszego PN wszystkimi możliwymi modułami – używaj-my tylko tych, które są nam potrzebne! Ale nie ma się co martwić na zapas – przeciętną stronę na tym CMSie "uciągnie" każde lepsze konto hostingowe. Można by rzec, że PN nie nadaje się na małe serwi-sy, które nie potrzebują tych wszystkich "bajerów". Jednak jeśli ktoś bardzo chce, zawsze może PostNu-ke odpowiednio odchudzić i przygotować do takiej strony, gdzie głowną rolę będzie odgrywała dobrze zrobiona skórka. Różni użytkownicy pokazywali np. portfolia wykonane na tym CMSie, zawierające zaledwie kilka podstron – niby nic trudnego, ale to się mija z celem. Najlepsze zastosowanie PN to ra-czej strony średniej wielkości, typu strony klubowe, hobbystyczne (np. o mniej popularnym sporcie), ale to nie jest reguła! Wszystko już zależy od osobistego punktu widzenia oraz od umiejętności programi-stycznych użytkownika – bo nawet najgorszy CMS w rękach dobrego programisty może dobrze wypaść na każdej stronie.

Zacznijmy naszą przygodę z PostNuke od ogól-nego zapoznania się z jego silnikiem i panelem administracyjnym. Jednak zanim przejdziemy do praktyki na naszej “postnukowej” stronie, po krót-ce pokażę jak owy CMS zainstalować. Załóżmy, że interesuje nas polska wersja tego CMSa. Polski PostNuke team szykuje spolszczenia zawsze na czas. Gotowe, polskie paczki (przetłumaczone ca-łe jądro i moduły) PostNuke jak i PostNuke Lite (“odchudzona” wersja tego CMSa) znajdują się na stronie http://www.post–nuke.pl. Pobieramy najnow-szą wersję, czyli PostNuke 0.764. Po zakończeniu pobierania rozpakowywujemy ją na naszym dysku twardym. Po rozpakowaniu ujrzymy dwa foldery – html oraz phoenix–sql. Pierwszy zawiera wszyst-kie pliki potrzebne do uruchomienia i instalacji PN (Rysunek 1.), drugi tylko zrzut z bazy danych – nie będzie on nam jednak potrzebny, gdyż użyjemy wbudowanego w PostNuke instalatora.

Rysunek 1. Pliki PostNuke

Rysunek 2. Początek instalacji

INSTALACJA

• Kopiujemy pliki na nasz serwer. Upewnij-my się, że nasz klient FTP nie zamienia li-ter przy kopiowaniu na małe. Po tym uru-chamiamy w przeglądarce plik install.php.

• Wybieramy język instalacji (Rysunek 2.)• Akceptujemy licencję GNU/GPL• Ustawiamy prawa zapisu, czyli chmod 777

na pliki config.php, config–old.php oraz ka-talogi pnTemp/pnRender_cache, pnTemp/pnRender_compiled, pnTemp/Xanthia_ca-

Page 64: PHP Solutions 04 2007 PL

4/2007

Narzędzia

64

PostNuke

65

che, pnTemp/Xanthia_compiled. Wtedy Post-Nuke wskaże nam, że katalogi mają odpo-wiednie prawa zapisu po kliknięciu w przy-cisk Sprawdź ponownie. Będzie można wtedy przejść do kolejnego punktu instalacji

• Uzupełniamy dane do naszej bazy danych MySQL (możemy założyć nową z pomo-cą skryptu instalacyjnego jeśli mamy takie uprawnienia lub panelu administracyjne-go serwerem. Jeśli mamy darmowy serwer dane powinny być dostarczone przy reje-stracji lub w panelu serwera) (Rysunek 3.)

• Potwierdzamy dane bazy przyciskiem No-wa instalacja

• Jeśli nie mamy stworzonej nowej bazy, a mamy uprawnienia do jej stworzenia, za-znaczamy Utwórz bazę danych, jeśli korzy-stamy z istniejącej bazy – wystarczy tylko kliknąć Start (Rysunek 4.)

• Gdy ukaże nam się wstępny wykaz tabel, klikamy Kontynuuj

• Podajemy login, hasło, e–mail i adres www konta, które będzie służyło jako główne konto w naszej stronie na PostNuke

• Po zobaczeniu końcowego wykazu tabel klikamy Zakończ

• Usuwamy katalog install i plik install.php bądź zmieniamy ich nazwę (jeśli będziemy chcieli później prosto przeinstalować PN) oraz zmie-niamy chmod config.php i config–old.php na 444

Po tych czynnościach możemy przejść już do index.php, gdzie ukaże się nam PostNuke świe-żo po instalacji (Rysunek 5.). Skoro instalacja jest już zakończona, ważna dla nas będzie na początek znajomość głównego schematu lin-ków. W wersji 0.76x wszystko ujednolicono jak najbardziej było to możliwe, aby przy okazji za-chować kompatybilność ze starymi modułami. W modułach linki generuje teraz jedna funk-cja. Najważniejsze co trzeba wiedzieć:

• index.php – strona główna, z parametrami name lub module wczytuje dany moduł. Np.: index.php?name=Downloads – mo-duł downloadu

• admin.php – panel administracyjny, dostęp-ny po zalogowaniu. Np. admin.php?module-=News – administracja newsami

• user.php – logowanie, rejestracja i zarzą-dzanie kontem użytkownika

• banners.php – sprawdzanie ilości odsłon i kliknięć w bannery klientów (skrypt logo-wania dla klientów)

• print.php – skrypt wyświetlający strony do druku, obecnie praktycznie nie używany

Rozłożenie istotnych katalogów:

• languages – do niego kopiuje się pliki ję-zykowe jądra, dla obsługi innych języ-ków. Każdy moduł i blok ma swój katalog “pnlang ” lub “lang ”, dla swych własnych plików językowych

Rysunek 3. Wpisywanie informacji o bazie danych

Rysunek 4. Tworzenie bazy

Page 65: PHP Solutions 04 2007 PL

4/2007

Narzędzia

64

PostNuke

65

• includes – ten katalog zawiera więcej istot-nych katalogów. Nas będą interesować

• blocks – katalog bloków menu oraz search – katalog wtyczek do wyszukiwarki

• modules – katalog modułów, zawiera wszystkie foldery z plikami modułów

• themes – katalog skórek, zawiera podfolde-ry ze skórkami, tam należy także umiesz-czać nowe skórki

Kolejną ważną rzeczą jest administracja. Każ-dy moduł może mieć panel zarządzania w pa-nelu administracji PostNuke, pod własną ikon-ką. 90% modułów z tej opcji korzysta. Poszcze-gólne moduły można w panelu administracyj-nym dzielić na kategorie (przełączanie między nimi odbywa się za pomocą zakładek) – tę opcję umożliwia moduł Panel administracyjny (gdyż tak naprawdę główne opcje PN to też moduły – np. ustawienia strony, czy też same zarządzanie modułami). Pod ikonkami panelu administra-cyjnego znajduje się menu szybkiego zarządzania newsami, lista ostatnio dodanych newsów oraz aktualna ankieta (Rysunek 6.).

Pierwsze ćwiczenie – zanim stworzymy własną skórkę, zmieńmy skórkę strony na jedną ze stan-dardowych. Standardowym modułem do obsługi szablonów jest Xanthia, czyli wszystkie szablony traktujemy jak szablony systemu Smarty. Zmień-my także nazwę strony i główne ustawienia. W tym celu wchodzimy w moduł Ustawienia. Zmie-niamy nazwę strony przykładowo na Moja testowa strona PostNuke, pole logo możemy sobie darować – jest to prawie nieistotne, gdyż takie elementy bę-dziemy ustawiać we własnej skórce – jednak moż-na tam podać adres URL do logo strony, slogan stro-ny – jest to tekst wyświetlany w pasku tytułowym obok nazwy strony, a także w opisie strony – mo-żemy wpisać co nam się podoba (warto zaopatrzyć ten tekst w słowa kluczowe dla wyszukiwarek), da-ta startu – data założenia strony, potrzebna jedy-nie do modułu statystyk, e–mail admina – adres email, na którego kierowane będą wszystkie maile z formularzy, wyłącz serwis – opcja przydaje się je-dynie wtedy, gdy jesteśmy zalogowani i chcemy na szybko dokonać jakichś zmian w systemie nie da-jąc dostępu użytkownikom do strony – należy tu-taj uważać na to, aby nie odejść od komputera, po-nieważ po czasie zostaniemy wylogowani i aby uzy-skać ponowny dostęp do strony będzie trzeba zmie-nić pewną wartość w bazie MySQL (rozwiązanie opisano na forum http://www.post–nuke.pl), słowa kluczowe – nic innego jak klucze dla wyszukiwa-rek zawarte w tagu meta, domyślny temat graficz-ny – główna szata graficzna serwisu – zauważmy, że na liście widnieje tylko obecnie użyty standardo-wy motyw ExtraLite, ponieważ nie jest to skórka modułu Xanthia (inne standardowe skórki należy zaktywować w Xanthia pod linkiem obok, aby by-ły widoczne na liście), zmieńmy temat dla testu na pnDefault, zezwól użytkownikom na zmianę moty-wu – jeśli wybierzemy tak, użytkownicy będą mo-gli zmienić skórkę w swoim panelu po zalogowa-niu – zostawmy tę opcję zaakceptowaną, by póź-

Rysunek 5. PostNuke tuż po instalacji

Rysunek 6. Panel administracyjny PostNuke

niej zobaczyć jak to działa, ustawienia wielojęzyko-we – można tam wybrać domyślny język strony i zezwolić lub zabronić zmiany języka – zostawmy także zezwolone, strona główna – możemy zmie-nić tam główny moduł – np. zamiast standardowe-go News ustawić Downloads, jeśli ma to być strona z pobieraniem plików, a także dodać funkcję starto-wą i argumenty (każdy moduł na swoją funkcję, np.

view – wyświetla moduł, odpowiada temu atrybut &func=view – dla przykładu: index.php?module-=Downloads&func=view), co pozwala na wyświe-tlenie np. konkretnej kategorii downloadu, ustawie-nia niusów – możemy ustawiać ilość newsów na stronie głównej oraz w panelu administracyjnym, sortowanie newsów oraz stroniconowanie – czy-li linki do kolejnych stron z newsami (pager), ra-

Page 66: PHP Solutions 04 2007 PL

4/2007

Narzędzia

66

portowanie błędu – po włączeniu tej opcji będzie-my informowani o błędach głównie w zapytaniach do bazy MySQL, a także innych głównych błę-dach związanych ze stroną – możemy także usta-wić zabawne komunikaty błędów, różne – opcje te mają wpływ na wydajność systemu – jeśli włączy-my wsparcie dla starych modułów, PostNuke bę-dzie działał minimalnie wolniej, ale będziemy mo-gli używać zazwyczaj bez problemów modułów ze starszych wersji, za to opcja kompresji przyspie-sza działanie strony, wiadomość w stopce – tekst w

tym polu będzie się wyświetlał na stronie w miej-scu, gdzie w kodzie skórki wstawiliśmy znacznik stopki – można tu używać HTML i spokojnie usu-nąć wszystkie powered by (choć miłym gestem jest zostawić te obrazki), konfiguracja źródła artykułów – inaczej konfiguracja RSS, opcje bezpieczeństwa – możemy tutaj ustawić na jaki czas użytkownicy mają być zalogowani (jeśli wcześniej nie użyją opcji wyloguj), włączyć sprawdzanie adresów polecają-cych stron do druku, włączyć pnAntiCracker (jeśli na stronie dzieje się coś podejrzanego pnAntiCrac-

ker wysyła o tym informacje na e–mail administra-tora, bardzo często są to alarmy fałszywe), opcje HTML – możemy ustawić które tagi HTML ma-ją być dozwolone do użytku przez użytkowników w komentarzach, postach na forum, newsach itp. – należy zwrócić uwagę, by nie zezwalać na wszyst-kie tagi, a szczególnie na te narażające serwis na nie-bezpieczeństwo, jak chociażby tag <script>. Wpro-wadzone zmiany w ustawieniach możemy już za-twierdzić. Jak widać nasz PostNuke nieco się zmie-nił (Rysunek 7.).

Następną sprawą jest rejestracja użytkowników – trzeba ją skonfigurować, by była dobra wg nas i przyjazna użytkownikom (Rysunek 8.). Od razu w oczy rzuca się ograniczenie wiekowe – czy przy-da nam się to np. na stronę hobbystyczną? Raczej nie, chyba że tworzymy jakąś stronę, na którą le-galny dostęp powinni mieć tylko pełnoletni. Dru-ga sprawa – przy podawaniu danych wybieramy tylko login i podajemy adres e–mail – na ten adres zostaje wysłane wygenerowane hasło, które po za-logowaniu możemy zmienić. Nic nie stoi na prze-szkodzie, by umożliwić od razu ustawianie hasła oraz dodanie dodatkowych pól, takich jak imię, nazwisko, czy też identyfikatory komunikatorów. W tym celu wchodzimy w panelu administracyj-nym w moduł Użytkownicy, wybieramy “konfigu-racja rejestracji użytkowników”. Widoczne opcje:

• Każdy e–mail może zostać użyty tylko raz – jeśli ustawimy opcję na tak, nie będzie możliwości ponownego zarejestrowania się z tym samym adresem e–mail

• Pokazuj opcjonalne pola – pokazuje pola z dodatkowymi informacjami, które mo-żemy dowolnie sobie zdefiniować pod lin-kiem “Dynamiczne dane użytkownika” – jest to bardzo duża zaleta tego systemu

• Zezwól na rejestrację nowych użytkowni-ków – możemy wyłączyć tutaj rejestrację, je-śli np. do serwisu ma mieć dostęp tylko ad-ministrator i rezygnujemy z logowania użyt-kowników, gdyż jest ono nam niepotrzebne

• Weryfikuj adres e–mail podczas rejestracji – jeśli ustawimy tę opcję na nie, będzie można podać od razu swoje hasło przy rejestracji

• Powiadomienie o nowych użytkownikach – można podać tam adres e–mail, na któ-ry będą przychodzić maila powiadamiają-ce nas o nowych rejestracjach

• Zarezerwowane nazwy użytkowników – oddzielamy tam przecinkiem nicki użyt-kowników, których nie będzie można użyć podczas rejestracji

• Pytanie i odpowiedź antyspamowa – wpi-sujemy pytanie, na które trzeba poprawnie odpowiedzieć, by się zarejestrować. Ma to na celu uniemożliwienie rejestracji botom spamujących np. komentarze. Przykłado-wo: pytanie – jak ma na nazwisko prezydent Polski, odpowiedź – Kaczyński. Jeśli użyt-kownik wpisze coś innego (czyli zazwyczaj bot będzie próbował podać jakieś dane), system odmówi mu rejestracji

Rysunek 7. Zmieniony PostNuke

Rysunek 8. Domyślny formularz rejestracji

Page 67: PHP Solutions 04 2007 PL
Page 68: PHP Solutions 04 2007 PL

4/2007

Narzędzia

68

• Zakazane adresy e–mail i klienci HTTP – w tych polach można wypisać po przecinku dane domeny e–mail oraz adresy klientów HTTP, którzy nie będą mogli się zarejestrować

• Minimalny wiek – wiek, który będzie poja-wiał się w informacji o ograniczeniu wieko-wym przy rejestracji. Jeśli ustawimy go na 0, informacja ta nie będzie się już pojawiać

• Minimalna długość hasła użytkownika• Domeny IDN – zezwala na podanie adre-

sów domen ze znakami narodowymi• Logowanie/wylogowywanie zgodne z

WCAG – aktywacja tej opcji spowoduje, że przekierowania po zalogowaniu nie bę-dą odbywać się na stronie niezgodnej ze standardami WCAG. Jest to opcja zbęd-na, gdyż nikt nie sprawdza poprawności stron podczas przekierowań.

Standardowe moduły nie koniecznie muszą słu-żyć w naszym serwisie – nie zawsze nas zado-wolą, a może i nawet będą miały dla naszego ser-wisu zbyt dużo funkcji. Krótka charakterysty-ka powinna dać nam podstawowe rozeznanie w tych modułach. Do panelu zarządzania mo-dułami wchodzimy klikając na ikonkę Moduły. Aby dodać nowy moduł wgrywamy jego kata-log do katalogu modules (zawsze tak, aby w modu-les znajdowała się nazwa modułu, np. TagIt, a w tym folderze pliki modułu), klikamy w admini-stracji modułami Regeneruj, po czym odszukuje-my danego modułu (bardzo łatwo wybierając po-kazywanie modułów niezainicjowanych lub pod daną literką). Aby moduł działał należy kliknąć inicjalizuj– w tym momencie dodawane są nowe tabele do bazy danych. Na koniec należy kliknąć już tylko na link aktywuj i moduł jest gotowy do użytku. Do każdego modułu możemy dodawać wtyczki (link Wtyczki). Możemy także nazywać moduły jak chcemy – np. Downloads wcale nie musi się tak nazwywać, po kliknięciu na Edytuj możemy ustawić nową nazwę na np. Pobieral-nia, wtedy adres modułu będzie wyglądał tak: in-dex.php?name=Pobieralnia. Jeśli nie lubimy prze-chodzić przez strony modułów, możemy usta-wić liczbę wyświetlanych modułów na liście np. na 100 pod linkiem modyfikuj konfigurację. Li-sta i krótki opis standardowych modułów pełnej paczki PostNuke 0.764 PL:

• AddStory – odpowiada za dodawanie artykułów/newsów i ich kategorii

• Admin – moduł panelu administracyjnego• Admin_Messages – moduł komunikatów,

które mogą być widoczne dla wszystkich, tylko dla gości lub tylko dla adminów. Ko-munikaty można wstawić do bloku menu

• Autolinks – ciekawy moduł umożliwiający podlinkowanie danych słów kluczowych, np. chcemy skierować wszystkie słowa jajko występujące na stronie do danej podstrony

• AvantGo – moduł dla wersji mobilnej strony, praktycznie bez grafiki i zbędnych obiektów, bardzo rzadko używany

• Banners – moduł służący do wyświetlania bannerów na stronie, posiada funkcje do-dawania klientów, zliczania kliknięć ban-nerów danego klienta, ustawiania limitu odsłon. Ponad to można osobne typy ban-nerów wyświetlać w osobnych blokach statycznie lub na zasadzie rotatora

• Blocks – odpowiada za zarządzanie bloka-mi, pozwala przenosić bloki menu, two-rzyć nowe, edytować je i usuwać

• Censor – odpowiada za filtrację niecenzu-ralnych słów, które możemy sami dodawać

• Comments – wtyczka umożliwiająca komen-towanie newsów i ankiet. Standardowo jej układ jest bardzo nieprzejrzysty, dlatego war-to zmienić tę wtyczkę na CommentsEx (ulep-szona wersja tego samego modułu) lub Ez-Comments (całkowicie inny moduł, posiada możliwość importu starych komentarzy)

• Credits – wyświetla informacje o licencji PostNuke oraz zainstalowanych modułów

• Downloads – odpowiada za pliki do po-brania, ma możliwość grupowania plików w kategorie, zlicza kliknięcia, pozwala na ocenianie plików itp.

• Ephemerids – prosty moduł kalendarza• Example – testowy moduł stworzony tyl-

ko po to, by programiści mogli się na nim wzorować tworząc swoje moduły

• FAQ – odpowiada za rozbudowany skrypt FAQ – najczęściej zadawanych pytań

• Groups – odpowiada za grupy użytkow-ników (administratorzy, moderatorzy, użytkownicy, zbanowani itp.), pozwala dodawać swoje grupy, a także usuwać ist-niejące

• Header_Footer – moduł generujący header strony oraz jej stopkę w podstawowym sys-temie szablonów, inne systemy, takie jak np. AutoTheme, już z niego nie korzystają

• legal – zawiera informacje o polityce pry-watności, warunkach korzystania z serwi-su itp., które można edytować

• LostPassword – odpowiada za przypo-mnienie hasła

• Mailer – moduł obsługuje całą pocztę, wszystkie maile wysyłane przez stronę. Po jego zdeaktywowaniu nie przychodzą np. maile z hasłem do logowania

• MailUsers – bardzo prosty moduł sub-skrypcji (bez możliwości wyboru czy użytkownik chce dostawać maile, czy nie)

• Members_List – podstawowa lista zareje-strowanych użytkowników, zawiera też rozbudowaną listę użytkowników online

• Messages – moduł prywatnych wiadomo-ści (używany także w dodatkowych mo-dułach forum)

• Modules – odpowiada za zarządzanie wszystkimi modułami

• Multisites – pozwala na łączenie kilku stron w jedną, tj. różnych stron korzystają-cych z tego samego skryptu i bazy danych, nawet na różnych domenach

• News – moduł odpowiadający za newsy i artykuły

• NewUser – odpowiada za rejestrację użyt-kowników

• Permissions – rozbudowany i z początku trudny w obsłudze moduł uprawnień (czyli zezwoleń co może użytkownik, co gość itp.)

• pnRender – wsparcie Smarty dla PostNu-ke, korzysta z niego także Xanthia (można rzec, że Xanthia i pnRender tworzą pod-stawowy system szablonów PN, dlatego te moduły powinny być razem aktywne)

• pn_bbcode – wtyczka umożliwiająca uży-wanie BBCode

• pn_bbsmile – wtyczka umożliwiająca uży-wanie emotoikon

• Polls – moduł ankiet• Quotes – wyświetla cytaty• Ratings – wtyczka do oceniania, np. new-

sów, recenzji• Recommend_Us – moduł na zasadzie “po-

leć nas”• Referers – moduł pełniący rolę statystyki

polecających stronę adresów• Reviews – odpowiada za recenzje, jest do-

myślnie zintegrowany z wtyczką Ratings• RSS – kanał RSS• Search – wyszukiwarka, ma możliwość

prostego podpięcia wtyczek z nowo zain-stalowanych modułów

• Sections – sekcje, rozbudowany i prosty moduł artykułów z większym poziomem zagnieżdżenia

• Settings – ustawienia strony• Sniffer – moduł sprawdzający identyfikator

przeglądarki oraz inne dane o użytkowniku• Stats – prosty moduł zapisujące statystyki

odsłon strony, niestety często błędnie• Submit_News – przydatny moduł umożli-

wiający pisanie newsów/artykułów przez

Rysunek 9. Menu administratora Rysunek 10. Menu użytkownika

Page 69: PHP Solutions 04 2007 PL

PostNuke

69

użytkowników, które później muszą być zaakceptowane przez administratora

• Topics – moduł pełni rolę kategorii dla większości modułów, innymi słowy po-zwala na grupowanie publikacji z różnych modułów w jeden temat, któremu można przypisać zdjęcie

• Top_List – pokazuje listę najczęściej czyta-nych tekstów, komentowanych artykułów, pobieranych plików itp.

• typetool – standardowy edytor WYSIWYG• User – zawiera funkcje użytkownika (wy-

logowywanie itp.)• Web_Links – prosty katalog stron z po-

działem na kategorie• Wiki – wtyczka umożliwiająca formatowa-

nie tekstu na takiej zasadzie jak w Wikipedii• Xanthia – podstawowy system szablonów• Your_Account – moduł twoje konto

Wersja PostNuke Lite 0.764 ma tylko 22 podsta-wowe moduły, co przekłada się na optymalność skryptu. Dodatkowo uciecha dla “grzebaczy” – instalujemy po kolei wszystkie moduły niezwią-zane z jądrem, które nam pasują. Jak widać każ-da część systemu jest także osobnym modułem, dlatego moduły często są porównywane do kloc-ków, z których składamy stronę na planszy, czyli na silniku CMSa. Co jeszcze warto wiedzieć ogó-łem o PostNuke? Jego system wielojęzykowości pozwala na dodawanie osobnych newsów, pod-stron, bloków itp. dla każdego z języków, dlate-go też przy zmianie języka automatycznie może zmienić się nam menu oraz wyświetlić się mo-że całkiem inna lista newsów. PostNuke ma tak-że zaawansowany, aczkolwiek nieintuicyjny, sys-tem uprawnień. To, czego nie ma większość dar-mowych CMSów, tutaj jest i sprawuje się bardzo dobrze. Możemy praktycznie określić dowolną regułę uprawnień dla osobnego użytkownika lub dla całej grupy (to jest bardziej zalecane, mniej ob-ciąża serwer), dzięki czemu Alfred będzie mógł dodawać pliki do downloadu, a Henio nawet nie będzie mógł tam wejść, za to grupa Koledzy He-nia będzie administrować downloadem. Należy tu pamiętać o hierarchii uprawnień – na począt-ku dodajemy zezwolenia, później zakazy, na po-czątku grupy o większych uprawnieniach (tak jak np. admini), później dopiero użytkownicy i goście (niezalogowani). Reguły można przesuwać w górę i w dół, w zależności od ich ważności. Po-le komponent oznacza część serwisu, której doty-czy uprawnienie, .* – zastępuje wszystko (czyli w tym przypadku tyczy się całego serwisu), ale gdy wpiszemy nazwę modułu z podwójnym dwu-kropkiem na końcu, np. News::, reguła będzie się tyczyła tylko modułu News. Instancja jest zależna

od danego modułu – schemat uprawnień każde-go modułu powinien być dostępny do sprawdze-nia w pliku version.php lub pnversion.php (zależy czy to moduł starej, czy nowej generacji) znajdu-jącego się w katalogu modułu. W przypadku blo-ków instancja wygląda tak: Nazwa bloku:Dana pozycja: . W instancji można grupować kilka po-zycji w tablice używając nawiasu i znaku |, któ-ry rozdziela poszczególne pozycje. Zatem upraw-nienie Menu główne:(Moje konto|Wyloguj|Prześlij nowiny): dotyczy tylko linków Moje konto, Wylo-guj i Prześlij nowiny w bloku menu o nazwie Menu główne. Reguła ta jest ustawiona dla niezalogowa-nych, a poziom uprawnień to “żaden”, więc nieza-logowani nie będą widzieć tych linków. Ciąg .* za-stępuje wszystkie instancje. Sytuacja z uprawnie-niami użytkowników wygląda identycznie, z tym wyjątkiem, że zamiast grupy wybieramy użyt-kownika. Skuteczność poziomu uprawnień tak-że zależy od modułu, jednakże poziom Admini-stracja zawsze daje “pełną władzę”.

Uprawnienia to bardzo duży plus tego syste-mu CMS, dzięki nim jak widać można uzależ-nić wyświetlanie nawet prostych linków w me-nu! Tak samo jedno uprawnienie może działać na konkretny plik w pobieralni, lub na wszyst-kie. Aby uniemożliwić pobieranie jednego pliku Antkowi, wstawiamy uprawnienie:

Antek | Downloads:: | ::27 | Żaden

gdzie 27 to ID pliku. Zamiast ID można przed podwójnym dwukropkiem wstawić nazwę da-nego pliku – efekt będzie taki sam. Ważną rze-czą są także bloki – odpowiadają one za genero-wanie całego menu strony. Domyślne pozycje bloków to lewo, prawo i środek – każdy blok można wstawić do odpowiedniej pozycji, a każ-dą pozycję wstawić w odpowiednie miejsce w szablonie skórki. Jeśli te 3 pozycje to dla nas za mało, zawsze możemy się ratować dodając so-bie tzn. bloki area, których mogą być nawet setki. Ciekawą opcją jest to, że bloków nie trze-ba usuwać – można je zdeaktywować i w do-wolnym czasie ponownie zaktywować. Pod lin-kiem zmień konfigurację możemy wyłączyć stan-dardową możliwość zwijania bloków – tj. obra-zek minusa obok nazwy bloku, który pozwala go ukryć pozostawiając sam tytuł. Strzałki w ko-

lumnie “porządek” pozwalają na prostą zmianę kolejności wyświetlania bloków. Bloki nie są jed-nego typu, standardowo mamy do wyboru róż-ne rodzaje bloków, takie jak np. blok menu, blok HTML, blok PHP, blok ankiety, blok wyświetla-jący ostatnio dodane newsy, ale możemy także doinstalować bloki (np. pokazujące użytkowni-ków online). Jeśli doinstalowany moduł ma pod-katalog pnblocks, możemy być pewni, że na liście wyboru bloków ukażą się nowe pozycje tego mo-dułu. Dodajmy zatem testowy blok. Klikamy na Nowy blok. Jeśli pokaże się pusta strona będzie to oznaczać, że jeden lub więcej modułów ma niepoprawną składnię kodu bloków, dlatego me-todą prób i błędów trzeba będzie ten moduł od-naleźć (najlepiej usuwając podkatalogi pnblocks z nowo zainstalowanych modułów). Niech nasz blok będzie typu HTML, abyśmy mogli wsta-wić dowolny kod HTML. Przy dodawaniu blo-ku możemy ustawić, czy ma być on zwinięty i w jakiej postaci ma się domyślnie pokazywać. Możemy także dodać różne bloki dla różnych ję-zyków. Z listy rozwijalnej Blok wybieramy inte-resujący nas blok. Wszystkie pozycje poprzedzo-ne tekstem Core należą do jądra CMSa. Standar-dowo pozycje na liście wyglądają tak:

• Core/Pokazywanie banerów – pozwala na wy-świetlenie jednego banneru lub wszystkich bannerów w rotatorze z modułu Banners

• Core/Dzisiejszy najważniejszy artykuł – po-kazuje link do artykułu, który w dniu dzi-siejszym był czytany największą ilość razy

• Core/Blok linku Button – pozwala na pro-ste dodanie popularnych buttonów na stro-nę, standardowo o rozmiarze 88x31

• Core/Menu kategorii – pokazuje menu wy-boru kategorii w postaci listy

• Core/Simple File Include – wczytuje pliku z podanego przez nas adresu

• Core/FXP Currency Exchange – przelicz-nik walut

• Core/HTML – blok pozwala na wstawie-nie dowolnego tekstu z możliwością for-matowania go przez HTML

• Core/Logowanie użytkownika – jak sama nazwa wskazuje pokazuje formularz logo-wania użytkowników na stronie

• Core/Menu generowane – generator menu w stylu drzewka lub listy linków

• Core/Online – pokazuje ilość gości i użyt-kowników online oraz informacje i pry-watnych wiadomościach

• Core/Starsze artykuły – wyświetla newsy, które nie pokazują się już na stronie głów-nej oraz starsze dodane artykuły w serwi-sie według naszych kryteriów

• Core/Skrypt PHP – pozwala na wstawienie dowolnego kodu PHP

• Core/Prezentacja ankiety – wyświetla ankie-tę – najnowszą lub wybraną przez nas z ist-niejących

• Core/Linki relacyjne artykułu – wyświetla linki powiązane z danym artykułemRysunek 11. Stworzony blok Rysunek 12. Ankieta

Page 70: PHP Solutions 04 2007 PL

4/2007

Narzędzia

70

• Core/Stopka z nowinami RSS – pozwala na wyświetlenie kanału RSS ze ścieżki do pli-ku źródła RSS

• Core/RSS Extra – funkcjonalność taka sama jak powyżej z tym wyjątkiem, że możemy wy-brać jeden z istniejących już kanałów na liście

• Core/Box Szukaj – pokazuje wyszukiwarkę• Core/Tytuły artykułów – wyświetla ostat-

nio dodane artykuły, możemy zdefinio-wać ich ilość, kategorię oraz temat

• Core/Pełny tekst – wyświetla podany przez nas tekst

• Core/Języki – pokazuje listę wyboru języka• Core/Menu tematów – pokazuje listę wy-

boru skórki• Core/Box zwykłego użytkownika – pokazu-

je blok użytkownika (każdy użytkownik domyślnie może w panelu swojego konta stworzyć sobie blok np. z notatkami)

• Core/Ostatnie linki Web – wyświetla ostat-nio dodane linki do katalogu

• Admin/Show admin categories and modules – wyświetla blok administratora, rozwią-zanie podobne jak w CMSie Xaraya

• Admin_Messages/Show Admin Messages – wy-świetla komunikaty modułu Admin_Messages

• pnRender/custom pnRender block – blok, w którym możemy używać znaczników pnRender (Smarty)

• pnRender/pnRender Loginblock – wyświetla blok logowania z szablonu pnRender

• Xanthia/Logo Block for Xanthia Themes – blok z logo skórek Xanthia

• Xanthia/Display module output in a block – pozwala na wyświetlenie modułu zgodne-go z Xanthia w bloku

Po wybraniu Aktulizuj możemy wstawić treść do wybranego bloku. Jak widać nie sprawia też pro-blemu aktulizacja danych z zewnętrznych źródeł co jakiś czas, np. w przypadku bloku RSS nie mu-simy martwić się o aktulizację linków. PostNuke oferuje nam edycję strony generatora standardowe-go bloku menu z linkami do danych modułów bez konieczności zmian w szablonie na naszym serwe-rze! Wybierzmy edycję naszego bloku Menu głów-ne, który jest typu Core/Menu. Edycja jest bardzo prosta – możemy m.in. zmienić wyświetlanie me-nu ze standardowego na “ostylowaną” listę, która często używana jest do wyświetlania menu w po-staci drzewka. Do każdego z linków możemy do-dać opis, który będzie widoczny w dymku po na-jechaniu myszką na dany link. Jeśli dodamy pozy-cję z tytułem nie podając URL, zostanie wyświetlo-ny tylko tekst w tytule. Usuwanie i dodawanie lin-ków odbywa się poprzez zaznaczenie odpowied-niego checkboxa w dwóch ostatnich kolumnach. Nie musimy także męczyć się z wpisywaniem lin-ków do modułów – w polu URL wystarczy wpi-sać nazwę modułu w kwadratowym nawiasie, a system sam wstawi odpowiedni link. Dla testu zmieńmy pozycję Tematy na Google z URL http://www.google.pl, a w pustym polu pod pozycją Wy-loguj dodajmy sam tytuł Dodatkowe.

Dodatkowe moduły, ich dostosowanie i optymalizacjaZainstalujmy teraz nowy moduł. Niech to bę-dzie dodatkowy system szablonów AutoThe-me, pozwalający na uruchamianie dużo pro-ściej konstruowanych skórek. Moduł ten za-wieraj wtyczkę krótkich linków do PostNu-ke (temat przyjaznych linków wraz z zastoso-waniem AutoTheme na CMSach opisany był w PHP Solutions Nr 6/2006 [17]) oraz jest dużo prostrzy do nauki tworzenia skórek. Jest to du-żo popularniejszy system szablonów, pomimo że nie znajduje się on w standardowej paczce PostNuke. Instalujemy AutoTheme tak jak każ-dy inny moduł z tym wyjątkiem, że nadpisu-jemy także pliki z folderu Blocks. Ma to na ce-lu umożliwienie używania bloków area AT w standardowym module bloków. Modułem tym zajmiemy się później tworząc własny sza-blon. Jeśli mamy zamiar instalować dużo mo-dułów tworząc wielką stronę o ogromnej ilości zróżnicowanej treści, warto zainteresować się modułem Pagesetter. Jest to chyba największy moduł jaki kiedykolwiek powstał na PN, a przy okazji jest nowoczesny i dobrze napisany. Mó-wiąc w skrócie można nim zrobić wszystko. Administrator post–nuke.pl mówi nawet żar-tobliwie: dla mnie to PostNuke jest dodatkiem do Pagesettera, a nie odwrotnie. Moduł ten po-

zwala na tworzenie własnych typów publika-cji, definiowania w nich swoich pól, nie musi-my trzymać się jakiegoś schematu – sami decy-dujemy jak dana publikacja ma wyglądać! Ła-two jest zrobić tym sposobem system newsów, artykułów, pobieralnię plików, katalog stron, czy nawet rozbudowaną galerię zdjęć. Najlep-sze w tym wszystkim jest to, że sami ustalamy szablony do każdej publikacji, wybieramy od-powiadające nam plugin do szablonów i ma-my pełną kontrolę nad tym co robimy, gdyż Pagesetter nie narzuca żadnego kodu, ani roz-wiązań, jak to bywa w innych modułach. Je-go system kategorii pozwala na nieskończe-nie głębokie zagnieżdżanie podkategorii. Jedy-nie jego trudność obsługi może przeszkadzać początkującym w tym module, dlatego na po-czątek przygody z PN nie jest on polecany. Na-sze moduły możemy także usprawnić. Nieste-ty temu CMSowi daleko do ideału, jest napisa-ny nieoptymalnie, a starsze moduły są nieprze-myślane. Spójrzmy chociażby na kwestię ilości newsów na stronie głównej – możemy wybrać z listy 5, 10, 15, 20 i więcej. Co jednak, jeśli chcemy, by ilość newsów wynosiła 7? A może 13? Zawsze można modyfikować konfigurację w bazie danych, ale gdzie tu wygodne rozwią-zanie? Takie rzeczy naszczęście nawet począt-kujący programista może ulepszyć sam! Nie

Listing 1. Nieoptymalny kod w pliku admin.php

.'<select name="xstoryhome" size="1">'

."<option value=\"5\"".$sel_storyhome['5'].">5</option>\n"

."<option value=\"10\"".$sel_storyhome['10'].">10</option>\n"

."<option value=\"15\"".$sel_storyhome['15'].">15</option>\n"

."<option value=\"20\"".$sel_storyhome['20'].">20</option>\n"

."<option value=\"25\"".$sel_storyhome['25'].">25</option>\n"

."<option value=\"30\"".$sel_storyhome['30'].">30</option>\n"

."</select>"

Listing 2. Warunek do modyfikacji

if ($info['withcomm'] == 0) {

if ($info['comments'] == 0) {$comment = _COMMENTSQ;

}else if ($info['comments'] == 1) {

$comment = '1 ' . _COMMENT;

}else { $comment = "$info[comments] "._COMMENTS; }

}

Listing 3. Zawartość pliku version.php

<?

$modversion['name'] = 'Modtest'; // nazwa modułu

$modversion['version'] = '1.0'; // wersja modułu

$modversion['description'] = 'Moj pierwszy modul'; // opis modułu

$modversion['credits'] = 'Autorem jestem tylko ja'; // uznania

$modversion['help'] = 'pomoc.txt'; // plik pomoc

$modversion['changelog'] = ''; // plik informacji o zmianach

$modversion['license'] = ''; // licencja modułu

$modversion['official'] = 0; // czy moduł jest oficialny 1 – tak, 0 – nie

$modversion['author'] = 'Autor to ja'; // autor modułu

$modversion['contact'] = '[email protected]'; // kontakt

$modversion['admin'] = 0;

?>

Page 71: PHP Solutions 04 2007 PL

PostNuke

usprawiedliwia to jednak tego, że przez tyle lat rozwoju PostNuke nie pomyślano o zwykłym polu tekstowym z wpisywaniem ilości new-sów. Aby dokonać takiej modyfikacji wchodzi-my w folder modułu Settings i otwieramy w do-wolnym edytorze plik admin.php. Odnajduje-my linię 300 i jej okolice (Listing 1.). na taki:

if ($info['withcomm'] == 0) {

$comment = _COMMENTS.': '.$info[comments];

}

i zamieniamy ten typowo nieestetyczny i starego typu kod, na którym absolutnie nie należy się wzorować, na taki: .'<input name="xstoryhome" />' Minusem tego rozwią-zania jest to, że przy każdej edycji ustawień należy podać tam jakąś liczbę, aby wszystko poprawnie się zapisało. Ambitni programi-ści mogą tę modyfikację wzbogacić o pobiera-nie aktualnej ilości newsów do value tego po-la input. Spójrzmy także na newsy – domyśl-nie układ linków Czytaj więcej z ikonką dru-kowania i polecania w każdej skórce jest taki sam. W dodatku PostNuke w nawiasie pokazu-je ilość bajtów tekstu, wstawionego w tekst roz-szerzony artykułu (tekst rozszerzony widoczny jest tylko po wejściu do artykułu). Czy jakie-goś użytkownika interesuje informacja o baj-tach? A może chcemy usunąć ikonkę poleca-nia artykułu bez pozbywania się modułu Po-leć nas? Wystarczy nieco zmodyfikować głów-

ne funkcje newsów, które znajdują się w kata-logu modules/News w pliku funcs.php. Co m.in. możemy zmienić? Linia 208, zmiana tytułu newsa/artykułu:

$info['catandtitle'] =

$info['cattitle'].": ".$info['title'];

Jeśli wybraliśmy kategorię dla newsa, jej na-zwa będzie poprzedzać jego tytuł przed dwu-kropkiem. Możemy całkowicie wyrzucić po-kazywanie kategorii w tytule lub dodać ją np. w nawiasie:

$info['catandtitle'] = $info['title'].

' ('.$info['cattitle'].')';

Linia 417:

$preformat['catandtitle'] =

"$preformat[category]: $preformat[

title]";

zamieniamy na:

$preformat['catandtitle'] =

$preformat[title].' (

'.$preformat[category].')';

Linia 312, pozbywanie się ilości bajtów:

$bytesmorelink = "$bytesmore "._BYTESMORE;

Zamieniamy na:

$bytesmorelink = '';

Lina 412:

$preformat['more'] .= "$preformat[readmore]

($preformat[bytesmore]) ";

zamieniamy na:

$preformat['more'] .=

$preformat[readmore];

Linie 333–341, zmiana schematu wyświe-tlania ilości komentarzyDomyślnie wyświe-tlana ilość komentarzy w przypadku jednego komentarza to 1 komentarz, a w większej ilo-ści ilość komentarzy. Jeśli komentarzy jest np. 2, to mimo tego widzimy tekst 2 komentarzy zamiast 2 komentarze. Można by dodać do-datkowy warunek do kodu, ale prościej bę-dzie po prostu wyświetlać ilość komentarzy po dwukropku, np.: komentarzy: 27, komen-tarzy: 1. W tym celu modyfikujemy waru-nek (Listing 2.). Od teraz nasze newsy będą wyglądały ciekawiej. Nic nie stoi na przeszko-dzie, by plik ten całkowicie przerobić pod swoją stronę – wystarczy znajomość podstaw PHP. Standardowy system komentarzy nie zadowala pewnie wielu użytkowników. Wy-świetla komentarze w postaci drzewka, jest

R E K L A M A

Page 72: PHP Solutions 04 2007 PL

4/2007

Narzędzia

72

nieintuicyjny i nie posiada szybkiej odpowie-dzi (musimy klikać na przycisk Wyślij komen-tarz lub linki Odpowiedz na to). Ratować mo-żemy się alternatywami. Dostępne są modyfi-kacje standardowego modułu – prosta mody-fikacja Comments mod by Izydor usprawniają-ce komentarze jak i ich layout oraz rozbudo-wana wersja NS–Comments Ex, która pomimo tego, że nie została wydana w nowej wersji fi-nalnej, pozbawiła modułu komentarzy zbęd-nych pól, a ponad to wyświetla avatary użyt-kowników przy komentarzach, ma jednolity layout oraz opcję szybkiej odpowiedzi pod ko-mentarzami. Możemy jednak wybrać alterna-tywny moduł pod nazwą EzComments – peł-ni on rolę wtyczki, którą możemy zaktywo-wać do dowolnego modułu. Nie ma on jed-nak możliwości zagnieżdżania komentarzy. Standardowo pozwala na import komentarzy z modułu Comments (który przy użyciu Ez-Comments należy wyłączyć). Wszystkie mo-duły są do pobrania na oficjalnej stronie Po-stNuke Polska. Co z optymalizacją? Nieste-ty trzeba to odważnie powiedzieć – PostNu-ke nie ma dobrze zoptymalizowanego kodu, a także przez lata nie zmieniło się wiele w kie-runku jego rozwiązań. Spójrzmy np. na bazy danych – ten CMS używa klasy AdoDB do obsługi wielu baz danych, pomimo że pozwa-la na korzystanie jedynie z MySQL. AdoDB to dość stara i wolna klasa, więc nie powinna być tutaj używana. Kolejna sprawa to kod – dotychczas kod całego PN nie wyglądał zbyt ciekawie, był pisany na zasadzie kod w kodzie – aby zedytować layout danego modułu trze-ba było modyfikować jego kod w funkcjach echo porozrzucanych śmiesznie po plikach. Obecnie 90% PostNuke korzysta już z pnRen-der, dlatego moduły mają osobne szablony tworzone zgodnie ze Smarty. W większości przypadków rozwiązanie te jeszcze bardziej spowalnia PostNuke, ale za to zyskujemy czy-sty kod. Ratować możemy się świetnym sys-temem cachowania (możliwość włączenia w administracji Xanthia i pnRender) oraz bufo-

rowania. Włączenie tych opcji daje wspania-łe rezultaty. Niestety także zapytania do ba-zy danych nieraz nie są optymalizowane. Do-brym przykładem jest pobieranie wszystkich newsów tylko po to, by je policzyć – a na tej podstawie wyświetlany jest pager na stronie głównej. Jeśli korzystamy z pagera i mamy dużo odwiedzin, warto pager wyłączyć lub zastąpić ten moduł jakimś alternatywnym. Nie zawsze trzeba przerzucać się na coraz lepsze serwery gdy strona się rozrasta – mu-simy pamiętać o zaawansowanych funkcjach szablonów, używaniu tylko nowszych modu-łów i używaniu jak najmniejszej ilości modu-łów. Wiele porad i tricków na temat optymali-zacji tego CMSa można znaleźć także na jego oficialnym polskim forum – większość stron da się prosto odciążyć. Bardziej zaawansowa-ni programiści PHP mogą pokusić się o stwo-rzenie własnego modułu. Na początek można posłużyć się modułem Example lub zacząć od prostego modułu, który będzie np. wyświetlał tekst Witaj w moim pierwszym module. W tym celu należy stworzyć katalog z nazwą modu-łu, dajmy na to Modtest. Struktura plików w najprostrostrzym module z własnym blokiem i panelem administracyjnym wygląda tak:

• index.php – główny plik odpowiadają-cy za wyświetlanie modułu, będziemy go wywoływać w PostNuke z adresu in-dex.php?name=Modtest

• admin.php – odpowiada za funkcje w pa-nelu administracyjnym

• version.php – zawiera informacje o module• Katalog images – zawiera obrazki modułu,

np. admin.gif z ikonką administracji• Katalog lang lub pnlang – zawiera podkata-

logi z plikami językowymi, np. eng z języ-kiem angielskim, pol z polskim. W każdym takim podkatalogu powinien znajdować się plik global.php ze stałymi językowymi

• Katalog blocks lub pnblocks – zawiera pli-ki php pełniące rolę bloków (tworząc swój blok najlepiej jest wzorować się na jakimś

z bloków typu Core w katalogu includes/blocks; blok modułu, jeśli jest poprawnie napisany, automatycznie pojawia się na li-ście przy tworzeniu nowego bloku)

Zacznijmy od opisania swojego modułu w pliku version.php (Listing 3.). Tworzenie mo-dułów jest bardzo proste. Plik index.php prak-tycznie nie daje nam żadnych ograniczeń, mo-żemy korzystać ze swoich funkcji oraz funk-cji PostNuke (jak chociażby klasy AdoDB do ob-sługi bazy danych). Stworzyć moduł wyświe-tlający tekst Witaj w moim pierwszym modu-le będzie bardzo prosto. Plik index.php powi-nien wyglądać tak (Listing 4.). Jak widać bez problemu możemy używać dowolnych funk-cji PHP jak i funkcji API PostNuke (pnUser-GetVar('uname') w tym przypadku pobiera nazwę użytkownika, parametr 'uid' pobrał by ID użytkownika itp.). Zaprogramujmy także prosty panel administracyjny. Plik admin.php powinien wyglądać tak (Listing 5.).

Struktura tego pliku jest bardzo podobna do index.php. W starszych wersjach PostNu-ke sprawdzało się, czy użytkownik jest admi-nistratorem – w nowszych wersjach PN robi to już za nas. W tym pliku po prostu programu-jemy nawigację po panelu administracyjnym, wszystkie funkcje i cokolwiek chcemy, by by-ło widoczne w administracji naszym modu-łem. Wystarczy teraz już tylko skopiować nasz folder Modtest do katalogu modules na serwe-rze, zainicjować i zaktywować moduł, po czym sprawdzić jego działanie. Temat modułów jest dosyć głęboki, a kiedy nie ma ograniczeń, mo-żemy działać cuda. Nic nie stoi także na prze-szkodzie, a nawet jest to wskazane, by do mo-dułów użyć systemu szablonów z pnRender, w czym pomoże dokumentacja. Polskich modu-łów do tego CMSa jest dość mało, nic nie stoi na przeszkodzie, aby któryś z czytelników wy-kazał się nowym pomysłem – może później dodać projekt do http://noc.postnuke.com (stro-na developerów) jak i do downloadu PostNu-ke Polska.

System szablonówStandardowy system szablonów Xanthia w Po-stNuke jest trudniejszy do pojęcia niż Auto-Theme. Oferuje on jednak większe możliwo-ści, większą swobodę i lepsze efekty w opty-malizacji. Mimo tego skórki pod ten system to mniejszość. Jednakże jeśli chcemy stwo-rzyć prawdziwą i poważną stronę, nie należy traktować wszystkiego na zasadzie tworzenia w 5 minut z darmową, ogólnodostępną skór-ką. Stwórzmy coś własnego, na początek naj-lepiej w AutoTheme. AT jest modułem bardzo prostym, nasza skórka składa się tam z zaled-wie kilku plików:

• theme.html – główny szablon strony• summary.html – szablon newsa na stronie

głównej

Listing 4. Zawartość pliku index.php

<?

// Sprawdzanie czy moduł został poprawnie wywołany (czy nie wpisano np. ścieżki

modules/

if (!defined('LOADED_AS_MODULE')) {

die ("You can't access this file directly...");

}

// wczytywanie headeru strony (generuje górny szablon)

include('header.php');

?>

Witaj w moim pierwszym module. Dzisiaj mamy dzień

<?=date('d.m.Y')?>, jesteś zalogowany jako <?=pnUserGetVar('uname')?>

<?

// wczytanie stopki strony (generuje dolny szablon)

include('footer.php');

?>

Page 73: PHP Solutions 04 2007 PL

PostNuke

73

• article.html – szablon pełnego newsa oraz artykułu

• leftblock.html – szablon lewych bloków• rightblock.html – szablon prawych bloków• centerblock.html – szablon środkowych bloków• theme.cfg – konfiguracja skórki• theme.php – plik identyczny we wszyst-

kich skórkach AutoTheme, wczytuje on od-powiednie funkcje systemu szablonów

Obrazki znajdują się w podkatalogu skórki ima-ges, a style w podkatalogu skórki style w pliku sty-le.css. Pliki theme.cfg i theme.php warto wyciągnąć z dowolnej skórki pod AutoTheme (w paczce z modu-łem są przykładowe skórki), gdyż theme.php jest za-wsze taki sam, a theme.cfg i tak ulegnie zmianie po skopiowaniu go na serwer z chmod 777. Interesu-ją nas teraz głównie znaczniki, które wstawia się do poszczególnych plików: theme.html:

• <!––[modules]––> – Wyświetla moduły• <!––[date]––> – Wyświetla datę• <!––[time]––> – Wyświetla czas• <!––[user]––> – Wyświetla nazwę użyt-

kownika• <!––[user–welcome]––> – Wyświetla po-

witanie użytkownika• <!––[user–login]––> – Wyświetla pozio-

my panel logowania• <!––[user–links]––> – Wyświetla linki

do logowania / rejestracji oraz wylogowa-nia / mojego konta

• <!––[banners]––> – Wyświetla bannery• <!––[banners–typeX]––> – Wyświetla

bannery wg. ID X • <!––[footer–msg]––> – Wyświetla stopkę• <!––[open–table]––> – Rozpoczyna tabelę• <!––[close–table]––> – Zamyka tabelę• <!––[open–table2]––> – Rozpoczyna

subtabelę• <!––[close–table2]––> – Zamyka tabelę

• <!––[table–content]––> – Wyświetla za-wartość tabeli

• <!––[site–slogan]––> – Wyświetla slo-gan strony

• <!––[site–name]––> – Wyświetla nazwę strony

• <!––[search]––> – Wyświetla wyszuki-warkę ze wszystkimi pluginami wyszuki-wania

• <!––[logo–image]––> – Wyświetla logo strony

• {image–path} – Zwraca ścieżkę do obraz-ków skórki (katalog images)

• {theme–path} – Zwraca ścieżkę do skórki

bloki:

• <!––[block–content]––> – Wyświetla za-wartość bloku

• <!––[block–title]––> – Wyświetla tytuł bloku

• <!––[left–blocks]––> – Wyświetla lewe bloki

• <!––[center–blocks]––> – Wyświetla środkowe bloki

• <!––[right–blocks]––> – Wyświetla pra-we bloki

artykuły/newsy:

• <!––[article–edit–del]––> – Wyświetla lin-ki do edycji i usuwania dla administratorów

• <!––[article–full]––> – Wyświetla peł-ną treść artykułu/newsa

• <!––[article–more]––> – Wyświetla link czytaj więcej, ikonkę drukowania, ikonkę polecania

• <!––[article–notes]––> – Wyświetla no-tatki dla artykułu/newsa

• <!––[article–summary]––> – Wyświetla wstęp artykułu/newsa

• <!––[cat–title]––> – Wyświetla tytuł poprzedzony kategorią

• <!––[posted–by]––> – Wyświetla autora tekstu

• <!––[posted–date–time]––> – Wyświe-tla datę dodania tekstu

• <!––[topic–image]––> – Wyświetla zdję-cie tematu

• <!––[article–reads]––> – Wyświetla ilość odsłon

Można także używać znaczników zdefiniowa-nych kolorów od {color1} do {color10}

Co wniesie nowa wersja? – PodsumowanieJak widać PostNuke ma wiele zalet, ale wad także mu nie brakuje. Niestety wersje 0.76x nie będą już kontynuowane, więc poprawek uciążliwych błędów się nie doczekamy. Jednak wersja 0.8 jest już od długiego czasu w budowie. Jest ona pisa-na w większości od nowa, dlatego silnik będzie dużo nowocześniejszy. Ostatnio wydano wersję Milestone 3, czyli wczesną niedopracowaną wer-sję testową, aby programiści mogli sprawdzić z nią swoje moduły. Dopiero w tej wersji wiele się zmienia. A co czeka nas nowego?

• Wsparcie dla Oracle, PostgreSQL i MsSQL• Całkowicie nowy moduł Search działający z

każdym modułem dzięki uniwersalnemu API• Uniwersalny moduł kategorii – Categories

– będzie on używany w każdym module do tworzenia kategorii. Koniec z katego-riami dla każdego modułu z osobna

• Moduły podzielono na systemowe i dodat-kowe – domyślnie w paczce znajdziemy standardowe moduł potrzebne do urucho-mienia PN w katalogu system, a resztę w katalogu modules

• Poprawiono obsługę błędów• Cały system będzie obsługiwać nowy moduł

szablonów (tylko jeden) oparty o pnRender, czyli taka nowsza Xanthia. Nie będzie nato-miast "kodu w kodzie", wszystko będzie zapi-sywane w szablonach pnRender

• Stworzono moduł do tłumaczeń, podobny do translatora w CMSie Xaraya

• Poprawiono bezpieczeństwo

Moim zdaniem warto wybrać PostNuke jako przyszłościowy CMS – ma duże możliwości, a zachowuje przy tym uniwersalność. Jest to do-bra podstawa do nauki o CMSach dla każdego początkującego programisty PHP.

MICHAŁ GACKIJest programistą-samoukiem. Od najmłodszych lat interesuje się informatyką, a najbardziej pro-gramowaniem, które jest jego pasją. Pracuje w za-łożonej przez siebie grupie (obecnie nie tylko pro-gramistycznej) pod nazwą Bil Software.Kontakt z autorem: [email protected]

Listing 5. Zawartość pliku admin.php

<?

// Sprawdzanie czy moduł został poprawnie wywołany (czy nie wpisano np. ścieżki

modules/

if (!defined('LOADED_AS_MODULE')) {

die ("You can't access this file directly...");

}

// wczytywanie headeru strony (generuje górny szablon)

include('header.php');

if (isset($_GET['action'])) {

if ($_GET['action'] == 'date') {

?>Dzisiaj mamy <?=date('d.m.Y')?>

<? } else { ?>Taka opcja nie istnieje!<? } } ?>

<p>

Witaj w panelu administracyjnym. Panel jest tymczasowo w budowie.<br />

<a href=”admin.php?module=Modtest&amp;action=date”>Wyświetl dzisiejszą datę</a></p>

<?

// wczytanie stopki strony (generuje dolny szablon)

include('footer.php');

?>

Page 74: PHP Solutions 04 2007 PL

4/2007

Testy konsumenckie

74

Punkt to nazwa firmy, która dziś kojarzy się niemal każdemu mieszkańcowi Opo-la, Nysy oraz miejscowości ościennych z

atrakcyjną ofertą stałego dostępu do Internetu, jeszcze kilka lat temu była całkowicie nieznana. Jak wytłumaczyć fakt, iż pasja kilku świeżo upie-czonych inżynierów rozpoczynających przygodę z Internetem w małym biurze stanowiącym jed-nocześnie serwerownię przerodziła się w spraw-nie działającą organizację o mocno ugruntowanej pozycji na opolskim rynku internetowym? Od-powiedź na to pytanie kryje w sobie sekret sukce-su jaki był i jest udziałem małej firmy w walce o klienta z gigantami rynku telekomunikacyjnego.

Firma Punkt rozpoczęła swoją działalność już w roku 1998, w którym Internet był „luksusem” dostępnym dla niewielkiej grupy zainteresowa-nych, czego głównym powodem była dostępnaw tamtym okresie droga technologia dystrybucji sygnału. Z tego samego powodu początkowo fir-ma oferowała dostęp do Internetu oraz usługi ho-stingowe tylko klientom korporacyjnym. By spro-stać konkurencji i zaistnieć na rynku usług inter-netowych firma położyła szczególny nacisk za-równo na jakość oferowanego dostępu do Inter-netu, jak i elastyczność oferty w pełni odzwier-ciedlającej potrzeby klienta. Szybko okazało się, że opieka informatyczna roztaczana nad klien-tem oraz troska o jego zadowolenie stało się moc-nym atutem firmy, wyróżniającym ją na tle pozo-stałych operatorów oraz przyczyniło się w bezpo-średni sposób do postrzegania Punkt jako partne-ra w interesach. Ciągłe inwestycje w rozbudowę

infrastruktury sieci pozwoliło firmie oferować swoje usługi na terenie całego miasta i świadczyć je każdej zainteresowanej firmie. Z upływem cza-su, zmieniające się warunki rynkowe oraz wzrost zapotrzebowania na usługi dostępowe ze strony odbiorców indywidualnych skłoniło właścicie-li firmy do poszerzenia wachlarzu świadczonych usług i rozpoczęciu inwestycji związanych z bu-dową okablowania strukturalnego w budynkach należących do największych opolskich spółdziel-ni mieszkaniowych. Postępująca rozbudowa sieci pozwoliła firmie na oferowanie dostępu do Inter-netu w ponad 45 000 mieszkaniach Opola i Ny-sy. Fakt ten przełożył się na ilość obsługiwanych klientów, których liczba w 2007 roku osiągnęła ponad 5000. By zaspokoić potrzeby tak dużej licz-by abonentów firma Punkt musiała wypracować efektywny system obsługi klienta, pozwalający na utrzymanie bezpośrednich relacji z klientem, któ-ry swój wyraz znalazł we wdrożonym w firmie Systemie Zarządzania Jakością ISO 9001-2000. Sytuacja, w której klient nie ma możliwości bez-pośredniego kontaktu ze swoim dostawcą usług jest pierwszym krokiem do zerwania z nim kon-taktu oraz brakiem zrozumienia potrzeb i oczeki-wań klienta, a co za tym idzie wzrostem jego nie-zadowolenia. Równie istotnym czynnikiem, który pozwolił na rozwój firmy do obecnej postaci by-ło i jest jednakowo troskliwe podejście do każdego klienta niezależnie od rodzaju usługi z jakiej korzy-sta. Bez względu na biznesowy czy indywidualny charakter, poziom oferowanego serwisu jest jedna-kowy. Zarówno klient korporacyjny, jak i indywi-

dualny otrzymuje od firmy w pełni serwisowaną usługę z towarzyszącym jej 24-godzinnym wspar-ciem administratorów oraz działu technicznego. Biuro Obsługi Klienta jest do dyspozycji zaintere-sowanych 6 dni w tygodni w szerokim przedziale czasowym od wczesnych godzin rannych do póź-nych godzin popołudniowych. Niezależnie od po-ry dnia, każdy klient może zgłosić swoje potrzeby bądź zażądać obsługi serwisowej korzystając z de-dykowanych numerów alarmowych. Prócz cało-dobowej opieki na uwagę zasługuje fakt szybkiej reakcji na otrzymane zgłoszenia nie przekracza-jący 4 godzin. Oczywiście na zadowolenie klien-ta prócz wymienionych wyżej czynników składa się również jakość oferowanych usług oraz szeroka oferta handlowa. Jakość usług bezpośrednio zwią-zana jest z kompetencjami pracowników Punkt oraz wydajnością infrastruktury obsługującej abo-nentów. Team Punkt stanowi młoda kadra absol-wentów wrocławskich i opolskich uczelni wyż-szych w szczególności o profilach informatycz-nych, która przez 9 lat działalności firmy pozyska-ła niezbędne kwalifikacje i praktyczne umiejętno-ści w prowadzeniu szczególnej działalności usłu-gowej jaką jest ISP. Infrastruktura sieciowa pod-lega natomiast nieprzerwanej ewolucji. W zależ-ności od dostępności nowinek technologicznych oraz rodzaju oferowanych usług modernizacja sie-ci polega na unowocześnieniu serwerów i urzą-dzeń dostępowych bądź na zastępowaniu me-dium transmisyjnego innym bardziej wydajnym. Kierunki rozwoju infrastruktury oraz jej moder-nizacji ściśle związane są z aktualnie panującymi trendami rynkowymi. Patrząc wstecz na kształt i szkielet infrastruktury można zauważyć, że fir-ma przeszła kilka etapów technologicznych po-cząwszy od asynchronicznych modemów kablo-wych, które pod koniec lat 90. oferowały zawrot-ne jak na te czasy przepustowości kilkuset kilobi-tów, przez modemy xDSL, radiolinie 802.11 b-g, 802.11 a. Dziś szkielet infrastruktury stanowią światłowody oraz profesjonalne systemy radiowe pracujące w paśmie koncesjonowanym. Obecny stan sieci pozwala na świadczenie usług Triple play i to właśnie w perspektywie najbliższych miesięcy stanowi główny cel firmy. Już dziś natomiast każ-dy abonent indywidualny może skorzystać z do-stępu do Internetu w pakietach od 512 kbps do 4 Mbps. W przypadku abonentów biznesowych je-dynym ograniczeniem szybkości oferowanego In-ternetu stają się lokalne warunki techniczne wpły-wające bezpośrednio na medium, z wykorzysta-niem którego abonent otrzyma usługę dostępu do Internetu.

Pomimo napotkanych trudności, silnej kon-kurencji, potrzeby ciągłego udoskonalania in-frastruktury sieciowej i nakładów inwestycyj-nych z tym związanych, firma Punkt utrzy-muje na opolskim rynku dominującą pozycję w śród komercyjnych ISP.

Dyrektor Działu Sieci firmy P.I. PUNKT Sp. z o.o.Jerzy Kołodziej

WWW.PUNKT.PL

Page 75: PHP Solutions 04 2007 PL

Stałe łącza internetowe

www.phpsolmag.org 75

Początkową działalnością naszej firmy było głównie projektowanie, wdraża-nie i utrzymywanie witryn interneto-

wych. Obecnie specjalizujemy się w budowa-niu i wdrażaniu unikalnych systemów bazo-danowych, sklepów internetowych (eCommer-ce), systemów zarządzania treścią stron inter-netowych (Content Management System) oraz systemów do obsługi Biuletynów Informacji Publicznej. Główni odbiorcy naszych usług to instytucje publiczne oraz firmy sektora MSP.

Pracownicy naszej firmy posiadają wy-kształcenie wyższe o kierunkach informa-tycznych i ekonomicznych oraz wielolet-nie doświadczenia w branży usług interneto-wych i programistycznych. Rozwój naszej fir-my został ukierunkowany przede wszystkim na udostępnianie bezpiecznej platformy sys-temów zarządzania treścią aplikacji interne-towych, dających klientom szerokie możli-wości samodzielnego redagowania treści udo-stępnianych w sieci Internet. Podczas wdraża-nia produktów obligatoryjnie prowadzone są szkolenia z zakresu obsługi systemu, udostęp-niane są szczegółowe instrukcje obsługi oraz profesjonalna pomoc techniczna.

Od kilkunastu miesięcy z powodzeniem opracowywane są (jako nowa linia produk-tów) aplikacje multimedialne. Są to prezen-tacje na nośnikach CD/DVD oraz interak-tywne mapy wyposażone w system zarządza-nia punktami aktywnymi na mapie oraz sko-relowaną informacją tekstową i graficzną. Już na starcie naszej działalności postanowiliśmy, że będziemy kładli duży nacisk na jakość ofe-rowanych usług. W ten sposób od razu wyklu-czyliśmy stawianie własnych serwerów inter-netowych w miejscach, które nie zapewnia-ją należytej ochrony zarówno pod względem technologicznym jak i dostępu fizycznego do pomieszczeń. Dlatego też oczywiste stało się, że nasze serwery będą umieszczane na zasa-dach kolokacyjnych w profesjonalnych cen-

trach danych. Z tego powodu łącze interne-towe, jakie potrzebowaliśmy do biura, miało i ma po dzień dzisiejszy charakter łącza pra-cowniczego.

Zmieniając kolejne rozwiązania w poszuki-waniu tego, które nam najbardziej by odpo-wiadało, korzystaliśmy w swojej historii z róż-nych technologii dostępu do Internetu. W po-przedniej lokalizacji biura mieliśmy większe możliwości wyboru operatorów.

Po przeprowadzeniu się w miejsce, gdzie znajdujemy się obecnie, różnorodność ope-ratorów posiadających infrastrukturę kablo-wą w naszym sąsiedztwie została zawężona praktycznie do jednej firmy. Przez dłuższy czas korzystaliśmy właśnie z tego rozwiąza-nia, ale niestety nie zapewniało nam ono od-powiednich warunków do pracy. Zbyt mała, jak na nasze potrzeby, dostępna prędkość łącz oraz częste awarie doprowadzały naszą cierpli-wość do granic wytrzymałości. Należy zwró-cić uwagę również na fakt, że obsługa posprze-dażna tamtej firmy, realizacja reklamacji oraz czas reakcji na awarie również pozostawiały wiele do życzenia.

Sytuacja taka miała miejsce do czasu, gdy w czasie spotkania z przedstawicielami fir-my P.I. Punkt Sp. z o.o. okazało się, że ta fir-ma może nam dostarczyć wydajne i stabilne łącze za pomocą technologii radiowych. Firmę Punkt znaliśmy od dawna. Jest ona, obok na-szej firmy, jedną z kilku liczących się przed-siębiorstw informatycznych w regionie reali-zujących między innymi zaawansowane ser-wisy internetowe. Pomimo tego, nigdy nie rozważaliśmy możliwości podłączenia do In-ternetu za pośrednictwem firmy Punkt. Ta-ki stan rzeczy miał miejsce aż do momentu wspomnianego już spotkania, na którym wy-mieniając się wzajemnie naszymi spostrze-żeniami dotyczącymi działalności obu firm, między innymi wspominaliśmy o naszych problemach z łączami internetowymi. Od mo-mentu nawiązania tego kontaktu wydarzenia potoczyły się dosyć szybko.

Pracownicy firmy Punkt pojawili się w na-szej firmie, dokonali niezbędnych pomiarów jakości połączenia radiowego z naszej lokali-zacji. Po tych wydarzeniach, nie trwało dłu-go, jak otrzymaliśmy z firmy Punkt ofertę łą-cza internetowego dla naszej firmy. Była ona na tyle konkurencyjna, że również podjęcie naszej decyzji nie wymagało zbyt wiele cza-su. W ten sposób już od kilku miesięcy jeste-śmy klientem firmy Punkt korzystając z dostę-pu do Internetu zestawionego dla nas przez tę firmę. W tym czasie nie odnotowaliśmy jakiś większych problemów ze stabilnością łącza, podobnie obsługa posprzedażna Biura Obsłu-gi Klienta firmy Punkt nie dostarcza nam żad-nych powodów do narzekań.

Z dotychczasowych łącz dostępowych do Internetu zrezygnowaliśmy pozostawiając tylko jedne, które służy tylko jako ewentual-

ne rozwiązanie zapasowe. Kontynuując do-brą współpracę nawiązaliśmy pomiędzy na-szymi firmami również szereg innych kon-taktów biznesowych i wspólnie dążymy do współdziałania również w innych tematach. Efektem tych działań jest wyrażana niejed-nokrotnie chęć współpracy przy realizowa-nych przez naszą firmę lub przez firmę Punkt przedsięwzięciach.

Od pewnego czasu korzystamy również z rozwiązań telefonii VoIP oferowanych przez firmę Punkt. Elastyczne podejście do klien-ta w tym zakresie oraz znacznie niższe ceny usług skłoniły nas do wybrania również i tego rozwiązania. Z tej usługi jesteśmy zadowoleni do tego stopnia, że nasze dotychczasowe linie telefoniczne służą nam już praktycznie tylko do odbierania połączeń.

Kolejną płaszczyzną współpracy pomiędzy naszą firmą i firmą Punkt są obecnie wspól-ne prace rozwojowe i administracyjne prze-prowadzane na naszych serwerach interne-towych. Korzystając z naszych doświadczeń oraz specjalistów firmy Punkt stale dosto-sowujemy stosowane u nas rozwiązania do obecnych wymogów bezpieczeństwa oraz wy-dajności.

Podsumowując dotychczasową współpra-cę z firmą Punkt muszę przyznać, że nie po-jawiły się dotychczas żadne zdarzenia mogą-ce mieć negatywny wpływ na wizerunek oraz jakość usług tej firmy. Z wybranych rozwią-zań oraz z dotychczasowego przebiegu współ-pracy pomiędzy naszymi firmami jesteśmy w 100% zadowoleni. Wszystko wskazuje na to, że w przyszłości będziemy mogli równie pochlebnie wypowiadać się o dostarczanych nam usługach przez firmę Punkt.

Wszystkie platformy usług, na jakich obec-nie współpracujemy, a jest to dostęp do In-ternetu, telefonia VoIP oraz usługi zarządza-nia serwerami internetowymi, w pełni speł-niają nasze oczekiwania. Nie mamy żadnych zastrzeżeń odnośnie tej oferty zarówno pod względem funkcjonalnym jak i cenowym.

Warto zaznaczyć, że na obserwowanej przez nas przestrzeni czasu firma Punkt dyna-micznie dostosowywała swoją ofertę do zmie-niających się warunków na rynku. Pochlebne opinie o usługach firmy Punkt jestem w sta-nie formułować z pełnym przekonaniem, po-nieważ prywatnie również korzystam z dostę-pu do Internetu oferowanego klientom indy-widualnym przez tę firmę i również jestem bardzo zadowolony z tej usługi. Gdybyśmy w obecnej chwili ponownie dokonywali wyboru związanego z tymi usługami to sądzę, że wy-bór byłby taki sam jak ten, dokonany w prze-szłości. W pięciopunktowej skali ocen jedy-ną właściwą oceną firmy Punkt jest ocena naj-wyższa, czyli pięć punktów.

Sławomir Milewski

netkoncept.com

Ocena: «««««

Page 76: PHP Solutions 04 2007 PL

4/2007

Testy konsumenckie

76

Przedsiębiorstwo Wielobranżowe Vegas Sp. z o.o. to firma skoncentrowana w swoich produktach i usługach na rynek związa-

ny z rozrywką i hazardem. Na ten rynek dostar-czamy np. kompleksowy system telemetrycz-ny (VAC.SMS/GPRS), który zbudowany jest w warstwie sprzętowej (VAC Moduł) jak i progra-mistycznej (VAC System) przez naszych specja-listów. Wszystkie dane jakie spływają (transmi-sja GPRS ewentualnie komunikaty SMS) z poje-dynczych urządzeń monitorowanych przez nasze moduły są gromadzone na centralnym serwerze, do którego dostęp zapewniony jest poprzez webo-we aplikacje klienckie. Innymi produktami, które wykorzystują serwery internetowe i bezpieczną transmisję danych są:

• Wirtualne Centrum Rozrywki, które w wersji FUN nadaje się do użycia w każdej sieci internetowej (np. operator sieci osie-dlowej czy telewizji kablowej może udo-stępnić swoim klientom gry z tego pakietu w formie programu lojalnościowego itp.); wersja Real Money - przeznaczona jest dla podmiotów posiadających odpowiednie zezwolenia i koncesje;

• SmartCasino - videoloterie w oparciu o który działa jedna z największych sieci vi-deoloteryjnych w Czechach.

Początki wyglądały jednak inaczej, a osiągnię-ty sukces jest wypadkową własnych pomysłów, kompetencji zgromadzonych wewnątrz firmy, jak również jakości partnerów. Do grona klu-czowych i strategicznych partnerów zaliczamy firmę Punkt, z którą współpracujemy właściwie od początku powstania Vegas Sp. z o.o. Począt-kowo działalność firmy skupiała się na produkcji multimediów i aplikacji prezentacyjnych dystry-buowanych na nośnikach CD. Wraz z rozwojem rynku usług internetowych działalność firmy została rozszerzona o produkcję witryn inter-netowych, w początkowej fazie typowo statycz-

nych, a następnie z wykorzystaniem języków skryptowych wykonywanych po stronie serwera oraz baz danych. Skupiliśmy się wówczas na pro-duktach adresowanych do większych odbiorców biznesowych (np. system zakupowy B2B), któ-rzy oczekiwali jednocześnie kompleksowej ob-sługi w tym zakresie. Konsekwencja obrania ta-kiego kierunku oraz chęć uelastycznienia ofer-ty automatycznie wygenerowała konieczność za-jęcia się również usługami hostingowymi. Wów-czas na rynku było już parę interesujących firm, którym można było powierzyć tę część działal-ności, ale konkurencja, a co za tym idzie atrak-cyjność ofert w owych latach, pozostawiała wie-le do życzenia, dlatego postanowiliśmy zająć się również hostingiem. Jako że zasoby sieciowe (w tym serwery) chcieliśmy mieć pod ręką, ko-nieczne było pozyskanie stabilnie działającego łą-cza internetowego o odpowiedniej przepustowo-ści. Rozpoczęliśmy poszukiwania dostawcy In-ternetu działającego na rynku lokalnym. W ten oto sposób zetknęliśmy się z ofertą firmy Punkt, która prócz przyzwoitych warunków cenowych dawała nam solidne wsparcie techniczne w po-staci wykwalifikowanej kadry administratorów sieciowych, gotowych nieść pomoc bez zbęd-nej zwłoki 24h na dobę, przez wszystkie dni ty-godnia. Wobec takich gwarancji nie mogliśmy pozostać obojętni i postanowiliśmy zaryzyko-wać - z perspektywy czasu już wiemy, że było warto. Od tego momentu sprawy toczyły się już szybko. Łącze internetowe zostało zrealizowane sprawnie i terminowo, a co najważniejsze dzia-łało stabilnie i zgodnie z deklarowanymi przez Punkt, podczas zawiązywania się współpracy, pa-rametrami. Do momentu załatwienia formalno-ści związanych ze zmianą adresacji IP, w czym Punkt wykazał się również dużą sprawnością, utrzymywaliśmy dotychczasowe łącze operato-ra wiodącego, z którego mogliśmy już, pozbawie-ni wszelkich obaw, spokojnie zrezygnować. Na tym etapie rozwoju firmy zaangażowaliśmy się w projekt, który trwa nieprzerwanie do dzisiaj, a mianowicie tworzenie oprogramowania do wi-deo gier działających w modelu on-line (służą do budowania kasyn internetowych i sieci videolo-teryjnych), co w skali kraju i Europy jest przed-sięwzięciem unikatowym.

Dzisiaj marka Vegas w tej dziedzinie jest już dobrze rozpoznawalna i znajduje uznanie na wielu rynkach europejskich. Projekt absorbował nas w stopniu powodującym konieczność albo rozbudowy zasobów ludzkich, albo skorzystania z pomocy firmy zewnętrznej, w zakresie obsługi usług sieciowych. Tutaj również firma Punkt, ze względu na spójny z potrzebami zakres kompe-tencji, okazała się pomocna. W pierwszej kolejno-ści zleciliśmy firmie Punkt administrację zasoba-mi hostingowymi (serwery, routery, firewall, po-lityka bezpieczeństwa) naszych serwerów oraz obsługę techniczną. Po jakimś czasie zdecydowa-liśmy się całkowicie przekazać Punkt obsługę ho-stingu, tym bardziej że ówczesne standardy ob-sługi wymagały zapewnienia panelu administra-

cyjnego, którym Punkt dysponował, a dodatko-wo rozwiązanie było korzystne z ekonomiczne-go Punktu widzenia. Obecność i rosnąca pozy-cja firmy Punkt w rankingu TOP100 (obsługiwa-nych domen), utrzymywała nas w przekonaniu, iż przekazujemy zdobywanych przez lata klien-tów w dobre ręce. Równie istotna też dla nas oka-zała się zapowiedz ze strony Punkt przygotowań do rozbudowy i przeniesienia wszystkich zaso-bów serwerowych mających związek z hostin-giem z ich dotychczasowej serwerowni na tere-nie miasta Opole do profesjonalnego centrum danych mieszczącego się w Warszawie. Tak się faktycznie za jakiś czas stało. Należy przy tym za-uważyć, iż całość prac z tym związanych odbyła się niemalże w sposób niezauważalny dla klien-ta, świadczy to o dużej dbałości firmy w podej-ściu do klienta (rozumieniu jego potrzeb), a tak-że dbałości w planowaniu działań w najdrobniej-szych szczegółach. Naturalną konsekwencją po-myślnych doświadczeń we współpracy z firmą Punkt, było powierzenie jej opieki nad serwera-mi, jakie wykorzystujemy do obsługi naszych systemów wideo gier on-line. Jako że każda po-tencjalna przerwa w działaniu tego systemu po-woduje znaczne i wymierne straty finansowe, serwery za namową Punkt są również kolokowa-ne w centrum danych.

Budując zespół zawsze kierujemy się zasadą doboru ludzi kompetentnych, wykazujących się dużą kreatywnością, potencjałem, odpowiedzial-nością, umiejętnością radzenia sobie w trudnych sytuacjach oraz nieprzeciętnym zakresie wiedzy merytorycznej. Te same kryteria stosujemy w od-niesieniu do współpracy z firmami zewnętrzny-mi i Punkt nie jest tutaj wyjątkiem, dlatego z czy-stym sumieniem zachęcamy naszych klientów do korzystania z usług świadczonych przez tę firmę, gdyż można na niej polegać. Cenimy ją szczególnie za wysoką jakość obsługi technicz-nej oraz zdroworozsądkowe podejście do pro-blemów, z jakimi mieliśmy do czynienia w ca-łym długoletnim okresie współpracy. Mimo iż skala działalności Punkt stale się poszerza, nig-dy nie czuliśmy się zaniedbywani czy traktowani z dystansem. Firma wykazuje się dużą determi-nacją w osiąganiu celów, idzie z duchem czasu i nie poddaje się coraz trudniejszemu i ciaśniejsze-mu rynkowi usług dostępowych, o czym świad-czy stale rosnąca liczba obsługiwanych klientów. Potwierdzeniem najwyższych standardów jako-ści jest uzyskany przez Punkt, w ostatnim czasie, certyfikat systemu zarządzania jakością według norm ISO 9001:2000, co dla branży w jakiej działa firma nie jest szczególnie powszechnym zjawiskiem. Podsumowując, w żaden sposób nie żałujemy wyborów, jakich dokonaliśmy na dro-dze historii współpracy z firmą Punkt, byłyby one identyczne, gdyby przyszło nam raz jeszcze się z nimi zmierzyć. Bezdyskusyjnie, przyzna-jemy firmie najwyższą z możliwych ocen, czyli pięciogwiazdkowa.

Dariusz Lewandowski

P.W. Vegas Sp. z o.o.

Ocena: «««««

Page 77: PHP Solutions 04 2007 PL
Page 78: PHP Solutions 04 2007 PL

78

Recenzja

Fireworks 8 jest programem graficznym o dużych możliwościach, za pomocą którego możemy zaprojektować zarówno: cały layout witryny www, jak i poszczególne jej elementy takie jak: animowa-ne banery, przyciski czy ikony. Fireworks i Dreamweaver to popu-larne narzędzia używane przez webmasterów, które wzajemnie się uzupełniają.

Książka Macromedia Fireworks 8. Oficjany podręcznik to nieocenione źródło wiedzy skierowane do początkujących osób, które pragną poznać obsługę i użytkowanie programu Fireworks 8, a być może później zostać projektantem stron WWW. Dobrą rekomandacją może być fakt, że książka poleca-na przez firmę Macromedia, czyli twórcę tego programu.

Przystępny język, logiczny podział całego materiału na 11 lek-cji, sprawia że raczej nikt nie powinien mieć problemów ze zro-zumieniem i wykonaniem poszczególnych ćwiczeń. Każda z lekcji poprzedzona jest krótkim wprowadzeniem do ćwicze-

nia. W formie wypunktowanej listy wyszczególnione są zagad-nienia które powinniśmy opanować po przerobieniu danej lek-cji, oraz czas potrzebny na wykonanie ćwiczenia. Na dołączo-nej do książki płycie, znajdziemy również materiały dodatko-we, czyli materiały źródłowe potrzebne do nauki.

Trudność jest stopniowana, i tak pierwsze lekcje opisują podstawy, m.in.: palety narzędziowe oraz menu programu. Najczęściej używane narzędzia zostały omówione na podsta-wie konkretnych przykładów, tak więc nawet laik, nie powi-nien mieć trudności w przyswojeniu materiału zawartego w tej książce.

Po skończeniu lektury, będziemy mogli spróbować zapro-jektować własną stronę www, wygenerować jej kod HTML do Dreamwevera, zoptymalizować grafikę, tak by przyspieszyć jej wczytywanie, a także w jaki sposób zautomatyzować niektóre czynności w Fireworks 8.

Wydawnictwo: HelionAutor: Patti SchulzeCena: 49,00 złStron: 296 + CDISBN: 83-246-0314-Xhttp://www.helion.com.pl

Bardzo często główną przeszkodą na posiadanie własnej profesjo-nalnej strony www, szczególnie dla małych firm z ograniczonym budżetem, lub osób prywatnych, może być brak odpowiednich umiejętności, niezbędnych do zaprojektowania i wykonania strony internetowej, oraz dość wysokie koszty, jeżeli wykonanie i aktuali-zację zlecimy wyspecjalizowanej firmie.

Jednak nie powinniśmy załamywać rąk z tego powodu, ponie-waż możemy skorzystać z coraz powszechniej stosowanego syste-mu zarządzania treścią CMS (ang. Content Menagement System). Dzięki któremu sami możemy aktualizować nasze strony w łatwy sposób, bez znajomości HTML, czy innych języków programowa-nia, służących do tworzenia stron.

Obecnie jest kilka różnych CMSów i tutaj z pomocą przychodzi nam książka CMS jak szybko i łatwo stworzyć stronę WWW i zarzą-dzać nią. Należy ją traktować jako swoisty przewodnik po najpopu-larniejszych systemach CMS.

Pierwsze rozdziały wprowadzają do CMS, szczególnie przydatne dla początkujących, a więc czym jest i czego potrzebujemy do po-prawnego zainstalowania i używania CMS. W kolejnych rozdziałach znajdziemy 6 najpopularniejszych systemów CMS: Quick CMSLite, WebText, SmodCMS, SmodBIP, Xoops, Joomla! i Mambo. Przydatne będą również informacje o ich instalacji, zarządzaniu do-datkowymi modułami, czy opisem paneli administracyjnych.

Ostatni rozdział porusza bardzo ciekawe zagadnienia prawne dotyczące materiałów publikowanych w Sieci, prawa autorskiego, jak również licencji na podstawie których CMSy są rozpowszech-niane. Książkę śmiało można polecić osobom które zastanawiają się nad stworzeniem własnej strony www i samodzielną aktualiza-cją jej za pomocą systemu CMS, a wiedziali który wybrać. Lektura książki powinna im w tym pomóc. Na uwagę zasługuje fakt że jest to jedna z pierwszych pozycji na rynku dotyczących CMS.

Zredenzował: Sławomir Zadrożny

Macromedia Fireworks 8 Oficjalny podręcznik

Wydawnictwo: HelionAutor: Paweł FrankowskiCena: 34,90 złStron: 256ISBN: 978-83-246-0809-6http://www.helion.com.pl

CMS. Jak szybko i łatwo stworzyć stronę WWW i zarządzać nią

Page 79: PHP Solutions 04 2007 PL

Felieton

www.phpsolmag.org 79

W sieci coraz częściej można natrafić na gotowe komponen-ty i rozwiązania dla webmasterów. Powstają specjalne strony, na których możemy pobrać już napisane i gotowe

do użycia systemy news-ów, sondy, kalendarze i tym podobne rzeczy bez zagłębiania się w ich strukturę. Coraz większą popularność zdo-bywają również CMS-y (systemy zarządzania treścią). Dzięki takim rozwiązaniom przy niewielkiej wiedzy i w stosunkowo krótkim czasie można stworzyć funkcjonalną stronę, w której konstrukcję zmienia-my bez ingerencji w kod, a jedynie przy pomocy administracyjnego menu. Ale czy dostępność tego typu rozwiązań wywiera dobry wpływ na osoby, które dopiero zaczynają swoją przygodę z programowa-nie i projektowaniem stron internetowych? Czy te systemy nie są rów-nież wykorzystywane przez niektórych profesjonalistów – w sposób karygodny – do wykorzystywania niewiedzy klientów i nabijania so-bie kabzy ich kosztem?

Nieraz spotkałem się już z prywatnymi ogłoszeniami typu: Wy-konam profesjonalnie stronę internetową - tanio! Za każdym ra-zem z zainteresowaniem zaglądałem na stronę takiej osoby i bar-dzo często musiałem mocno trzymać się krzesła, żeby pozostać w pozycji sprzed jej wyświetlenia. Najczęściej pierwszy rzut oka da-wał do zrozumienia, że to jakaś prowizorka mało doświadczonej osoby, która może ma pomysł, ale nie umie go poprawnie wpro-wadzić w życie.

Każdemu niezaprzeczalnie zdarzają się błędy, ale są pewne gra-nice niedoskonałości, z których większość webmasterów zdaje so-bie sprawę. Jedno pikselowe przesunięcia w grafice mogą się prze-cież zdarzyć każdemu. Źle dobrana kolorystyka, to przypuszczalnie kwestia gustu. Strona wyglądająca inaczej pod każdą przeglądar-ką – to wina Microsoftu i Billa Gatesa. Problem z kodowaniem zna-ków – przecież każdy i tak odczyta, co jest napisane. Ale najwięk-szy szok, zawsze przeżywam, gdy ciekawość zaprowadzi mnie do kodu strony.

W tym miejscu możemy spotkać ogromną liczbę różnorodnych i „nowoczesnych” rozwiązań, które z pewnością poprawią humor i podbudują nasze ego. Zaglądamy w to nieszczęsne źródło stro-ny i co widzimy? Przed naszymi oczami ukazuje się istna magia ge-neratorów stron z FrontPage na czele. Kod zaśmiecony do granic możliwości, z pojawiającymi się w każdym tagu właściwościami, które Bóg jeden wie, po co się tam znalazły, jeżeli właściwie nie są potrzebne. Ale żeby to dostrzec trzeba jeszcze rozszyfrować po-toki kodu, bez jakichkolwiek wcięć i komentarzy. Zawsze nasuwa mi się dodatkowo jedno pytanie. A gdzie w tym wszystkim podzia-ły się style, które są przecież znacznie praktyczniejsze od atrybu-tów html.

Zapewne, taki profesjonalny webmaster odpowiedziałbym nam: Style? A po co mi one, przecież mogę zrobić stronę i bez nich. Tagi

pojawiające się raz w stylu html raz w xhtml, to przecież też nor-malność. A jakakolwiek zgodność ze standardami W3C to już czy-sta abstrakcja. Przecież nie wszyscy musieli słyszeć o organizacji, która ukradkiem wiedzie swój byt gdzieś w internecie.

Innym często praktykowanym rozwiązaniem podczas tworzenia „profesjonalnej” strony jest korzystanie właśnie z gotowych roz-wiązań, które zasadniczo zostały stworzone dla osób, które ro-bią stronę dla siebie (w domyśle domową) a nie stronę „firmo-wą”. Przecież jak można potraktować poważnie osobę , która de-klaruje się jako twórca stron internetowych, gdy korzysta np. z za-implementowanego przez kogoś systemu news-ów gdzie od razu rzuca się w oczy napis informujący, przez kogo ten system został wykonany.

Po tych atrakcjach pozostają nam jeszcze profesjonalni entuzja-ści Open Source-owych CMS-ów, rozpowszechniających je jako swo-je dzieła sztuki. Wydaje mi się, że zrobienie swojej reklamowej stro-ny to nie jest aż tak duże wyzwanie, że trzeba do niego zaprzęgać od razu rozbudowany CMS. Poza tym znacznie ładniej wygląda w stopce napis informujący, że strona została wykonana przez naszą firmę, a nie w oparciu o np. Joomla czy Mambo.

Ludzie traktujący ten interes poważnie mogliby pokusić się o na-pisanie swojego CMS-a, co wcale nie jest trudne w przypadku two-rzenia go z myślą o niewielkich stronach, więc nawet jednoosobowe firmy powinny dać sobie z tym radę. Niestety natrafiłem też na fir-mę i tutaj mam na myśli prawdziwą instytucję, która rozpowszech-niała Mambo dodając swoją grafikę i pomagając w konfiguracji za naprawdę grube pieniądze.

Podejrzewam, że oferta tej firmy była raczej skierowana do ludzi, którzy nie mają zielonego pojęcia o tworzeniu stron internetowych i nie są zorientowani w całym rynku usług www – niestety parę ta-kich osób się znalazło.

Teraz zastanówmy się, jak wyglądałoby to wszystko, gdyby zamiast gotowych skryptów były rozpowszechniane tutoriale pokazujące krok po kroku czy też bardziej intuicyjnie jak napisać dany skrypt, dajmy na to pojawiający się już w tym artykule system news-ów.

Skopiowanie i bezmyślne korzystanie z czyjejś pracy byłoby wtedy niemożliwe, a jednocześnie mobilizowałoby do nauki i myślenia. A nie-stety coraz częściej ludzie mają problemy z myśleniem, bo przecież, wszystko zawsze dostają podane na tacy, bez większego wysiłku, za darmo lub za pieniądze.

Gotowe rozwiązania przeciwko zdrowemu rozsądkowi

ŁUKASZ SKOWROŃSKIAutor jest studentem III roku informatyki na Uniwersytecie w Białymstoku.Kontakt z autorem: [email protected]

Page 80: PHP Solutions 04 2007 PL

Zaprenumeruj swoje ulubione magazyny i zamów archiwalne numery!

Już teraz w kilka minut możesz zaprenumerować swoje ulubione pismo.Gwarantujemy:- preferencyjne ceny- bezpieczną płatność on-line- szybką realizację Twojego zamówienia Bezpieczna prenumerata on-line wszystkich tytułów Wydawnictwa Software!

www.buyitpress.com zamówienie prenumeraty

Page 81: PHP Solutions 04 2007 PL

Prosimy wypełnić czytelnie i przesłać faksem na numer: (22) 887 10 11 lub listownie na adres: Software-Wydawnictwo Sp. z o.o., Bokserska 1, 02-682 Warszawa, e-mail: [email protected]. Przyjmujemy też zamówienia telefoniczne: (22) 887 14 44

Imię i nazwisko............................................................................................ ID kontrahenta..........................................................................................

Nazwa firmy................................................................................................. Numer NIP firmy.......................................................................................

Dokładny adres....................................................................................................................................................................................................................

Telefon (wraz z numerem kierunkowym)................................................... Faks (wraz z numerem kierunkowym) ....................................................

E-mail (niezbędny do wysłania faktury)............................................................................................................................................................................

zamówienie prenumeraty

1 Cena prenumeraty rocznej dla osób prywatnych 2 Cena prenumeraty rocznej dla osób prenumerujących już Software Developer’s Journal lub Linux+3 Cena prenumeraty dwuletniej Aurox Linux

Jeżeli chcesz zapłacić kartą kredytową, wejdź na stronę naszego sklepu internetowego:

www.buyitpress.com

automatyczne przedłużenie prenumeraty

Suma

Tytuł Ilość numerów

Ilość zamawianych prenumerat

Od numeru pisma lub miesiąca

Opłata w zł

z VATSoftware Developer’s Journal (1 płyta CD)– dawniej Software 2.0Miesięcznik profesjonalnych programistów

12 250/1801

SDJ Extra (od 1 do 4 płyt CD lub DVD)– dawniej Software 2.0 Extra!Numery tematyczne dla programistów

6 150/1352

Linux+DVD (2 płyty DVD)Miesięcznik o systemie Linux 12 199/1791

Linux+Extra! (od 1 do 7 płyt CD lub DVD)Numery specjalne z najpopularniejszymi dystrybucjami Linuksa 8 232/1982

PHP Solutions (1 płyta CD)Dwumiesięcznik o zastosowaniach języka PHP 6 135

hakin9, jak się obronić (1 płyta CD)Miesięcznik o bezpieczeństwie i hakingu 12 1991/219

.psd (2 płyty CD)Dwumiesięcznik użytkowników programu Adobe Photoshop 6 140

.psd numery specjalne (.psd Extra + .psd Starter Kit) 6 140

2

Page 82: PHP Solutions 04 2007 PL

W sprzedaży od kwietnia

W następnym numerze PHP Solutions 5/2007 (22)

I wiele innych artykułów, których nie możesz przeoczyć!

NA CD

n Kurs Code Igniter – stwórz własny serwis

Redakcja zastrzega sobie możliwość zmiany zawartości pisma.

UWAGA KOLEJNY TEST KONSUMENCKI

n Statystyki zewnętrzne

NOWE ARTYKUŁY W DZIAŁACH:

n dla początkujących

n dla zaawansowanych

n bezpieczeństwo

NARZĘDZIA

n Code Igniter aplikacja wykorzystująca bazę danych

n PHP i Flash łączymy aplikacje z bazą danych

Page 83: PHP Solutions 04 2007 PL
Page 84: PHP Solutions 04 2007 PL