You are on page 1of 84

SPIS TREŚCI

06 AKTUALNOŚCI
Krzysztof Trynkiewicz

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

DLA POCZĄTKUJĄCYCH
10 osCommerce
Magdalena Maryańska
Magdalena 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.

PRAKTYKA
14 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.

TECHNIKA
18 CakePHP
Piotr Gapiński
Piotr 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.

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

Dyrektor wydawniczy: Sylwia Pogroszewska

Redaktor naczelny: Patrycja Wądołowska patrycja.wadolowska@software.com.pl

Redaktor prowadzący: Dorota Pączka dorota.paczka@software.com.pl

Korekta: Mateusz Lipiński mateusz@lipinski.wroclaw.pl

Kierownik produkcji: Marta Kurpiewska marta.kurpiewska@software.com.pl

Projekt okładki: Agnieszka Marchocka

Skład i łamanie: Robert Zadrożny robert.zadrozny@software.com.pl

Dział reklamy: adv@software.com.pl

Prenumerata: Marzena Dmowska pren@software.com.pl

Nakład: 6 000 egz.

4
24 Prado NARZĘDZIA
Michał Gajek
Michał opisuje zasady tworzenia stron z użyciem frameworka PRADO. 46 Agavi
W tekście znajdziesz też sposób na zrobienie prostej aplikacji – księgi Łukasz Dywicki
gości. Dzięki dużej liczbie gotowych komponentów wykorzystanie PRA- Łukasz pokaże Ci, jakie możliwości posiada framework Agavi oraz jak
DO jest bardzo wygodne. możesz je wykorzystać. Prosto przeprowadzi Cię przez instalację, a
następnie pokaże, jak utworzyć nowy projekt.
28 Python kontra PHP
Piotr Maliński 54 PDF
Piotr opisuje opensourcowy projekt Python. Z pewnością znasz już ję- Tomasz Krawczyk
zyk PHP, służący do tworzenia stron, a teraz zapraszamy Cię do przyj- Tomasz pokaże Ci, jak przygotować bibliotekę do pracy oraz utworzyć
rzenia się innemu projektowi. Piotr prezentuje go w przyjemny do czy- dokumenty PDF i wypełniać je. Musisz tylko wiedzieć, jak tworzyćo-
tania sposób analizy w kontekście PHP. biekty w PHP oraz dziedziczyć i pisać własne funkcje. Artykuł pokaże
Ci, jak możesz używać tego najpopularniejszego formatu.

BEZPIECZEŃSTWO 62 PostNuke
36 eZ Publish Michał Gacki
Juliusz Całyniuk Michał prezentuje zasady działania PostNuke. Jest to system zarzą-
Juliusz pokaże Ci, czym jest CMF oraz eZ Ecosystem. Poznasz również dzania treścią powstały na bazie starej wersji PHP-Nuke. Każdy po-
podstawy architektury eZ Publish i jej możliwości. Dzięki temu arty- czątkujący programista PHP po zapoznaniu się z artykułem będzie
kułowi dowiesz się, że eZ Publish znany jako system zarządzania tre- miał doskonałą podstawę do nauki o CMSach.
ścią możesz wykorzystać jako wzorzec projektowy. Artykuł pokazuje,
że system dostarcza doskonałe możliwości integracyjne
TESTY KONSUMENCKIE
40 RBAC 74 Stałe łącza internetowe
Adam Byrtek
Adam pokaże Ci model RBAC i nauczy, jak przy jego użyciu zaprojek- 78 RECENZJE
tować elastyczny i rozszerzalny model kontroli dostępu. Dzięki opisa-
nemu modelowi opartemu o role dowiesz się, jak łatwo administro- 79 FELIETON
wać uprawnieniami. Artykuł opisuje, jak uniknąć zaszywania kontroli Łukasz Skowroński
dostępu bezpośrednio w kodzie. Gotowe rozwiązania przeciwko zdrowemu rozsądkowi

Adres korespondencyjny: Redakcja używa systemu automatycznego składu


Software-Wydawnictwo Sp. z o.o.,
ul. Bokserska 1, 02-682 Warszawa, Polska Do tworzenia wykresów i diagramów wykorzystano program firmy
tel. +48 22 887 13 35, fax +48 22 887 10 11
www.phpsolmag.org cooperation@software.com.pl
Osoby zainteresowane współpracą prosimy o kontakt:
cooperation@software.com.pl
Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy
G DATA Software Sp. z o.o. Druk: ArtDruk

Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy
nośnikach informacje i programy były poprawne, jednakże nie bierze odpowiedzialności technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie
za efekty wykorzystania ich; nie gwarantuje także poprawnego działania programów CD-ROM dostarczonej razem z pismem.
shareware, freeware i public domain.
Sprzedaż aktualnych lub archiwalnych numerów pisma po innej cenie niż
wydrukowana na okładce – bez zgody wydawcy – jest działaniem na jego
Uszkodzone podczas wysyłki płyty wymienia redakcja. szkodę i skutkuje odpowiedzialnością sądową.

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


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

5
Aktualności

10 podstawowych zasad
prowadzenia projektów open source Trac – otwieramy własny
projekt opensource
W życiu niemal każdego dewelopera przy-
chodzi wreszcie moment, w którym uświa-
damia sobie, że większość jego wiedzy

C
została zdobyta dzięki projektom open zy wreszcie nadszedł Twój czas na
source oraz darmowym tutorialom. Wtedy zajęcie miejsca wśród społeczno-
też często zapada decyzja o zaangażo- ści deweloperskiej? Jeśli odpowiedź
waniu się w rozwój gotowych rozwią-
brzmi tak i zamierzasz dokonać tego przez
zań o ogólnodostępnym kodzie - czy to
w ramach wdzięczności, czy też z potrze- udostępnienie kodu jednego ze swoich pro-
by zaistnienia w społeczności. Bywa także, jektów, to na pewno dojdziesz do wniosku, że
że dobre pomysły z fazy planowania prze- w praktyce uruchamiasz kolejny projekt.
chodzą do fazy realizacji, tworząc równo- Dobry pomysł i jego realizacja to bowiem
cześnie wokół siebie sieć community mem-
nie wszystko, co gwarantuje, że użytkownicy
bers. Tobias Schlitt, certyfikowany przez
Zend programista, brał udział w tego typu będą wdzięczni. Jeśli prezentujemy nasz pro-
przedsięwzięciach. Efektem wielu lat pracy dukt, to musimy pokazać go jak najlepiej. W
jest opisany na jego blogu zbiór dziesięciu praktyce oznacza to, że potrzebujemy nowej
trafnych porad, które być może, po prze- witryny do obsługi naszego projektu openso- Trac oferuje także podział na kategorie w
czytaniu przygaszą lekko zapał począt- urce. wielu działach – na przykład w tzw. Road-
kujących deweloperów, ale równocześnie
Witryna ta musi być przejrzysta, łatwa w Map, która stanowi plan rozwoju naszego
gładko wprowadzą w realia prowadze-
nia projektu open source. Jeśli planuje- edytowaniu (w końcu nasz projekt powinien projektu. Możemy w niej umieszczać kolejne
my dorzucić nasze trzy grosze do wspólnej rozwijać się prężnie) i zawierać typowe mo- zadania i przypisywać je do określonych wer-
puli open source, to warto najpierw zapo- duły: dział download z podziałem na wersje, sji aplikacji, co bardzo pomaga w zarządzaniu
znać się z jego doświadczeniami. FAQ, forum dla użytkowników, system ra- projektem.
http://schlitt.info/applications/blog/ portowania błędów, system wprowadzania Lista projektów, które korzystają z Trac
index.php?/archives/541-10-golden-rules-for-
nowych pomysłów i udoskonaleń, wyszuki- jest już bardzo długa – ma ponad 100 pozy-
starting-with-open-source.html
warkę oraz dokumentację. cji i szybko rośnie. Sam skrypt zawiera w so-
XML do PHP Jak widać, udostępnienie naszego kodu bie schludny layout, zaś jego atutem jest szyb-
Czysty HTML powoli odchodzi w niepa- wymaga niejednokrotnie napisania znacznie kość działania. Jeśli zamierzamy udostępnić
mięć. Wprawdzie niedawno powołano większej jego ilości (oprogramować trzeba nasz kod światu, Trac bardzo ułatwi nam to
zespół mający pracować jeszcze nad udo-
skonaleniem wersji 4 tego języka, jednak
jeszcze stronę). zadanie.
wiadomo, dokąd zazwyczaj zmierza webde- Z pomocą przychodzi Trac – darmowy sys-
velopment. Pierwszym, świeższym podej- tem opensource w stylu Wiki, który oferuje
ściem do tematu ustandaryzowania znacz- wsparcie dla wyżej wymienionych działów i
ników był xHTML. Teraz na popularności świetnie zdaje egzamin, jeśli zależy nam na
zyskuje XML – nadaje się bowiem także do
szybkim udostępnieniu kodu w dobrym sty-
przechowywania danych oraz komunikacji
przy pomocy różnych protokołów. Jeśli więc lu – nasz czas będziemy mogli poświęcić na
jeszcze nie stosowaliśmy XML w naszych rozwój faktycznego projektu. http://trac.edgewall.org
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.net
http://pl2.php.net/xml
http://devzone.zend.com/node/view/id/1713

6 xxxxxxxxxxx
Aktualności

Resources w sesji? Czemu nie!

Konkurencja dla Wordpress? Wszyscy dobrze wiemy, jak wielkim mankamen-


tem jest niemożność używania różnego typu
danych w zmiennych sesyjnych. Przykładem

S
zybciej niż serwisów społecznościowych może być choćby identyfikator połączenia z bazą
Web 2.0 przybywa już tylko blogów. W danych. Jeśli przekażemy go do sesji, otrzymamy
Internecie mnożą się oferty serwisów, któ- ciąg niewiele mówiących znaków, a w przypad-
ku PHP5, otrzymamy informację o błędzie. Pro-
re za darmo oferują możliwość założenia własne-
blem polega na tym, że dane sesyjne przechowy-
go dziennika. Ciężko określić, który z nich wie- wane są najczęściej w plikach tekstowych, podle-
dzie prym, bowiem niemal każdy serwis społecz- gają więc konwersji na ciąg znaków. Jakkolwiek
nościowy ma wbudowaną możliwość blogowania problemem nie jest wtedy zapisanie zmiennych
dla użytkowników i jest zintegrowany z dodatko- typu string, tablic, czy obiektów, natomiast sytu-
wymi funkcjonalnościami – przykładem może acja z innymi typami jest już patowa – w przy-
padku połączenia MySQL, nie mamy szans na
być YouTube czy MySpace. Pewne jest natomiast,
osiągnięcie zamierzonego celu. Przynajmniej
że dla dewelopera PHP takie rozwiązanie nie jest teoretycznie, bowiem w praktyce możemy zse-
najlepsze – jako programiści, często potrzebuje- rializować dane połączenia, a potem je odtwo-
my dodatkowych funkcjonalności, a co za tym wano system automatycznego sprawdzania obec- rzyć. Sprytny sposób rozwiązania tego problemu
idzie – dostępu do interpretera PHP. Tego, z oczy- ności nowych wersji na oficjalnej witrynie. Do dys- zaprezentował Damien Seguy. Dodatkowo, pod
wistych względów, nie uświadczymy w przypad- pozycji mamy także edytor WYSIWYG, komen- poniższym adresem przeczytamy, jak skompre-
sować tego typu dane, by zaoszczędzić na trans-
ku darmowych serwisów typu Blogger. Przy po- tarze, wielokrotnie zagnieżdżane kategorie, ob-
ferze. Dla zaawansowanych programistów lektu-
szukiwaniu gotowych aplikacji pozwalających na sługę wielu języków, wbudowaną bazę mediów, ra obowiązkowa.
założenie własnego bloga niewątpliwie najpierw wątki RSS, filtry antyspamowe oraz to, co mo- http://www.nexen.net/articles/dossier/
trafimy na Wordpress. System ten jest bardzo po- że się bardzo przydać – system importowania i 16932-the_month_of_php_functions_:
pularny, rozwinięty i oferuje szeroką gamę dodat- eksportowania wpisów, obsługujący m.in. Word- _home_made_serialisation.php
ków dla zaawansowanych użytkowników. Moż- press. Całość może działać na bazach MySQL, Nowy zarząd PEAR
na rzec, że konkurencja nie ma nawet możliwo- MySQLi, PostgreSQL lub SQLite. Przy pomocy Grupa PEAR przechodzi zmiany. Wybra-
ści przebicia się. W praktyce, zaawansowani użyt- dzielonych zasobów, możemy z jednej instalacji ny został bowiem nowy zarząd, a co za tym
kownicy coraz częściej wybierają rozwiązania ty- poprowadzić wiele blogów. Lista użytkowników idzie, nowe cele. W chwili pisania aktualności,
pu Jogger – wpisów do takiego pamiętnika można systemu podawana jest w tysiącach, co gwaran- nie była znana jeszcze dokładna obsada trzy-
nastu wolnych stanowisk. Znane natomiast
dokonywać bezpośrednio z poziomu komunika- tuje, że zawsze możemy liczyć na pomoc społecz-
były postulaty osób mających je zająć. Ogól-
tora sieci Jabber (XMPP). Warto jednak przyjrzeć ności oraz dobrze opracowaną dokumentację. Sys- nie nie są one zbyt rewolucyjne, wyjątkiem
się także innym rozwiązaniom, bowiem z czasem tem ten dostępny jest na licencji BSD i ma zadatki jest wiadomość, umieszczona w notkach na
Wordpress także może ulec, jak to zwykle bywa, na poważnego rywala Wordpress. blogach deweloperów, na temat PEAR2 (do-
przerostowi formy nad treścią (jak np. phpBB w stępnego tylko dla PHP5). Więcej informacji
opinii wielu użytkowników). Alternatywą może http://wordpress.org na ten temat można znaleźć na blogach:
http://blog.agoraproduction.com/
być Serendipity. Co oferuje? Na dobry początek http://www.s9y.org
index.php?/archives/35-PEAR-Group-Elec-
ponad 120 dodatków. System szablonów oparto http://blogger.com tions-tomorow!-Vote-for-me!-D.html
o Smarty (obecnie jest ich kilkadziesiąt), zastoso- http://jabberstudio.org http://blog.joshuaeichorn.com/archives/
2007/04/19/pear-elections-begin-tomorrow

Stubbles – nowy framework dla PHP 5


Nowe 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.org
http://www.stubbles.org/archives

xxxxxxxxxxxxxxx 7
Opis CD

MySQL (film instruktażowy) OsCommerce (animacja)


Specjalnie dla czytelników PHP Solutions przygotowaliśmy Na płycie CD dołączonej do tego numeru magazynu umieszczo-
krótką serię filmów, których tematyka oscyluje wokół MySQL. ne zostały pliki potrzebne do uruchomienia i odpowiedniego
W pięciu krótkich filmach przekażemy Ci wiedzę dotyczącą in- działania sklepu osCommerce (wersja 1.03 PL).
stalacji i administracji serwerem MySQL. Jeżeli wcześniej nie Pliki zostały odpowiednio zmodyfikowane w celu uzyska-
miałeś styczności z tymi zagadnieniami, powinieneś obejrzeć nia nowego wyglądu - w sposób szczegółowo opisany w artyku-
ten materiał. le (osCommerce Nowy wygląd krok po kroku, Magdalena Ma-
W pierwszym filmie zajmiemy się instalacją serwera My- ryańska).
SQL oraz dodatkowo zainstalujemy serwer Apache z PHP i Ponadto na płycie znajduje się animowana instrukcja instalacji
PHPMyAdmin. W efekcie otrzymamy serwer gotowy do na- oraz konfiguracji sklepu.
uki i do pracy. W filmie pokazano krok po kroku, jak samodzielnie zainstalo-
W następnych filmach zajmiemy się administracją naszej ba- wać sklep na serwerze. Animacja składa się z trzech części - pre-
zy danych spod linii komend jak i PHPMyAdmin-a. Dowiesz się, zentacja pokazująca instalację poprzedzona jest informacjami o
jak tworzyć nowych użytkowników ze zróżnicowanymi prawa- wymaganiach oraz przygotowaniach potrzebnych do zainstalowa-
mi dostępu oraz tworzyć kopie zapasowe Twoich danych. Obie nia sklepu.
te umiejętności są niezbędne do swobodnej i bezpiecznej pracy Druga część pokazuje wszystkie kolejne etapy instalacji oraz
z MySQL. wskazuje potrzebne zmiany w plikach na serwerze.
W dwóch kolejnych filmach zajmiemy się przykładowym opro- Część trzecia natomiast przedstawia ustawienia zainstalo-
gramowaniem, które pomoże Ci w projektowaniu (DBDesigner) i wanego sklepu oraz sposoby ich modyfikacji - w tym opis pa-
zarządzaniu bazą danych (AquaDataStudio). Takie programy mo- nelu administracyjnego, zarządzanie kontami, zmiany poszcze-
gą ułatwić Ci korzystanie z MySQL. Na pewno są ciekawą alterna- gólnych wartości, edycję strony głównej, opis najważniejszych
tywą dla tradycyjnych metod. działów oraz prezentację dodawania cech do produktów.
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.

8 04/2007
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: cd@software.com.pl

Redakcja nie udziela pomocy technicznej w instalowaniu


i użytkowaniu programów zamieszczonych na płytach
CD-ROM dostarczonych razem z pismem.

www.phpsolmag.org 9
Dla początkujących

osCommerce
Nowy wygląd krok po kroku

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.
Plik stylesheet.css
Dowiesz się... Powinieneś wiedzieć... Znaczna część wyglądu sklepu określona jest
• Pokażemy, jak zmienić domyślny wygląd sklepu • Należy posiadać umiejętność zainstalowania przez plik stylesheet.css (katalog główny). Mo-
osCommerce – wyjaśnimy, w jaki sposób moż- sklepu osCommerce. dyfikując go możemy np. zmienić kolor tła ca-
na wstawić własny baner, ikony oraz przyciski, • Wymagana jest również podstawowa znajo- łej strony (będzie ono jednak widoczne tylko w
a także, jak zmienić rozmiary i kolorystykę skle- mość CSS oraz PHP. trakcie ładowania się strony, a następnie zosta-
pu oraz usunąć niepotrzebne elementy. nie przysłonięte przez kolor tła pierwszej tabeli,
• Opiszemy, które pliki umożliwią nam wprowa- która obejmuje 100% strony). Kolor tła strony
dzenie zmian oraz jakie rezultaty osiągniemy określa wartość background w klasie BODY.
modyfikując poszczególne wpisy.
Wstawiamy własny
baner oraz ikony górne
• dodatkowy margines dookoła sklepu (do- Zmieniając wpis w pliku center_shop.php usunę-
myślnie brak), liśmy już logo osCommerce wyświetlające się ja-
Poziom trudności • wyświetlanie logo osCommerce jako górny ko górny baner. Teraz umieścimy w tym miejscu
baner. nasz własny baner oraz zamienimy 3 górne do-
myślne ikony na własne. W pliku header.php kolej-
Oprócz wymienionych, znajdują się tam rów- na (trzecia) tabela wyznacza obszar zarezerwowa-

M
imo utrudnień – pamiętając o tym, nież ustawienia dotyczące wyświetlania obraz- ny na baner oraz ikon, a jej wygląd określa klasa he-
że wygląd jest równie ważny w sprze- ka (logo osCommerce) wraz z linkiem na stro- ader w pliku stylesheet.css. Modyfikujemy tę klasę
daży internetowej jak funkcjonalność nie głównej. Poprzez modyfikację odpowied- odnajdując w pliku stylesheet.css wpis TR.header
– warto poświęcić trochę czasu na opracowanie nich sekcji tego pliku, możliwa jest zmiana (wygląd wiersza w tabeli) i umieszczając w nim
własnej, ciekawszej formy. W artykule tym po- domyślnego loga na własne (wraz z linkiem) . dane odpowiedzialne za odpowiednią wysokość
każemy, że nie jest to takie trudne, zwłaszcza kie- Wygląd strony głównej łatwiej jest jednak edy- oraz wyświetlenie baneru jako tła. Po wprowadze-
dy wiadomo, gdzie należy szukać danych infor- tować za pomocą panelu administracyjnego. niu zmian nasza klasa wygląda tak:
macji. Obrazki Rysunek 1. oraz Rysunek 2. po- W naszym przykładzie zmieniona została
kazują wygląd sklepu przed i po wprowadzeniu wartość CENTER_SHOP_WIDTH (szerokość TR.header {
zmian (przeglądarka Internet Explorer, rozdziel- sklepu) na 1002 i CENTER_SHOP_BACK- background: url('baner.png') no-repeat;
czość ekranu 1024x768). GROUND_COLOR_OUT na #CDC7D8 (ko- height: 160px;
lor tła wokół sklepu). Ustawiliśmy również war- }
Zmieniamy szerokość tość HEADER_IMG_LINK_ON na 0, żeby nie
sklepu i kolor tła wyświetlać loga osCommerce w banerze. W naszym przykładzie jako tło wstawiliśmy
Plik center_shop.php (katalog includes/languages/ plik baner.png (umieszczony w katalogu głów-
polish) zawiera następujące ustawienia: Plik header.php nym) o wysokości 160 px .
Plik header.php (katalog includes) zawiera definicje
• wyśrodkowanie sklepu (domyślnie włą- głównych tabel sklepu. Pierwsza z nich to „otocz- Ikony
czone), ka” wokół sklepu, druga to sklep „właściwy”. Żeby W prawym dolnym rogu baneru wyświetlają się
• szerokość (domyślnie ustawioną na 780 px), zlikwidować dodatkowy margines wokół sklepu, trzy domyślne ikony sklepu: Moje konto, Zawar-
• wyświetlanie tła wokół sklepu (domyślnie ustawiamy wartości CELLSPACING, CELLPAD- tość koszyka oraz Zamówienie. Możemy je usunąć
włączone), DING oraz BORDER w dwóch pierwszych tabe- lub podmienić własnymi obrazkami. Aby pod-
• kolor tła wokół sklepu (domyślnie ciemno- lach na 0. W pliku tym zawarte są również infor- mienić ikony na własne, należy skopiować własne
szary), macje o górnej części sklepu: banerze, górnych iko- pliki graficzne jako: header_account.gif (Moje kon-
• kolor tła dla zawartości sklepu (domyślnie nach oraz pasku znajdującym się pod ikonami. Bę- to), header_cart.gif (Zawartość koszyka) oraz he-
biały), dziemy je modyfikować w dalszej części artykułu. ader_checkout.gif (Zamówienie) do katalogu ima-

10 04/2007
osCommerce

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ę sklepu


Pod 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 Rysunek 1. Domyślny wygląd sklepu osCommerce
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).

Ramki
W 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 2. Wygląd sklepu po dokonaniu zmian

www.phpsolmag.org 11
Dla początkujących

Przyciski Napis ten wyświetla się ciemnoszarą, pogru-


Domyślne przyciski w osCommerce, to zaokrą- bioną czcionką o rozmiarze 20px – tak samo
glone niebieskie prostokąty na białym tle, z bia- jak nazwa i cena w szczegółach produktu (okre-
łym napisem oraz ikonką. Ich pliki znajdują się w śla je ta sama klasa). Możemy zmienić te usta-
katalogu includes/languages/polish/images/buttons wienia, modyfikując w pliku stylesheet.css wpis
– możemy je przerobić lub zamienić na własne. TD.pageHeading, DIV.pageHeading. Kolejnym
Rysunek 3. Jedna z domyślnych ikonek W naszym przykładzie zmieniliśmy tylko ich ko- napisem umieszczonym na stronie głównej jest
wyświetlanych w tle
lor z niebieskiego na czerwony, który bardziej pa- Witaj Nieznajomy! – możemy go zmienić we
żemy zmienić w pliku stylesheet.css (klasa A), suje do wybranej przez nas kolorystyki. wspomnianym już wcześniej pliku polish.php
należy jednak pamiętać, że ustawienia, jakie (katalog includes/languages). Przeglądając ten
tu wprowadzimy będą dotyczyły wszystkich Usuwamy, co niepotrzebne plik znajdziemy wiele domyślnie używanych
linków w sklepie. Kolor tła dla ramek określa Na podstronach, w części środkowej, wyświe- opisów. Zawiera on m.in. tytuł strony oraz tekst
klasa infoBoxContents, a kolor obramowania tlają się domyślnie małe obrazki (Rysunek powitalny, za który odpowiada linijka:
znajduje się w klasie infoBox. Aby zmienić 3.), które nie wszystkim jednak mogą się po-
wygląd napisów na „belkach” modyfikujemy dobać. Jeśli chcemy z nich zrezygnować, mu- define('TEXT_GREETING_GUEST',
wpisy TD.infoBoxHeading w pliku styleshe- simy usunąć wszystkie pliki *.gif, których na- 'Witaj <span class="greetUser">
et.css – można zmienić rozmiar, kolor i czcion- zwa zaczyna się od table_background, z kata- Nieznajomy!</span> Czy chcesz się
kę napisu. „Belka” nad każdą ramką składa logu images (w katalogu głównym). <a href="%s"><u>zalogować</u></a>?
się z 3 plików graficznych: corner_left.gif, cor- A może jeszcze nie masz u nas konta i
ner_right.gif oraz corner_left_right.gif, a na nie- Co nowego? i Witaj Nieznajomy! <a href="%s"><u>chciałbyś założyć
których znajduje się jeszcze dodatkowo mała W domyślnej konfiguracji sklepu, na stro- </u></a>?');
strzałka – arraw_right.gif. Wszystkie te pliki nie głównej, pojawia się napis Co nowego?
znajdują się w katalogu images/infobox/. Mo- – możemy go usunąć lub zmienić w pliku in- Obrazek na stronie głównej
żemy wykonać własne obrazki i zamienić ni- dex.php z katalogu includes/languages/polish Stronę główną możemy edytować korzystając z
mi istniejące; w naszym przykładzie przerobi- modyfikując wpis: panelu administracji (Administracja –> Sklep: Za-
liśmy te pliki zmieniając ich kolor z zielonego wartość –> Boczne menu –> Sklep –> Edycja strony
na czerwony. define('HEADING_TITLE', 'Co nowego?'); 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
W Sieci (katalog includes/languages/polish). Plik ten może-
• Główna strona osCommerce – informacje, skrypty, skórki oraz wiele różnych dodatków
my również modyfikować „ręcznie” – możliwość
http://www.oscommerce.com ta przydaje się zwłaszcza, jeśli chcemy mieć więk-
• Polskie forum poświęcone osCommerce – porady, dyskusje, moduły i dodatki szą kontrolę nad wprowadzaną treścią.
http://www.oscommerce.pl
• Generator przycisków osCommerce. – http://generator.oscpremium.com Podsumowanie
• Tabela kolorów dla stron www – http://algorytmy.pl/doc/xhtml/index.php?id=0108
W tym artykule pokazaliśmy jak można samodziel-
• 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 nie dopasować wygląd sklepu osCommerce do wła-
• MED (wersja angielska lub niemiecka) – http://www.pfersdorff.de/de/downloadwin.html 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-
Listing 1. Likwidacja górnych ikon.. niaturki czy nagłówki (Administracja –> Sklep: Za-
wartość –> Boczne menu –>Konfiguracja –> Obraz-
echo '<a href="' . tep_href_link(FILENAME_ACCOUNT, '', 'SSL') . '">' . tep_image( ki) . Możemy również określić liczbę produktów
DIR_WS_IMAGES . 'header_account.gif', HEADER_TITLE_MY_ACCOUNT) (Konfiguracja –> Wartości maksymalne) wyświetla-
. '</a>&nbsp;&nbsp;<a href="' . tep_href_link(FILENAME_SHOPPING_CART) nych na stronie głównej (nowości) oraz w poszcze-
. '">' . tep_image(DIR_WS_IMAGES . 'header_cart.gif', gólnych ramkach (Bestsellery, Promocje, Nowe recen-
HEADER_TITLE_CART_CONTENTS) . '</a>&nbsp;&nbsp;<a href="' . tep_href_link( zje itd.), czy też zrezygnować z wyświetlania ramki
FILENAME_CHECKOUT_SHIPPING, '', 'SSL') . '">' . tep_image(DIR_WS_IMAGES Produkty polecane (Konfiguracja –> Produkty poleca-
. 'header_checkout.gif', HEADER_TITLE_CHECKOUT) . '</a>'; ne). Żeby jednak bardziej znacząco wpłynąć na wy-
gląd sklepu, musimy zagłębić się w zawartość pli-
Listing 2. Linijka kodu, którą należy usunąć. ków. Wiedząc, gdzie rozmieszczone są poszcze-
<?php if (HEADER_IMG_LINK_ON=='1') { ?> gólne elementy odpowiedzialne za wygląd, można
<td valign="middle"><?php echo '<a href="' . tep_href_link(FILENAME_DEFAULT) . '"> zmodyfikować domyślny szablon według własnych
' . tep_image(DIR_WS_IMAGES . 'oscommerce.gif', 'osCommerce') preferencji. Pomocne, w osiągnięciu zamierzonego
. '</a>'; ?></td><?php efektu, mogą okazać się dodatkowe materiały, za-
} else { mieszczone na stronach których adresy znajdują się
?> w ramce W Sieci.
<td valign="middle">
<?php echo tep_image(
DIR_WS_IMAGES . HEADER_IMG_PIC, HEADER_IMG_ALT) MAGDALENA MARYAŃSKA
. '<BR>'; ?></td> Autorka pracuje w firmie a3a jako projektant stron
<?php } ?> internetowych.
Kontakt: magda@a3a.pl

12 04/2007
Praktyka

Aplikacje www
Buforowanie

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.

problemu będzie mógł zastosować tę metodę w


Dowiesz się... Powinieneś wiedzieć... bardziej rozbudowanych projektach, w których
• Jak wykorzystywać buforowanie do zwiększe- • Powinieneś znać PHP5, zyski z takiego postępowania będą widoczne.
nia wydajności strony oraz do eleganckiego ob- • Wymagana jest znajomość zasad programo- Rozszerzymy teraz nasz skrypt do postaci wi-
sługiwania błędów. wania obiektowego i podstaw HTML i MySQL. docznej na Listingu 2.
Jak widać, skrypt rozrósł się tylko odrobinę. W
pierwszej kolejności deklarujemy w nim nazwę
by uaktualniać go po zmianach lub po upłynię- naszego pliku. Następnie sprawdzamy czy po-
ciu określonej ilości czasu. Przy dużym obciąże- dany plik istnieje oraz czy nie został on utworzo-
Poziom trudności niu serwera na pewno będzie można odczuć róż- ny na tyle dawno, że wymagana jest jego aktuali-
nicę. Tego typu rozwiązanie zda również egzamin zacja. W naszym przypadku czas przedawnienia
w przypadku, gdy nasza baza danych znajduje się został ustawiony na 60 sekund. Jeżeli oba warun-
na innym serwerze, ponieważ dane z bazy mogą ki zostaną spełnione to naszą stronę wyświetlamy

W
raz ze wzrostem doświadczenia za- zostać zbuforowane np. w XML-owym pliku. Za- odczytując ją z pliku i dodając komunikat, tylko
czynamy zastanawiać się nie nad oszczędzimy wtedy czas potrzebny na połączenie dla własnej wygody, że strona została wczytana z
tym, jak coś napisać, ale jak zrobić to do bazy danych i przesłanie informacji, a dodatko- pliku. Natomiast, jeżeli warunki nie zostaną speł-
optymalnie. Chcemy mieć pewność, że aplikacja wo czas na sformatowanie wyników, bo przecież nione deklarujemy nazwę dla pliku tymczasowe-
będzie działać szybko nawet przy dużym obciąże- wszystko może już być przechowywane w odpo- go, w którym będziemy przechowywać bufor do
niu i tutaj właśnie przychodzi nam z pomocą bufo- wiedniej postaci w naszym pliku. czasu jego zapisania w pliku temp.cache. Nazwa
rowanie. W artykule tym zajmiemy się buforowa- Zaczniemy od stworzenia bardzo prostej tymczasowa zostaje zróżnicowana poprzez do-
niem w pliku informacji, które nie muszą być ge- strony internetowej, na której przykładzie bę- danie do nazwy identyfikatora procesu, który jest
nerowane za każdym razem oraz buforowaniem dziemy ćwiczyć. Rzecz jasna nie będziemy zaj- unikalny w danym momencie. O ile w tym przy-
stron internetowych we współpracy z wyjątkami. mowali się jej wyglądem, bo przecież nie to jest padku nie jest to aż tak bardzo ważne, to w mo-
To tylko dwa przykłady zastosowania buforowa- naszym celem. Zrezygnujemy też z wykorzy- mencie, gdy warunkiem uaktualnienia pliku by-
nia, ale warto je znać. Zapraszam do lektury. stania w tym przykładzie bazy danych, choć w łyby np. zmiany wprowadzone przez użytkowni-
praktyce metoda ta w tego typu zastosowaniach ków byłoby już ważne, gdyż zaszłoby ryzyko za-
Buforowanie przydaje się najbardziej. Nasza strona właściwie pisywania danych do jednego pliku jednocześnie.
dynamicznej strony www w pliku będzie składać się tylko z jednego dynamiczne- Następnie otwieramy nasz plik do zapisu – jeże-
Wyobraźmy sobie, że mamy serwis napisany go elementu, którym będzie wyświetlenie go- li nie istnieje zostanie utworzony, co zajdzie wła-
przy pomocy PHP i MySQL. Za każdym razem dziny wraz z minutami (Listing 1.). śnie w naszym przypadku, a po tym za pomo-
wszystkie podstrony są generowane dynamicznie. Podany kod będzie wyświetlać na stronie go- cą polecenia funkcji ob_start() zaczynamy bu-
Serwer musi więc przetworzyć kod PHP, połączyć dzinę jej otwarcia. Treść naszej strony będzie ge- forowanie informacji wyświetlanych na stronie.
się z bazą danych, wygenerować stronę oraz ją wy- nerowana za każdym razem przez skrypt PHP. Wszystko, co od tej pory miałoby zostać wyświe-
świetlić. Możemy sobie zadać pytanie, co działoby Łatwo możemy zauważyć, że przez 60 sekund
się, gdyby serwer musiał jednocześnie wygenero- strona zawsze będzie przybierać tę samą postać,
Listing 1. Strona internetowa generowana
wać tysiąc takich stron? Prawdopodobnie każda z po co ma być więc ponownie generowana, jeżeli od nowa przy każdym jej otworzeniu
osób łączących się z naszą stroną musiałaby dłuż- jej zawartość nie uległa zmianie? Lepiej byłoby,
szą chwilę odczekać, a jak wiadomo, nikt nie lubi gdyby strona przez ten czas pozostała statyczna. <HTML>
tracić czasu. Z tego powodu któryś z odwiedzają- Do tego celu użyjemy pliku, w którym będzie- <BODY>
cych mógłby w ogóle zrezygnować z wejścia na na- my zapisywać statyczną stronę i zmieniać ją, co Aktualna godzina to: &nbsp;
szą stronę. Tutaj właśnie przychodzi nam z pomo- minutę. Pomimo że w naszym przypadku czas <?php echo date("H:i"); ?>
cą buforowanie, ponieważ możemy dzięki niemu dostępu do pliku może przewyższyć czas wyge- </BODY>
zapisać raz wygenerowaną stronę w pliku, który nerowania strony, to wydaje mi się, że dzięki </HTML>
będzie naszym buforem i w zależności od potrze- swojej prostocie każdy zrozumie intencję i bez

14 4/2007
Aplikacje www

tlone, zostanie przechowane w buforze. Cały kod z odpowiednio sformatowanym komunikatem o użytkownik strony powinien wiedzieć, jak naj-
HTML oraz PHP nie zostanie wyświetlony. Po za- błędzie. W naszym przypadku informacja ta bę- mniej na temat powstałego problemu, więc najle-
ładowaniu strony do bufora chcielibyśmy zapisać dzie się ograniczać jedynie do napisu podawane- piej wyświetlić mu tylko przygotowany komuni-
ją do pliku. W tym celu sprawdzamy, czy posia- go przy rzuceniu wyjątku. Możemy też dodać kat. Dobrym pomysłem może być np. spowodo-
damy uchwyt do otwartego pliku tymczasowego. inne informacje odpowiednio zmieniając funk- wanie, aby pozostałe informacje były wysyłane na
Jeżeli warunek jest spełniony, całą treść z bufora cję template i przyjmowane przez nią argumen- adres e-mail administratora strony. Wszystko to
zapisujemy za pomocą funkcji ob_get_contents() ty. Dodatkowo można wykorzystać informacje o już tylko kwestia własnej inwencji twórczej. Na-
do naszej zmiennej, a następnie zapisujemy ją do kodzie błędu pliku, w którym powstał problem szą klasę umieszczamy w oddzielnym pliku, któ-
naszego pliku tymczasowego, któremu po chwili wraz z podaniem konkretnej linii. Z założenia ry nazwiemy class_page_error.php.
zmieniamy nazwę na temp.cache. Pozostało nam
już tylko wyświetlenie strony, co czynimy dzięki
Listing 2. Strona internetowa z zaimplementowanym buforowaniem – generowana raz na 60
funkcji ob_end_flush(). W ten oto właśnie sposób sekund (przez resztę czasu pozostaje statyczna)
utworzyliśmy plik, w którym przechowywana
jest nasza strona w postaci statycznej, wywoływa- <?php
na dynamicznie tylko w przypadku potrzeby. $file_name="temp.cache";
Wyobraźmy sobie teraz, że mielibyśmy wy- if(file_exists($file_name) && (filemtime($file_name)+60)>time()){
korzystać ten mechanizm do wyświetlania stro- include($file_name);
ny, której proces wygenerowania wykorzystuje echo '<BR/> Godzina pobrana z Pliku';
dużo pamięci i procesora. Przykładem takiego exit();
przypadku może być strona oparta o bazę da- }
nych, która musi odczytać informacje, prze- $file_tmp=$file_name.'.'.getmypid();
tworzyć je, a dopiero później wyświetlić wyni- $file_handle=fopen($file_tmp,"w");
ki tej operacji. Jeżeli wiemy, że treści te nie mu- ob_start();
szą być za każdym razem przetwarzane, zdecy- ?>
dowanie lepiej stworzyć stronę statyczną niż za <HTML>
każdym razem ją generować. <BODY>
Aktualna godzina:&nbsp;<?php echo date("H:i"); ?>
Buforowanie strony </BODY>
internetowej w parze z wyjątkami </HTML>
Innym zastosowaniem dla buforowania mo- <?php
że być następująca sytuacja. Załóżmy, że nasz if($file_handle){
skrypt dla strony www pobiera dodatkowe in- $page_content=ob_get_contents();
formacje z zewnątrz (tzn. z bazy danych, pli- fwrite($file_handle, $page_content);
ku, zmiennych superglobalnych) i po wczyta- fclose($file_handle);
niu pewnej części strony następuje jakiś błąd. if(file_exists($file_name)){ unlink($file_name); }
Cała strona zostaje w takim wypadku rozsypa- rename($file_tmp,$file_name);
na, a jej konstrukcja ulega uszkodzeniu i nasz }
“odwiedzający” zamiast przeglądać spodziewa- ob_end_flush();
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 Listing 3. Klasa Exception – niepełna deklaracja
może nas od tego ustrzec i wyświetlić wcześniej class Exception{
przygotowaną stronę z informacją o błędzie. protected $message = 'Unknown exception';
Zaczniemy od zapoznania z klasą Exception protected $code = 0;
(Listing 3.), po której będziemy następnie dzie- protected $file;
dziczyć, tworząc naszą klasę. protected $line;
Jak widzimy, klasa Exception większość me- private $trace;
tod odpowiadających za nasz komunikat o wy- private $string;
jątku ma zadeklarowane jako final, przez co nie function __construct (string $message=NULL, int $code=0){
możemy ich przedefiniować w klasie dziedzi- if (func_num_args(){ $this->message=$message; }
czącej. Jedyną metodą, którą możemy zmienić, $this->code = $code;
jest __toString() i to właśnie za pomocą niej $this->file=__FILE__;
zmienimy formę naszego komunikatu. Zrobi- $this->line=__LINE__;
my to podczas deklaracji naszej klasy PageError, $this->trace=debug_backtrace();
która dziedziczy po Exception – Listing 4. $this->string=StringFormat($this);
W naszej deklaracji, dodaliśmy dodatkowo }
metodę template, w której będziemy przecho- final function getMessage(){ return $this->message; }
wywać szablon naszej strony będącej komuni- final function getCode(){ return $this->code; }
katem. Dzięki takiemu podejściu łatwiej będzie final function getFile(){ return $this->file; }
nam edytować późniejszy wygląd strony. Następ- final function getTrace(){ return $this->trace; }
nie wywołujemy naszą funkcję template() z ar- function __toString(){ return $this->string; }
gumentem $this->getMessage() w metodzie ...
__toString(), dzięki czemu w wyniku pojawie- }
nia się wyjątku zostanie wyświetlona nasza strona

www.phpsolmag.org 15
Praktyka

Nadszedł czas na napisanie głównego skryp-


Listing 4. Deklaracja klasy PageError tu naszej strony. Zakładamy, że zadaniem tej
class PageError extends Exception { strony jest wyświetlenie odpowiednio sforma-
public function construct($message){ parent::__construct($message); } towanej zawartości jednej z tabel naszej bazy
public function __toString(){ return $this->template($this->getMessage()); } danych. Nie będziemy zastanawiać się nad tym,
protected function template ($only_message){ co jest w tej bazie oraz jak to ma być obudowa-
return '<html><body>'.$only_message.'</body></html>'; 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.
Listing 5. Strona wykorzystująca buforowanie oraz wyjątki Przeanalizujemy teraz nasz skrypt. Zaczęliśmy
<?php od deklaracji funkcji show_error(), której zada-
include_once('class_page_error.php'); niem jest wyczyszczenie bufora oraz rzucenie wy-
function show_error($message){ jątku. Moglibyśmy z niej zrezygnować, ale ponie-
ob_end_clean(); waż korzystamy z niej kilka razy, lepiej jest korzy-
throw new PageError($message); stać z funkcji niż kopiować kod. Następnie poja-
} wia się blok try, w którym generowana jest na-
try{ sza strona. Następuje wystartowanie bufora, a na-
ob_start(); stępnie próba połączenia do serwera bazy danych
?> i próba wybrania bazy. Jeżeli któreś z odwołań do
<HTML> bazy zakończy się niepowodzeniem zostanie wy-
<BODY> wołana funkcja show_error(), co oznacza rzuce-
<?php nie wyjątku i wygenerowanie wcześniej przygo-
if(!$db= @mysql_connect('localhost','user','password')){ towanej strony o błędzie. Jeżeli wszystko prze-
show_error('Błąd połączenia do bazy danych.'); biegnie pomyślnie, strona jest generowana dalej,
} a następnie zostaje wyświetlona poprzez opróż-
if(!@mysql_select_db('database_name')){ nienie bufora.
show_error('Błąd podczas wybierania bazy danych.'); Jest to bardziej eleganckie podejście do tego
} samego tematu. Istnieje jeszcze inny sposób wy-
if(!$request=mysql_query('select * from my_table',$db)){ świetlenia tej samej strony, jedyna różnica tkwi
show_error('Błąd podczas wybierania bazy danych.'); w sposobie implementacji. Otóż zamiast tworzyć
} swoją klasę możemy skorzystać z klasy Exception.
?> Nie musimy wtedy deklarować klasy, ale kod jest
<TABLE><TR><TD>key</TD><TD>value</TD></TR> też mniej czytelny i trudniejszy w edycji. Przy-
<?php kład ten widoczny jest na Listingu 6.
while($row=mysql_fetch_assoc($request)){ Jak widzimy, różnica wydaje się nieduża, ale
foreach ($row as $key => $value){ tylko dlatego, że mamy do czynienia z bardzo
echo “<tr><td>$key</td><td>$value</td></tr>”; 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-
</TABLE> trakcyjną i dziedziczyć po naszej klasie PageEr-
</BODY> ror, aby tworzyć całą gamę podstron błędów. W
</HTML> obecnym przypadku nie możemy tego zrobić.
<?php Na tej podstawie widać, że poprzedni kod jest
ob_end_flush(); znacznie mniej elastyczny, ale dla prostych przy-
} kładów możemy go wykorzystać. Połączenie obu
catch(PageError $e){ omówionych metod buforowania, może dać jesz-
echo $e; 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-
Listing 6. Strona wykorzystująca buforowanie oraz wyjątki – mniej elegancka wersja ko to jest już kwestią indywidualnego podejścia.
<?php Mam nadzieje, że poznane techniki, pozwolą
function show_error($message){ wam tworzyć jeszcze wydajniejsze witryny in-
ob_end_clean(); ternetowe, którymi naprawdę będziecie mogli
throw new Exception($message); się pochwalić nie tylko ze względu na wygląd,
} ale i wydajność.
try{ // ten sam kod co w Listingu 5.
...
} ŁUKASZ SKOWROŃSKI
catch(Exception $e){ echo '<html><body>'.$e->getMessage().'</body></html>'; } Autor jest studentem III roku informatyki na Uniwer-
?> sytecie w Białymstoku.
Kontakt z autorem: szeryfek@gmail.com

16 4/2007
Technika

CakePHP
Tags i Tags clouds – znaczniki

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ł.

morzem możemy nadać znaczniki „wakacje”,


Dowiesz się... Powinieneś wiedzieć... „morze”, „molo”, „zachód słońca” itp. Oczywi-
• Poznasz zasady tworzenia i zarządzania znacz- • Wymagana jest podstawowa znajomość fra- ście możliwe jest nadawanie wielu znaczników
nikami oraz sposoby ich wyświetlania jako tzw. meworku CakePHP; do tego samego zdjęcia.
„chmury znaczników”. • Przydatna będzie znajomość języka SQL i umie- Takie podejście do gromadzenia i katalogo-
jętność administrowania bazą danych MySQL. wania danych ma zasadniczą zaletę - wyszu-
kiwanie jest szybkie i intuicyjne. Niestety sto-
sowanie znaczników ma także swoje wady.
i zarządzanie zdjęciami). Pomysł się przyjął i Przede wszystkim za każdym razem znaczni-
obecnie „chmurki” można znaleźć w bardzo ki mogą być nazywane nieco odmiennie („za-
Poziom trudności wielu serwisach umożliwiających zarządza- chód-słońca”, „Zachód Słońca!”, „zachodzące
nie treścią. słońce” itp.) i mogą mieć rożne znaczenie dla
różnych osób przez co nie uda nam się dotrzeć
Znaczniki do odpowiednich danych. Rozwiązaniem tych

S
posób wyróżnienia poszczególnych Stosowanie znaczników (ang. tags) powiąza- problemów może być tzw. normalizacja lub
fraz nie jest przypadkowy, gdyż niesie nych z danymi udostępnianymi w serwisie jest wybór znaczników z pewnej ograniczonej pu-
ze sobą dodatkowe informacje. Przyj- bardzo popularnym sposobem zarządzania tre- li. Normalizacja to proces ujednolicania. Dzię-
mijmy, że znaczniki-linki są uszeregowane ścią. Dzięki temu, że znaczniki są pewnego ro- ki niemu wyrazy o podobnym znaczeniu, ale
alfabetycznie, natomiast wielkość i pogrubie- dzaju etykietami, możliwe staje się grupowanie różnej pisowni będą mogły być zarządzane w
nie fontu jest zależne od popularności dane- danych. Na przykład zdjęciom z wakacji nad ten sam sposób. W najprostszym przypadku
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 Rysunek 1. Przykładowa chmura znaczników (serwis flickr.com)

18 04/2007
CakePHP

normalizacja polega na usunięciu polskich li- by przecież ujednolicać znaczniki bazując na standardowej) pisowni. Ograniczeniem w tym
ter, znaków interpunkcyjnych i spójników. Po np. odmianie wyrazów. Jest to dosyć skompli- przypadku jest sama lista, która może nie za-
takim zabiegu ze znaczników „zachód-słońca” kowane zadanie, czasochłonne i w większości wierać haseł oddających charakter danych. Na-
oraz „Zachód Słońca!” otrzymamy np. znacz- przypadków po prostu zbędne. wet jeżeli proces aktualizacji listy o nowe wy-
nik „zachodslonca”. Metoda ta niestety nie Zdecydowanie skuteczniejsza od normaliza- razy będzie przebiegał sprawnie, to możemy
sprawdza się w bardziej złożonych przypad- cji jest metoda ograniczonego wyboru znaczni- stanąć przed koniecznością ponownego przy-
kach („zachodzące słońce”), ale odpowiednio ków. Wybierając hasła z gotowej listy, nie nara- pisywania znaczników do danych. Jeżeli do li-
zaawansowany algorytm normalizacji mógł- żamy się na kłopoty wynikające z błędnej (nie- 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.
Listing 1. Struktury danych wykorzystane do przechowywania informacji o znacznikach (tags)
powiązanych z wiadomościami (messages)
Zarządzanie znacznikami
mysql> desc messages; W internecie dominują dwa sposoby zarzą-
+------------+------------------+------+-----+---------+----------------+ dzania znacznikami (techniki przypisywania
| Field | Type | Null | Key | Default | Extra | znaczników do danych). Różnica między ni-
+------------+------------------+------+-----+---------+----------------+ mi polega na tym, że w formularzu widoczne są
| id | int(10) unsigned | NO | PRI | NULL | auto_increment | wszystkie lub tylko nowe znaczniki. W pierw-
| title | varchar(60) | YES | | NULL | | szym przypadku istnieje możliwość natychmia-
| content | text | YES | | NULL | | stowej, prostej edycji i w razie potrzeby usunię-
| created_at | datetime | YES | | NULL | | cia wszystkich znaczników jednocześnie. W
+------------+------------------+------+-----+---------+----------------+ drugim przypadku, nowe znaczniki są dołącza-
4 rows in set (0,05 sec) ne do danych, a ich usunięcie wymaga dodatko-
wych zabiegów (najczęściej każdy ze znaczni-
mysql> desc tags; ków musi być usunięty oddzielnie).
+---------+-------------+------+-----+---------+----------------+ Ze sposobem zarządzania znacznikami wią-
| Field | Type | Null | Key | Default | Extra | że się sposób ich prezentacji oraz konstrukcji
+---------+-------------+------+-----+---------+----------------+ adresu www. Znaczniki, które były poddawa-
| id | int(10) | NO | PRI | NULL | auto_increment | ne normalizacji mogą być wyświetlane w posta-
| raw | varchar(60) | YES | | NULL | | ci surowej (ang. raw) lub znormalizowanej. Nie-
| name | varchar(60) | YES | | NULL | | które serwisy pozostawiają wybór sposobu pre-
+---------+-------------+------+-----+---------+----------------+ zentacji użytkownikowi, który najczęściej wi-
3 rows in set (0,03 sec) dzi „swoje” znaczniki w takiej postaci, w jakiej
je wprowadził do systemu (raw). Inni użytkow-
mysql> desc messages_tags; nicy te same znaczniki widzą w postaci znorma-
+-------------+---------+------+-----+---------+----------------+ lizowanej. Prezentacja znaczników przechowy-
| Field | Type | Null | Key | Default | Extra | wanych jako lista haseł odbywa się najczęściej
+-------------+---------+------+-----+---------+----------------+ za pomocą numeru identyfikującego konkret-
| id | int(10) | NO | PRI | NULL | auto_increment | ną pozycję w liście (ID znacznika).
| message_id | int(10) | NO | | 0 | | Sposób prezentacji znaczników ma istotny
| tag_id | int(10) | NO | | 0 | | wpływ na konstrukcję adresu www. Intuicyjny i
+------------ +---------+------+-----+---------+----------------+ łatwy do zapamiętania adres będzie dodatkowo
3 rows in set (0,02 sec) zachęcał użytkowników do odwiedzenia serwi-
su. Wystarczy porównać poniższe adresy:
Listing 2. Relacje między modelami danych Tag oraz Message
class Tag extends AppModel { • http://www.serwer.pl/tags/friends/;
... • http://www.serwer.pl/albumy.php?start=0&
var $hasAndBelongsToMany = array( kategoria=1.
'Messages' => array(
'className' => 'Message',
'fields' => 'Message.id,Message.title', HABTM a nazwy tabel
CakePHP wymaga, by nazwa dodatko-
'order' => 'Message.created_at'
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-
class Message extends AppModel {
deli Message i Tag nazwa tabeli będzie mia-
ła postać: messages_tags, dla Message
...
i UserTag: messages _ user _ tags . Klu-
var $hasAndBelongsToMany = array( cze obce w tabeli muszą pasować do wzor-
'Tags' => array( ca [liczba _ pojedyncza _ model] _ id .
'className' => 'Tag', W naszym przypadku będzie to odpowied-
'order'=>'Tags.name ASC' 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).

www.phpsolmag.org 19
Technika

Pierwszy z powyższych adresów www za-


wiera w sobie wyjaśnienie: link prowadzi Listing 3. Zapisywanie wiadomosci wraz z informacją o znaczniku (powiazanie HABTM)
do strony zawierającej dane powiązane z ha- var $uses = array('Tag','Message');
słem friends (pol. przyjaciele). Już na podsta- $tag_name = $this->data['Message']['tag'];
wie tych informacji możemy określić, czy je- $existing = $this->Tag->findByName($tag_name);
steśmy zainteresowani odwiedzeniem ser- if (!empty(existing)) {
wisu czy też nie. Drugi adres www jest po- $tag = $existing[$this->Tag->name][$this->Tag->primaryKey];
zbawiony takich informacji. CakePHP do- } else {
myślnie obsługuje intuicyjne adresy www $this->data[$this->Tag->name]['raw'] = trim($tag_name);
i w naszym przykładzie wykorzystamy tą $this->data[$this->Tag->name]['name'] = preg_replace('/[^a-z0-9]/', '', low($tag_
właściwość. name));
$this->Tag->recursive = -1; // zapisz tylko dane modelu Tag
Jak to się robi w CakePHP $this->Tag->save($this->data);
Tworzenie chmury znaczników zaczniemy $tag = $this->Tag->id;
od zaprojektowania struktur umożliwiają- }
cych przechowywanie wiadomości i znacz-
ników oraz relacji między nimi. Musimy pa- Listing 4. Przykładowy formularz umożliwiający wprowadzanie informacji (wiadomość i
miętać, że każdy znacznik może być przypi- powiązane znaczniki rozdzielone przecinkami)
sany do wielu wiadomości oraz że każda wia- <h2>Nowa wiadomość</h2>
domość może mieć dowolną liczbę znaczni- <table><tr>
ków (lub nie mieć ich wcale). Taką relację <td>Tytuł:</td><td><?php echo $html->input('Message/title'); ?></td>
między danymi określa się jako m:m (wiele </tr>
do wielu), a w CakePHP jako hasAndBelong- <tr>
sToMany (HABTM). <td>Znaczniki powiązane z wiadomością</td>
Utworzymy tablicę messages (wiadomości), <td><?php echo $html->input('Tag/tag'); ?></td>
tags (znaczniki) oraz tablicę messages_tags. Ta </tr>
ostatnia tablica będzie zawierała informacje o <tr><td colspan="2">
tym, które wiersze tabel messages i tags łączą się <?php echo $html->textarea('Message/content'); ?>
ze sobą (z tego powodu taka tabela nazywana <?php echo $html->hidden('Message/id' , array('value'=>'0')); ?>
jest czasem „przesiadką”). <?php echo $html->submit('Zapisz'); ?>
Przykładowe struktury danych znajdują się </td>
na Listingu 1. (tabela tags zawiera dwie kolum- </tr>
ny raw i name, w których będą przechowy- </table>
wane nazwy znaczników przed i po norma-
lizacji). Listing 5. Metoda saveTags() tworząca listę identyfikatorów (ID) na podstawie nazw znaczników
Relacje między poszczególnymi modela- rozdzielonych przecinkami
mi danych zostały przedstawione na Listin- class Tag extends AppModel {
gu 2. Od strony modelu danych Tag będą wi- ...
doczne tylko kolumny messages.id oraz messa- function saveTags($string = null) {
ges.title, a wiadomości będą posortowane we- $return = array();
dług daty utworzenia messages.created_at. Od if($string) {
strony modelu danych Message będą widocz- $array = explode(',', $string);
ne wszystkie kolumny tabeli tags, które do- foreach($array as $tag) {
datkowo będą posortowane w porządku al- if(!empty($tag)) {
fabetycznym. $this->data[$this->name]['raw'] = trim($tag);
$this->data[$this->name]['name'] = preg_replace('/[^a-z0-9]/', '',
Wprowadzanie danych low($tag));
Zapisywanie danych z uwzględnieniem relacji $this->recursive = -1;
HABTM jest nieco bardziej skomplikowane niż $existing = $this->find("name = '{$this->data[$this->name]['name']}'");
dla pozostałych relacji. W CakePHP zapisywa- if(!empty($existing)) {
nie jest wykonywane w kontekście modelu da- $return[] = $existing[$this->name][$this->primaryKey];
nych tzn. każdy model może zapisywać dane } else {
tylko do „swojej” tabeli. Relacja HABTM skła- $this->id = null;
da się aż z trzech tabel i z tego powodu zapis if($this->save($this->data)) {
jest przeprowadzany „na raty”. Najpierw mu- $return[] = $this->id;
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- return $return;
beli messages_tags. }
Załóżmy, że w bazie danych już znajdu- ?>
je się wiadomość, do której chcemy dołączyć

20 04/2007
Technika

znaczniki. W pierwszym kroku upewniamy


Listing 6. Kod weryfikujący zawartości tabeli messages się, że znacznik, który ma zostać przypisany
$message = $this->Message->read(null, $this->data['Message']['id']); do wiadomości już istnieje i zapamiętujemy
$this->set('message', $message); jego numer ID.
print_r($message); Jeżeli znacznik jeszcze nie istnieje, to mu-
simy go utworzyć i poddać normalizacji.
// wynik W naszym przykładzie usuwamy wszyst-
Array kie znaki nie należące do alfabetu łacińskie-
( go i nie będące cyframi arabskimi. Patrz Li-
[Message] => Array sting 3.
( Numer ID znacznika otrzymany w jed-
[id] => 1 nym z powyższych kroków posłuży jako po-
[title] => Cake Model Associations wiązanie między modelem danych Message i
[content] => Time saving, easy, and powerful. Tag. Odczytujemy strukturę danych z żąda-
[created_at] => 2006-04-15 09:33:24 nego wiersza tabeli messages, umieszczamy w
) niej numer ID znacznika (lub tablicę znaczni-
[Tags] => Array ków) i ponownie zapisujemy zmodyfikowa-
( ny rekord. Istotne jest by powiązanie wpro-
[0] => Array wadzić jako zagnieżdżoną tablicę asocjacyjną
( o nazwie zgodnej z relacją HABTM, która zo-
[id] => 1 stała zdefiniowana w modelu danych Message
[raw] => CakePHP (tablica ['Tags']['Tags']).
[name] => cakephp
) $this->data = $this->Message->read
) (null, $this->data['Message']['id']);
) $this->data['Tags']['Tags'] = $tag;
$this->Message->Save($this->data);
Listing 7. Metoda popular() tworząca listę znaczników posortowaną według liczby wiadomości
do których zostały przypisane Powyższy przykład dotyczy przypisania do
class Tag extends AppModel { wiadomości tylko jednego znacznika. Jeżeli
... chcemy przypisywać większą liczbę znacz-
function popular($limit = 10) { ników, to musimy założyć, że będą one
return $this->query("select Tag.id, Tag.name, count(MT.message_id) count wprowadzane do formularza jako ciąg wy-
from tags Tag inner join messages_tags MT on MT.tag_id=Tag.id razów rozdzielonych przecinkami (Listing
inner join messages Message on MT.message_id=Message.id 4.) i zapisywane za pomocą metody Tag-
group by Tag.id order by Tag.name limit $limit "); >saveTags() przedstawionej na Listingu
} 5. W takim przypadku oczywiście zamiast
} jednego numeru ID znacznika w zmiennej
$this->data['Tags']['Tags'] musi się zna-
Listing 8. Przeskalowanie wilekości czcionek przed wyświetleniem chmury znacznkiów leźć tablica zawierająca wszystkie ID znacz-
// minimalna i maksymalna wielkość czcionki ników, które mają być przypisane do wiado-
$minfsize = 8; mości.
$maxfsize = 40;
$dstfsize = $maxfsize - $minfsize; Chmura znaczników
Wreszcie możemy zweryfikować zapisane da-
// minimalna i maksymalna popularność znaczników ne korzystając z metody $this->Message-
$minmax = array(); >read() (Listing 6.) i zabrać się za tworze-
foreach($tags as $no => $tag) { $minmax[$no] = $tag[0]['count']; } nie chmury znaczników. Chmura taka, to nic
asort($minmax); innego jak specyficzna lista wartości, w któ-
$mincnt = $minmax[0]; rej zakodujemy informacje o popularności
$maxcnt = $minmax[sizeof($minmax)-1]; poszczególnych znaczników. CakePHP do-
$dstcnt = $maxcnt + 1 - mincnt; myślnie nie zawiera funkcji, która podsumu-
je nam wykorzystanie znaczników. Musimy
foreach ($tags as $tag) { posłużyć się kodem SQL (Listing 7.), który
// skalowanie wielkości napisu zwróci listę zawierającą m.in. nazwę znacz-
$cnt = $tag[0]['count']; nika i liczbę wiadomości, do których został
$fsize = $minfsize + $dstfsiz * ($cnt - $mincnt)/$dstcnt; przypisany. Listę taką wystarczy wyświetlić
wyróżniając wielkością czcionki odpowied-
echo $html->link($tag['name'], nie hasła.
'/tags/'.$tag['raw'], Oczywiście jest bardzo wiele sposobów wy-
array('style'=>'font-size:'.$fsize.'px;')); świetlania chmury znaczników jednak nie
echo '&nbsp;'; wszystkie dają pożądany efekt. Najczęstszym
} błędem popełnianym przez programistów jest
bezpośrednie mapowanie popularności znacz-

22 04/2007
CakePHP

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;';
}
Rysunek 2. Chmura znaczników, w której popularność znaczników przekłada się bezpośrednio na
wielkość czcionki
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-
Rysunek 3. Chmura znaczników, w której wielkość czcionki jest skalowana liniowo względem
popularności znaczników 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-
Rysunek 4. Chmura znaczników, w której wielkość czcionki jest skalowana względem popularności mie, otrzymamy listę zawierającą pozycje róż-
znaczników w funkcji logarytmu dziesiętnego 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-
Listing 9. Widok CakePHP tworzący chmurę znaczników przeskalowaną za pomocą funkcji
logarytmicznej li funkcji, która pozwoli uwypuklić niewielkie
zmiany między poszczególnymi znacznikami.
<h2>Chmura znaczników</h2> W tym celu do skalowania wielkości czcion-
<div> ki wykorzystamy popularność znaczników w
<?php if(!empty($tags)): ?> funkcji logarytmu dziesiętnego (Listing 9.). Do-
// minimalna i maksymalna wielkość czcionki piero taki sposób tworzenia chmury znaczni-
$minfsize = 8; ków da pożądany efekt (Rysunek 4).
$maxfsize = 40;
$dstfsize = $maxfsize - $minfsize; Podsumowanie
Stosowanie chmur znaczników wymusza ko-
// minimalna i maksymalna popularność znaczników nieczność takiego ich zorganizowania, by od-
$minmax = array(); powiadały potrzebom użytkowników. Trudno
foreach($tags as $no => $tag) { $minmax[$no] = $tag[0]['count']; } mówić o przydatności listy zawierającej np. kil-
asort($minmax); kaset pozycji ze wszystkimi hasłami, jakie użyt-
$minlog = log($minmax[0]); kownicy serwisu nadali dostępnym artykułom.
$maxlog = log($minmax[sizeof($minmax)-1]); Bardzo trudno dostrzec zmiany w tak rozbudo-
$dstlog = $maxlog - minlog; wanej liście i z punktu widzenia użytkownika
if ($dstlog == 0) $dstlog = 1; będzie ona statyczna (za każdym razem, gdy
odwiedzi serwis będzie miał wrażenie, że lista
foreach ($tags as $tag) { nie uległa zmianie). Korzystniejsze jest wyświe-
// skalowanie wielkości napisu tlanie listy np. kilkunastu najpopularniejszych
$cnt = $tag[0]['count']; haseł. Lista taka prawdopodobnie będzie zmie-
$fsize = $minfsize + $dstfsize * (log($cnt) - $minlog)/$dstlog; niała się dosyć często, co może spowodować, że
użytkownicy serwisu będą mieli możliwość do-
echo $html->link($tag['name'], tarcia do danych, które dotychczas pomijali.
'/tags/'.$tag['raw'],
array('style'=>'font-size:'.$fsize.'px;'));
echo '&nbsp;'; PIOTR GAPIŃSKI
} Autor w wolnych chwilach zajmuje się programo-
?> waniem w różnych językach (głównie Rebol, Ruby,
</div> PHP i AmigaE).
Adres do korespondencji: piotr-gapinski@wp.pl

www.phpsolmag.org 23
Technika

Prado
PHP Framework

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ń.
Plik home.php – plik z implementacją klasy
Dowiesz się... Powinieneś wiedzieć... Home , w nim znajdzie się kod odpowiedzial-
• Poznasz zasady tworzenia stron z użyciem fra- • Powinieneś znać podstawy PHP oraz programo- ny za obsługę kliknięcia przycisku (funkcja
meworka PRADO. wania obiektowego. buttonClicked ).
• Dowiesz się, jak stworzyć prostą aplikację -
księgę gości. class Home extends TPage {
public function buttonClicked(
$sender,$param)
me.php. Dwa ostatnie pliki muszą znaleźć się w {//funkcja ta zostanie wywołana
katalogu \protected\pages (Rysunek 1.). po kliknięciu przycisku $sender->
Poziom trudności Musimy pamiętać, że katalogi assets (do Text="Kliknąłeś przycisk
niego trafiają zasoby udostępniane użytkow- "; //ustaw nową wartość Text,
nikowi przez komponenty np. obrazki, arku- czyli etykiety przycisku
sze styli CSS itp.) oraz \protected\runtime

J
ednak w przeciwieństwie do P4A, PRA- (w nim zapisywane są tymczasowo dane do- W wersji PRADO 3.1.0 (w chwili pisania
DO oferuje znacznie szerszy zestaw kom- tyczące aplikacji, np. stan aplikacji i kompo- artykułu jest to jeszcze wersja alpha) au-
ponentów oraz, co ważniejsze, obsługę sza- nentów) muszą być dostępne do zapisu dla torzy wprowadzili bibliotekę ActiveCon-
blonów. Dzięki szablonom mamy w zasadzie serwera (muszą mieć nadane odpowiednie trols, która zawiera zamienniki większo-
pełną kontrolę nad generowaną stroną, w pli- prawa). ści podstawowych, występujących w PRA-
ku możemy np. przeplatać kod HTML z kom- Plik index.php jest jedynym plikiem do- DO, elementów, jedyna różnica polega na
ponentami PRADO. stępnym bezpośrednio dla użytkownika stro- tym, że do ich obsługi używana jest tech-
ny. Plik ten składa się przynajmniej z trzech nologia AJAX, zamiast przeładowywania
Szablon, komponenty i obsługa linii, zawierających odpowiednie polecenia, całej strony. Wystarczy, że w pliku szablo-
zdarzeń, czyli HelloWorld czyli: komendy dołączenia biblioteki PRADO, nu zamiast TButton napiszemy TActive-
Dzięki plikowi szablonu (rozszerzenie takiego stworzenia nowej instancji aplikacji i jej uru- Button oraz w pliku z implementacją klasy
pliku to .page), możemy łatwo wstawiać kom- chomienia. Home dodamy linię Prado::using ('System.
ponenty w określone miejsca kodu HTML. Kod Web.UI.ActiveControls.*');, która jest od-
wygląda niezwykle podobnie do zwykłego tagu require_once('sciezka/do/prado.php'); powiedzialna za załadowanie biblioteki Ac-
XHTML, czyli dość schematycznie //dołączenie biblioteki tiveControls.
$application=new Tapplication;
<com:TypKomponentu parametr1= //nowa instancja aplikacji Księga Gości
”wartosc1” parametr2=”wartosc2” /> $application->run(); Napiszemy teraz niezwykle prostą księgę go-
//uruchomienie aplikacji ści, używającą technologii AJAX do przesyła-
Przykładowo, aby utworzyć przycisk nale-
ży napisać <com:TButton Text=”Przycisk Plik home.page – to szablon dla strony głów-
1” /> . nej aplikacji. W naszej aplikacji, w sekcji BO- Instalacja PRADO
Obsługa kliknięcia wymaga stworzenia DY kodu HTML napiszemy następujące trzy Instalacja PRADO sprowadza się do pobra-
skryptu php, który będzie „reagował” na różne linie (odpowiedzialne za stworzenie formula- nia spod adresu http://www.pradosoft.com/
download/ odpowiedniej wersji frameworku
zdarzenia występujące na danej stronie, np. na rza i przycisku):
(prezentowane w artykule skrypty testowane
kliknięcie. Dlatego, aby poznać działanie PRA- były na wersji 3.1.0a.r1626) oraz rozpakowa-
DO napiszemy najprostszy możliwy przykład <com:TForm> niu plików do katalogu dostępnego z sieci. Do
– przycisk z obsługą kliknięcia. <com:TButton Text= poprawnej pracy PRADO wymagany jest inter-
Nasza pierwsza aplikacja będzie składała się "Kliknij tutaj" OnClick="buttonClicked" /> preter języka PHP w wersji 5.1.0 lub wyższej.
z trzech plików – index.php, Home.page i Ho- </com:TForm>

24 04/2007
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).

Szablon
Rysunek 1. Struktura katalogów dla pierwszej
Najpierw musimy stworzyć plik szablonu – bę- aplikacji
dzie to standardowy plik HTML. W jego treści
stworzymy sekcję div, w której wyświetlane bę- <com:TActiveTextBox id="nick" />
dą wpisy. <com:TActiveTextBox TextMode=
"MultiLine" id="message" />
<div id="messages"> <com:TActiveButton Text="Dodaj wpis" id=
Ładowanie ... "addEntry" OnClick="addEntry" />
<com:TPlaceHolder ID=
"messageList" /> W drugim z komponentów TActiveTextBox
Rysunek 2. Efekt końcowy naszych prac
</div> ustawiliśmy parametr TextMode=”MultiLine”
dzięki czemu zezwala on na wpisanie wielu czasu zacznie się zaraz po załadowaniu stro-
W przykładzie zamieszczonym na płycie CD, linii tekstu (zamiast jednej). ny. Ostateczny kod powinien wyglądać mniej
w treści dokumentu znajduje się arkusz sty- W przykładzie dołączonym do płyty poszcze- więcej tak:
lów, którego ze względu na rozmiar nie będę gólne komponenty zostały rozmieszczone w ko-
tutaj prezentował. mórkach tabeli. Ze względu na czytelność przy- <com:TTimeTriggeredCallback OnCallback=
Skoro gotowe jest już miejsce, w którym kładu, nie zamieściłem tu pełnego kodu, a jedy- "refresh" Interval="15"
wpisy będą wyświetlane, musimy dać możli- nie szkielet aplikacji. StartTimerOnLoad=
wość dodawania wpisów. Mamy już możliwość dodawania wpisu, "true" />.
W tym celu utworzymy kolejną sekcję div, przydałoby się jeszcze odświeżać wpisy co ja-
tym razem jej id to newEntryBox. Wewnątrz kiś czas np. co 15 sekund. W tym celu doda- Klasa Home
utworzymy komponent TForm (<com:TForm> my jeszcze jeden komponent – TimeTriggered- Tradycyjnie, musimy stworzyć klasę Home (dzie-
... </com:TForm>) - to właśnie ten formularz Callback. Już sama jego nazwa sugeruje do dziczącą po TPage), w której znajdzie się obsłu-
będzie odpowiedzialny za przesłanie wpisu czego służy. ga kliknięcia przycisku oraz funkcja odświeża-
użytkownika do księgi. Komponent ten co podaną ilość czasu wy- jąca listę wpisów.
Wewnątrz sekcji utworzymy również wołuje podaną funkcję (oczywiście używając Funkcja dodająca wpis (o nazwie AddEntry)
trzy komponenty – dwa typu TActiveText- technologii AJAX). jest dosyć prosta.
Box (nick i message) oraz jeden typu TActi- Atrybuty, których użyjemy to Interval – Tworzymy w niej obiekt klasy GuestBook
veButton. odstępy czasu między kolejnymi wywołania- (klasę tę niedługo zaimplementujemy, będzie
Pierwsze z nich będą służyły do wpisania mi funkcji, oraz OnCallback – nazwa funkcji ona odpowiedzialna za obsługę pliku XML
nicka i wiadomości (treści wpisu), zaś trzeci, z klasy Home do wywołania. zawierającego wpisy), wywołujemy funk-
przycisk, będzie służył do ich wysłania. Kod Dodatkowo, atrybut StartTimerOnLoad cję dodającą wpis, ukrywamy obiekty służą-
powinien wyglądać tak: ustawimy na true, dzięki czemu odliczanie ce do dodawania wpisów oraz odświeżamyna

R E K L A M A
Technika

stronie. Treść funkcji addEntry($sender,$param) użycia obu tych klas nauczymy się na przy- $elem = new TxmlElement(array());
przedstawia się więc następująco: kładzie, czyli pisząc klasę GuestBook. //utwórz element
Na początku, w pliku \protected\App_ $elem->TagName = "entry";
$entry = new GuestBook (); Code\GuestBook.php definiujemy nazwę // nazwij go "entry"
$entry->AddMessage pliku XML, w którym przechowywane będą $elem->setAttribute("nick", $nick);
($this->message->Text, wpisy (musimy pamiętać, aby nadać upraw- // dodaj atrybut o nazwie nick i
$this->nick->Text); nienia pozwalające na zapis do tego pliku), zawartości nicka podanego
$this->Page->CallbackClient-> w naszym przykładzie będzie to DEFINE( przez użytkownika
puff("newEntryBox", ""); "StorageFile", dirname(__FILE__) . "./../en- $elem->setValue($message);
$this->refresh("", ""); tries.xml" ); //w wartości elementu ustaw wiadomość
//wywołujemy z pustymi parametrami Tak więc plik entires.xml znajdzie się w
katalogu \protected . Nasza klasa Guest- Teraz pozostało nam już tylko dodanie nowe-
Musimy jeszcze zaimplementować funkcję Book będzie posiadać jedną zmienną - $doc, go elementu do dokumentu XML oraz zapis
refresh . Wewnątrz niej utworzymy obiekt do której przypiszemy obiekt TXMLDocu- dokumentu do pliku:
GuestBook, wywołamy metodę GetMessages, ment. Jego utworzeniem zajmiemy się w
a następnie w pętli odczytamy i zaprezentuje- konstruktorze klasy, tutaj też załadujemy $this->doc->elements->
my dane dotyczące każdego wpisu. zawartość entries.xml (pod warunkiem, że add ( $elem ); //dodaj element
Za chwilę zaimplementujemy klasę Gu- plik istnieje): $this->doc->saveToFile
estBook (znajdzie się ona w pliku \protected\ ( StorageFile ); //zapisz plik
App_Code\GuestBook.php), aby tego doko- $this->doc = new TxmlDocument
nać musimy poinformować PRADO, że- ('1.0', 'utf-8'); Ostatnią wymaganą operacją jest napisanie
by dołączył ten plik do aplikacji. W tym ce- if (file_exists(StorageFile)) funkcji pobierającej z dokumentu wszystkie
lu wywołamy polecenie Prado:using('Applica- //jeśli plik istnieje, elementy o nazwie entry:
tion.App_Code.*'); Linię tę musimy umieścić załaduj dokument
na samym początku Home.php. Jak widać, ja- $this->doc->loadFromFile( StorageFile ); function GetMessages()
ko podmoduł modułu Application podajemy $this->doc->TagName = "guestbook"; { //zwraca liste elementow jako TList
nazwę katalogu. // nazwa głównego elementu (root) return $this->doc->
dokumentu getElementsByTagName("entry");
Obsługa XML w PRADO }
PRADO umożliwia nam niezwykle prostą Kolejnym zdaniem będzie funkcja dodająca
obsługę plików XML, a wszystko za sprawą wpis – w niej też nauczymy się, jak tworzyć Nasza księga gości jest już gotowa do użycia!
TXMLDocument i TXMLElement. Techniki element, ustawiać jego atrybuty i wartość:
Podsumowanie
Nauczyliśmy się, jak wygląda szkielet aplikacji
Listing 1. Metoda refresh klasy Home
używającej PRADO, jak tworzyć szablony, re-
public function refresh($sender, $param) agować na zdarzenia z umieszczonych kompo-
{ nentów, wreszcie, jak stworzyć aplikację używa-
$entry = new GuestBook (); jącą AJAX nie pisząc ani jednej linii kodu w ję-
zyku JavaScript.
// pobierz wpisy Osoby znające nieco narzędzia do tworzenia
aplikacji dla Windows (takie jak Borland® Del-
$msgs = $entry->GetMessages(); phi® czy Microsoft VisualStudio .NET) na pew-
$code = ""; no zauważyły, że duża część pomysłów zreali-
zowanych w PRADO jest „zapożyczona” z bi-
if (!empty($msgs)){ bliotek dla Microsoft Windows, co wielu pro-
gramistom ułatwa życie.
//w pętli odczytuj po jednej wiadomości Warta uwagi jest dokumentacja, dostępna
pod adresem http://www.pradosoft.com/docs/
for ($i = 0; $i < $msgs->Count; $i++){ manual/.
Zawiera ona bogaty opis klas i ich metod.
// formatuj wiadomości Godne uwagi są również przykłady dołączo-
ne do PRADO, m.in. blog napisany w opar-
(generowanie kodu XHTML) $code .= "<b>".$msgs[$i]-> getAttribute('nick'). ciu o SQLite.
"</b><br />\n"; Księga gości stworzona w tym artykule nie
$code .= "<span class=\"msg\">".$msgs[$i]->getValue()."</span><hr /><br />"; wyróżnia się w żaden sposób od innych skryp-
} tów, jednak była doskonałym wprowadzeniem
} do funkcjonalności PRADO.

// prześlij zawartość do

<div id = "messages" > MICHAŁ GAJEK


$this->Page->CallbackClient->update("messages", $code); Autor jest programistą – amatorem, od kilku lat
} piszącym również w języku PHP.
Kontakt z autorem: migajek@yahoo.com

26 04/2007
Technikę

Python kontra PHP


czyli węże i słonie

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.
wiązań, które zostały wykorzystane w wie-
Dowiesz się... Powinieneś wiedzieć... lu projektach.
• Zapoznasz się z nowymi narzędziami do two- • Podstawowa znajomość PHP i wzorca MVC. Niestety na większości kont hostingowych
rzenia stron www. wciąż dominuje PHP4. Wydanie PHP6 jesz-
cze bardziej spotęguje to zjawisko, a progra-
miści oprócz wykonania swojej pracy będą
• Działają na wielu platformach i architek- musieli co chwilę uwzględniać wersję PHP,
turach. pod którą ma działać ich aplikacja.
Poziom trudności
Mimo podobieństw są to dwa różne języki. Python dla programisty PHP
Zbiór różnic przedstawia Tabela 1. Programista PHP dość szybko może połapać
Nie ulega wątpliwości, że PHP jest popular- się w konkurencyjnym języku, choć będzie

W
królestwo PHP zaczynają wkra- ny i ma bardzo dużą społeczność, również w musiał przyzwyczaić się do pewnych różnic.
czać inne języki oferując kon- Polsce. Znalezienie pomocy, czy to w postaci Pierwszą jest brak średnika na końcu linii,
kurencyjne rozwiązania, które opublikowanych materiałów, czy też w posta- drugą grupowanie kodu za pomocą wcięć. Pę-
to omówimy w tym artykule. Cytując wiki- ci forum dyskusyjnego to nie problem. Rów- tla for w PHP wygląda znajomo:
pedię Python jest interpretowanym, interak- nież praktycznie każdy darmowy, tani ho-
tywnym językiem programowania stworzo- sting będzie zawierał w ofercie obsługę skryp- <?PHP
nym przez Guido van Rossuma w 1990 ro- tów PHP. for($i=1;$i <=5;$i++)
ku. Rozwijany jest jako projekt Open Source, Python ma mniejszą społeczność, w Pol- {
zarządzany przez niedochodową Python So- sce jest raczej mało popularny, lecz w skali print $i.'<br />';
ftware Foundation. PHP to wykonywany po światowej społeczność jest dość duża i sku- }
stronie serwera skryptowy język programo- piona wokół mniejszej ilości serwisów i orga- ?>
wania służący do generowania stron inter- nizacji. W kwestii hostingu umożliwiające-
netowych. Python tak samo jak Ruby sam go obsługę aplikacji Zope, Django czy Pylons W Pythonie wyglądać może tak:
z siebie nie jest przystosowany do tworzenia nie będziemy mieć licznego grona kandyda-
stron www, jako że jest to język uniwersal- tów, lecz jakość usług będzie wysoka (np. for i in range(1,6):
ny od początku swojego istnienia. PHP nato- WebFaction). Skrypty PHP wystarczy umie- print i
miast od początku tworzony był jako język ścić na serwerze, korzystając np. z klien-
do tworzenia stron www. W niniejszym ar- ta FTP. W przypadku aplikacji wspomnia- Nieco większą różnicą jest brak tablic zna-
tykule skupimy się nie tyle na porównaniu nych frameworków praktycznie nieodzow- nych z PHP, a obecność list, tupli i dzienni-
języków, ale frameworków napisanych w Py- ny będzie dostęp do shella oraz odpowied- ków. Pierwsze dwa typy uznać można za tabli-
thonie i PHP. nia konfiguracja serwera www. Framewor- ce numeryczne, a dzienniki za tablice asocja-
ki Pythonowe nie nadają się więc jako „Mo- cyjne. Oto przykład:
Różnice i podobieństwa ja pierwsza strona”.
Oba języki mają wiele wspólnego, ponieważ są: Kolejnym punktem, który warto poruszyć dziennik = {'klucz': 'wartosc'}
to wsteczna zgodność Pythona. Aplikacja pi- print dziennik['klucz']
• Interpretowalnymi językami wysokiego sana pod Pythonem 2.5 będzie w stanie dzia- lista = ['element1', 'element2']
poziomu z dynamicznym systemem ty- łać pod Pythonem 2.3. Potencjalne zmiany w print lista[1]
pów; kodzie ograniczą się do zmian nazw modu- print lista[0]
• Rozwijane jako projekty OpenSource; łów czy sposobu ich użytkowania (chyba że tupla = ['element tupli1', 'element
• Posiadają duże społeczności; użyjemy „starszej” nazwy modułu). W przy- tupli2']
• Łatwe w nauce (w porównaniu do np. Javy); padku PHP jest jeden problem. PHP5 udo- for i in tupla:
• Łatwe do rozszerzenia poprzez C/C++; stępniło programistom wiele dobrych roz- print i

28 04/2007
Python kontra PHP

Nowością będzie przestrzeń nazw i importo- nia aplikacji – dla Apache mamy mod_python go systemu szablonów. Krótkie porównanie
wanie modułów. W przypadku PHP w skryp- i mod_fcgid, dla Lighttpd, Cherokee czy przedstawia Tabela 2.
cie mamy dostęp do wszystkich funkcji i klas Nginx możemy wykorzystać protokół FastC- Oba frameworki są bardzo dobrymi rozwią-
danej instalacji PHP. W przypadku Pythona GI lub SCGI. zaniami. Django jest frameworkiem najlepiej
by uzyskać dostęp np. do klas obsługujących Za chwilę poznamy bliżej framework Django. pasującym do aplikacji typu CMS. Pylons ma
pliki ZIP musimy zaimportować odpowied- W jego przypadku dodanie keszowania dla całe- podejście „zrób to sam” i króluje w przypad-
ni moduł: go projektu, to dodanie jednego wiersza w usta- kach, gdy wymagamy elastyczności i stawiamy
wieniach, a do keszowania możemy użyć m.in. nietypowe wymagania.
import zipfile memcache – wydajnego systemu bazującego na Portale takie jak Grono.net i lawrence.com
z = zipfile.ZipFile("plik.zip", "r") pamięci RAM. wykonane są w Django – i są dużymi serwisa-
for plik in z.namelist(): Stosując Pythona do tworzenia dynamicz- mi internetowymi. Poradnikzdrowie.pl to ser-
print 'Plik: ', plik, nych stron www, na pewno nie stracimy na wy- wis napisany w Pylons zintegrowany z RedDo-
bajty = z.read(plik) dajności gotowych aplikacji, a nawet dość często tem (istniejącą wcześniej strukturą serwisów
print 'ma', len(bajty), 'bajtow' nawet zyskamy. właściciela). Serwisy te dobrze obrazują różni-
ce między Django a Pylons.
Wydajność i skalowalność Frameworki Pythona
Oba języki są interpretowane (do wykonania W Pythonie znajdziemy kilka (a nie kil- WSGI
skryptu używa się interpretera), lecz PHP nie kadziesiąt i więcej) frameworków do two- WSGI czyli Web Server Gateway Interface to
jest kompilowany do bajtkodu i zapisywany rzenia stron www, które można wykorzy- standard interfejsu aplikacji napisanej w Py-
do wielokrotnego użytku. Każde żądanie wy- stać. Prym wiedzie Django i Pylons, a trze- thonie do porozumiewania się z serwerami.
słane do serwera spowoduje zinterpretowanie ci – TurboGears znajduje się obecnie w fa- Stworzono standard interfejsu, który obec-
i wykonanie kodu w locie. W przypadku Py- zie przejściowej między starą i stabilną se- nie stosowany jest przez wiele pythonowych
thona kompilacja do bajtkodu jest automa- rią 1.X a przygotowywaną serią 2.X zgodną aplikacji, głównie frameworków i aplikacji
tyczna, natomiast użytkownicy PHP muszą z WSGI. Dobrze znane od dawna Zope i Plo- sieciowych.
skorzystać z kompilatorów nie wchodzących ne też ewoluują, lecz to Pylons i Django pod Przestrzeganie standardu ułatwiło współ-
w skład domyślnej dystrybucji PHP, takich sztandarem nowoczesności i web 2.0 ataku- pracę wielu aplikacji ze sobą i z serwera-
jak Xcache, eaccelerator, APC czy produktów ją układ LAMP. mi – pojawiło się pojęcie middleware, czyli
firmy Zend. W bezpośrednim starciu bez za- Django to framework dla „profesjonalistów z skryptu o określonym interfejsie, modyfiku-
biegów optymalizacyjnych Python wygra, terminami”, jak głosi jego motto. Jest to dobrze jącym żądanie bądź odpowiedź wysyłaną do
lecz odpowiednio skonfigurowane PHP nie zintegrowany zestaw własnych komponentów lub z serwera.
będzie miało się czego wstydzić. takich jak ORM wysokiego poziomu, system Dany skrypt middleware może być bez mo-
Python i niektóre jego frameworki mo- szablonów czy mapper adresów URL. Pylons dyfikacji stosowany w każdym frameworku,
gą działać wielowątkowo, co jest wydajniej- to framework bazujący na integracji „najlep- zgodnym z wytycznymi WSGI, co stanowi
sze od zwykłego trybu pracy PHP, jako że ta- szych ze swojego rodzaju” rozwiązań. ogromne pole do rozbudowy narzędzi tego
ki tryb pracy zużywa mniej zasobów. Rów- Wykorzystuje on istniejące podzespoły jak typu o nowe możliwości. Przykładem jest tu
nież w przypadku Django czy Pylons może- również umożliwia łatwą ich wymianę, tak framework Pylons stawiający na WSGI. Sam
my skorzystać z różnych sposobów hostowa- więc nie jesteśmy ograniczani do np. jedne- 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, Zalecane stosowanie ORMa SQLAlchemy – większe możliwości i łatwiejsza
SQLite i PostgreSQL (Oracle od wersji 1.0) 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 Wiele pomocników JavaSript, Ajax (w tym Scriptaculous)
uprawnień

www.phpsolmag.org 29
Technikę

obsługi openID, ale middleware, takie jak np. Django kontra Instalacja
AuthKit, bezproblemowo dodają te funkcjo- CodeIgniter i spółka Ostatnią wydaną wersją Django jest wersja
nalności do frameworka. Chęć przestrzega- Zajmiemy się teraz porównaniem obu frame- 0.96. Pobieramy archiwum z frameworkiem ze
nia specyfikacji jest w społeczności tak du- worków, jak i drogi tworzenia aplikacji z ich strony projektu i rozpakowujemy. Otwieramy
ża, że trzeci duży framework – TurboGears użyciem (CodeIgniter opisany został w nume- konsolę i przechodzimy do katalogu z kodem
zawiesił rozwój dotychczasowego niezgodne- rze 2/2007 phpSolutions). Django wykorzystuje Django. Wydajemy polecenie:
go z WSGI drzewa 1.X tworząc zarazem roz- wzorzec MVC , lecz w porównaniu z CI wpro-
wojową obecnie gałąź 2.X, zgodną z WSGI. wadza kilka zmian. Pierwszą z nich jest nazwa python setup.py install
Dla programistów rozwijających framewor- – MTV czyli Model-Template-View. W Django
ka oznacza to przepisanie wielu modułów model określa strukturę tabeli (logikę bazoda- Django wymaga kilku dodatkowych bibliotek
TurboGears. nową ogólnie), widok zawiera logikę aplikacji, Pythona:
W PHP standaryzacja rozwiązań kuleje. Na- a szablon wygląd. Kolejna różnica dotyczy sa-
wet na poziomie nazw funkcji trafimy na róż- mego modelu. W przypadku CodeIgnitera mo- • Do obsługi SQLite Django używa pysqlite;
ne style nazewnictwa. W kategorii komponen- del zawierał definicje różnych operacji na ba- • Postgres: psycopg;
tów sprawę nieco wyjaśnia PEAR, lecz czy Co- zie danych, takich jak pobieranie ostatnich • MySQL: mysql-python.
deIgniter, Symfony lub Zend Framework bez- newsów, kasowanie i aktualizowanie wpisów.
boleśnie integrują API pakietów PEAR? Nie- W Django model definiuje strukturę tabeli, a Tworzenie aplikacji w Django
stety nie. operacje wykonujemy w widokach za pomo- Tworzenie projektu. Projekt składa się z aplika-
Zend Framework i ezComponents jako zbiór cą ORMa. cji, np. CMS z różnych modułów. By stworzyć
luźniejszych komponentów, które łatwiej wy- projekt wystarczy wydać polecenie:
korzystywać w innych frameworkach, dają na- Przykładowy projekt Django
dzieję, lecz na tak daleko posuniętą standary- Zaprezentuję teraz prosty projekt Django – blog django-admin.py startproject NAZWA_PROJEKTU
zację jak w przypadku Pythona nie mamy na z systemem newsów obrazujący sposób tworze- django-admin.py startproject blog
razie co liczyć. nia projektów Django.
Stworzone zostaną podstawowe pliki projek-
tu, możemy nawet uruchomić serwer Django
Listing 1. Podłączenie bazy danych do naszego CMSa
dla tego projektu.
DATABASE_ENGINE =
'sqlite3' # 'postgresql', 'mysql', 'sqlite3' lub 'ado_mssql'. Uruchamianie serwera Django
DATABASE_NAME = Z konsoli po przejściu do katalogu projektu wy-
'bazka.db' # nazwa bazy danych lub ścieżka dla bazy sqlite3 konaj polecenie:
DATABASE_USER =
'' # użytkownik bazy, puste dla sqlite3 python manage.py runserver 8080
DATABASE_PASSWORD =
'' # hasło użytkownika, puste dla sqlite3 Komenda ta uruchomi deweloperski serwer
DATABASE_HOST = Django. Będzie on dostępny pod adresem http:
'' # host do bazy danych, puste localhost //localhost:8080/.
DATABASE_PORT =
'' # Podaj port jeżeli niestandardowy, puste dla sqlite3. Konfiguracja projektu – bazy danych
następnie zmieniamy język i strefę czasową: Django jest silnie powiązane z bazami danych
TIME_ZONE = 'Europe/Warsaw' i do dalszych operacji będzie nam potrzeb-
LANGUAGE_CODE = 'pl' na dostępna baza danych (sqlite3, mysql lub
postgresql). Edytujemy settings.py i ustawia-
Listing 2. Model aplikacji wiadomości my SQLite jako naszą bazę danych: patrz Li-
from django.db import models sting 1.
class News(models.Model): Teraz zatrzymujemy serwer Django i syn-
news_title = models.CharField( chronizujemy bazę danych. Po dodaniu nowej
maxlength=255, verbose_name='Tytuł') aplikacji, bądź danych do bazy danych nowe-
news_text = models.TextField( go projektu, musimy te dane zsynchronizować.
verbose_name='Treść') Służy do tego polecenie:
news_date = models.DateTimeField(
auto_now_add = True, blank= python manage.py syncdb
True, verbose_name='Data dodania')
class Meta: W przypadku rozpoczynania pracy z bazą da-
verbose_name = "Wiadomość" nych Django zapyta nas też o dane głównego
verbose_name_plural = "Wiadomości" admina projektu.
class Admin:
list_display = ('news_title', 'news_date') Tworzenie aplikacji
list_filter = ['news_date'] By stworzyć aplikację wystarczy wykonać pole-
search_fields = ['news_title', 'news_text'] cenie z katalogu projektu:
date_hierarchy = 'news_date'
def __str__(self): python manage.py startapp
return self.news_title NAZWA_APLIKACJI
python manage.py startapp news

30 04/2007
Python kontra PHP

Co stworzy katalog aplikacji wraz z plikami: Szablony Teraz wystarczy, że stworzymy szablo-
ny. Skorzystamy z darmowego szablonu.
news/ • W katalogu projektu utwórz katalog Załóżmy, że zawiera on XHTML zawie-
__init__.py templates (na szablony) i site _ media ra katalog images oraz pliki: default.css i
models.py (na pliki statyczne); index.html .
views.py • Dodaj 'templates' (nazwę katalogu na sza-
blony) w settings.py do TEMPLATE _ • Katalog i plik css kopiujemy do /site _
Zbiór models.py zawiera modele naszej aplika- DIRS. media a index.html do /templates ;
cji. Kod modelu dla naszej przykładowej apli- TEMPLATE_DIRS = ( • Edytujemy plik index.html i zastępujemy
kacji przedstawia Listing 2. 'templates', przykładową treść tagiem:
Każdy model, klasa dziedziczy z ) {% block content %}{% endblock %};
django.db.models.models, przez co może- • Znajdujemy <link rel="stylesheet"
my zdefiniować strukturę poszczególnych Edytuj plik urls.py i dodaj regułę: type="text/css" href="default.css" /> ;
tabel. Pole CharField i TextField służą do prze- • Zamieniamy na <link rel="stylesheet"
chowywania tekstu, DateTimeField daty. Te- (r'^site_media/(.*)$', 'django.views.static type="text/css" href="/site _ media/
raz edytujemy settings.py projektu. Do IN- .serve', default.css" /> ;
STALLED_APPS dodajemy naszą aplikację {'document_root': '/ŚCIEŻKA/DO/site_ • Tworzymy plik /templates/news _
(NAZWA_PROJEKTU.NAZWA_APLIKA- media'}), list.html z kodem: Listing 4.
CJI), czyli blog.news. Zapisujemy i synchroni-
zujemy bazę danych.
Listing 3. Dopasowanie adresów URL w urls.py

Panel Admina from django.conf.urls.defaults import *


By włączyć panel administracyjny wykonu- from blog.news.models import *
jemy: urlpatterns = patterns('',
(r'^admin/', include(
• Do INSTALLED_APPS w settings.py doda- 'django.contrib.admin.urls')),
jemy django.contrib.admin; (r'^/?$', 'django.views.generic.
• Synchronizujemy bazę danych; list_detail.object_list', {
• Edytujemy urls.py i usuwamy komentarz 'queryset':News.objects.all().
(#) z wiersza: order_by('-id'), 'paginate_by':10,
(r'^admin/', include('django.contrib. 'allow_empty':True, 'template_name':
admin.urls')), 'news_list.html'}),
(r'^/(?P<page>[0-9]+)$',
Panel Admina dostępny jest pod adresem 'django.views.generic.list_detail.object_list',
http://localhost:8080/admin/ i umożliwia {'queryset':News.objects.all().order_by('-id'),
zarządzanie aplikacją – dodawanie, usu- 'paginate_by':10, 'allow_empty':True,
wanie i edytowanie wpisów wraz z opcja- 'template_name':'news_list.html'}),
mi pomocniczymi jak listowanie i wyszu- )
kiwanie.
Listing 4. Przykładowy plik news_list.html
Interfejs użytkownika {% extends "index.html" %}
Mamy gotowy panel administratora wiado- {% block content %}
mości, lecz nie mamy jeszcze interfejsu od {% if object_list %}
strony użytkownika. Zaczynamy od zapro- {% for new in object_list %}
jektowania adresów URL. urls.py zawierają <h3>{{ new.news_title }}</h3>
listę powiązanych adresów URL z akcjami <p>{{ new.news_text }}... {{
wywoływanymi w przypadku dopasowania new.news_date|truncatewords:"1" }}</p>
URLa. Format: {% endfor %}

(wyrażenie regularne, funkcja pythona {% if has_previous %}


do wykonania [, opcjonalnie katalog]) <div style="text-align:center;">
<a href="/?page={{ previous }}">
urls.py powinien wyglądać tak: Listing 3. <b>Nowsze Wiadomości</b></a></div>
W wielu frameworkach MVC, w tym miej- {% endif %}
scu, musielibyśmy napisać kontrolery (wido- {% if has_next %}
ki w Django) wykonujące określone czynno- <div style="text-align:center;">
ści. Lecz Django posiada coś takiego, jak Gene- <a href="/?page={{ next }}">
ryczne Widoki, czyli predefiniowane akcje ta- <b>Starsze Wiadomości</b></a></div>
kie jak: pokaż określony wpis, listuj wpisy ze {% endif %}
stronicowaniem i inne. W powyższym kodzie {% else %}
urls.py użyliśmy generycznego django.vie Brak wiadomości
ws.generic.list_detail.object_list – li- {% endif %}
sty wpisów ze stronicowaniem. Teraz musi- {% endblock %}
my tylko stworzyć szablony.

www.phpsolmag.org 31
Technikę

Otwieramy główną stronę swojej aplika- świetla zawartość tego szablonu. Oprócz dzie- mie modelu poprzez wysokopoziomowe
cji w przeglądarce, wpisując adres http:// dziczenia skorzystaliśmy z drugiego ważnego typy pól.
localhost:8080/. Efekt przedstawiono na Ry- elementu – bloków. W news_list.html podali-
sunku 2. śmy zawartość dla bloku content: Smaczki Django
Trochę wyjaśnień, otóż zaczęliśmy od poda- Prezentowana przed chwilą aplikacja, nie
nia w settings.py nazwy katalogu na szablony, {% block content %} pokazała wszystkich możliwości framewor-
następnie w urls.py podaliśmy regułę obsługu- tutaj zawartość ka. Poznanie ich wymaga bardziej dokładne-
jącą pliki statyczne pod serwerem deweloper- {% endblock %} go poznania tego narzędzia, lecz poniżej opi-
skim (w warunkach produkcyjnych to serwer szę kilka innych przydatnych komponentów
www tym się zajmuje). Pliki statyczne to gra- W efekcie wypełniliśmy index.html określoną Django.
fiki, pliki JS czy css, jak i inne, do których chce- przez nas zawartością – listą newsów. Oczy-
my mieć dostęp z poziomu aplikacji Django. Ko- wiście możemy stworzyć identyczną aplika- ORM Django
lejną czynnością było przystosowanie szablonu cję w PHP, lecz kluczowym czynnikiem jest ORM mapuje strukturę bazy danych – po-
HTML. Przypomnijmy sobie regułę serwującą tutaj szybkość tworzenia. Django jest bardzo szczególnych tabel na obiekty. W Django obsłu-
statyczne pliki: dobrym narzędziem, gdyż jego komponenty ga ORMa jest bardzo prosta, a sam komponent
umożliwiają bardzo wydajne tworzenie wyso- jest mocno rozbudowany. Propel dostępny dla
(r'^site_media/(.*)$', 'django.views.static kiej jakości aplikacji. W porównaniu do takie- PHP niestety nie może pochwalić się tak czy-
.serve', go samego programu wykonanego w CodeIgni- stym i przyjemnym interfejsem.
{'document_root': '/ŚCIEŻKA/DO/site_ terze różnice są następujące: Listing 5. przedstawia model dla systemu
media'}), blogów złożony z trzech tabel. Blog – nazwa i
• Nie tworzymy tabeli w bazie danych, robi opis blogów, Author – Nazwisko i email auto-
r'^site _ media/(.*)$' – oznacza, iż to framework (dbając m.in. o indeksy); rów. Entry – wpis dla danego bloga.
wszystkie pliki statyczne dostępne są przez • Mamy gotowy Panel Admina do zarządza- Zaprezentowany na listingu model prezen-
/site_media/plik_ statyczny, tak więc musie- nia aplikacjami; tuje obsługę powiązanych tabel – Entry ma
liśmy zmienić odnośnik do pliku CSS. Ko- • Generyczne Widoki znacznie ułatwiają pole authors zależne od Author i pole blog za-
lejnym etapem było zastąpienie przykłado- tworzenie interfejsu od strony użytkowni- leżne od Blogs. Proste zależności wiele-do-
wej treści przez tag bloku. Następnie stwo- ka; jednego określane są przez pola typu Foreign-
rzyliśmy drugi szablon dziedziczący in- • Model opisuje tabele bazy danych, a nie Key, zawierające jako parametr nazwę mode-
dex.html: operacje na nich – w przypadku CI bez lu. Tak więc dany wpis (Entry) przypisany jest
struktury tabel trudno byłoby je odtwo- do konkretnego autora i bloga. Django oferu-
{% extends "index.html" %} rzyć bazując na kodzie modeli (brak wy- je również obsługę zależności wiele-do-wielu
cieku informacji poza projekt); czyli np. gdyby taka zależność dotyczyła pola
Szablony Django obsługują dziedziczenie – • Walidacja na poziomie mapowania URLi blog, to dany wpis (Entry) mógłby być przy-
news_list.html dziedziczy index.html, czyli wy- poprzez wyrażenia regularne i na pozio- pisany do wielu blogów. Listing 6. przedsta-
wia operacje na rekordach wykonywane po-
przez ORM.

System uprawnień i użytkowników


Django 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
Rysunek 1. Panel Admin w akcji 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.

Middleware
Middleware 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

32 04/2007
Python kontra PHP

naszej aplikacji może wykonać kod middle- Zedo.pl – Dlaczego Django? Nie jest to nic, czego nie można zrobić w PHP,
ware, aktualizujący listę użytkowników Na Zedo.pl to nowo powstały portal społeczno- ale tutaj liczy się czas programisty i wysiłek ja-
Stronie. Może też posłużyć do modyfikacji ściowy, w którym użytkownicy dzielą się ki należy włożyć, by uzyskać założony efekt.
nagłówków, czy zmiany działania serwisu komponentami do telefonów komórkowych, Django zawiera dobry system użytkowników i
w określonych warunkach (np. obsługa ope- takimi jak tapety i w przyszłości motywy czy uprawnień oraz rozbudowany, elastyczny sys-
nID w Pylons). dzwonki. Pierwotnie właściciel chciał, by ser- tem walidacji i obsługi formularzy, dzięki te-
wis był wykonany w znanej mu technologii mu dość łatwo rozwiązać możliwe problemy:
Maper adresów URL – PHP i MySQL, lecz gdy zapoznałem go z
Jak już mogliśmy zauważyć w Django (w Py- Django i jego możliwościami zgodził się na to • Skrypt Middleware w przypadku zalogo-
lons również) adresy URL są mapowane, co rozwiązanie. Dlaczego wybrałem Django? Ze wanego użytkownika, co 5 minut aktuali-
w PHP jest niespotykane. Za pomocą wyra- względu na szybkość i przyjemność tworze- zuje jego obecność na stronie, wykorzystu-
żeń regularnych określamy URL i przypi- nia kodu aplikacji. Główne problemy, jakie jąc cookie z zapisanym znacznikiem czasu,
sujemy mu widok, jaki ma zostać wykona- dostrzegłem po zapoznaniu się ze specyfika- do określania czy i kiedy zaktualizować
ny. URLe, które nie zostaną dopasowane do cją portalu to: wpis w bazie danych;
żadnego wyrażenia nie istnieją (zwrócony zo- • Do walidacji wysyłanych tapet, oprócz
stanie kod 404). Wymaga to od programisty • Rozbudowany system użytkowników walidacji rozszerzenia wykorzystany zo-
znajomości podstaw wyrażeń regularnych. wraz z „użytkownikami online”, rozbudo- stał PIL do walidacji rozmiaru i typu MI-
W efekcie dostajemy przyjazne wyszukiwar- wanymi profilami z komentarzami, przy- ME (wykrywa łączone pliki typu grafika-
kom odnośniki oraz w przypadku zastosowa- jaciółmi itp.; +PHP);
nia poprawnych formuł – walidację na pozio- • Walidacja formularzy, w szczególności do- • System użytkowników został rozszerzony
mie mapowania odnośników (nie trzeba tego dawanie tapet (walidacja i skalowanie pli- o zależne tabele zapewniające funkcjonal-
robić w widoku). Mapowane adresy URL to ków); ność profilu użytkownika.
nie przepisany Query String, który również • Powiązane między sobą tabele (Komór-
istnieje i może być stosowany w wyjątkowych ki z przypisaną rozdzielczością – tapeta o Nietypowe rozwiązania
okolicznościach (zaleca się stosowanie mapo- określonej rozdzielczości) i filtrowanie da- Python to język ogólnego przeznaczenia, istnie-
wanych odnośników). nych z powiązanych tabel. je więc wiele komponentów, które nie były two-

R E K L A M A
Technikę

rzone z myślą o stronach www, co nie oznacza,


W Sieci: że nie możemy ich wykorzystać. Chcąc zro-
bić bazę danych wyników analiz chromato-
• http://www.python.org – strona Pythona; graficznych – wystarczy skorzystać z bibliote-
• http://www.ipersec.com/index.php?q=en/bench_ea_vs_apc – porównanie wydajności róż-
ki pyCDF i zapisać wyniki w formacie CDF. Je-
nych enkoderów bajtkodu PHP;
• http://www.python.org/dev/peps/pep-0333/ – opis WSGI; żeli chcemy generować złożone wykresy z tych
• http://wiki.rubyonrails.com/rails/pages/Framework+Performance – porównanie wydajności analiz, lub z innych danych, problem nasz roz-
Symfony, Ruby on Rails i Django; wiąże matplotlib. Generowaniem raportów, pli-
• http://twistedmatrix.com/trac/ – strona frameworka Twisted; ków PDF czy prostych wykresów zajmie się re-
• http://www.djangoproject.com – strona Django;
portlab, a skanowaniem przesyłanych załącz-
• http://www.pylonshq.com – strona Pylons;
• http://www.python.rk.edu.pl/ – polska dokumentacja Django i Pylons ników, pod kątem obecności wirusów, pyCla-
• http://docs.pythonweb.org/ – wiki Pylons mAV. Odpowiednikiem GD z PHP będzie PIL
o równie bogatej, jeżeli nie większej funkcjo-
nalności.
Listing 5. Model systemu blogów
Programowanie sieciowe
class Blog(models.Model): Python w swojej bibliotece standardowej po-
name = models.CharField(maxlength=100) siada szereg modułów przydatnych przy pro-
tagline = models.TextField() gramowaniu sieciowym. Moduł socket, jak sa-
def __str__(self): ma nazwa wskazuje, daje nam możliwość ope-
return self.name rowania na gniazdach. Moduły wyższego po-
class Author(models.Model): ziomu jak urllib, telnetlib, imaplib czy ftplib
name = models.CharField(maxlength=50) zapewniają obsługę poszczególnych protoko-
email = models.URLField() łów. Nie jest to nic nadzwyczajnego. Wymaga-
def __str__(self): jących zapewne zainteresuje coś innego – fra-
return self.name mework sieciowy Twisted, wspierający TCP,
class Entry(models.Model): UDP, SSL/TLS, multicast czy protokoły takie
blog = models.ForeignKey(Blog) jak HTTP, NNTP, IMAP, SSH, IRC, FTP. Fra-
headline = models.CharField(maxlength=255) mework ten umożliwia pisanie asynchronicz-
body_text = models.TextField() nych klientów i serwerów różnego typu.
pub_date = models.DateTimeField()
authors = models.ManyToManyField(Author) Test Driven Development
def __str__(self): Testy jednostkowe i ciągła kontrola rozwija-
return self.headline nej aplikacji w przypadku dużych projektów
jest nieodzowna. Również w Pythonie znaj-
Listing 6. Przykładowe operacje ORMa django dziemy narzędzia do przeprowadzania ta-
# Dodanie wpisu kich testów. Dostępnych jest kilka rozwiązań
b = Blog(name= 'Blog Andrzeja', tagline= jak: unittest, pymock, nose, nosy czy py.test. Py-
'Najnowsze wieści z pola') lons, swój system testów jednostkowych oparł
b.save() o nose, a Django o doctest i unittest, dodając
#edycja dodatkowo własny system do testowania ele-
b.name='Blog Zbyszka' mentów kodu powiązanego z bazą danych (fi-
b.save() xtures). Można również stosować aplikacje ta-
# pobranie wszystkich blogów kie jak Selenium.
blogi = Blog.objects.all()
# pobranie 5 blogów Podsumowanie
blogi = Blog.objects.all()[:5] Powyższy artykuł miał za zadanie przybliżyć
# filtrowanie i sortowanie wyników programistom PHP alternatywne rozwiąza-
wpisy = Entry.objects.filter( nia, jakie można wykorzystać przy tworzeniu
pub_date__year=2005).order_by( stron internetowych. Zarówno PHP, jak i Py-
'-pub_date', 'headline') thon, mają swoje wady i zalety, lecz oba języki
dobrze sprawdzają się w powierzonych im za-
Listing 7. Przykładowy widok wykorzystujący system użytkowników i uprawnień daniach. Jeżeli chcesz poznać nowy język o sze-
def moj_widok(request): rokich możliwościach, nie odchodząc zarazem
if request.user.is_authenticated(): od tworzenia stron www to, moim zdaniem, Py-
# zalogowany thon będzie dobrym wyborem.
else:
# niezalogowany
if request.user.is_staff and PIOTR MALIŃŚKI
request.user.has_perm( Autor jest studentem Politechniki Warszawskiej
'news.add_news'): na kierunku Technologia Chemiczna. Od 4 lat zaj-
# zalogowany, muje się tworzeniem aplikacji w PHP, jak też od
z odpowiednimi uprawnieniamibv niedawna aplikacji o Pythonie.
Kontakt z autorem: riklaunim@gmail.com

34 04/2007
Prenumerata PRO
Więcej informacji: patrycja.wadolowska@software.com.pl tel.: 022 887-13-45

v
Bezpieczeństwo

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

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).

Dodatkowo możliwe jest stworzenie własnego


Dowiesz się... Powinieneś wiedzieć... rozszerzenia obsługującego autoryzację. Meto-
• Prezentujemy, czym jest CMF oraz eZ Ecosys- • Powinieneś wiedzieć, czym jest CMS. da autoryzacji ustawiana jest przez administratora
tem. • Powinieneś wiedzieć, jak działają systemy web- na poziomie plików konfiguracyjnych systemu. W
• Poznasz podstawy architektury eZ Publish oraz based. jednym z nich, settings/site.ini, gromadzącym pod-
jej możliwości. stawowe ustawienia znajduje się następujący wpis:

[UserSettings]
Metody autoryzacji LoginHandler[]=standard
użytkowników w eZ Publish
Poziom trudności eZ Publish posiada trzy wbudowane metody au- Aby umożliwić autoryzację opartą na pliku tek-
toryzacji użytkowników. Opierają się one na: stowym, należy nadpisać domyślną konfigura-
cję (Ramka 1.) w następujący sposób:
• kontach zarejestrowanych w systemie;

B
azując na wbudowanych możliwo- • informacjach przechowywanych w pli- [UserSettings]
ściach systemu możemy go dodatko- kach tekstowych; LoginHandler[]=standard
wo rozbudować, dostosowując do po- • integracji z LDAP. LoginHandler[]=textfile
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ów


Jednym 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. Rysunek 1. Grupa użytkowników o różnych typach uprawnień

36 04/2007
eZ Publish

Taka modyfikacja oznacza, że autoryzacja nadal konieczne jest odpowiednie skonfigurowanie Dodatkowo możemy zachować informacje na
opiera się na standardowym mechanizmie eZ systemu, czyli zamieszczenie odpowiedniego temat struktury pliku tekstowego. Do tego ce-
Publish. Jeżeli jednak operacja logowania nie wpisu w pliku settings/site.ini: lu służy: settings/textfile.ini. Patrz Listing 1.
zakończy się powodzeniem, system będzie pró-
bował wykorzystać dodatkowy mechanizm, [UserSettings] LDAP
aby sprawdzić uprawnienia użytkownika. LoginHandler[]=standard Metoda autoryzacji oparta na LDAP polega na
LoginHandler[]=textfile integracji usług katalogowych z eZ Publish. Aby
Konta użytkowników w eZ Publish
Domyślna metoda autoryzacji oparta jest na syste-
mie kont użytkowników, zarejestrowanych w eZ Konfiguracja eZ Publish
Ustawienia konfiguracyjne eZ Publish przechowywane są w plikach tekstowych, zgromadzonych w ka-
Publish. Ich struktura opiera się na grupach użyt-
talogu settings/ systemu oraz jego podkatalogach. Pliki z rozszerzeniem .ini zawierają predefiniowa-
kowników oraz kontach zarejestrowanych przez ne ustawienia – domyślną konfigurację systemu. Konstrukcja pliku konfiguracyjnego jest bardzo prosta
administratora lub samodzielnie przez użytkow- – składa się z bloków gromadzących pokrewne ustawienia oraz z par: “nazwa zmiennej” = “wartość
nika końcowego. Konto użytkownika zawiera zmiennej”. Przykładowo blok zawierający konfigurację bazy danych wygląda w następujący sposób:
przede wszystkim dane identyfikacyjne, czyli:
[DatabaseSettings]
DatabaseImplementation=ezmysql
• nazwę użytkownika (login); Server=localhost
• hasło; User=root
• adres e-mail. Password=
Database=nextgen
Dodatkowo może zawierać inne informacje Charset=
związane z osobą lub jej profilem. Przykłado- Socket=disabled
Transactions=enabled
wo, zgromadzić można: imię, nazwisko, ad-
res, sygnaturę, zdjęcie i inne dane. Rejestracja Konfigurację domyślną można zastąpić własną, tworząc pliki o nazwie zgodnej z wzorcową (zwykle do-
samodzielna (dokonywana przez użytkownika dawane są rozszerzenia .append.php) oraz umieszczając je w podkatalogach settings/. System spraw-
końcowego) może podlegać autoryzacji. Stosuje dza ustawienia konfiguracyjne na kolejnych poziomach i ostatecznie bierze pod uwagę te o najwyższym
się wtedy mechanizm przesyłania potwierdze- priorytecie. Kolejność nadpisań od najmniej do najbardziej-istotnego pliku jest następująca:
nia pocztą elektroniczną na podany adres, a na-
/settings/site.ini
stępnie, po zatwierdzeniu poprawności (kliknię- /settings/siteaccess/<identyfikator-serwisu>/site.ini.append.php
cie specjalnie spreparowanego odnośnika w wia- /settings/override/site.ini.append.php
domości), konto zostaje aktywowane. Aktywne
konto użytkownika służy do autoryzacji tożsa- <identyfikator-serwisu> to ciąg znaków, który związany jest z konkretnym interfejsem dostępo-
mości przed każdorazowym rozpoczęciem pra- wym lub serwisem WWW. Przykładowo: Zapis ogólny: http://www.domena.com/<identyfikator-ser-
wisu> Może mieć formę:
cy w systemie.
• http://www.domena.com/pl – serwis WWW w polskiej wersji językowej;
Pliki tekstowe • http://www.domena.com/en – serwis WWW w angielskiej wersji językowej;
Metoda przechowywania danych o użytkow- • http://www.domena.com/administrator – panel administracyjny;
nikach w pliku tekstowym bliska jest mecha-
Dla każdego z tych interfejsów możliwe jest stworzenie niezależnej konfiguracji.
nizmom znanym z systemów operacyjnych ro-
dziny Linux.
Aby skorzystać z autoryzacji opartej na infor-
Listing 2. Zawartość pliku settings/ldap.ini
macjach przechowanych w pliku tekstowym,
[LDAPSettings]
LDAPEnabled=true
Listing 1. Zawartość pliku settings/
textfile.ini LDAPServer=ldap.example.com
LDAPPort=389
[TextFileSettings] LDAPBaseDn=ou—users,dn--example,dn--com
TextFileEnabled=true LDAPSearchScope=sub
# nazwa pliku # ustawienie zamiany ciągu znaków w “--” na "="
FileName=konta.txt # dla zmiennych LDAPBaseDn or LDAPSearchFilters
# polożenie pliku LDAPEqualSign=--
FilePath=var/storage/konta # ustawienia filtrowania wyników
# separator danych LDAPSearchFilters[]
FileFieldSeparator=; # identyfikator użytkownika
# domyślna grupa użytkowników LDAPLoginAttribute=uid
DefaultUserGroupType=name # przykładowa konfiguracja powiązania użytkowników w grupy
DefaultUserGroup=Editors LDAPUserGroupType=id
# kolejność kolumn LDAPUserGroup=12
LoginAttribute=3 LDAPUserGroupAttributeType=name
PasswordAttribute=4 LDAPUserGroupAttribute=pracownicy
FirstNameAttribute=1 LDAPFirstNameAttribute=givenname
LastNameAttribute=2 LDAPLastNameAttribute=sn
EmailAttribute=5 LDAPEmailAttribute=mail

www.phpsolmag.org 37
Bezpieczeństwo

skorzystać z tej metody, należy posiadać odpo- kami w pliku settings/site.ini, powinien zostać Kolejnym ważnym krokiem jest dostosowanie
wiednio skonfigurowane środowisko serwera. zmodyfikowany w następujący sposób: konfiguracji związanej bezpośrednio z usługą.
Przede wszystkim konieczny jest dostęp do usłu- Do tego celu wykorzystywany jest plik settings/
gi katalogowej z serwera www oraz moduł LDAP [UserSettings] ldap.ini (Listing 2.).
dla PHP (opcja --with-ldap[=DIR]). Blok, za- LoginHandler[]=standard Ponieważ eZ Publish tworzy duplikaty kont
wierający ustawienia związane z użytkowni- LoginHandler[]=LDAP użytkowników, potrzebne jest cykliczne prze-

Listing 3. Fragment pliku cronjobs/ldapusermanage.php

<?php $r = ldap_bind( $ds );


/* ... */ }
else
// pobranie tablicy użytkowników zapisanych {
// w bazie danych eZ Publish $r = ldap_bind(
$db =& eZDB::instance(); $ds, $LDAPBindUser, $LDAPBindPassword );
$query = "SELECT contentobject_id, login }
FROM ezcontentobject, ezuser
WHERE remote_id like 'LDAP%' if ( !$r )
AND ezcontentobject.id=contentobject_id"; {
$LDAPUsers = $db->arrayQuery( $query ); eZDebug::writeError( 'Cannot bind in to LDAP server',
// odczytanie ustawień konfiguracyjnych dla LDAP 'ldapusermanage.php' );
$ini =& eZINI::instance(); return false;
$LDAPIni =& eZINI::instance( 'ldap.ini' ); }
$LDAPVersion = $LDAPIni->variable( ldap_set_option( $ds, LDAP_OPT_SIZELIMIT, 0 );
'LDAPSettings', 'LDAPVersion' ); ldap_set_option( $ds, LDAP_OPT_TIMELIMIT, 0 );
$LDAPServer = $LDAPIni->variable( }
'LDAPSettings', 'LDAPServer' ); else
$LDAPHost = $LDAPServer; {
$LDAPPort = $LDAPIni->variable( eZDebug::writeError( 'Cannot initialize connection
'LDAPSettings', 'LDAPPort' ); for LDAP server', 'ldapusermanage.php' );
$LDAPBaseDN = $LDAPIni->variable( return false;
'LDAPSettings', 'LDAPBaseDn' ); }
$LDAPBindUser = $LDAPIni->variable(
'LDAPSettings', 'LDAPBindUser' ); // aktualizacja kont użytkowników
$LDAPBindPassword = $LDAPIni->variable( $db->begin();
'LDAPSettings', 'LDAPBindPassword' );
/* ... */ foreach ( array_keys ( $LDAPUsers ) as $key )
{
// nawiązanie połączenia z serwerem LDAP /* ... */
$ds = ldap_connect( $LDAPHost, $LDAPPort ); }
if ( $ds ) $db->commit();
{
ldap_set_option( if ( !$isQuiet )
$ds, LDAP_OPT_PROTOCOL_VERSION, $LDAPVersion ); $cli->output( "All LDAP users have been updated!" );

if ( $LDAPBindUser == '' ) ?>


{

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

<?php }
include_once( // funkcja obsługująca logowanie użytkownika
"kernel/classes/datatypes/ezuser/ezusersetting.php" ); function &loginUser(
include_once( $login, $password, $authenticationMatch = false )
"kernel/classes/datatypes/ezuser/ezuser.php" ); {
include_once( // zwrócenie obiektu eZUser w przypadku powodzenia
'lib/ezutils/classes/ezini.php' ); return $user;
// lub false po niepowodzeniu logowania
class eZMyLoginHandlerUser extends eZUser // return false;
{
// konstruktor }
function eZDedykowanaAutoryzacjaUser() }
{ ?>

38 04/2007
eZ Publish

Zadania cykliczne w eZ Publish


eZ 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.

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-
Rysunek 2. Ekran logowania użytkownika do panelu administracyjnego. Dostęp przez adres typu: niami settings/dedykowanaautoryzacja.ini. Je-
http://www.domena.com/administrator 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

Podsumowanie
Jak 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-
Rysunek 3. Ekran logowania użytkownika do publicznego serwisu WWW. Dostęp przez adres typu:
gracyjne.
http://www.domena.com/pl Jako system otwarty, może być idealnym
kandydatem na łącznika aplikacji w trakcie
prowadzanie aktualizacji ich ustawień. Do te- Autoryzacja użytkowników budowania portalu korporacyjnego. Udostęp-
go celu wykorzystywany jest moduł zadań cy- w eZ Publish na podstawie kont w LDAP nienie funkcjonalności pojedynczego logowania
klicznych – cron. Do autoryzacji użytkowników, których kon- to tylko jeden z punktów jego wykorzystania.
Zadania cykliczne można podzielić na sek- ta zapisane zostały w katalogu LDAP, słu- Integracji mogą podlegać również inne mecha-
cje i wykonywać je w tle, w różnych odstępach ży skrypt: /kernel/classes/datatypes/ezuser/ nizmy związane z gromadzeniem i udostęp-
czasu. ezldapuser.php. nianiem danych.

Synchronizacja kont użytkowników Dedykowany system autoryzacji


Do aktualizacji kont użytkowników ba- Poza wymienionymi wyżej trzema predefi-
zy danych eZ Publish, na podstawie za- niowanymi przez producenta metodami au- JULIUSZ CAŁYNIUK
pisów z LDAP, służy skrypt: cronjobs/ toryzacji, możliwe jest stworzenie własnego Autor zajmuje się zarządzaniem projektami w We-
ldapusermanage.php. mechanizmu i zintegrowanie go z eZ Publish. bStyle. Od 7 lat związany z oprogramowaniem dla
Oto fragment zawierający najciekawsze czę- Aby stworzyć rozszerzenie dedykowana au- platformy LAMP.
ści kodu obrazuje Listing 3. toryzacja należy przygotować skrypt PHP Kontakt z autorem: juliusz.calyniuk@ws-webstyle.com

www.phpsolmag.org 39
Bezpieczeństwo

RBAC
Kontrola dostępu w aplikacjach webowych

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.

niczeniu dostępu do pewnych obszarów czy


Dowiesz się... Powinieneś wiedzieć... funkcji jedynie dla wybranych klas, poprzez
• Zaprezentujemy model RBAC i pokażemy, jak • Wskazana jest znajomość architektury MVC i zapisanie warunków bezpośrednio w kodzie.
przy jego użyciu zaprojektować elastyczny i wzorca dekoratora; Na przykład w systemach śledzenia błędów
rozszerzalny moduł kontroli dostępu. • Podstawowa wiedza z zakresu kontroli dostępu. 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-
Na ogół ma dostęp jedynie do ekranu logo- stawienia).
wania (system intranetowy) lub może ko- W przypadku systemu, w którym zadania są
Poziom trudności rzystać z pewnych podstawowych funkcji jasno zdefiniowane i niezmienne w czasie (jak
(system internetowy); wspomniany już system śledzenia błędów) ta-
• Zalogowany użytkownik to taki, który po- kie rozwiązanie może się sprawdzić. Jednak
myślnie przeszedł proces uwierzytelnie- zastosowanie tego podejścia w dużym syste-

W
artykule omówimy pokrótce teo- nia. Konta użytkowników są na ogół two- mie biznesowym, rozwijanym w warunkach
retyczny model kontroli dostępu, rzone przez administratora (system intra- ciągle zmieniających się wymagań, częstych
opartej o role w konfrontacji z in- netowy) lub ich samych, na przykład po reorganizacji i zmian strategii firmy ma licz-
nymi powszechnie stosowanymi rozwiązania- weryfikacji mailowej (system interneto- ne wady.
mi, a następnie zaproponujemy przykładową wy); Po pierwsze, cała logika kontroli dostępu za-
implementację kontroli dostępu w aplikacji we- • Administrator to specjalny użytkow- pisywana jest bezpośrednio w kodzie, jej mo-
bowej, stosującej wzorzec kontrolera strony. nik, który ma pełną kontrolę nad syste- dyfikacja wymaga ingerencji u źródła. Weryfi-
mem. Często (choć nie zawsze) korzysta kacja, dbanie o jej spójność i bezpieczeństwo
Problem w tym celu z odrębnego panelu admini- jest mocno utrudnione. Co więcej, audyt wy-
Przy tworzeniu praktycznie każdej aplikacji, wy- stratora. maga wiedzy programistycznej i znajomości
korzystywanej przez więcej niż jednego użyt- architektury systemu. Logika kontroli dostępu
kownika, trzeba zmierzyć się z problemami kon- Takie rozwiązanie sprawdza się całkiem rozrzucona jest w różnych miejscach kodu, co
troli dostępu. Jeden z nich to uwierzytelnianie, nieźle w prostych scenariuszach, gdy wszy- utrudnia tworzenie nowych klas użytkowni-
a więc weryfikacja tożsamości podmiotu. Drugi scy użytkownicy są równorzędni, a admini- ków czy implementację nowych modułów sys-
to autoryzacja, czyli sprawdzanie, czy dany pod- stratorów jest niewielu i mają władzę abso- temu, zwiększa też prawdopodobieństwo po-
miot ma dostęp do zasobów, o które prosi. lutną. To założenie można śmiało przyjąć w myłek. W końcu nie ma możliwości wdroże-
W aplikacjach webowych uwierzytelnianie przypadku wielu aplikacji internetowych, nia w oparciu o te same źródła kilku instancji
odbywa się na ogół poprzez podanie loginu i może stąd wynika jego powszechność. Jed- systemu, z których każda ma inaczej zdefinio-
hasła. Implementacja ekranu logowania, to te- nak rzadko kiedy, tak prosty model okazu- waną logikę kontroli dostępu. Warto pamiętać
mat opisywany już wielokrotnie, więc na po- je się wystarczający dla intranetowych sys- także o tym, że każda zmiana w kodzie wyma-
trzeby tego tekstu założymy, że mechanizm temów o strategicznym znaczeniu, modelu- ga testów, co więcej, na serwerze produkcyj-
uwierzytelniania jest już gotowy i skupimy się jących logikę biznesową firmy. W takiej sy- nym pojawi się nie od razu, a dopiero po wyda-
na bardziej złożonym problemie autoryzacji. tuacji oczywiste jest, że szef powinien mieć niu nowej wersji aplikacji.
Powszechną praktyką, stosowaną przez twór- inny poziom dostępu niż szeregowy pracow- Jak widać, w takiej sytuacji cała odpowie-
ców aplikacji webowych (nawet jeśli nie są te- nik, ten jeszcze inny niż podwykonawca, a dzialność za zarządzanie dostępem spada na
go świadomi), jest zdefiniowanie trzech pod- dział techniczny inne uprawnienia niż dział programistów, podczas gdy powinna spoczy-
stawowych poziomów dostępu: obsługi klienta.
Rozwiązanie, które często stosowane jest w ���� ���� ���� ����
������� ���� �����������
• Anonimowy użytkownik to taki, który takich sytuacjach, polega na sztywnym okre-
nie przeszedł procesu uwierzytelnienia. śleniu klas użytkowników, a następnie ogra- Rysunek 1. Model RBAC

40 04/2007
RBAC

wać na administratorze systemu, czy osobie Przykład implementacji sobem dostępu do bazy danych czy przebie-
odpowiedzialnej za bezpieczeństwo informa- Omówiliśmy pokrótce podstawy teoretycz- giem procesu logowania. Przykład celowo nie
cji w firmie. ne, spróbujmy więc zaimplementować RBAC jest związany z żadnym konkretnym frame-
Takie rozwiązanie, choć często stosowane, w przykładowej aplikacji webowej. Wyjdzie- workiem (choć opiera się na architekturze
narzuca wiele ograniczeń, które mogą oka- my od analizy przypadków użycia, która uła- stosowanej w wielu z nich), aby pokazać ogól-
zać się nie do przyjęcia. W dalszej części ar- twi określenie potrzebnych ról i uprawnień. ność rozwiązania.
tykułu zaproponujemy alternatywne rozwią- Następnie, korzystając ze wzorca dekoratora
zanie, dzięki któremu można uniknąć więk- (opisanego m.in. w artykule „Dekorator: wzo- Przypadki użycia
szości powyższych problemów. Opiszemy rzec projektowy na każdą bolączkę” z nume- Rozważmy typowy system obsługi zgłoszeń
prosty, a zarazem bardzo elastyczny model ru 4/2006, dostępnego do ściągnięcia na stro- (ang. trouble tickets), którego głównym zada-
RBAC i zaprezentujemy jego przykładową nie PHP Solutions), zaprojektujemy i zaimple- niem jest usprawnienie kontaktu z klientami.
implementację. mentujemy klasy, odpowiadające za kontrolę Po analizie dziedziny mógłby powstać diagram
dostępu w przykładowej architekturze stosują- przypadków użycia taki, jak na Rysunku 2.
Model RBAC cej kontroler strony. (mocno uproszczony dla celów przykładu). Po-
Kontrola dostępu oparta o role (ang. Role-Ba- Skupimy się na najbardziej interesują- może on nam zdefiniować role i uprawnienia.
sed Access Control, w skrócie RBAC), to teo- cych z punktu widzenia niniejszego artyku- Jak wiadomo, role opisują funkcje, jakie w
retyczny model kontroli dostępu, od lat po- łu aspektach, nie zajmując się chociażby spo- organizacji pełnią użytkownicy (mówiąc bar-
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. Rysunek 2. Diagram przypadków użycia
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. Rysunek 3. Diagram kontrolerów

www.phpsolmag.org 41
Bezpieczeństwo

dziej ogólnie, podmioty). Jeśli korzystamy z je się, że uprawnienia powinny być nieco bar- lera), a każdy kontroler to osobny plik PHP,
diagramu przypadków użycia, dobrymi kan- dziej szczegółowe i niskopoziomowe. Wtedy obsługujący żądanie dla danego URL. Do-
dydatami na role są aktorzy (choć nie zawsze jeden przypadek użycia można rozbić na kilka datkowo zakładamy, że kontroler otrzymuje
musi to być relacja jeden-na-jeden). W opisa- uprawnień. jako parametr żądania nazwę zdarzenia, któ-
nym przykładzie możemy wyróżnić następu- Implementacja kontroli dostępu staje się re ma obsłużyć. Wszystkie kontrolery dzie-
jące role: znacznie łatwiejsza, jeśli uprawnienia mają dziczą po wspólnej abstrakcyjnej nadklasie i
swoje odpowiedniki w samym systemie. Dla- implementują metody onAction(), gdzie ac-
• Klient: osoba korzystająca z systemu, aby tego w przykładzie opisanym poniżej zastosu- tion to nazwa zdarzenia, które obsługuje da-
zgłosić swój problem i śledzić jego stan; jemy kontrolę uprawnień w warstwie kontro- na metoda.
• Konsultant: pracownik odpowiadający za lera, a uprawnienia utożsamimy ze zdarzenia- W uproszczonym przykładzie projektowa-
obsługę zgłoszeń klientów; mi kontrolera (a same kontrolery zaprojektuje- nego systemu obsługi zgłoszeń, podstawowy-
• Menedżer: osoba nadzorująca pracę kon- my tak, aby ich zdarzenia odpowiadały upraw- mi pojęciami są zgłoszenia i raporty, a więc
sultantów. nieniom). to dla nich utworzymy kontrolery. Projektu-
jąc zdarzenia najlepiej wyjść od przypadków
Kolejnym krokiem jest określenie upraw- Kontrolery użycia, choć często okazuje się, że zdarze-
nień, najmniejszego i niepodzielnego kwantu, Projektując architekturę aplikacji webowej, nia powinny być bardziej szczegółowe. Do-
umożliwiającego kontrolę dostępu w modelu najprawdopodobniej skorzystamy z jakie- brym przykładem są tu tzw. przypadki użycia
RBAC. Role zawsze można zmienić, jednak goś rodzaju kontrolera, obsługującego żąda- CRUD (ang. Create, Read, Update, Delete), łą-
odpowiedni dobór ,,rozdzielczości” upraw- nia HTTP. Jeśli wszystkie żądania przecho- czące operacje tworzenia obiektu, jego modyfi-
nień, to ważna decyzja projektowa. Od tego dzą przez kontroler, wybór uprawnień i im- kacji i usuwania (a więc trzech osobnych zda-
zależy, jak łatwe i elastyczne będzie definiowa- plementacja kontroli dostępu staje się prosta rzeń) w jeden przypadek użycia ,,zarządzanie
nie ról, i jak precyzyjna kontrola dostępu bę- i przejrzysta. obiektem”.
dzie możliwa. Załóżmy, że stosujemy wzorzec Page Con- Przykładowy diagram kontrolerów dla nasze-
Także w tym przypadku można oprzeć się troler (choć podobny sposób rozumowania go systemu obsługi zgłoszeń znajduje się na Ry-
na przypadkach użycia, często jednak okazu- można także zastosować dla Front Control- sunku 3.

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

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

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

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


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

Rysunek 4. Diagram dekoratorów kontrolera

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

���

���

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

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

���

Rysunek 5. Diagram sekwencji kontroli dostępu

42 04/2007
Bezpieczeństwo

Jak łatwo się już domyślić, w aplikacji webo- ułatwia pracę, ale także ogranicza możli- automatycznie, za pomocą refleksji klas
wej o takiej architekturze, dobrym kandydatem we dziury w bezpieczeństwie wynikające kontrolerów);
na uprawnienie (w rozumieniu modelu RBAC) z przeoczeń; • Równoważność uprawnień i zdarzeń
będzie para $(kontroler, zdarzenie)$. Przema- • Taki wybór uprawnień sprawia, że me- kontrolera ułatwia komunikację w ze-
wia za tym kilka faktów: chanizm kontroli dostępu staje się rozsze- spole, nie ma potrzeby tworzenia i doku-
rzalny wraz z rozbudową systemu, a na- mentowania nowego pojęcia. Sprawę do-
• Kontrolę uprawnień możemy przeprowa- rzut związany z jego utrzymaniem i ak- datkowo ułatwia fakt, że oba pochodzą
dzić na poziomie kontrolera, wtedy staje tualizacją jest minimalny (nowe upraw- od przypadków użycia, a te bezpośred-
się ona przezroczysta dla programisty, co nienia mogą być nawet rozpoznawane nio powiązane są z aktorami (a więc i ro-
lami).
Listing 1. Dekorator kontrolera
Tabela 1. zawiera podsumowanie przypad-
abstract class ControllerDecorator implements Controller ków użycia, odpowiadających im zdarzeń i
{ uprawnień w projektowanym przez nas sys-
temie.
protected $decoratedController; W dalszej części artykułu zaproponujemy
implementację przezroczystej dla kontrolera
function __construct(Controller $decoratedController) kontroli dostępu, przy założeniu, że uprawnie-
{ niami są zdarzenia kontrolera.
$this->decoratedController = $decoratedController;
} Dekorowanie kontrolera
Skoro uprawnienia są jednoznaczne z prawami
function getEventName() dostępu do zdarzeń kontrolera, a każde żądanie
{ musi przejść przez kontroler, dobrym miejscem
return $this->decoratedController->getEventName(); na implementację kontroli dostępu jest właśnie
} klasa kontrolera.
Oczywiście można zapisać odpowiednie
function getName() warunki w kodzie nadklasy, po której dzie-
{ dziczą kontrolery (albo utworzyć klasę po
return $this->decoratedController->getName(); niej dziedziczącą), jednak nie jest to zbyt
} eleganckie rozwiązanie. Obsługa żądań i
kontrola dostępu to dwa różne zadania, któ-
function run() re nie powinny być łączone. W takich sytu-
{ acjach dobrym pomysłem jest skorzystanie z
return $this->decoratedController->run(); 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
Listing 2. Dekorator kontroli dostępu dekorator i dziedziczący po nim dekorator prze-
prowadzający kontrolę uprawnień.
class ControllerRbacDecorator extends ControllerDecorator Na Listingu 1. znajduje się kod dekorato-
{ ra, realizującego interfejs kontrolera, który w
konstruktorze otrzymuje obiekt do udekoro-
private $profile; wania i przekierowuje do niego wszystkie me-
tody interfejsu.
public function __construct(Controller $decoratedController, Profile $profile) Warto zauważyć, że klasa jest zdefiniowana
{ jako abstrakcyjna mimo, że nie posiada żad-
$this->profile = $profile; nych abstrakcyjnych metod. Po prostu two-
parent::__construct($decoratedController); 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ż-
function run() dym razem implementować mechanizmu de-
{ koracji.
Na Listingu 2. znajduje się kod dekoratora
if (!$this->profile->hasPermission($this->getName(), $this->getEventName())) { przeprowadzającego kontrolę dostępu przed
throw new Exception("Brak uprawnień"); przekazaniem sterowania do metody realizu-
} jącej zdarzenie. Zakładamy, że w konstruk-
torze został przekazany profil opisujący ak-
return $this->decoratedController->run(); 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

44 04/2007
RBAC

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


W Sieci Przypadek użycia Metoda kontrolera Uprawnienie
Utworzenie zgłoszenia TicketsController::onCreate() (tickets, create)
• David Ferraiolo, Richard Kuhn. Role-Based
Access Control, http://csrc.nist.gov/rbac/ TicketsController::onView() (tickets, view)
Podgląd zgłoszenia
Role_Based_Access_Control-1992.html;
• Wikipedia: Role-Based Access Control, Zamknięcie zgłoszenia TicketsController::onClose() (tickets, close)
http://en.wikipedia.org/wiki/Role-Ba- TicketsController::onComment()
sed_Access_Control. Dodanie komentarza (tickets, comment)
Generowanie raportu ReportsController::onGenerate() (reports, generate)

przekazuje sterowania do dekorowanego kon- wzorca dekoratora, udało się w prosty sposób za- W bardziej skomplikowanych projektach
trolera. Utworzenie i wywołanie udekorowa- implementować przezroczysty dla programisty i można rozważyć zastosowanie bardziej za-
nego kontrolera przebiega w następujący spo- rozszerzalny moduł kontroli dostępu. awansowanych aspektów modelu RBAC:
sób (zakładając, że mamy referencję do profi- Dzięki zastosowaniu modelu RBAC logi-
lu użytkownika): ka kontroli dostępu nie jest zapisana bezpo- • Nietrudno dodać, bardzo przydatny
średnio w kodzie, a w dynamicznych zależno- w praktyce, mechanizm dziedzicze-
$controller = new ControllerRbacDe ściach między podmiotami, rolami i upraw- nia uprawnień. Dzięki temu menedżer
corator(new nieniami. Dzięki temu cała struktura jest bar- będzie mógł dziedziczyć z roli konsul-
TicketsController(), dzo przejrzysta, łatwa w administracji i mo- tanta, przejmując wszystkie uprawnie-
$profile); że być modyfikowana przez osoby nie będące nia roli dziedziczonej i uzupełniając je
try { programistami. Co więcej, polityka bezpie- o uprawnienia specyficzne dla roli dzie-
$controller->run(); czeństwa może różnić się między kilkoma in- dziczącej (podobnie do mechanizmu
} catch (Exception $e) { stalacjami systemu. dziedziczenia w programowaniu obiek-
echo "Błąd: ". $e->getMessage(); towym);
} Możliwe ulepszenia • Założyliśmy, że użytkownik po zalogo-
Zaprezentowany powyżej szkic implementa- waniu może korzystać ze wszystkich
Nie są wymagane żadne zmiany w samych kla- cji nie jest jedynym możliwym, można go roz- swoich ról i związanych z nimi upraw-
sach kontrolera, za kontrolę dostępu odpowia- winąć i ulepszyć na wiele sposobów, oto kil- nień. Alternatywnym i bardziej zgod-
da tylko dekorator. ka z nich: nym z modelem RBAC rozwiązaniem
jest wymuszenie wyboru jednej z do-
Jak to działa • Przydatny będzie panel administracyjny, po- stępnych ról w momencie logowania.
Na koniec warto przeanalizować diagram se- zwalający na zarządzanie rolami, przypisy- Wtedy powstaje sesja, łącząca użytkow-
kwencji przedstawiony na Rysunku 5., przed- wanie uprawnień do ról i ról do użytkowni- nika z aktywną rolą (nie mylić z mecha-
stawiający dynamiczny obraz procesu kontro- ków. Oczywiście dostęp do takiego modu- nizmem sesji PHP);
li dostępu. łu także można, i należy chronić za pomocą • Można zaimplementować politykę se-
Przeglądarka użytkownika wysyła żądanie opisanego mechanizmu kontroli dostępu; paracji obowiązków (ang. Separation of
HTTP, które serwer kieruje do odpowiednie- • Główną wadą kontroli dostępu na pozio- Duties), mającą na celu ograniczenie za-
go kontrolera, wywoływana jest jego metoda mie kontrolera jest to, że jest ściśle zwią- grożeń wynikających z łączenia kilku
run(). Kontroler został udekorowany, więc zana z żądaniami HTTP i warstwą kon- ról przez jednego pracownika. Ta zasa-
dekorator najpierw pobiera nazwę dekoro- trolera. Jeśli system posiada bogaty mo- da mówi, że dla pewnego zbioru operacji
wanego kontrolera oraz zdarzenia, które zo- del domeny, wykorzystywany przez wię- (np. zlecenia przelewu i akceptacji prze-
stało wywołane przez użytkownika. Następ- cej niż jedną aplikację, warto rozważyć lewu) nie może istnieć osoba, która ma
nie profil proszony jest o sprawdzenie, czy kontrolę dostępu w warstwie domeny. W uprawnienia do wszystkich z nich.
aktualnie zalogowany użytkownik ma upraw- takiej sytuacji teoretyczne podstawy po-
nienia do danego kontrolera i zdarzenia (i czy zostają bez zmian, ale zmienia się znacze- Zachęcamy Czytelników do dalszych ekspery-
jest w ogóle zalogowany). To, jak działa i kie- nie uprawnień i implementacja kontroli mentów i dzielenia się swoimi pomysłami.
dy tworzony jest profil, nie wchodzi w zakres dostępu;
niniejszego artykułu. Warto jednak wspo- • Można zmodyfikować szablony tak, aby Podsumowanie
mnieć, że profil powinien obsługiwać logowa- deaktywować czy nawet usuwać odnośni- Stosując sprawdzony model kontroli dostępu
nie, wylogowanie i przechowywanie informa- ki do operacji, do których bieżący użyt- opartej o role, udało nam się w łatwy sposób za-
cji o użytkowniku w sesji, a także powinien kownik nie ma dostępu; projektować prosty, elegancki i elastyczny me-
przekierowywać niezalogowanego użytkow- • Łatwo napisać skrypt, który automa- chanizm kontroli dostępu. Uniknęliśmy za-
nika do kontrolera logowania (który oczywi- tycznie zaktualizuje tabelę uprawnień szywania kontroli dostępu bezpośrednio w ko-
ście nie może być dekorowany kontrolą dostę- na podstawie analizy kodu kontrole- dzie, pozwalając na dynamiczne przydzielanie
pu). Profil, sprawdzając uprawnienia, powi- rów. Dzięki temu nie trzeba pamiętać o uprawnień do ról, a zarazem ułatwiając admini-
nien opierać się na liście ról bieżącego użyt- uzupełnianiu tabeli uprawnień w bazie strację uprawnieniami.
kownika. Jeśli posiada on dane uprawnienie, wraz z rozwojem systemu. Taki skrypt
kontrola przekazywana jest do udekorowane- może po prostu szukać w plikach źró-
go kontrolera, który z kolei wywołuje metodę dłowych wzorców, odpowiadających me- ADAM BYRTEK
obsługującą dane zdarzenie. Jeśli nie, wyrzu- todom kontrolera (np. przy użyciu wyra- Autor odpowiada za zespół programistyczny,
cany jest wyjątek, który oczywiście powinien żeń regularnych), albo wykorzystać me- zajmujący się rozwojem wewnętrznego systemu
zostać odpowiednio obsłużony. chanizm refleksji. Na podstawie zebra- OSS/BSS dla ogólnopolskiego dostawcy internetu.
Jak widać dzięki założeniu, że wszystkie żąda- nych danych można synchronizować ta- Kontakt z autorem: adambyrtek@gmail.com
nia muszą przejść przez kontroler i dzięki użyciu belę uprawnień. http://adambyrtek.blogspot.com/

www.phpsolmag.org 45
Narzędzia

Agavi
Pierwsze kroki

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.
prosi o nazwy dla akcji systemowych tj. akcja lo-
Dowiesz się... Powinieneś wiedzieć... gowania, akcja do obsługi błędów 404, przykła-
l Po zapoznaniu się z tekstem czytelnik będzie w l Wymagana jest podstawowa znajomość PHP dowa akcja wymagająca autoryzacji, strona po-
stanie budować szybciej, prościej oraz wydaj- oraz umysł otwarty na gotowe rozwiązania. kazywana w przypadku, gdy wyłączymy mo-
niej aplikacje internetowe w oparciu o frame- duł.
work Agavi. Strukturę katalogów nowostworzonego pro-
jektu można zobaczyć na Rysunku 1.

niego ustawienia dyrektywy include_path, tak Pierwsza akcja


by wskazywało na agavi i ewentualnie użyte Zgodnie z paradygmatem MVC Agavi dzie-
Poziom trudności przez nas biblioteki. li aplikację na niezależne od siebie warstwy.
Warstwę logiki biznesowej, którą reprezentu-
Tworzymy projekt ją kontrolery obiektów biznesowych, reprezen-
Stworzenia akcji w Agavi wiąże się ze stworze- towanych przez modele oraz warstwę logiki wi-

C
elem developerów Agavi było i jest two- niem projektu. Po instalacji przez PEAR (patrz doku.
rzenie frameworka uniwersalnego, któ- ramka Instalacja) mamy do dyspozycji polece- Każda akcja w Agavi musi być przyporządko-
ry nie ogranicza programisty poprzez nie agavi, które umożliwia tworzenie modułów, wana do określonego modułu (jakiejś wydzielo-
narzucenie mu mechanizmów, z których musi akcji oraz widoków na podstawie predefiniowa- nej, logicznie spójnej części aplikacji) i rozsze-
korzystać, nie ma zatem mechanizmów typu nych szablonów kodu, które można zmienić rzać klasę abstrakcyjną – AgaviAction.
ORM, czy też scaffolding. Technologia obsługu- (folder agavi/buildtools/code_templates). Stwórzmy swoją pierwszą akcję, która bę-
jąca widok jest dowolna (do wyboru php, xslt, Jest ono o tyle użyteczne, że zwalnia nas z ko- dzie wyświetlać formularz i dane wprowadzo-
smarty, phptal) podobnie jak sposób dostępu do nieczności ręcznego kopiowania plików i zmie- ne przy jego pomocy.
bazy danych (m.in. pdo, adodb, creole). W wy- niania nazw klas. Poleceniem agavi module tworzymy nowy
borze narzędzi mamy wolną rękę. Jeśli przy- Aby stworzyć strukturę katalogów na potrze- moduł o nazwie Welcome. Zostaniemy zapyta-
zwyczaiłeś się do którejkolwiek z tych biblio- by artykułu, wpisujemy w konsoli agavi project. ni również o akcje, jakie powinny zostać stwo-
tek, nie musisz z niej rezygnować, framework Instalator zapyta nas o położenie projektu i po- rzone. Pozostawiamy domyślną – Index. Po-
wspiera ich obsługę.
Listing 1. Pierwsza akcja do obsługi formularza
Instalacja Agavi
Najszybszym sposobem na instalację Agavi jest <?php
użycie kanału PEAR. Sposób ten wymaga wcze-
śniejszego skonfigurowania PHP i instalacji pa- // Schemat nazwy akcji:
kietu PEAR. NazwaModułu_NazwaAkcjiAction
class Welcome_IndexAction extends ProjectBaseAction {
pear config-set auto_discover 1
pear install --alldeps channel:// // obsługa żądania POST
pear.agavi.org/agavi public function executeWrite(
AgaviRequestDataHolder $rd) { return 'Success'; }
Instalacja z opcją alldeps spowoduje zainstalo-
wanie wszystkich, nawet opcjonalnych pakie- // obsługa żądania GET
tów, tj. Propel, Creole. public function getDefaultViewName() { return 'Input'; }
Wyżej opisany sposób jest przewidziany dla }
stanowisk deweloperskich. Na serwerze napisa- ?>
na przez nas aplikacja wymaga tylko odpowied-

46 Kwiecień 2007
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ę
Rysunek 1. Struktura katalogów nowego projektu
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 2. Działająca akcja

R E K L A M A
Narzędzia

słaniu pokażemy użytkownikowi stronę, na


Obiekty predefiniowane, dostępne w szablonach której wykorzystamy przesłaną wartość – Li-
Agavi daje możliwość określenia w konfiguracji typów wyjściowych (ang. output types) predefinio- sting 3.
wanych zmiennych. W szablonach pojawiają się zmienne, których
• routing – instancja klasy AgaviRouting – elementu odpowiedzialnego za tworzenie i zarzą-
w żaden sposób nie deklarowaliśmy w widoku.
dzanie adresami URL. Są to obiekty zdefiniowane w konfiguracji me-
• request – instancja klasy pochodnej AgaviRequest – dostarcza informacji o obecnym żąda- chanizmu typów wyjściowych (ang. output ty-
niu np. w przypadku HTTP metodę dostępu, adres etc. pes). Omówimy je w dalszej części artykułu. W
• user – instancja klasy AgaviUser – dostęp do zmiennych zapisanych w sesji tej chwili istotne są dwie, zdefiniowane domyśl-
• translation_manager – instancja klasy AgaviTranslationManager – zarządzanie tłumacze-
nej konfiguracji zmienne – rd, czyli obiekt klasy
niami komunikatów, formatowaniem dat oraz liczb
AgaviRequestDataHolder oraz ro – obiekt kla-
• request_data – wszystkie dane wejściowe jakie otrzymało Agavi
• validation_manager – instancja klasy AgaviValidationManager – dostęp do błędów wali- sy AgaviRouting. Pierwszy jest pochodną kla-
dacji. 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-
Listing 2. Szablon widoku WelcomeInput
resów URL. Mechanizm routingu (ang. routes)
<html> jest jednym z bardziej istotnych w Agavi. Jest on
odpowiedzialny za mapowanie adresów URL
<head> do akcji. Definicję wszystkich mapowań apli-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> kacji znajdziemy w pliku app/config/routes.xml.
</head> Warto zapamiętać, że kolejność definiowania
poszczególnych mapowań ma znaczenie. I tak,
<body> pusty wzorzec dla mapowania zdefiniowanego
<h1>Podaj imię</h1> na początku zawsze będzie pasował, do każdego
<form action="<?php echo $ro->gen('welcome'); ?>" method="post"> adresu. Agavi przy tworzeniu nowego projektu
<label for="fe-name">Imię</label> domyślnie tworzy mapowanie, które przechwy-
<input type="text" name="name" id="fe-name" /> tuje wszystkie żądania, by wyświetlić stronę po-
<input type="submit" /> witalną. Usuwamy zatem pierwsze mapowanie
</form> i dodajemy na końcu własne, kierujące z adresu
</body> index.php/Welcome/Index (serwer http musi wi-
dzieć katalog pub aplikacji) do dopiero co stwo-
</html> rzonej akcji. Jeśli chcemy używać danego mapo-
wania do generowania adresu musimy określić
Listing 3. Szablon widoku WelcomeSuccess wartość dla atrybutu name.
<html> Konfiguracja po zmianach powinna wyglą-
dać tak jak na Listingu 4. Po dokonaniu tych
<head> modyfikacji jesteśmy gotowi, by uruchomić
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> akcję. Wpisujemy zatem w adresie przeglądar-
</head> ki adres, pod którym stworzyliśmy aplikację
(miejsce, gdzie jest dostępny katalog pub aplika-
<body> cji) i dodajemy w adresie, po pliku wzorzec zde-
<h1>Witaj <?php echo $rd->getParameter('name'); ?>!</h1> finiowany w mapowaniu – /Welcome/Index.
</body>
Walidacja danych
</html> Nieodłącznym elementem każdej aplikacji, nie
tylko webowej, jest weryfikacja poprawności i
Listing 4. Konfiguracja mechanizmu mapowania adresów spójności otrzymywanych danych. Walidacja
<?xml version="1.0" encoding="UTF-8" standalone="no"?> poprawności obejmuje format i zakresy wpro-
wadzonych wartości podczas, gdy walidacja
<configurations> pod kątem spójności wiąże się zwykle ze spraw-
<configuration> dzaniem, czy wprowadzone wartości są repre-
<routes> zentowane w bazie danych. Agavi potrafi znacz-
nie ułatwić pierwszy z tych procesów dostar-
<route pattern="^/$" module="%actions.default_module%" czając komplet klas i odpowiedni mechanizm
action="%actions.default_action%" /> do ich obsługi.
Definicja walidacji jest unikalna dla każdej
<route pattern="^/Welcome/Index$" module="Welcome" action="Index" akcji jakkolwiek jest możliwość elastycznego
name="welcome" /> łączenia walidacji poprzez doczytywanie ko-
lejnych plików (zresztą to się tyczy całej kon-
</routes> figuracji Agavi) przy pomocy Xinclude. Wali-
</configuration> dację dla każdej akcji definiujemy przy pomo-
</configurations> cy XML-a w pliku validate/nazwa-akcji.xml.
Na Listingu 5. znajduje się konfiguracja dla ak-

48 Kwiecień 2007
Narzędzia

cji Index. Sprawdzamy w niej, czy podane imię dzie wyglądać tak, jak na Listingu 6. Po urucho- global_filters oraz dodajemy styl CSS w szablo-
(zmienna name) jest w prawidłowym formacie mieniu akcji i wprowadzeniu nieprawidłowych nie widoku WelcomeInput z Listingu 7.
przy użyciu wyrażeń regularnych. danych zobaczymy ponownie stronę z formula- Filtr, który włączyliśmy przed chwilą jest od-
W chwili, gdy proces walidacji wygeneru- rzem. Tu nasuwa się pytanie, co trzeba zrobić, powiedzialny za integrowanie walidacji oraz wi-
je błędy Agavi domyślnie będzie usiłowywało by dorzucić do widoku WelcomeInput obsługę doku. Jest on wykonywany dopiero po wygene-
uruchomić widok Error dla danej akcji. Można błędów? Tak naprawdę, niewiele. Po pierwsze rowaniu odpowiedzi i operuje na kodzie, tuż
zmienić to zachowanie dodając do akcji metodę włączamy FormPopulationFilter (w skrócie przed jego wysłaniem do przeglądarki. Stąd ma
handleWriteError(AgaviRequestDataHolder FPF) poprzez zmianę atrybutu enabled na true dostęp do wszystkich powstałych błędów i mo-
), która powinna zwracać nazwę widoku obsłu- przy jego definicji (fragment filter name=" że z powodzeniem wypełniać ponownie dany-
gującego błąd. W naszym wypadku akcja ta bę- FormPopulationFilter") w pliku app/config/ 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-
Listing 5. Walidowanie danych dla akcji Index
nież etykiet tekstowych (ang. labels) wskazują-
<?xml version="1.0" encoding=" UTF-8" standalone="no"?> cych na dane pole.
<configurations> Po ponownym wprowadzeniu danych na-
<configuration> szym oczom ukaże się pokolorowane pole oraz
<validators method="write"> czerwona etykieta tekstowa tak jak na Rysunku
<validator class="regex" name="name"> 3. Niestety w wersji Agavi 0.11 FPF nie wstawia
<!-- zmienne, które obejmuje walidacja --> komunikatów błędów obok etykiet tekstowych.
<arguments><argument>name</argument></arguments> Taką możliwość będzie dawał dopiero w wersji
<!-- komunikaty błędów --> 1.0. Obsługę błędów bez dodatkowego kodu
<errors><error>Zły format danych</error></errors> można zrealizować przy pomocy rozszerzonej
<!-- konfiguracja walidatora --> implementacji FPF dostępnej do pobrania wraz
<parameters><parameter name="pattern">/\w{2,7}/</parameter></parameters> z listingami do artykułu.
</validator>
</validators> Klasy widoków
</configuration> Ważnym elementem, który pozwala nam na
</configurations> bardzo dokładną separację kodu są klasy wido-
ków. Do tej pory nie definiowaliśmy żadnych
Listing 6. Metoda wykonywana w chwili niepowodzenia walidacji klas widoku – zrobiło to za nas Agavi. W kla-
//obsługa błędów w przypadku żądania POST sie widoku powinna znaleźć się logika i opera-
public function handleWriteError (AgaviRequestDataHolder $rd) cje związane z prezentacją treści tj. pobranie ja-
{ kiegoś rekordu z bazy danych, dorzucenie ja-
return 'Input'; kiejś dodatkowej zmiennej, która nie pochodzi
} od użytkownika.
Na Listingu 8. znajduje się klasa podobna do
Listing 7. Styl CSS do obsługi błędów walidacji tej, którą wygenerował framework. Podobnie jak
.error { color: maroon; } akcja, tak i klasa widoku musi rozszerzać odpo-
input.error { background-color: #ffe0e0; } wiednią klasę – w tym przypadku AgaviView.
Metoda setupHtml jest zdefiniowana w wido-
Listing 8. Klasa widoku IndexInput
<?php
Listing 10. Dokument XML z definicjami
// Schemat nazwy akcji: NazwaModułu_NazwaAkcjiView uprawnień
class Welcome_IndexInputView extends ProjectBaseView {
// Nazwa metody: executeNazwaTypuWynikowego <?xml version="1.0"
public function executeHtml(AgaviRequestDataHolder $rd) { encoding="UTF-8"
$this->setupHtml($rd); standalone="yes"?>
// ustawienie zmiennej _title dostępnej z poziomu szablonu
$this->setAttribute('_title', 'Index Action'); <configurations>
} <configuration>
}
?> <roles>
<role name="member">
Listing 9. Najprostsza akcja logowania <permissions>
<?php <permission>
class Default_LoginAction extends AgaviAction { welcome.index
public function execute(AgaviRequestDataHolder $rd) { </permission>
$user = $this->getContext()->getUser(); </permissions>
$user->setAuthenticated(true); </role>
return array('Welcome', 'IndexInput', $rd); </roles>
}
} </configuration>
?> </configurations>

50 Kwiecień 2007
Narzędzia

ku podstawowym projektu. Jeden widok może


W Sieci: zawierać wiele metod execute* w zależności
od formatów, jakie obsługuje dana akcja.
• http://agavi.org/ - oficjalna strona projektu Agavi W szablonie mamy dostęp do zmien-
• http://wact.sourceforge.net/ - witryna jednego ze starszych frameworków dla PHP
nych, które ustawiliśmy w klasie widoku,
• http://cakephp.org/ - framework wzorowany na Ruby on Rails
• http://symfony-project.com/ - framework wzorowany na Ruby on Rails, oparty na zmodyfiko- za pośrednictwem tablicy $template (np.
wanym szkelecie Mojavi $template['zmienna']).
• http://framework.zend.com/ - framework tworzony przez firmę Zend
• http://code-house.net/ - polskojęzyczna strona poświęcona między innymi Agavi Obsługa sesji i autoryzacja
W 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-
Rysunek 3. Walidatory oraz Form Population Filter w działaniu chanizmu musimy zaimplementować akcję lo-
gowania, która odpowiednio zmodyfikuje in-
stancję klasy AgaviSecurityUser. Przykłado-
Listing 11. Kompletny kod naszej akcji
wa akcja znajduje się na Listingu 9. Nie zawie-
<?php ra ona jakichkolwiek operacji związanych z ba-
zą danych, a tylko ustawia odpowiednią flagę,
// Schemat nazwy akcji: NazwaModułu_NazwaAkcjiAction która powoduje, że Agavi dopuszcza użytkow-
class Welcome_IndexAction extends ProjectBaseAction nika do uruchomienia akcji.
{ Jeśli tworzymy większą aplikację z biegiem
czasu powstają grupy użytkowników, które
// obsługa żądania POST mają różne uprawnienia, np w sklepie księgo-
public function executeWrite(AgaviRequestDataHolder $rd) wy nie może dodawać produktów, sprzedawca
{ nie może przeglądać statystyk sprzedaży i tak
return 'Success'; dalej. Każda grupa ma dostęp do określonych
} akcji. W Agavi możemy zrealizować to w bar-
// obsługa żądania GET dzo prosty sposób. Po pierwsze – mówimy
public function getDefaultViewName() { frameworkowi, by zaczął obsługiwać grupy
return 'Input'; użytkowników. Robimy to przez wyedytowa-
} nie pliku app/config/factories.xml, w znaczni-
// obsługa błędów w przypadku żądania POST ku user zmieniamy wartość atrybutu class na
public function handleWriteError(AgaviRequestDataHolder $rd) AgaviRbacSecurityUser. Następnie w akcji
{ nadpisujemy metodę getCredentials, tak by
return 'Input'; zwracała tablicę z listą uprawnień, które mu-
} si posiadać użytkownik by framework odpalił
// wymagamy autoryzacji akcję. Po wykonaniu tej czynności tworzymy
public function isSecure() { plik rbac_definitions.xml w folderze app/config
return true; z zawartością z Listingu 10. Następnie mo-
} dyfikujemy akcję logowania, tak by nadawała
// lista wymaganych uprawnień zalogowanemu użytkownikowi odpowiednie
public function getCredentials() { uprawnienie. Robimy to przez wykonanie me-
return array('welcome.index'); tody grantRole na obiekcie AgaviUser.
}
}
?> ŁUKASZ DYWICKI
Kontakt z autorem: lukasz@dywicki.pl

52 Kwiecień 2007
Strona poświęcona językowi PHP. Skierowa- Strona zawierająca skrypty, newsy i artykuły Strona poświęcona językowi php. Można tu
na głównie do webmasterów i twórców opro- dotyczące aplikacji CMS oraz forum poświęco- znaleźć m.in. artykuły oraz dział “download”
gramowania. ne temu zagadnieniu. oraz wypowiedzieć się na forum.
www.strefaphp.net www.trycms.org www.php.org.pl

Główna strona firmy gdaq.pl multimedia zajmu- Strona zajmująca się różnymi zagadnieniami z Strona jest polską bazą tutoriali, zawierającą
jącej się kreowaniem wizerunku firm poprzez działu IT. Prezentuje m.in. newsy, artykuły oraz różnorodne teksty o tematyce informatycznej.
projektowanie stron, hosting, e-marketing etc. pliki do ściągnięcia i forum. www.webtutorials.pl
www.gdaq.pl www.huntersq2.boo.pl

Misją serwisu jest dostarczanie rzetelnych in- Portal w całości poświęcony językowi PHP. Strona, na której znajdziesz profesjonalne sza-
formacji z zakresu szeroko pojętej informatyki. Można tu znaleźć m.in. recenzje, artykuły oraz blony stron www. Ponadto prezentuje tutoriale,
Strona zawiera newsy m.in. z działów: progra- newsy poświęcone temu zagdnieniu. artykuły i porady dla webmasterów.
mowania, bezpieczeństwa oraz Internetu. www.php.pl www.d4u.pl
www.itnews.icx.pl

To serwis branży IT, oferujący m.in. newsy, ar- Serwis dla początkujących, jak i zaawansowa- Główna strona studentów Politechniki War-
tykuły, recenzje książek i magazynów oraz fo- nych webmasterów. Zawiera gotowe szablony szawskiej.
rum. Strona obejmuje również patronat nad stron oraz posegregowane skrypty PHP i Ja- www.polibuda.info
projektami IT. vaScript.
www.webhat.pl www.szablonypro.com
Narzędzia

PDF
Generowanie z poziomu PHP

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?

tykułu, to 1.53), następnie rozpakowujemy ar-


Dowiesz się... Powinieneś wiedzieć... chiwum (zip lub tgz). Po rozpakowaniu powin-
• Jak przygotować bibliotekę do pracy • Jak tworzyć obiekty w PHP niśmy otrzymać następujące pliki: FAQ.htm,
• Jak tworzyć dokumenty PDF oraz jak je wypeł- • Jak dziedziczyć oraz pisać własne funkcje. fpdf.css, fpdf.php, histo.htm, install.txt oraz kata-
niać. 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
my pewne pole do manewru w kwestii wyboru skopiowaniu ich do odpowiedniej lokalizacji,
wyspecjalizowanej biblioteki dla danego języka, możemy przejść do tworzenia pierwszego do-
Poziom trudności którym się aktualnie posługujemy. kumentu.
Nas jednak interesuje, w tym przypadku, tyl- Czas na odrobinę wyjaśnień. Linijka nr 2 po-
ko jeden język oraz tylko jedna biblioteka. woduje dołączenie pliku fpdf.php, wymaganego
do poprawnego generowania dokumentów. Li-

O
tóż PDF (ang. Portable Document For- PHP + FPDF nijka 3 tworzy obiekt pdf, na którym będziemy
mat) jest formatem plików, służą- FPDF jest biblioteką, a konkretniej klasą PHP, właściwie operować.
cym do prezentacji danych teksto- która umożliwia generowanie dokumentów w Tworzenie każdego dokumentu PDF zaczyna
wych oraz graficznych, z zachowaniem wyso- formacie PDF. Literka F na początku nazwy się od dodania strony (linijka 4). Jeśli tego nie
kiej jakości i małego rozmiaru. Takie specjal- oznacza, że jest ona darmowa (ang. Free) i może- uczynimy generator „utworzy” nam dokument,
ne pliki można drukować, edytować (nie za- my jej używać do swoich celów oraz modyfiko- lecz program później go odczytujący stwier-
wsze), a co najważniejsze można je samemu bu- wać w miarę potrzeb. dzi, że jest on uszkodzony lub nie jest to PDF.
dować. Do odczytu plików PDF służą specjalne Klasa oferuje między innymi takie możliwo- Aby cokolwiek móc zacząć pisać w naszym do-
programy, które potrafią w odpowiedni sposób ści jak: kumencie jesteśmy zmuszeni wybrać czcionkę
zaprezentować to, co w pliku zostało umiesz- oraz określić jej właściwości takie jak styl oraz
czone. Najpopularniejszym czytnikiem plików • ustawienie sposobu formatowania strony rozmiar. Linijka 5 przedstawia ustawianie po-
PDF jest Adobe Acrobat Reader. Jest to darmo- (jej układ); grubionej czcionki Arial o rozmiarze 16. Moż-
wy program stworzony przez twórców PDF. Ist- • nagłówki stron oraz stopki; liwe jest również łączenie właściwości czcionek
nieje również wiele innych darmowych narzę- • automatyczne łamanie stron (dodawanie np. BUI ustawi nam czcionkę na pogrubioną,
dzi do odczytu tychże plików, jednak Acrobat nowej strony, jeśli tekst z poprzedniej stro- pochyloną i zarazem podkreśloną.
Reader, moim zdaniem, jest najlepszy. Tyle sło- ny się na niej nie mieści); Samo pisanie jest możliwe dzięki trzem me-
wem wstępu o samym formacie. • łamanie zbyt długich linijek tekstu; todom udostępnianym przez FPDF. Jedną z
• wstawianie obrazków w formatach JPEG nich jest Cell(). Jest ona czymś więcej niż tyl-
To, co tygryski lubią najbardziej oraz PNG; ko narzędziem do pisania. Jak widać w linijce
Przejdźmy zatem do sedna problemu jakim jest • kolorowanie; 6 przyjmuje ona aż 3 argumenty (w rzeczywi-
tworzenie plików PDF. Firma Adobe Systems • rysowanie linii; stości może przyjmować ich trochę więcej, ale
udostępnia odpłatnie narzędzia do tworzenia • manipulacja kursorem; o tym później). Metoda Cell(), tak napraw-
plików PDF. Ale kogo będzie interesował zakup • podpisywanie dokumentu; dę, rysuje prostokąt (komórkę) i wypełnia go
programu, jeśli chce tylko użyć go raz? • oraz inne, których jest tyle, co metod udo- tekstem. Pierwszy argument określa szerokość
W sieci znajduje się wiele programów darmo- stępnianych przez klasę. Spis wraz z obja- owej komórki, drugi zaś wysokość i wreszcie
wych, wyspecjalizowanych w tego typu zada- śnieniami znajduje się na końcu artykułu. trzeci to sam tekst. Ostatnia, bardzo istotna,
niach. Problematyczna jest natomiast ich funk- linijka to zamknięcie dokumentu PDF. Służy
cjonalność. Innym sposobem generowania pli- Zaczynamy do tego metoda Output(). Jeśli wywołamy ją
ków PDF jest ich tworzenie z poziomu któregoś Ze strony domowej projektu ściągamy najnow- w takiej postaci jak jest to przedstawione w li-
z języków programowania. Tutaj również ma- szą wersję klasy (najnowsza, w chwili pisania ar- nijce 7, to przeglądarka (w zależności od usta-

54 04/2007
Zaprojektuj i zbuduj swój własny dokument PDF

wień) otworzy nam taki dokument. Metodzie bieski w celu otrzymania interesującej nas bar- Wracając do naszego przykładu kolorem
Output() możemy przekazać jeszcze 2 argu- wy. Kolejną ważną opcją jest możliwość naryso- czerwonym zostały narysowane 3 linie. Ko-
menty np. Output(dokument.pdf, true), w ten wana ramki komórki w wybranym kolorze: niec każdej linii jest początkiem następnej, ła-
sposób spowodujemy wymuszenie zapisania two więc domyśleć się, że rysowaną figurą bę-
dokumentu na dysku lokalnym o nazwie doku- $pdf->SetDrawColor(255, 0, 0); dzie trójkąt.
ment.pdf. Jest to dość przydatne. $pdf->SetTextColor(255, 0, 0); Kolejną figurą jaką narysowaliśmy również
Wynikiem działania kodu z Listingu 1. jest $pdf->Cell(50, 20, "Czerwony", 1) jest trójkąt z tą tylko różnicą, że boki tego trój-
nic innego jak tylko dokument PDF o następu- kąta są znacznie grubsze niż u poprzedniego
jącym wyglądzie: patrz Rysunek 1. Metoda SetDrawColor() służy do ustawia- oraz mają inny kolor. Grubość linii wynika z
Nasz dokument nie jest, jak na razie, zbyt roz- nia koloru obramowań komórek oraz do ry- faktu wywołania metody SetLineWidth(x),
budowany. Na Rysunku 2. przedstawię bar- sowania pojedynczych linii. Stosując ją do na- gdzie x stanowi określenie grubości w milime-
dziej urozmaicony przykład. rysowania ramki komórki należ pamiętać, że- trach. Standardowo wartość ta wynosi 2 mm.
Jak widać dodałem troszkę elementów do na- by metodzie Cell() przekazać argument mó- No dobrze, mamy namalowane figury. Ale cze-
szego PDF-a. Nowy kod nie różni się niczym wiący o wyświetleniu ramki. Inaczej nie zo- goś tu w wyjaśnieniach jeszcze brakuje. Otóż
nadzwyczajnym od poprzedniego. Ważną baczymy interesującego nas efektu: patrz Ry- w przykładzie użyłem metody Text(x, y,
zmianą jest jedynie dodanie czterech wywołań sunek 4. string), która to pozwala na wypisanie tek-
metody Cell() z odpowiednimi argumentami. Kolejnym prezentowanym przeze mnie spo- stu, którego początek będzie znajdować się w
Fragment kodu formatującego komórkę: sobem „upiększania” PDF-a jest wypełnianie
komórek kolorem. W tym celu należy posłu-
$pdf->Cell(60,20, żyć się metodą SetFillColor() oraz przekazać
"Czciona pochylona", 1, 1, "c") jej argumenty w postaci składowych RGB. Nie-
stety nie wystarczy tylko wywołać tej metody i
Rysunek 1. Fragment wygenerowanego prostego
Trzy pierwsze argumenty nie wymagają zbyt- rysując komórkę oczekiwać, że otrzymamy za- PDF-a
niego wyjaśnienia. Natomiast kolejne 3 wyglą- mierzony efekt. Metodzie Cell() należy jeszcze
dają dość interesująco. Wcześniej wspomnia- przekazać kolejny argument mówiący o tym, że
łem już, że metoda Cell() może przyjmować ma użyć zdefiniowanego przed chwilą koloru �������������������
więcej niż 3 argumenty. Teraz słowo wyjaśnie- wypełnienia. Całą tę procedurę wraz z efektem
nia co do pozostałych. Pierwsza cyfra 1 mówi, przedstawiam kod poniżej i Rysunek 5.:
aby narysować ramkę o rozmiarach 60 na 20 ������������������
oraz, aby była ona widoczna. Jeśli argument $pdf->SetDrawColor(255, 0, 0);
ten ustawimy na 0, ramka pozostanie niewi- $pdf->SetFillColor(255, 0, 0);
�����������������
doczna. Kolejna 1-ka mówi, gdzie ustawić kur- $pdf->Cell(50, 20, "Czerwony", 1, 0, "", 1)
sor, czyli na początek nowej linii. Wartość tego
argumentu również może zostać ustawiona na Jak widać manipulowanie kolorami jest dość ��������������������������������
zero, wtedy kursor zostanie ustawiony na pra- proste, ale efektowne. Aby osiągnąć ciekawe
wo od ramki (jest to opcja domyślna). Ostat- efekty nie trzeba wcale posiadać specjalnych
Rysunek 2. Urozmaicony dokument PDF
ni argument opisuje, w jaki sposób ma zostać umiejętności plastycznych.
ustawiony tekst w stosunku do komórki (ram- Na sam deser przygotowałem przykład pre-
ki). C oznacza, że ma zostać wycentrowany. zentujący, w jaki sposób należy posługiwać się Rysunek 3. Efekt kolorowania tekstu
Domyślną wartością (gdy żaden argument nie metodą Line(), która umożliwia rysowanie
zostanie podany) jest L – wyrównaj do lewej, pojedynczych linii. Oczywiście nic nie stoi na
istnieje również wyrównanie do prawej – R . przeszkodzie, aby proste linie łączyć w bardziej
złożone kształty.
Rysunek 4. Efekt kolorowania tekstu i
„Chodź pomaluj mój świat” Na pierwszy rzut oka konstrukcja wydaje się obramowania komórki
Klasa FPDF udostępnia nam możliwość ryso- być trochę dziwna, ale odrobina wyjaśnienia z
wania. Nie jest to może funkcjonalność rozbu- mojej strony i przykład stanie się jasny jak słoń-
dowana, ale można ją wykorzystać nawet przy ce. W linijce pierwszej znajduje się metoda, któ-
tworzeniu dość skomplikowanych kształtów. I rą już wcześniej poznaliśmy przy rysowaniu
tak możemy rysować linie o różnych kolorach i obramowań komórek. W ten sposób ustawia- Rysunek 5. Efekt wyboru koloru wypełnienia
grubościach, wypełniać kolorem opisane wcze- my kolor linii, który za chwilę będą rysowany. wnętrza komóki oraz kolorowania jej obramowania
śniej komórki, kolorować tekst oraz ustanawiać Właściwe rysowanie odbywa się wraz z wywo-
kolor obrysu komórki. Zaprezentuję pokrótce łaniem metody Line(x1, y1, x2, y2). Przyjmu-
w/w możliwości. Oto fragment kodu ustawia- je ona 4 argumenty. Pierwszy to współrzędna ������������������

jącego kolor tekstu: x1 początku linii, druga to współrzędna y1 po-


czątku linii. Kolejne dwie to współrzędne x2 i
$pdf->SetTextColor(255, 0, 0) y2 końca linii. Należy pamiętać, iż początkiem
układu współrzędnych jest górny lewy róg ak-
Powyższa linijka sprawi, że każdy tekst, jaki tualnej strony dokumentu. I po narysowaniu li-
������������
będziemy umieszczać w naszym dokumencie, nii pozycja kursora nie zmienia się tylko pozo-
będzie koloru czerwonego tak jak, ten pokaza- staje w tym samym miejscu jak np. po zakoń-
ny na Rysunku 3. czeniu pisania za pomocą Cell(). W przypad-
Metoda SetTextColor() pobiera 3 argumen- ku chęci wypisania czegoś pod daną linią należy Rysunek 6. Efekt malowania liniami o określonych
ty, które stanowią składowe RGB. W ten sposób ustawić odpowiednio kursor metodą SetXY(x, kolorach. Oraz wypisywanie tekstu w określonym
możemy mieszać kolor czerwony, zielony i nie- y) lub SetY(y) i SetX(x). miejscu dokumentu

www.phpsolmag.org 55
Narzędzia

punkcie x,y. rech nie muszę chyba wyjaśniać, ostatni nato- kazu stanu magazynu. W takim przypadku da-
Efekt takiego fragmentu kodu przedstawia miast jest właściwym linkiem do zasobu. Przy ne reprezentowane są w postaci tabel – upo-
Rysunek 6. osadzaniu linków najczęściej wykorzystywa- rządkowanych zbiorów wierszy i kolumn.
ne są trzy pozostałe metody, które jako ostatni FPDF umożliwia tworzenie i wypełnianie ta-
Odnośniki i obrazki argument przyjmują właśnie określony link. Po- bel. Sprytny czytelnik pomyśli, że pewnie two-
Dokumenty PDF niejednokrotnie zawierają niżej znajduje się przykładowy kod pokazujący, rzy się je za pomocą metody Table() lub po-
różnego rodzaju obrazki (grafiki). Klasa FPDF jak dodać do dokumentu odnośnik: dobnej. Otóż nic bardziej mylnego. Tabele two-
również udostępnia nam taką możliwość. Słu- rzy się za pomocą narzędzia już wcześniej pre-
ży do tego metoda Image(plik, x, y, w, h). $pdf->Write(5, "Zapraszam na strone zentowanego, jakim jest metoda Cell(). Pamię-
Posiada jeszcze dwa dodatkowe argumenty, ale domowa projektu FPDF "); tacie, że pozwala ona na rysowanie obramowań
o nich za chwilę. $pdf->SetTextColor(0, 0, 255); komórek? To właśnie dzięki tej funkcjonalno-
X i Y oznacza początek obrazka względem $pdf->Write(5, "www.fpdf.org", ści jesteśmy w stanie osadzać tabele w PDF-ach.
początku aktualnej strony dokumentu, W i H "http://www.fpdf.org") Kod w Listingu 3. prezentuje przykładową ta-
jak duży ma być wyświetlany obrazek (width belę wraz z wypełnionymi i pokolorowanymi
– szerokość i height – wysokość). Sam obrazek Wykorzystałem tutaj metodę Write(), która komórkami. Jak widać nie ma tu zbyt wielkiej
jest określony w argumencie plik. Warto w tym wypisuje żądany tekst. Pierwszym argumen- „magii”. Ale krótkie wyjaśnienie będzie na pew-
miejscu wspomnieć, że FPDF rozpoznaje for- tem jest wielkość pisanego tekstu. Trzeci ar- no pomocne. W pierwszej kolejności dobrze by
maty JPEG, JPG, PNG. Wspomniałem już, że gument, jak widzimy przy drugim wywołaniu było, aby nasza tabela posiadała nagłówki. Ich
istnieją jeszcze 2 argumenty. Są one opcjonal- Write(), stanowi określony przeze mnie link do tworzenie zawarte jest w trzech pierwszych li-
ne i określają typ obrazka (jeśli nie zostaną okre- strony domowej projektu FPDF. Wynik takiego nijkach. Czynność ta wykonywana jest w pę-
ślone, to typ zostanie wyznaczony na podstawie działania możemy oglądać na Rysunku 8. tli. Komórki będą ustawione obok siebie – sty-
rozszerzenia pliku) oraz odnośnik. Odnośnik to Klikając napis www.fpdf.org zostaniemy prze- kając się krawędziami. Ich zawartość będzie za-
np. adres do strony www, na którą zostaniemy niesieni na stronę domową projektu FPDF. wierać napis Kolumna 1, Kolumna 2 itd. aż do
przekierowani, po kliknięciu odnośnika w po- Kolumna 5.
staci obrazka. Tabele Omówmy teraz tworzenie wierszy. W tym ce-
Polecenie wczytania prostego obrazka bez Dokumenty PDF często służą do prezentacji lu utworzenia wiersza tabeli wykorzystujemy dwie
określenia linii przedstawia poniższa linijka: wyników różnych badań, zestawień lub też wy- pętle – zewnętrzną oraz wewnętrzną. Pętla we-

$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-

Listing 1. Kod prostego PDF-a

<?
require("fpdf.php");
$pdf=new FPDF();
$pdf->AddPage(); Rysunek 7. Efekt wstawienia obrazka do dokumentu
$pdf->SetFont("Arial","B",16);
$pdf->Cell(30,20,"Witaj w FPDF :)"); Rysunek 8. Efekt zastosowania odnośnika do zasobu w Internecie
$pdf->Output();
?>
Rysunek 9. Efekt zastosowania wlasnoręcznie utworzonej czcionki

56 04/2007
Narzędzia

wnętrzna (linijka 8) dba o to, aby została wykreślo-


na odpowiednia ilość wierszy, czyli 6. Między linij- Listing 2. Fragment kodu prezentującego rysowanie liniami o pewnych kolorach oraz wstawianie
kami 10 i 19 odbywa się wypełnianie wierszy od- tekstu w określone miejsce dokumentu
powiednią ilością komórek. Aby urozmaicić przy- $pdf->SetDrawColor(255, 0, 0);
kład postanowiłem pokolorować tworzone komór- $pdf->Line(30, 10, 50, 10);
ki w zależności od spełnianego warunku (parzysta, $pdf->Line(30, 10, 25, 50);
nieparzysta) – linijka 10. W linijce 22 znajduje się $pdf->Line(50, 10, 25, 50);
polecenie przejścia do nowej linii w celu rozpoczę- $pdf->SetFont("Arial", "", 12);
cia nowego wiersza z danymi. Jeśli tego byśmy nie $pdf->Text(60, 40, "Taka dziwna figura");
uczynili, to 6 wierszy byłoby w jednej linijce wy- $pdf->SetLineWidth(5);
chodząc poza obręb dokumentu. $pdf->SetDrawColor(0, 255, 255);
$pdf->Line(30, 70, 30, 130);
Do You speak polish? $pdf->Line(30, 130, 80, 130);
W FPDF mamy do dyspozycji określoną ilość $pdf->Line(80, 130, 30, 70);
czcionek. Co zrobić w przypadku, gdy chcemy $pdf->Text(90, 100, "Gruba figura");
użyć jakiejś niestandardowej lub też brakuje nam
pewnej podstawowej czcionki o danym kodowa- Listing 3. Fragment kodu prezentujący tworzenie przykładowej tabeli oraz jej wypełnienie z
niu znaków. W tym momencie z pomocą przy- kolorowaniem wierszy
chodzi nam metoda MakeFont(). Lecz zanim for($i = 0; $i < 5; $i++) {
przystąpimy do tworzenia czcionki powinniśmy $l = $i + 1;
przygotować plik afm, który jest wymagany przez $pdf->Cell(35, 15, "Kolumna ".$l, 1);
metodę MakeFont(). Uczynić możemy to dzięki }
programowi tt2pt1. Gdy już zaopatrzymy się w
tt2pt1 wystarczy, że wpiszemy w linii poleceń: $pdf->Ln();
$pdf->SetFont("Arial", "", 12);
ttf2pt1 -a c:\windows\fonts\
times.ttf mojtimes for($k = 0; $k < 6; $k++) {
$wiersz = $k+1;
Dzięki temu uzyskamy potrzebny plik moj- if(($wiersz%2) == 0) {
times.afm. Poniżej prezentuję kod skryptu $pdf->SetFillColor(0, 255, 0);
PHP, który stworzy czcionkę mojtimes z pol- for($j = 0; $j < 5; $j++) {
ską stroną kodową: $pdf->Cell(35, 10, "Dana ".$j+$k+1, 1, 0, "", 1);
}
require('font/makefont/makefont.php'); }
MakeFont('times.ttf','mojtimes.afm',
'iso-8859-2') else {
$pdf->SetFillColor(0, 255, 255);
for($j = 0; $j < 5; $j++) {
W Sieci $pdf->Cell(35, 10, "Dana ".$j+$k+1, 1, 0, "", 1);
}
• http://www.fpdf.org – strona domowa
projektu FPDF. }
$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");

Rysunek 10. Efekt zastosowania wlasnoręcznie Listing 5. Fragment kodu prezentującego przetwa�anie danych z formularza
utworzonej czcionki
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();
Rysunek 11. Efekt przetworzonych danych z }
formularza

58 04/2007
Narzędzia

Jak widać na listingu, w pierwszej kolejności mu- miętajmy, aby umieścić je w tym samym katalo- tody AddFont(). Pierwszym argumentem przyj-
simy wczytać kod metody MakeFont(), aby na- gu, co skrypt z nich korzystający lub w katalo- mowanym przez tę metodę jest nazwa, pod jaką
stępnie móc ją wywołać. Do prawidłowego dzia- gu font wraz z definicją lokalizacji czcionek po- będzie rozpoznawana w skrypcie nasza czcionka,
łania metoda ta wymaga oryginalnej czcionki przez define(FPDF_FONTPATH, font/). Obo- drugi to styl (pogrubiony, pochylony, podkreślo-
pliku, który wcześniej stworzyliśmy oraz usta- jętnie, który z warunków spełnimy, możemy ny, zwykły) oraz ostatni – nazwa pliku PHP, któ-
lenia trybu kodowania znaków (strony kodo- już przystąpić do korzystania z nowoutworzo- ry został wcześniej wygenerowany. Teraz może-
wej). W wyniku działania skryptu otrzyma- nej czcionki (Listing 4.). Na początek musimy my już za pomocą poznanego wcześniej polece-
my dwa pliki mojtimes.z oraz mojtimes.php. Pa- zarejestrować czcionkę, najlepiej za pomocą me- nia SetFont() ustawić nową czcionkę. Zwracam
uwagę na pierwszy argument metody, który musi
Tabela 1. Efekt utworzenia przykładowej tabeli wraz z wypełnieniem jej danych i kolorowaniem wierszy być taki sam jak nazwa, pod jaką czcionka zosta-
ła wcześniej zarejestrowana. W ten sposób może-
Kolumna 1 Kolumna 2 Kolumna 3 Kolumna 4 Kolumna 5
my już cieszyć się własną czcionką wraz z polski-
1 1 1 1 1 mi znakami patrz Rysunek 9.
2 2 2 2 2
W miarę jedzenia apetyt rośnie
3 3 3 3 3
Mam nadzieję, że troszkę przybliżyłem czytel-
4 4 4 4 4 nikowi wybrane możliwości pakietu FPDF.
5 5 5 5 5 Przyszedł czas na prezentację połączenia nie-
których w/w funkcji w małą aplikację. Sposób
6 6 6 6 6
działania programu polega na pobraniu, po-
przez prosty formularz, danych od użytkowni-
ka oraz przekazaniu ich do skryptu PHP, który
Spis wszystkich metod udostępnianych przez FPDF:
wygeneruje na ich podstawie dokument PDF.
• AcceptPageBreak – włącza lub wyłącza automatyczne łamanie strony; Rysunek 10. przedstawia wygląd formularza
• AddFont – dodaje nową czcionkę; z przykładowymi danymi. W Listingu 5. przed-
• AddLink – tworzy wewnętrzny odnośnik; stawię fragment kodu formatowania przesła-
• AddPage – dodaje nową stronę; nych danych (pełny kod został dołączony do
• AliasNbPages – definuje alias dla liczby stron;
artykułu).
• Cell – wypisuje ramkę tekstową;
• Close – zamyka dokument; Zdeklarowana funkcja przyjmuje parametr
• Error – błąd krytyczny; $imie, który wcześniej został przesłany za po-
• Footer – stopka strony; mocą metody POST. Następnie w pętli rysowa-
• FPDF – konstruktor; na jest odpowiednia ilość komórek, poszczególne
• GetStringWidth – oblicz szerokość tekstu; wypełniane są danym znakiem pochodzącym ze
• GetX – zwraca współrzędną X kursora;
• GetY – zwraca współrzędną Y kursora;
zmiennej $imie (linijki 5, 6). W ten napis został
• Header – nagłówek strony; rozbity na poszczególne elementy, z których każ-
• Image – wstawia obrazek; dy „opakowany” jest przez komórkę. Efekt dzia-
• Line – Kreśli linię; łania skryptu zaprezentowany został poniżej:
• Link – wstaw odnośnik;
• Ln – koniec linii;
• MultiCell – wypisuje wieloliniowy tekst;
Podsumowanie
• Open – tworzy dokument; Jak widać na powyższym obrazku, dokument
• Output – zapisz albo wyślij dokument; zawsze będzie generowany dynamicznie w za-
• PageNo – numer strony; leżności od otrzymanych danych. Używanie
• Rect – prostokąt; FPDF jest dobrym pomysłem na generowanie
• SetAuthor – ustawia autora dokumentu; plików PDF w przypadku, gdy zawartość doku-
• SetAutoPageBreak – ustawia tryb automatycznego łamania stron;
• SetCompression – włącza lub wyłącza kompresję;
mentu może się zmieniać.
• SetCreator – ustawia źródło dokumentu; Możliwości FPDF nie kończą się jednak na
• SetDisplayMode – ustawia tryb wyświetlania; obsłudze formularzy. Bibliotekę tę możemy
• SetDrawColor – ustawia kolor rysowania; wykorzystać np. do prezentacji zawartości tabel
• SetFillColor – ustawia kolor wypełnienia; zawartych w bazach danych. Jedynym ograni-
• SetFont – ustaw czcionkę;
czeniem jest tylko wyobraźnia.
• SetFontSize – ustawia rozmiar czcionki;
• SetKeywords – przypisz słowa kluczowe do dokumentu; Życzę powodzenia i dobrej zabawy, w eks-
• SetLeftMargin – ustawia lewy margines; perymentowaniu z tworzeniem dokumentów
• SetLineWidth – ustawia grubość linii; PDF via PHP.
• SetLink – ustawia cel wewnętrznego odnośnika;
• SetMargins – ustawia marginesy;
• SetRightMargin – ustawia prawy margines;
• SetSubject – ustawia temat dokumentu;
TOMASZ KRAWCZYK
• SetTextColor – ustawia kolor tekstu; Autor jest studentem informatyki w Społecznej Wy-
• SetTitle – ustaw tytuł dokumentu; szej Szkole Przedsiębiorczości i Zarządzania w Ło-
• SetTopMargin – ustawia wielkość górnego marginesu; dzi. Obecnie jest w trakcie przygotowania do obro-
• SetX – ustawia bieżącą pozycję X kursora; ny pracy inżynierskiej. Interesuje się systemami
• SetXY – ustawia pozycję kursora;
operacyjnymi, różnymi językami programowania
• SetY – ustwia współrzędną Y kursora;
• Text – wypisuje tekst; (w szczególności Java), algorytmami genetyczny-
• Write – wypisuje tekst w określonej lokalizacji na stronie. mi oraz tworzy różnego rodzaju oprogramowanie.
Kontakt z autorem: tkrawczyk_net@o2.pl

60 04/2007
Narzędzia

PostNuke
System zarządzania treścią

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.
developerzy kompletnie przerobili silnik i z PostNu-
Dowiesz się Powinieneś wiedzieć ke w Xarayi zostało praktycznie tyle co nic). Zazwy-
• Zaznajomienie się z działaniem PostNuke i jego • Należy znać podstawowe pojęcia, m.in: serwer, czaj po doinstalowaniu kilku modułów z PN np. do
modułami PHP, baza danych MDPro, można uruchomić nowe moduły dedyko-
• Nauczenie się konfiguracji systemu pod swoje po- • Należy znać podstawy administracji serwerem wane tylko pod PostNuke. Ważną rolę odrywa tu
trzeby łącznie z instalacją dodatkowych modułów i jego komponentami, np. tworzenie nowych pnRender, ale o tym także później.
• Zapoznanie się z regułami uprawnień baz danych
Ogólnie o PostNuke
i jego standardowych modułach
takie osoby "atakują" fora supportowe z pytaniem Do czego przyda nam się PostNuke i do jakiego
jak ktoś mógł włamać się im na stronę lub dlaczego typu stron go używać? PostNuke jest dość uniwer-
Poziom trudności nowsza wersja dotychczas używanego przez nich salnym systemem CMS, dzięki temu, że możemy
modułu nie działa. Zazwyczaj odpowiedź jest prosta wyłaczyć bez żadnego problemu modułu (moduł
– Dokonaj aktulizacji, jednak nie wszyscy po tym są to odpowiedni "podskrypt" korzystający z funkcji
szczęśliwi, ale o tym w dalszej części artykułu. Kon- PN i swoich, bedący tylko konkretną częścią stro-

P
ierwsze wersje PostNuke utrzymywały tynuując – dużo nowego wniosła wersja 0.726, któ- ny; modułem są np. Newsy, Recenzje), których
kompatybilność z PHP–Nuke pod wzglę- ra mimo tego, że jest odradzana z powodu wielu luk nie używamy. Mało tego – można także wyłaczyć
dem API (ang. application programming w bezpieczeństwie, nadal ma ogromną ilość użyt- wtyczki dla poszczególnych modułów, np. Komen-
interface, w tym przypadku główny zbiór funkcji kowników. Była to chyba jedyna wersja, która była tarze dla Newsów, Ankiet. Takie zarządzanie mo-
CMSa), a obecnie pozostałosci z tego CMSa pra- jeszcze w miarę szybka i funkcjonalna, ale wszyst- dułami, które oferuje ten CMS, jest jego ogromną
wie wcale nie ma, dlatego też nie możemy uru- kiego – teoretycznie – mieć nie moża. PHP idzie do zaletą. Instalacja modułów pobranych z internetu
chamiać modułów z PN (skrót od PostNuke) na przodu, serwery mamy coraz lepsze i powoli ludzie nie stanowi także problemów – wystarczy odpo-
PHP–Nuke i odwrotnie. PN zawsze zachowywał przestawają myśleć o optymalizacji, co jest błedem. wiednio skopiować folder na serwer i zaktywować
licencję GNU/GPL, co przywiodło mu więcej zwo- Kolejną wersją był przełomowy PostNuke 0.75 – ta moduł w panelu administracyjnym jednym klik-
lenników niż PHP–Nuke. W przeciwieństwie do wersja była dużym krokiem do przodu, miała nieco nięciem myszki. Dla porównania np. dla polskiego
swojego przodka, który nadal jest aktulizowany, inną filozofię dotyczącą modułów, była bardziej spo- jPortalu można doinstalować moduły (co i tak jest
PN na bieżaco miał łatane dziury, a także był dużo pularyzowana dzięki temu, że po kilku przeróbkach dużo bardziej uciążliwe niż w przypadku PN), ale
bardziej efektownie udoskonalany (np. PHP–Nuke można było zrobić stronę całkiem wyróżniającą się o ich usuwaniu już nikt nie myślał. PN odrożnia
do dzisiaj nie ma instalatora). PostNuke jest do dzi- od innych, ale problem był jeden – moduły miały jeszcze jedna rzecz – system wtyczek. Takie mo-
siaj jednym z najczęściej używanych CMSów, a nic kod HTML na zasadzie "kod w kodzie", czyli ich duły jak komentarze są traktowane przez system
nie zwiastuje, aby to się zmieniło – nowa wersja Po- layout wbudowany był po prostu w funkcje echo jako wtyczki, które można podpiąć do dowolnych
stNuke jest już w budowie – co prawda trwa to już (funkcja PHP wyświetlająca dany tekst). Dopiero modułów – np. do modułu sklepu umożliwiając
kilka lat, ale można pobrać już pierwsze wersje RC w PostNuke 0.760 moduły zaczęły korzystać z syste- komentowanie jego produktów. Instalując jedną
(ang. release candidate) i wszystko wskazuje na to, że mu szablonów Smarty. Wersja ta jest najnowszą sta- wtyczke sami wybieramy gdzie ma być ona używa-
wersję finalną zobaczymy już w tym roku. bilną wersją, którą wzbogacono już o poprawki i łatki na. Przykładowo instalując wtyczke umożliwiającą
kolejno wydając paczki PN 0.761, 0.762, 0.763 (na używanie emotoikon możemy ją aktywować tylko
Rozwój i CMSy na nim bazujące dniach po wydaniu zauważono kolejne problemy), dla forum lub dla forum, newsów, artykułów, czy
Tak naprawdę ludzie zaczęli dostrzegać Postnuke już 0.764. Wersja 0.76x jest zarazem najwolniejszą też do wszystkich modułów. Tu nie trzeba nic kom-
od wydania pierwszych wersji 0.7x. Wersje starsze, wersją PN (najbardziej obciąża serwery). Z PostNu- binować – wszystko "załatwiamy" dzięki zaledwie
jak np. 0.716 byly bardzo wydajne, aczkolwiek nie ke także zostały stworzone forki. Najpopularniejsze kilku kliknięcią myszą. Gdzie jednak w modułach
miały w sobie nic odrózniającego się od konkuren- z nich to MDPro (powstały z PN 0.726, zachowuje uniwersalność PostNuke? Otóz polega to na tym, że
cyjnych systemów. Do teraz tych wersji używaja oso- 80% kompatybilności z PN 0.75 oraz ok. 60% z PN możemy usunąć modułu, które są dla nas zbyt bar-
by, które uważaja, iż wersje te są dla nich wystarcza- 0.76x), enVolution, Xoops oraz Xaraya (obecna wer- dzo rozbudowane lub nieintuicyjne, albo posiadają-
jące i nie obciążają zbytnio serwera. Często jednak sja praktycznie nie jest wcale kompatybilna z PN, jej ce zbyt mała funkcjonalność. Wszystkie możemy

62 4/2007
PostNuke

zamienić na moduły alternatywne (oficjalne bądź INSTALACJA • Wybieramy język instalacji (Rysunek 2.)
nieoficjalne), których w internecie do pobrania • Akceptujemy licencję GNU/GPL
setki i to za darmo. W dodatku nie trzeba daleko • Kopiujemy pliki na nasz serwer. Upewnij- • Ustawiamy prawa zapisu, czyli chmod 777
szukać – na stronach supportowych, których jest my się, że nasz klient FTP nie zamienia li- na pliki config.php, config–old.php oraz ka-
dość sporo (chociażby świetny polski support http: ter przy kopiowaniu na małe. Po tym uru- talogi pnTemp/pnRender_cache, pnTemp/
//www.post–nuke.pl), wszystko znajduje się w dziale chamiamy w przeglądarce plik install.php. pnRender_compiled, pnTemp/Xanthia_ca-
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. Rysunek 1. Pliki PostNuke
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 2. Początek instalacji

63
Narzędzia

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
Rysunek 3. Wpisywanie informacji o bazie danych
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
Rysunek 4. Tworzenie bazy plików językowych

64 4/2007
PostNuke

• includes – ten katalog zawiera więcej istot- niej zobaczyć jak to działa, ustawienia wielojęzyko- view – wyświetla moduł, odpowiada temu atrybut
nych katalogów. Nas będą interesować we – można tam wybrać domyślny język strony i &func=view – dla przykładu: index.php?module-
• blocks – katalog bloków menu oraz search zezwolić lub zabronić zmiany języka – zostawmy =Downloads&func=view), co pozwala na wyświe-
– katalog wtyczek do wyszukiwarki także zezwolone, strona główna – możemy zmie- tlenie np. konkretnej kategorii downloadu, ustawie-
• modules – katalog modułów, zawiera nić tam główny moduł – np. zamiast standardowe- nia niusów – możemy ustawiać ilość newsów na
wszystkie foldery z plikami modułów go News ustawić Downloads, jeśli ma to być strona stronie głównej oraz w panelu administracyjnym,
• themes – katalog skórek, zawiera podfolde- z pobieraniem plików, a także dodać funkcję starto- sortowanie newsów oraz stroniconowanie – czy-
ry ze skórkami, tam należy także umiesz- wą i argumenty (każdy moduł na swoją funkcję, np. li linki do kolejnych stron z newsami (pager), ra-
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- Rysunek 5. PostNuke tuż po instalacji
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 6. Panel administracyjny PostNuke

65
Narzędzia

portowanie błędu – po włączeniu tej opcji będzie- tym polu będzie się wyświetlał na stronie w miej- ker wysyła o tym informacje na e–mail administra-
my informowani o błędach głównie w zapytaniach scu, gdzie w kodzie skórki wstawiliśmy znacznik tora, bardzo często są to alarmy fałszywe), opcje
do bazy MySQL, a także innych głównych błę- stopki – można tu używać HTML i spokojnie usu- HTML – możemy ustawić które tagi HTML ma-
dach związanych ze stroną – możemy także usta- nąć wszystkie powered by (choć miłym gestem jest ją być dozwolone do użytku przez użytkowników
wić zabawne komunikaty błędów, różne – opcje te zostawić te obrazki), konfiguracja źródła artykułów w komentarzach, postach na forum, newsach itp.
mają wpływ na wydajność systemu – jeśli włączy- – inaczej konfiguracja RSS, opcje bezpieczeństwa – należy zwrócić uwagę, by nie zezwalać na wszyst-
my wsparcie dla starych modułów, PostNuke bę- – możemy tutaj ustawić na jaki czas użytkownicy kie tagi, a szczególnie na te narażające serwis na nie-
dzie działał minimalnie wolniej, ale będziemy mo- mają być zalogowani (jeśli wcześniej nie użyją opcji bezpieczeństwo, jak chociażby tag <script>. Wpro-
gli używać zazwyczaj bez problemów modułów wyloguj), włączyć sprawdzanie adresów polecają- wadzone zmiany w ustawieniach możemy już za-
ze starszych wersji, za to opcja kompresji przyspie- cych stron do druku, włączyć pnAntiCracker (jeśli twierdzić. Jak widać nasz PostNuke nieco się zmie-
sza działanie strony, wiadomość w stopce – tekst w na stronie dzieje się coś podejrzanego pnAntiCrac- 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-
Rysunek 7. Zmieniony PostNuke 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),
Rysunek 8. Domyślny formularz rejestracji system odmówi mu rejestracji

66 4/2007
Narzędzia

• Zakazane adresy e–mail i klienci HTTP – • Banners – moduł służący do wyświetlania • Members_List – podstawowa lista zareje-
w tych polach można wypisać po przecinku bannerów na stronie, posiada funkcje do- strowanych użytkowników, zawiera też
dane domeny e–mail oraz adresy klientów dawania klientów, zliczania kliknięć ban- rozbudowaną listę użytkowników online
HTTP, którzy nie będą mogli się zarejestrować nerów danego klienta, ustawiania limitu • Messages – moduł prywatnych wiadomo-
• Minimalny wiek – wiek, który będzie poja- odsłon. Ponad to można osobne typy ban- ści (używany także w dodatkowych mo-
wiał się w informacji o ograniczeniu wieko- nerów wyświetlać w osobnych blokach dułach forum)
wym przy rejestracji. Jeśli ustawimy go na statycznie lub na zasadzie rotatora • Modules – odpowiada za zarządzanie
0, informacja ta nie będzie się już pojawiać • Blocks – odpowiada za zarządzanie bloka- wszystkimi modułami
• Minimalna długość hasła użytkownika mi, pozwala przenosić bloki menu, two- • Multisites – pozwala na łączenie kilku
• Domeny IDN – zezwala na podanie adre- rzyć nowe, edytować je i usuwać stron w jedną, tj. różnych stron korzystają-
sów domen ze znakami narodowymi • Censor – odpowiada za filtrację niecenzu- cych z tego samego skryptu i bazy danych,
• Logowanie/wylogowywanie zgodne z ralnych słów, które możemy sami dodawać nawet na różnych domenach
WCAG – aktywacja tej opcji spowoduje, • Comments – wtyczka umożliwiająca komen- • News – moduł odpowiadający za newsy i
że przekierowania po zalogowaniu nie bę- towanie newsów i ankiet. Standardowo jej artykuły
dą odbywać się na stronie niezgodnej ze układ jest bardzo nieprzejrzysty, dlatego war- • NewUser – odpowiada za rejestrację użyt-
standardami WCAG. Jest to opcja zbęd- to zmienić tę wtyczkę na CommentsEx (ulep- kowników
na, gdyż nikt nie sprawdza poprawności szona wersja tego samego modułu) lub Ez- • Permissions – rozbudowany i z początku
stron podczas przekierowań. Comments (całkowicie inny moduł, posiada trudny w obsłudze moduł uprawnień (czyli
możliwość importu starych komentarzy) zezwoleń co może użytkownik, co gość itp.)
Standardowe moduły nie koniecznie muszą słu- • Credits – wyświetla informacje o licencji • pnRender – wsparcie Smarty dla PostNu-
żyć w naszym serwisie – nie zawsze nas zado- PostNuke oraz zainstalowanych modułów ke, korzysta z niego także Xanthia (można
wolą, a może i nawet będą miały dla naszego ser- • Downloads – odpowiada za pliki do po- rzec, że Xanthia i pnRender tworzą pod-
wisu zbyt dużo funkcji. Krótka charakterysty- brania, ma możliwość grupowania plików stawowy system szablonów PN, dlatego te
ka powinna dać nam podstawowe rozeznanie w kategorie, zlicza kliknięcia, pozwala na moduły powinny być razem aktywne)
w tych modułach. Do panelu zarządzania mo- ocenianie plików itp. • pn_bbcode – wtyczka umożliwiająca uży-
dułami wchodzimy klikając na ikonkę Moduły. • Ephemerids – prosty moduł kalendarza wanie BBCode
Aby dodać nowy moduł wgrywamy jego kata- • Example – testowy moduł stworzony tyl- • pn_bbsmile – wtyczka umożliwiająca uży-
log do katalogu modules (zawsze tak, aby w modu- ko po to, by programiści mogli się na nim wanie emotoikon
les znajdowała się nazwa modułu, np. TagIt, a w wzorować tworząc swoje moduły • Polls – moduł ankiet
tym folderze pliki modułu), klikamy w admini- • FAQ – odpowiada za rozbudowany skrypt • Quotes – wyświetla cytaty
stracji modułami Regeneruj, po czym odszukuje- FAQ – najczęściej zadawanych pytań • Ratings – wtyczka do oceniania, np. new-
my danego modułu (bardzo łatwo wybierając po- • Groups – odpowiada za grupy użytkow- sów, recenzji
kazywanie modułów niezainicjowanych lub pod ników (administratorzy, moderatorzy, • Recommend_Us – moduł na zasadzie “po-
daną literką). Aby moduł działał należy kliknąć użytkownicy, zbanowani itp.), pozwala leć nas”
inicjalizuj– w tym momencie dodawane są nowe dodawać swoje grupy, a także usuwać ist- • Referers – moduł pełniący rolę statystyki
tabele do bazy danych. Na koniec należy kliknąć niejące polecających stronę adresów
już tylko na link aktywuj i moduł jest gotowy do • Header_Footer – moduł generujący header • Reviews – odpowiada za recenzje, jest do-
użytku. Do każdego modułu możemy dodawać strony oraz jej stopkę w podstawowym sys- myślnie zintegrowany z wtyczką Ratings
wtyczki (link Wtyczki). Możemy także nazywać temie szablonów, inne systemy, takie jak np. • RSS – kanał RSS
moduły jak chcemy – np. Downloads wcale nie AutoTheme, już z niego nie korzystają • Search – wyszukiwarka, ma możliwość
musi się tak nazwywać, po kliknięciu na Edytuj • legal – zawiera informacje o polityce pry- prostego podpięcia wtyczek z nowo zain-
możemy ustawić nową nazwę na np. Pobieral- watności, warunkach korzystania z serwi- stalowanych modułów
nia, wtedy adres modułu będzie wyglądał tak: in- su itp., które można edytować • Sections – sekcje, rozbudowany i prosty
dex.php?name=Pobieralnia. Jeśli nie lubimy prze- • LostPassword – odpowiada za przypo- moduł artykułów z większym poziomem
chodzić przez strony modułów, możemy usta- mnienie hasła zagnieżdżenia
wić liczbę wyświetlanych modułów na liście np. • Mailer – moduł obsługuje całą pocztę, • Settings – ustawienia strony
na 100 pod linkiem modyfikuj konfigurację. Li- wszystkie maile wysyłane przez stronę. Po • Sniffer – moduł sprawdzający identyfikator
sta i krótki opis standardowych modułów pełnej jego zdeaktywowaniu nie przychodzą np. przeglądarki oraz inne dane o użytkowniku
paczki PostNuke 0.764 PL: maile z hasłem do logowania • Stats – prosty moduł zapisujące statystyki
• MailUsers – bardzo prosty moduł sub- odsłon strony, niestety często błędnie
• AddStory – odpowiada za dodawanie skrypcji (bez możliwości wyboru czy • Submit_News – przydatny moduł umożli-
artykułów/newsów i ich kategorii użytkownik chce dostawać maile, czy nie) wiający pisanie newsów/artykułów przez
• 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 Rysunek 9. Menu administratora Rysunek 10. Menu użytkownika

68 4/2007
PostNuke

użytkowników, które później muszą być od danego modułu – schemat uprawnień każde- lumnie “porządek” pozwalają na prostą zmianę
zaakceptowane przez administratora go modułu powinien być dostępny do sprawdze- kolejności wyświetlania bloków. Bloki nie są jed-
• Topics – moduł pełni rolę kategorii dla nia w pliku version.php lub pnversion.php (zależy nego typu, standardowo mamy do wyboru róż-
większości modułów, innymi słowy po- czy to moduł starej, czy nowej generacji) znajdu- ne rodzaje bloków, takie jak np. blok menu, blok
zwala na grupowanie publikacji z różnych jącego się w katalogu modułu. W przypadku blo- HTML, blok PHP, blok ankiety, blok wyświetla-
modułów w jeden temat, któremu można ków instancja wygląda tak: Nazwa bloku:Dana jący ostatnio dodane newsy, ale możemy także
przypisać zdjęcie pozycja: . W instancji można grupować kilka po- doinstalować bloki (np. pokazujące użytkowni-
• Top_List – pokazuje listę najczęściej czyta- zycji w tablice używając nawiasu i znaku |, któ- ków online). Jeśli doinstalowany moduł ma pod-
nych tekstów, komentowanych artykułów, ry rozdziela poszczególne pozycje. Zatem upraw- katalog pnblocks, możemy być pewni, że na liście
pobieranych plików itp. nienie Menu główne:(Moje konto|Wyloguj|Prześlij wyboru bloków ukażą się nowe pozycje tego mo-
• typetool – standardowy edytor WYSIWYG nowiny): dotyczy tylko linków Moje konto, Wylo- dułu. Dodajmy zatem testowy blok. Klikamy na
• User – zawiera funkcje użytkownika (wy- guj i Prześlij nowiny w bloku menu o nazwie Menu Nowy blok. Jeśli pokaże się pusta strona będzie
logowywanie itp.) główne. Reguła ta jest ustawiona dla niezalogowa- to oznaczać, że jeden lub więcej modułów ma
• Web_Links – prosty katalog stron z po- nych, a poziom uprawnień to “żaden”, więc nieza- niepoprawną składnię kodu bloków, dlatego me-
działem na kategorie logowani nie będą widzieć tych linków. Ciąg .* za- todą prób i błędów trzeba będzie ten moduł od-
• Wiki – wtyczka umożliwiająca formatowa- stępuje wszystkie instancje. Sytuacja z uprawnie- naleźć (najlepiej usuwając podkatalogi pnblocks z
nie tekstu na takiej zasadzie jak w Wikipedii niami użytkowników wygląda identycznie, z tym nowo zainstalowanych modułów). Niech nasz
• Xanthia – podstawowy system szablonów wyjątkiem, że zamiast grupy wybieramy użyt- blok będzie typu HTML, abyśmy mogli wsta-
• Your_Account – moduł twoje konto kownika. Skuteczność poziomu uprawnień tak- wić dowolny kod HTML. Przy dodawaniu blo-
że zależy od modułu, jednakże poziom Admini- ku możemy ustawić, czy ma być on zwinięty
Wersja PostNuke Lite 0.764 ma tylko 22 podsta- stracja zawsze daje “pełną władzę”. i w jakiej postaci ma się domyślnie pokazywać.
wowe moduły, co przekłada się na optymalność Uprawnienia to bardzo duży plus tego syste- Możemy także dodać różne bloki dla różnych ję-
skryptu. Dodatkowo uciecha dla “grzebaczy” – mu CMS, dzięki nim jak widać można uzależ- zyków. Z listy rozwijalnej Blok wybieramy inte-
instalujemy po kolei wszystkie moduły niezwią- nić wyświetlanie nawet prostych linków w me- resujący nas blok. Wszystkie pozycje poprzedzo-
zane z jądrem, które nam pasują. Jak widać każ- nu! Tak samo jedno uprawnienie może działać ne tekstem Core należą do jądra CMSa. Standar-
da część systemu jest także osobnym modułem, na konkretny plik w pobieralni, lub na wszyst- dowo pozycje na liście wyglądają tak:
dlatego moduły często są porównywane do kloc- kie. Aby uniemożliwić pobieranie jednego pliku
ków, z których składamy stronę na planszy, czyli Antkowi, wstawiamy uprawnienie: • Core/Pokazywanie banerów – pozwala na wy-
na silniku CMSa. Co jeszcze warto wiedzieć ogó- świetlenie jednego banneru lub wszystkich
łem o PostNuke? Jego system wielojęzykowości Antek | Downloads:: | ::27 | Żaden bannerów w rotatorze z modułu Banners
pozwala na dodawanie osobnych newsów, pod- • Core/Dzisiejszy najważniejszy artykuł – po-
stron, bloków itp. dla każdego z języków, dlate- gdzie 27 to ID pliku. Zamiast ID można przed kazuje link do artykułu, który w dniu dzi-
go też przy zmianie języka automatycznie może podwójnym dwukropkiem wstawić nazwę da- siejszym był czytany największą ilość razy
zmienić się nam menu oraz wyświetlić się mo- nego pliku – efekt będzie taki sam. Ważną rze- • Core/Blok linku Button – pozwala na pro-
że całkiem inna lista newsów. PostNuke ma tak- czą są także bloki – odpowiadają one za genero- ste dodanie popularnych buttonów na stro-
że zaawansowany, aczkolwiek nieintuicyjny, sys- wanie całego menu strony. Domyślne pozycje nę, standardowo o rozmiarze 88x31
tem uprawnień. To, czego nie ma większość dar- bloków to lewo, prawo i środek – każdy blok • Core/Menu kategorii – pokazuje menu wy-
mowych CMSów, tutaj jest i sprawuje się bardzo można wstawić do odpowiedniej pozycji, a każ- boru kategorii w postaci listy
dobrze. Możemy praktycznie określić dowolną dą pozycję wstawić w odpowiednie miejsce w • Core/Simple File Include – wczytuje pliku z
regułę uprawnień dla osobnego użytkownika lub szablonie skórki. Jeśli te 3 pozycje to dla nas za podanego przez nas adresu
dla całej grupy (to jest bardziej zalecane, mniej ob- mało, zawsze możemy się ratować dodając so- • Core/FXP Currency Exchange – przelicz-
ciąża serwer), dzięki czemu Alfred będzie mógł bie tzn. bloki area, których mogą być nawet nik walut
dodawać pliki do downloadu, a Henio nawet nie setki. Ciekawą opcją jest to, że bloków nie trze- • Core/HTML – blok pozwala na wstawie-
będzie mógł tam wejść, za to grupa Koledzy He- ba usuwać – można je zdeaktywować i w do- nie dowolnego tekstu z możliwością for-
nia będzie administrować downloadem. Należy wolnym czasie ponownie zaktywować. Pod lin- matowania go przez HTML
tu pamiętać o hierarchii uprawnień – na począt- kiem zmień konfigurację możemy wyłączyć stan- • Core/Logowanie użytkownika – jak sama
ku dodajemy zezwolenia, później zakazy, na po- dardową możliwość zwijania bloków – tj. obra- nazwa wskazuje pokazuje formularz logo-
czątku grupy o większych uprawnieniach (tak zek minusa obok nazwy bloku, który pozwala wania użytkowników na stronie
jak np. admini), później dopiero użytkownicy i go ukryć pozostawiając sam tytuł. Strzałki w ko- • Core/Menu generowane – generator menu
goście (niezalogowani). Reguły można przesuwać w stylu drzewka lub listy linków
w górę i w dół, w zależności od ich ważności. Po- • Core/Online – pokazuje ilość gości i użyt-
le komponent oznacza część serwisu, której doty- kowników online oraz informacje i pry-
czy uprawnienie, .* – zastępuje wszystko (czyli w watnych wiadomościach
tym przypadku tyczy się całego serwisu), ale gdy • Core/Starsze artykuły – wyświetla newsy,
wpiszemy nazwę modułu z podwójnym dwu- które nie pokazują się już na stronie głów-
kropkiem na końcu, np. News::, reguła będzie się nej oraz starsze dodane artykuły w serwi-
tyczyła tylko modułu News. Instancja jest zależna 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
Rysunek 11. Stworzony blok Rysunek 12. Ankieta linki powiązane z danym artykułem

69
Narzędzia

• Core/Stopka z nowinami RSS – pozwala na Dodatkowe moduły, zwala na tworzenie własnych typów publika-
wyświetlenie kanału RSS ze ścieżki do pli- ich dostosowanie i optymalizacja cji, definiowania w nich swoich pól, nie musi-
ku źródła RSS Zainstalujmy teraz nowy moduł. Niech to bę- my trzymać się jakiegoś schematu – sami decy-
• Core/RSS Extra – funkcjonalność taka sama dzie dodatkowy system szablonów AutoThe- dujemy jak dana publikacja ma wyglądać! Ła-
jak powyżej z tym wyjątkiem, że możemy wy- me, pozwalający na uruchamianie dużo pro- two jest zrobić tym sposobem system newsów,
brać jeden z istniejących już kanałów na liście ściej konstruowanych skórek. Moduł ten za- artykułów, pobieralnię plików, katalog stron,
• Core/Box Szukaj – pokazuje wyszukiwarkę wieraj wtyczkę krótkich linków do PostNu- czy nawet rozbudowaną galerię zdjęć. Najlep-
• Core/Tytuły artykułów – wyświetla ostat- ke (temat przyjaznych linków wraz z zastoso- sze w tym wszystkim jest to, że sami ustalamy
nio dodane artykuły, możemy zdefinio- waniem AutoTheme na CMSach opisany był w szablony do każdej publikacji, wybieramy od-
wać ich ilość, kategorię oraz temat PHP Solutions Nr 6/2006 [17]) oraz jest dużo powiadające nam plugin do szablonów i ma-
• Core/Pełny tekst – wyświetla podany przez prostrzy do nauki tworzenia skórek. Jest to du- my pełną kontrolę nad tym co robimy, gdyż
nas tekst żo popularniejszy system szablonów, pomimo Pagesetter nie narzuca żadnego kodu, ani roz-
• Core/Języki – pokazuje listę wyboru języka że nie znajduje się on w standardowej paczce wiązań, jak to bywa w innych modułach. Je-
• Core/Menu tematów – pokazuje listę wy- PostNuke. Instalujemy AutoTheme tak jak każ- go system kategorii pozwala na nieskończe-
boru skórki dy inny moduł z tym wyjątkiem, że nadpisu- nie głębokie zagnieżdżanie podkategorii. Jedy-
• Core/Box zwykłego użytkownika – pokazu- jemy także pliki z folderu Blocks. Ma to na ce- nie jego trudność obsługi może przeszkadzać
je blok użytkownika (każdy użytkownik lu umożliwienie używania bloków area AT początkującym w tym module, dlatego na po-
domyślnie może w panelu swojego konta w standardowym module bloków. Modułem czątek przygody z PN nie jest on polecany. Na-
stworzyć sobie blok np. z notatkami) tym zajmiemy się później tworząc własny sza- sze moduły możemy także usprawnić. Nieste-
• Core/Ostatnie linki Web – wyświetla ostat- blon. Jeśli mamy zamiar instalować dużo mo- ty temu CMSowi daleko do ideału, jest napisa-
nio dodane linki do katalogu dułów tworząc wielką stronę o ogromnej ilości ny nieoptymalnie, a starsze moduły są nieprze-
• Admin/Show admin categories and modules zróżnicowanej treści, warto zainteresować się myślane. Spójrzmy chociażby na kwestię ilości
– wyświetla blok administratora, rozwią- modułem Pagesetter. Jest to chyba największy newsów na stronie głównej – możemy wybrać
zanie podobne jak w CMSie Xaraya moduł jaki kiedykolwiek powstał na PN, a przy z listy 5, 10, 15, 20 i więcej. Co jednak, jeśli
• Admin_Messages/Show Admin Messages – wy- okazji jest nowoczesny i dobrze napisany. Mó- chcemy, by ilość newsów wynosiła 7? A może
świetla komunikaty modułu Admin_Messages wiąc w skrócie można nim zrobić wszystko. 13? Zawsze można modyfikować konfigurację
• pnRender/custom pnRender block – blok, Administrator post–nuke.pl mówi nawet żar- w bazie danych, ale gdzie tu wygodne rozwią-
w którym możemy używać znaczników tobliwie: dla mnie to PostNuke jest dodatkiem zanie? Takie rzeczy naszczęście nawet począt-
pnRender (Smarty) do Pagesettera, a nie odwrotnie. Moduł ten po- kujący programista może ulepszyć sam! Nie
• pnRender/pnRender Loginblock – wyświetla
blok logowania z szablonu pnRender
Listing 1. Nieoptymalny kod w pliku admin.php
• Xanthia/Logo Block for Xanthia Themes –
blok z logo skórek Xanthia .'<select name="xstoryhome" size="1">'
• Xanthia/Display module output in a block – ."<option value=\"5\"".$sel_storyhome['5'].">5</option>\n"
pozwala na wyświetlenie modułu zgodne- ."<option value=\"10\"".$sel_storyhome['10'].">10</option>\n"
go z Xanthia w bloku ."<option value=\"15\"".$sel_storyhome['15'].">15</option>\n"
."<option value=\"20\"".$sel_storyhome['20'].">20</option>\n"
Po wybraniu Aktulizuj możemy wstawić treść do ."<option value=\"25\"".$sel_storyhome['25'].">25</option>\n"
wybranego bloku. Jak widać nie sprawia też pro- ."<option value=\"30\"".$sel_storyhome['30'].">30</option>\n"
blemu aktulizacja danych z zewnętrznych źródeł ."</select>"
co jakiś czas, np. w przypadku bloku RSS nie mu-
simy martwić się o aktulizację linków. PostNuke Listing 2. Warunek do modyfikacji
oferuje nam edycję strony generatora standardowe- if ($info['withcomm'] == 0) {
go bloku menu z linkami do danych modułów bez if ($info['comments'] == 0) {$comment = _COMMENTSQ;
konieczności zmian w szablonie na naszym serwe- }else if ($info['comments'] == 1) {
rze! Wybierzmy edycję naszego bloku Menu głów- $comment = '1 ' . _COMMENT;
ne, który jest typu Core/Menu. Edycja jest bardzo }else { $comment = "$info[comments] "._COMMENTS; }
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- Listing 3. Zawartość pliku version.php
staci drzewka. Do każdego z linków możemy do- <?
dać opis, który będzie widoczny w dymku po na- $modversion['name'] = 'Modtest'; // nazwa modułu
jechaniu myszką na dany link. Jeśli dodamy pozy- $modversion['version'] = '1.0'; // wersja modułu
cję z tytułem nie podając URL, zostanie wyświetlo- $modversion['description'] = 'Moj pierwszy modul'; // opis modułu
ny tylko tekst w tytule. Usuwanie i dodawanie lin- $modversion['credits'] = 'Autorem jestem tylko ja'; // uznania
ków odbywa się poprzez zaznaczenie odpowied- $modversion['help'] = 'pomoc.txt'; // plik pomoc
niego checkboxa w dwóch ostatnich kolumnach. $modversion['changelog'] = ''; // plik informacji o zmianach
Nie musimy także męczyć się z wpisywaniem lin- $modversion['license'] = ''; // licencja modułu
ków do modułów – w polu URL wystarczy wpi- $modversion['official'] = 0; // czy moduł jest oficialny 1 – tak, 0 – nie
sać nazwę modułu w kwadratowym nawiasie, a $modversion['author'] = 'Autor to ja'; // autor modułu
system sam wstawi odpowiedni link. Dla testu $modversion['contact'] = 'ziomek@pocztaautora.pl'; // kontakt
zmieńmy pozycję Tematy na Google z URL http:// $modversion['admin'] = 0;
www.google.pl, a w pustym polu pod pozycją Wy- ?>
loguj dodajmy sam tytuł Dodatkowe.

70 4/2007
PostNuke

usprawiedliwia to jednak tego, że przez tyle lat ne funkcje newsów, które znajdują się w kata- Zamieniamy na:
rozwoju PostNuke nie pomyślano o zwykłym logu modules/News w pliku funcs.php. Co m.in.
polu tekstowym z wpisywaniem ilości new- możemy zmienić? Linia 208, zmiana tytułu $bytesmorelink = '';
sów. Aby dokonać takiej modyfikacji wchodzi- newsa/artykułu:
my w folder modułu Settings i otwieramy w do- Lina 412:
wolnym edytorze plik admin.php. Odnajduje- $info['catandtitle'] =
my linię 300 i jej okolice (Listing 1.). na taki: $info['cattitle'].": ".$info['title']; $preformat['more'] .= "$preformat[readmore]
($preformat[bytesmore]) ";
if ($info['withcomm'] == 0) { Jeśli wybraliśmy kategorię dla newsa, jej na-
$comment = _COMMENTS.': '.$info[comments]; zwa będzie poprzedzać jego tytuł przed dwu- zamieniamy na:
} kropkiem. Możemy całkowicie wyrzucić po-
kazywanie kategorii w tytule lub dodać ją np. $preformat['more'] .=
i zamieniamy ten typowo nieestetyczny w nawiasie: $preformat[readmore];
i starego typu kod, na którym absolutnie
nie należy się wzorować, na taki: .'<input $info['catandtitle'] = $info['title']. Linie 333–341, zmiana schematu wyświe-
name="xstoryhome" />' Minusem tego rozwią- ' ('.$info['cattitle'].')'; tlania ilości komentarzyDomyślnie wyświe-
zania jest to, że przy każdej edycji ustawień tlana ilość komentarzy w przypadku jednego
należy podać tam jakąś liczbę, aby wszystko Linia 417: komentarza to 1 komentarz, a w większej ilo-
poprawnie się zapisało. Ambitni programi- ści ilość komentarzy. Jeśli komentarzy jest np.
ści mogą tę modyfikację wzbogacić o pobiera- $preformat['catandtitle'] = 2, to mimo tego widzimy tekst 2 komentarzy
nie aktualnej ilości newsów do value tego po- "$preformat[category]: $preformat[ zamiast 2 komentarze. Można by dodać do-
la input. Spójrzmy także na newsy – domyśl- title]"; datkowy warunek do kodu, ale prościej bę-
nie układ linków Czytaj więcej z ikonką dru- dzie po prostu wyświetlać ilość komentarzy
kowania i polecania w każdej skórce jest taki zamieniamy na: po dwukropku, np.: komentarzy: 27, komen-
sam. W dodatku PostNuke w nawiasie pokazu- tarzy: 1. W tym celu modyfikujemy waru-
je ilość bajtów tekstu, wstawionego w tekst roz- $preformat['catandtitle'] = nek (Listing 2.). Od teraz nasze newsy będą
szerzony artykułu (tekst rozszerzony widoczny $preformat[title].' ( wyglądały ciekawiej. Nic nie stoi na przeszko-
jest tylko po wejściu do artykułu). Czy jakie- '.$preformat[category].')'; dzie, by plik ten całkowicie przerobić pod
goś użytkownika interesuje informacja o baj- swoją stronę – wystarczy znajomość podstaw
tach? A może chcemy usunąć ikonkę poleca- Linia 312, pozbywanie się ilości bajtów: PHP. Standardowy system komentarzy nie
nia artykułu bez pozbywania się modułu Po- zadowala pewnie wielu użytkowników. Wy-
leć nas? Wystarczy nieco zmodyfikować głów- $bytesmorelink = "$bytesmore "._BYTESMORE; świetla komentarze w postaci drzewka, jest

R E K L A M A
Narzędzia

nieintuicyjny i nie posiada szybkiej odpowie- rowania. Włączenie tych opcji daje wspania- z bloków typu Core w katalogu includes/
dzi (musimy klikać na przycisk Wyślij komen- łe rezultaty. Niestety także zapytania do ba- blocks; blok modułu, jeśli jest poprawnie
tarz lub linki Odpowiedz na to). Ratować mo- zy danych nieraz nie są optymalizowane. Do- napisany, automatycznie pojawia się na li-
żemy się alternatywami. Dostępne są modyfi- brym przykładem jest pobieranie wszystkich ście przy tworzeniu nowego bloku)
kacje standardowego modułu – prosta mody- newsów tylko po to, by je policzyć – a na tej
fikacja Comments mod by Izydor usprawniają- podstawie wyświetlany jest pager na stronie Zacznijmy od opisania swojego modułu w
ce komentarze jak i ich layout oraz rozbudo- głównej. Jeśli korzystamy z pagera i mamy pliku version.php (Listing 3.). Tworzenie mo-
wana wersja NS–Comments Ex, która pomimo dużo odwiedzin, warto pager wyłączyć lub dułów jest bardzo proste. Plik index.php prak-
tego, że nie została wydana w nowej wersji fi- zastąpić ten moduł jakimś alternatywnym. tycznie nie daje nam żadnych ograniczeń, mo-
nalnej, pozbawiła modułu komentarzy zbęd- Nie zawsze trzeba przerzucać się na coraz żemy korzystać ze swoich funkcji oraz funk-
nych pól, a ponad to wyświetla avatary użyt- lepsze serwery gdy strona się rozrasta – mu- cji PostNuke (jak chociażby klasy AdoDB do ob-
kowników przy komentarzach, ma jednolity simy pamiętać o zaawansowanych funkcjach sługi bazy danych). Stworzyć moduł wyświe-
layout oraz opcję szybkiej odpowiedzi pod ko- szablonów, używaniu tylko nowszych modu- tlający tekst Witaj w moim pierwszym modu-
mentarzami. Możemy jednak wybrać alterna- łów i używaniu jak najmniejszej ilości modu- le będzie bardzo prosto. Plik index.php powi-
tywny moduł pod nazwą EzComments – peł- łów. Wiele porad i tricków na temat optymali- nien wyglądać tak (Listing 4.). Jak widać bez
ni on rolę wtyczki, którą możemy zaktywo- zacji tego CMSa można znaleźć także na jego problemu możemy używać dowolnych funk-
wać do dowolnego modułu. Nie ma on jed- oficialnym polskim forum – większość stron cji PHP jak i funkcji API PostNuke (pnUser-
nak możliwości zagnieżdżania komentarzy. da się prosto odciążyć. Bardziej zaawansowa- GetVar('uname') w tym przypadku pobiera
Standardowo pozwala na import komentarzy ni programiści PHP mogą pokusić się o stwo- nazwę użytkownika, parametr 'uid' pobrał by
z modułu Comments (który przy użyciu Ez- rzenie własnego modułu. Na początek można ID użytkownika itp.). Zaprogramujmy także
Comments należy wyłączyć). Wszystkie mo- posłużyć się modułem Example lub zacząć od prosty panel administracyjny. Plik admin.php
duły są do pobrania na oficjalnej stronie Po- prostego modułu, który będzie np. wyświetlał powinien wyglądać tak (Listing 5.).
stNuke Polska. Co z optymalizacją? Nieste- tekst Witaj w moim pierwszym module. W tym Struktura tego pliku jest bardzo podobna
ty trzeba to odważnie powiedzieć – PostNu- celu należy stworzyć katalog z nazwą modu- do index.php. W starszych wersjach PostNu-
ke nie ma dobrze zoptymalizowanego kodu, a łu, dajmy na to Modtest. Struktura plików w ke sprawdzało się, czy użytkownik jest admi-
także przez lata nie zmieniło się wiele w kie- najprostrostrzym module z własnym blokiem nistratorem – w nowszych wersjach PN robi to
runku jego rozwiązań. Spójrzmy np. na bazy i panelem administracyjnym wygląda tak: już za nas. W tym pliku po prostu programu-
danych – ten CMS używa klasy AdoDB do jemy nawigację po panelu administracyjnym,
obsługi wielu baz danych, pomimo że pozwa- • index.php – główny plik odpowiadają- wszystkie funkcje i cokolwiek chcemy, by by-
la na korzystanie jedynie z MySQL. AdoDB cy za wyświetlanie modułu, będziemy ło widoczne w administracji naszym modu-
to dość stara i wolna klasa, więc nie powinna go wywoływać w PostNuke z adresu in- łem. Wystarczy teraz już tylko skopiować nasz
być tutaj używana. Kolejna sprawa to kod – dex.php?name=Modtest folder Modtest do katalogu modules na serwe-
dotychczas kod całego PN nie wyglądał zbyt • admin.php – odpowiada za funkcje w pa- rze, zainicjować i zaktywować moduł, po czym
ciekawie, był pisany na zasadzie kod w kodzie nelu administracyjnym sprawdzić jego działanie. Temat modułów jest
– aby zedytować layout danego modułu trze- • version.php – zawiera informacje o module dosyć głęboki, a kiedy nie ma ograniczeń, mo-
ba było modyfikować jego kod w funkcjach • Katalog images – zawiera obrazki modułu, żemy działać cuda. Nic nie stoi także na prze-
echo porozrzucanych śmiesznie po plikach. np. admin.gif z ikonką administracji szkodzie, a nawet jest to wskazane, by do mo-
Obecnie 90% PostNuke korzysta już z pnRen- • Katalog lang lub pnlang – zawiera podkata- dułów użyć systemu szablonów z pnRender, w
der, dlatego moduły mają osobne szablony logi z plikami językowymi, np. eng z języ- czym pomoże dokumentacja. Polskich modu-
tworzone zgodnie ze Smarty. W większości kiem angielskim, pol z polskim. W każdym łów do tego CMSa jest dość mało, nic nie stoi
przypadków rozwiązanie te jeszcze bardziej takim podkatalogu powinien znajdować się na przeszkodzie, aby któryś z czytelników wy-
spowalnia PostNuke, ale za to zyskujemy czy- plik global.php ze stałymi językowymi kazał się nowym pomysłem – może później
sty kod. Ratować możemy się świetnym sys- • Katalog blocks lub pnblocks – zawiera pli- dodać projekt do http://noc.postnuke.com (stro-
temem cachowania (możliwość włączenia w ki php pełniące rolę bloków (tworząc swój na developerów) jak i do downloadu PostNu-
administracji Xanthia i pnRender) oraz bufo- blok najlepiej jest wzorować się na jakimś ke Polska.

Listing 4. Zawartość pliku index.php


System szablonów
Standardowy system szablonów Xanthia w Po-
<? stNuke jest trudniejszy do pojęcia niż Auto-
// Sprawdzanie czy moduł został poprawnie wywołany (czy nie wpisano np. ścieżki Theme. Oferuje on jednak większe możliwo-
modules/ ści, większą swobodę i lepsze efekty w opty-
if (!defined('LOADED_AS_MODULE')) { malizacji. Mimo tego skórki pod ten system
die ("You can't access this file directly..."); to mniejszość. Jednakże jeśli chcemy stwo-
} rzyć prawdziwą i poważną stronę, nie należy
// wczytywanie headeru strony (generuje górny szablon) traktować wszystkiego na zasadzie tworzenia
include('header.php'); w 5 minut z darmową, ogólnodostępną skór-
?> ką. Stwórzmy coś własnego, na początek naj-
Witaj w moim pierwszym module. Dzisiaj mamy dzień lepiej w AutoTheme. AT jest modułem bardzo
<?=date('d.m.Y')?>, jesteś zalogowany jako <?=pnUserGetVar('uname')?> prostym, nasza skórka składa się tam z zaled-
<? wie kilku plików:
// wczytanie stopki strony (generuje dolny szablon)
include('footer.php'); • theme.html – główny szablon strony
?> • summary.html – szablon newsa na stronie
głównej

72 4/2007
PostNuke

• article.html – szablon pełnego newsa oraz • <!––[table–content]––> – Wyświetla za- • <!––[cat–title]––> – Wyświetla tytuł
artykułu wartość tabeli poprzedzony kategorią
• leftblock.html – szablon lewych bloków • <!––[site–slogan]––> – Wyświetla slo- • <!––[posted–by]––> – Wyświetla autora
• rightblock.html – szablon prawych bloków gan strony tekstu
• centerblock.html – szablon środkowych bloków • <!––[site–name]––> – Wyświetla nazwę • <!––[posted–date–time]––> – Wyświe-
• theme.cfg – konfiguracja skórki strony tla datę dodania tekstu
• theme.php – plik identyczny we wszyst- • <!––[search]––> – Wyświetla wyszuki- • <!––[topic–image]––> – Wyświetla zdję-
kich skórkach AutoTheme, wczytuje on od- warkę ze wszystkimi pluginami wyszuki- cie tematu
powiednie funkcje systemu szablonów wania • <!––[article–reads]––> – Wyświetla
• <!––[logo–image]––> – Wyświetla logo ilość odsłon
Obrazki znajdują się w podkatalogu skórki ima- strony
ges, a style w podkatalogu skórki style w pliku sty- • {image–path} – Zwraca ścieżkę do obraz- Można także używać znaczników zdefiniowa-
le.css. Pliki theme.cfg i theme.php warto wyciągnąć z ków skórki (katalog images) nych kolorów od {color1} do {color10}
dowolnej skórki pod AutoTheme (w paczce z modu- • {theme–path} – Zwraca ścieżkę do skórki
łem są przykładowe skórki), gdyż theme.php jest za- Co wniesie nowa wersja?
wsze taki sam, a theme.cfg i tak ulegnie zmianie po bloki: – Podsumowanie
skopiowaniu go na serwer z chmod 777. Interesu- Jak widać PostNuke ma wiele zalet, ale wad także
ją nas teraz głównie znaczniki, które wstawia się do • <!––[block–content]––> – Wyświetla za- mu nie brakuje. Niestety wersje 0.76x nie będą
poszczególnych plików: theme.html: wartość bloku już kontynuowane, więc poprawek uciążliwych
• <!––[block–title]––> – Wyświetla tytuł błędów się nie doczekamy. Jednak wersja 0.8 jest
• <!––[modules]––> – Wyświetla moduły bloku już od długiego czasu w budowie. Jest ona pisa-
• <!––[date]––> – Wyświetla datę • <!––[left–blocks]––> – Wyświetla lewe na w większości od nowa, dlatego silnik będzie
• <!––[time]––> – Wyświetla czas bloki dużo nowocześniejszy. Ostatnio wydano wersję
• <!––[user]––> – Wyświetla nazwę użyt- • <!––[center–blocks]––> – Wyświetla Milestone 3, czyli wczesną niedopracowaną wer-
kownika środkowe bloki sję testową, aby programiści mogli sprawdzić z
• <!––[user–welcome]––> – Wyświetla po- • <!––[right–blocks]––> – Wyświetla pra- nią swoje moduły. Dopiero w tej wersji wiele się
witanie użytkownika we bloki zmienia. A co czeka nas nowego?
• <!––[user–login]––> – Wyświetla pozio-
my panel logowania artykuły/newsy: • Wsparcie dla Oracle, PostgreSQL i MsSQL
• <!––[user–links]––> – Wyświetla linki • Całkowicie nowy moduł Search działający z
do logowania / rejestracji oraz wylogowa- • <!––[article–edit–del]––> – Wyświetla lin- każdym modułem dzięki uniwersalnemu API
nia / mojego konta ki do edycji i usuwania dla administratorów • Uniwersalny moduł kategorii – Categories
• <!––[banners]––> – Wyświetla bannery • <!––[article–full]––> – Wyświetla peł- – będzie on używany w każdym module
• <!––[banners–typeX]––> – Wyświetla ną treść artykułu/newsa do tworzenia kategorii. Koniec z katego-
bannery wg. ID X • <!––[article–more]––> – Wyświetla link riami dla każdego modułu z osobna
• <!––[footer–msg]––> – Wyświetla stopkę czytaj więcej, ikonkę drukowania, ikonkę • Moduły podzielono na systemowe i dodat-
• <!––[open–table]––> – Rozpoczyna tabelę polecania kowe – domyślnie w paczce znajdziemy
• <!––[close–table]––> – Zamyka tabelę • <!––[article–notes]––> – Wyświetla no- standardowe moduł potrzebne do urucho-
• <!––[open–table2]––> – Rozpoczyna tatki dla artykułu/newsa mienia PN w katalogu system, a resztę w
subtabelę • <!––[article–summary]––> – Wyświetla katalogu modules
• <!––[close–table2]––> – Zamyka tabelę wstęp artykułu/newsa • Poprawiono obsługę błędów
• Cały system będzie obsługiwać nowy moduł
szablonów (tylko jeden) oparty o pnRender,
Listing 5. Zawartość pliku admin.php
czyli taka nowsza Xanthia. Nie będzie nato-
<? miast "kodu w kodzie", wszystko będzie zapi-
// Sprawdzanie czy moduł został poprawnie wywołany (czy nie wpisano np. ścieżki sywane w szablonach pnRender
modules/ • Stworzono moduł do tłumaczeń, podobny
if (!defined('LOADED_AS_MODULE')) { do translatora w CMSie Xaraya
die ("You can't access this file directly..."); • Poprawiono bezpieczeństwo
}
// wczytywanie headeru strony (generuje górny szablon) Moim zdaniem warto wybrać PostNuke jako
include('header.php'); przyszłościowy CMS – ma duże możliwości, a
if (isset($_GET['action'])) { zachowuje przy tym uniwersalność. Jest to do-
if ($_GET['action'] == 'date') { bra podstawa do nauki o CMSach dla każdego
?>Dzisiaj mamy <?=date('d.m.Y')?> początkującego programisty PHP.
<? } else { ?>Taka opcja nie istnieje!<? } } ?>
<p>
Witaj w panelu administracyjnym. Panel jest tymczasowo w budowie.<br /> MICHAŁ GACKI
<a href=”admin.php?module=Modtest&amp;action=date”>Wyświetl dzisiejszą datę</a></p> Jest programistą-samoukiem. Od najmłodszych
<? lat interesuje się informatyką, a najbardziej pro-
// wczytanie stopki strony (generuje dolny szablon) gramowaniem, które jest jego pasją. Pracuje w za-
include('footer.php'); łożonej przez siebie grupie (obecnie nie tylko pro-
?> gramistycznej) pod nazwą Bil Software.
Kontakt z autorem: michal@bilsoftware.com

73
Testy konsumenckie

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ą-
WWW.PUNKT.PL dzeń dostępowych bądź na zastępowaniu me-
dium transmisyjnego innym bardziej wydajnym.

P
unkt to nazwa firmy, która dziś kojarzy infrastruktury sieci pozwoliło firmie oferować Kierunki rozwoju infrastruktury oraz jej moder-
się niemal każdemu mieszkańcowi Opo- swoje usługi na terenie całego miasta i świadczyć nizacji ściśle związane są z aktualnie panującymi
la, Nysy oraz miejscowości ościennych z je każdej zainteresowanej firmie. Z upływem cza- trendami rynkowymi. Patrząc wstecz na kształt i
atrakcyjną ofertą stałego dostępu do Internetu, su, zmieniające się warunki rynkowe oraz wzrost szkielet infrastruktury można zauważyć, że fir-
jeszcze kilka lat temu była całkowicie nieznana. zapotrzebowania na usługi dostępowe ze strony ma przeszła kilka etapów technologicznych po-
Jak wytłumaczyć fakt, iż pasja kilku świeżo upie- odbiorców indywidualnych skłoniło właścicie- cząwszy od asynchronicznych modemów kablo-
czonych inżynierów rozpoczynających przygodę li firmy do poszerzenia wachlarzu świadczonych wych, które pod koniec lat 90. oferowały zawrot-
z Internetem w małym biurze stanowiącym jed- usług i rozpoczęciu inwestycji związanych z bu- ne jak na te czasy przepustowości kilkuset kilobi-
nocześnie serwerownię przerodziła się w spraw- dową okablowania strukturalnego w budynkach tów, przez modemy xDSL, radiolinie 802.11 b-g,
nie działającą organizację o mocno ugruntowanej należących do największych opolskich spółdziel- 802.11 a. Dziś szkielet infrastruktury stanowią
pozycji na opolskim rynku internetowym? Od- ni mieszkaniowych. Postępująca rozbudowa sieci światłowody oraz profesjonalne systemy radiowe
powiedź na to pytanie kryje w sobie sekret sukce- pozwoliła firmie na oferowanie dostępu do Inter- pracujące w paśmie koncesjonowanym. Obecny
su jaki był i jest udziałem małej firmy w walce o netu w ponad 45 000 mieszkaniach Opola i Ny- stan sieci pozwala na świadczenie usług Triple play
klienta z gigantami rynku telekomunikacyjnego. sy. Fakt ten przełożył się na ilość obsługiwanych i to właśnie w perspektywie najbliższych miesięcy
Firma Punkt rozpoczęła swoją działalność już klientów, których liczba w 2007 roku osiągnęła stanowi główny cel firmy. Już dziś natomiast każ-
w roku 1998, w którym Internet był „luksusem” ponad 5000. By zaspokoić potrzeby tak dużej licz- dy abonent indywidualny może skorzystać z do-
dostępnym dla niewielkiej grupy zainteresowa- by abonentów firma Punkt musiała wypracować stępu do Internetu w pakietach od 512 kbps do 4
nych, czego głównym powodem była dostępna efektywny system obsługi klienta, pozwalający na Mbps. W przypadku abonentów biznesowych je-
w tamtym okresie droga technologia dystrybucji utrzymanie bezpośrednich relacji z klientem, któ- dynym ograniczeniem szybkości oferowanego In-
sygnału. Z tego samego powodu początkowo fir- ry swój wyraz znalazł we wdrożonym w firmie ternetu stają się lokalne warunki techniczne wpły-
ma oferowała dostęp do Internetu oraz usługi ho- Systemie Zarządzania Jakością ISO 9001-2000. wające bezpośrednio na medium, z wykorzysta-
stingowe tylko klientom korporacyjnym. By spro- Sytuacja, w której klient nie ma możliwości bez- niem którego abonent otrzyma usługę dostępu
stać konkurencji i zaistnieć na rynku usług inter- pośredniego kontaktu ze swoim dostawcą usług do Internetu.
netowych firma położyła szczególny nacisk za- jest pierwszym krokiem do zerwania z nim kon- Pomimo napotkanych trudności, silnej kon-
równo na jakość oferowanego dostępu do Inter- taktu oraz brakiem zrozumienia potrzeb i oczeki- kurencji, potrzeby ciągłego udoskonalania in-
netu, jak i elastyczność oferty w pełni odzwier- wań klienta, a co za tym idzie wzrostem jego nie- frastruktury sieciowej i nakładów inwestycyj-
ciedlającej potrzeby klienta. Szybko okazało się, zadowolenia. Równie istotnym czynnikiem, który nych z tym związanych, firma Punkt utrzy-
że opieka informatyczna roztaczana nad klien- pozwolił na rozwój firmy do obecnej postaci by- muje na opolskim rynku dominującą pozycję w
tem oraz troska o jego zadowolenie stało się moc- ło i jest jednakowo troskliwe podejście do każdego śród komercyjnych ISP.
nym atutem firmy, wyróżniającym ją na tle pozo- klienta niezależnie od rodzaju usługi z jakiej korzy-
stałych operatorów oraz przyczyniło się w bezpo- sta. Bez względu na biznesowy czy indywidualny
średni sposób do postrzegania Punkt jako partne- charakter, poziom oferowanego serwisu jest jedna- Dyrektor Działu Sieci firmy P.I. PUNKT Sp. z o.o.
ra w interesach. Ciągłe inwestycje w rozbudowę kowy. Zarówno klient korporacyjny, jak i indywi- Jerzy Kołodziej

74 4/2007
Stałe łącza internetowe

trach danych. Z tego powodu łącze interne- ne rozwiązanie zapasowe. Kontynuując do-
towe, jakie potrzebowaliśmy do biura, miało brą współpracę nawiązaliśmy pomiędzy na-
i ma po dzień dzisiejszy charakter łącza pra- szymi firmami również szereg innych kon-
cowniczego. taktów biznesowych i wspólnie dążymy do
Zmieniając kolejne rozwiązania w poszuki- współdziałania również w innych tematach.
waniu tego, które nam najbardziej by odpo- Efektem tych działań jest wyrażana niejed-
wiadało, korzystaliśmy w swojej historii z róż- nokrotnie chęć współpracy przy realizowa-
nych technologii dostępu do Internetu. W po- nych przez naszą firmę lub przez firmę Punkt
przedniej lokalizacji biura mieliśmy większe przedsięwzięciach.
możliwości wyboru operatorów. Od pewnego czasu korzystamy również z
Po przeprowadzeniu się w miejsce, gdzie rozwiązań telefonii VoIP oferowanych przez
znajdujemy się obecnie, różnorodność ope- firmę Punkt. Elastyczne podejście do klien-
ratorów posiadających infrastrukturę kablo- ta w tym zakresie oraz znacznie niższe ceny
wą w naszym sąsiedztwie została zawężona usług skłoniły nas do wybrania również i tego
praktycznie do jednej firmy. Przez dłuższy rozwiązania. Z tej usługi jesteśmy zadowoleni
czas korzystaliśmy właśnie z tego rozwiąza- do tego stopnia, że nasze dotychczasowe linie
nia, ale niestety nie zapewniało nam ono od- telefoniczne służą nam już praktycznie tylko
powiednich warunków do pracy. Zbyt mała, do odbierania połączeń.
Sławomir Milewski jak na nasze potrzeby, dostępna prędkość łącz Kolejną płaszczyzną współpracy pomiędzy
oraz częste awarie doprowadzały naszą cierpli- naszą firmą i firmą Punkt są obecnie wspól-
netkoncept.com wość do granic wytrzymałości. Należy zwró- ne prace rozwojowe i administracyjne prze-

P
oczątkową działalnością naszej firmy cić uwagę również na fakt, że obsługa posprze- prowadzane na naszych serwerach interne-
było głównie projektowanie, wdraża- dażna tamtej firmy, realizacja reklamacji oraz towych. Korzystając z naszych doświadczeń
nie i utrzymywanie witryn interneto- czas reakcji na awarie również pozostawiały oraz specjalistów firmy Punkt stale dosto-
wych. Obecnie specjalizujemy się w budowa- wiele do życzenia. sowujemy stosowane u nas rozwiązania do
niu i wdrażaniu unikalnych systemów bazo- Sytuacja taka miała miejsce do czasu, gdy obecnych wymogów bezpieczeństwa oraz wy-
danowych, sklepów internetowych (eCommer- w czasie spotkania z przedstawicielami fir- dajności.
ce), systemów zarządzania treścią stron inter- my P.I. Punkt Sp. z o.o. okazało się, że ta fir- Podsumowując dotychczasową współpra-
netowych (Content Management System) oraz ma może nam dostarczyć wydajne i stabilne cę z firmą Punkt muszę przyznać, że nie po-
systemów do obsługi Biuletynów Informacji łącze za pomocą technologii radiowych. Firmę jawiły się dotychczas żadne zdarzenia mogą-
Publicznej. Główni odbiorcy naszych usług to Punkt znaliśmy od dawna. Jest ona, obok na- ce mieć negatywny wpływ na wizerunek oraz
instytucje publiczne oraz firmy sektora MSP. szej firmy, jedną z kilku liczących się przed- jakość usług tej firmy. Z wybranych rozwią-
Pracownicy naszej firmy posiadają wy- siębiorstw informatycznych w regionie reali- zań oraz z dotychczasowego przebiegu współ-
kształcenie wyższe o kierunkach informa- zujących między innymi zaawansowane ser- pracy pomiędzy naszymi firmami jesteśmy
tycznych i ekonomicznych oraz wielolet- wisy internetowe. Pomimo tego, nigdy nie w 100% zadowoleni. Wszystko wskazuje na
nie doświadczenia w branży usług interneto- rozważaliśmy możliwości podłączenia do In- to, że w przyszłości będziemy mogli równie
wych i programistycznych. Rozwój naszej fir- ternetu za pośrednictwem firmy Punkt. Ta- pochlebnie wypowiadać się o dostarczanych
my został ukierunkowany przede wszystkim ki stan rzeczy miał miejsce aż do momentu nam usługach przez firmę Punkt.
na udostępnianie bezpiecznej platformy sys- wspomnianego już spotkania, na którym wy- Wszystkie platformy usług, na jakich obec-
temów zarządzania treścią aplikacji interne- mieniając się wzajemnie naszymi spostrze- nie współpracujemy, a jest to dostęp do In-
towych, dających klientom szerokie możli- żeniami dotyczącymi działalności obu firm, ternetu, telefonia VoIP oraz usługi zarządza-
wości samodzielnego redagowania treści udo- między innymi wspominaliśmy o naszych nia serwerami internetowymi, w pełni speł-
stępnianych w sieci Internet. Podczas wdraża- problemach z łączami internetowymi. Od mo- niają nasze oczekiwania. Nie mamy żadnych
nia produktów obligatoryjnie prowadzone są mentu nawiązania tego kontaktu wydarzenia zastrzeżeń odnośnie tej oferty zarówno pod
szkolenia z zakresu obsługi systemu, udostęp- potoczyły się dosyć szybko. względem funkcjonalnym jak i cenowym.
niane są szczegółowe instrukcje obsługi oraz Pracownicy firmy Punkt pojawili się w na- Warto zaznaczyć, że na obserwowanej
profesjonalna pomoc techniczna. szej firmie, dokonali niezbędnych pomiarów przez nas przestrzeni czasu firma Punkt dyna-
Od kilkunastu miesięcy z powodzeniem jakości połączenia radiowego z naszej lokali- micznie dostosowywała swoją ofertę do zmie-
opracowywane są (jako nowa linia produk- zacji. Po tych wydarzeniach, nie trwało dłu- niających się warunków na rynku. Pochlebne
tów) aplikacje multimedialne. Są to prezen- go, jak otrzymaliśmy z firmy Punkt ofertę łą- opinie o usługach firmy Punkt jestem w sta-
tacje na nośnikach CD/DVD oraz interak- cza internetowego dla naszej firmy. Była ona nie formułować z pełnym przekonaniem, po-
tywne mapy wyposażone w system zarządza- na tyle konkurencyjna, że również podjęcie nieważ prywatnie również korzystam z dostę-
nia punktami aktywnymi na mapie oraz sko- naszej decyzji nie wymagało zbyt wiele cza- pu do Internetu oferowanego klientom indy-
relowaną informacją tekstową i graficzną. Już su. W ten sposób już od kilku miesięcy jeste- widualnym przez tę firmę i również jestem
na starcie naszej działalności postanowiliśmy, śmy klientem firmy Punkt korzystając z dostę- bardzo zadowolony z tej usługi. Gdybyśmy w
że będziemy kładli duży nacisk na jakość ofe- pu do Internetu zestawionego dla nas przez tę obecnej chwili ponownie dokonywali wyboru
rowanych usług. W ten sposób od razu wyklu- firmę. W tym czasie nie odnotowaliśmy jakiś związanego z tymi usługami to sądzę, że wy-
czyliśmy stawianie własnych serwerów inter- większych problemów ze stabilnością łącza, bór byłby taki sam jak ten, dokonany w prze-
netowych w miejscach, które nie zapewnia- podobnie obsługa posprzedażna Biura Obsłu- szłości. W pięciopunktowej skali ocen jedy-
ją należytej ochrony zarówno pod względem gi Klienta firmy Punkt nie dostarcza nam żad- ną właściwą oceną firmy Punkt jest ocena naj-
technologicznym jak i dostępu fizycznego do nych powodów do narzekań. wyższa, czyli pięć punktów.
pomieszczeń. Dlatego też oczywiste stało się, Z dotychczasowych łącz dostępowych do
że nasze serwery będą umieszczane na zasa- Internetu zrezygnowaliśmy pozostawiając
dach kolokacyjnych w profesjonalnych cen- tylko jedne, które służy tylko jako ewentual- Ocena: «««««

www.phpsolmag.org 75
Testy konsumenckie

nych, a następnie z wykorzystaniem języków cyjnego, którym Punkt dysponował, a dodatko-


skryptowych wykonywanych po stronie serwera wo rozwiązanie było korzystne z ekonomiczne-
oraz baz danych. Skupiliśmy się wówczas na pro- go Punktu widzenia. Obecność i rosnąca pozy-
duktach adresowanych do większych odbiorców cja firmy Punkt w rankingu TOP100 (obsługiwa-
biznesowych (np. system zakupowy B2B), któ- nych domen), utrzymywała nas w przekonaniu,
rzy oczekiwali jednocześnie kompleksowej ob- iż przekazujemy zdobywanych przez lata klien-
sługi w tym zakresie. Konsekwencja obrania ta- tów w dobre ręce. Równie istotna też dla nas oka-
kiego kierunku oraz chęć uelastycznienia ofer- zała się zapowiedz ze strony Punkt przygotowań
ty automatycznie wygenerowała konieczność za- do rozbudowy i przeniesienia wszystkich zaso-
jęcia się również usługami hostingowymi. Wów- bów serwerowych mających związek z hostin-
czas na rynku było już parę interesujących firm, giem z ich dotychczasowej serwerowni na tere-
którym można było powierzyć tę część działal- nie miasta Opole do profesjonalnego centrum
ności, ale konkurencja, a co za tym idzie atrak- danych mieszczącego się w Warszawie. Tak się
cyjność ofert w owych latach, pozostawiała wie- faktycznie za jakiś czas stało. Należy przy tym za-
le do życzenia, dlatego postanowiliśmy zająć się uważyć, iż całość prac z tym związanych odbyła
również hostingiem. Jako że zasoby sieciowe się niemalże w sposób niezauważalny dla klien-
(w tym serwery) chcieliśmy mieć pod ręką, ko- ta, świadczy to o dużej dbałości firmy w podej-
nieczne było pozyskanie stabilnie działającego łą- ściu do klienta (rozumieniu jego potrzeb), a tak-
Dariusz Lewandowski cza internetowego o odpowiedniej przepustowo- że dbałości w planowaniu działań w najdrobniej-
ści. Rozpoczęliśmy poszukiwania dostawcy In- szych szczegółach. Naturalną konsekwencją po-
P.W. Vegas Sp. z o.o. ternetu działającego na rynku lokalnym. W ten myślnych doświadczeń we współpracy z firmą

P
rzedsiębiorstwo Wielobranżowe Vegas Sp. oto sposób zetknęliśmy się z ofertą firmy Punkt, Punkt, było powierzenie jej opieki nad serwera-
z o.o. to firma skoncentrowana w swoich która prócz przyzwoitych warunków cenowych mi, jakie wykorzystujemy do obsługi naszych
produktach i usługach na rynek związa- dawała nam solidne wsparcie techniczne w po- systemów wideo gier on-line. Jako że każda po-
ny z rozrywką i hazardem. Na ten rynek dostar- staci wykwalifikowanej kadry administratorów tencjalna przerwa w działaniu tego systemu po-
czamy np. kompleksowy system telemetrycz- sieciowych, gotowych nieść pomoc bez zbęd- woduje znaczne i wymierne straty finansowe,
ny (VAC.SMS/GPRS), który zbudowany jest w nej zwłoki 24h na dobę, przez wszystkie dni ty- serwery za namową Punkt są również kolokowa-
warstwie sprzętowej (VAC Moduł) jak i progra- godnia. Wobec takich gwarancji nie mogliśmy ne w centrum danych.
mistycznej (VAC System) przez naszych specja- pozostać obojętni i postanowiliśmy zaryzyko- Budując zespół zawsze kierujemy się zasadą
listów. Wszystkie dane jakie spływają (transmi- wać - z perspektywy czasu już wiemy, że było doboru ludzi kompetentnych, wykazujących się
sja GPRS ewentualnie komunikaty SMS) z poje- warto. Od tego momentu sprawy toczyły się już dużą kreatywnością, potencjałem, odpowiedzial-
dynczych urządzeń monitorowanych przez nasze szybko. Łącze internetowe zostało zrealizowane nością, umiejętnością radzenia sobie w trudnych
moduły są gromadzone na centralnym serwerze, sprawnie i terminowo, a co najważniejsze dzia- sytuacjach oraz nieprzeciętnym zakresie wiedzy
do którego dostęp zapewniony jest poprzez webo- łało stabilnie i zgodnie z deklarowanymi przez merytorycznej. Te same kryteria stosujemy w od-
we aplikacje klienckie. Innymi produktami, które Punkt, podczas zawiązywania się współpracy, pa- niesieniu do współpracy z firmami zewnętrzny-
wykorzystują serwery internetowe i bezpieczną rametrami. Do momentu załatwienia formalno- mi i Punkt nie jest tutaj wyjątkiem, dlatego z czy-
transmisję danych są: ści związanych ze zmianą adresacji IP, w czym stym sumieniem zachęcamy naszych klientów
Punkt wykazał się również dużą sprawnością, do korzystania z usług świadczonych przez tę
• Wirtualne Centrum Rozrywki, które w utrzymywaliśmy dotychczasowe łącze operato- firmę, gdyż można na niej polegać. Cenimy ją
wersji FUN nadaje się do użycia w każdej ra wiodącego, z którego mogliśmy już, pozbawie- szczególnie za wysoką jakość obsługi technicz-
sieci internetowej (np. operator sieci osie- ni wszelkich obaw, spokojnie zrezygnować. Na nej oraz zdroworozsądkowe podejście do pro-
dlowej czy telewizji kablowej może udo- tym etapie rozwoju firmy zaangażowaliśmy się blemów, z jakimi mieliśmy do czynienia w ca-
stępnić swoim klientom gry z tego pakietu w projekt, który trwa nieprzerwanie do dzisiaj, łym długoletnim okresie współpracy. Mimo iż
w formie programu lojalnościowego itp.); a mianowicie tworzenie oprogramowania do wi- skala działalności Punkt stale się poszerza, nig-
wersja Real Money - przeznaczona jest dla deo gier działających w modelu on-line (służą do dy nie czuliśmy się zaniedbywani czy traktowani
podmiotów posiadających odpowiednie budowania kasyn internetowych i sieci videolo- z dystansem. Firma wykazuje się dużą determi-
zezwolenia i koncesje; teryjnych), co w skali kraju i Europy jest przed- nacją w osiąganiu celów, idzie z duchem czasu i
• SmartCasino - videoloterie w oparciu o sięwzięciem unikatowym. nie poddaje się coraz trudniejszemu i ciaśniejsze-
który działa jedna z największych sieci vi- Dzisiaj marka Vegas w tej dziedzinie jest już mu rynkowi usług dostępowych, o czym świad-
deoloteryjnych w Czechach. dobrze rozpoznawalna i znajduje uznanie na czy stale rosnąca liczba obsługiwanych klientów.
wielu rynkach europejskich. Projekt absorbował Potwierdzeniem najwyższych standardów jako-
Początki wyglądały jednak inaczej, a osiągnię- nas w stopniu powodującym konieczność albo ści jest uzyskany przez Punkt, w ostatnim czasie,
ty sukces jest wypadkową własnych pomysłów, rozbudowy zasobów ludzkich, albo skorzystania certyfikat systemu zarządzania jakością według
kompetencji zgromadzonych wewnątrz firmy, z pomocy firmy zewnętrznej, w zakresie obsługi norm ISO 9001:2000, co dla branży w jakiej
jak również jakości partnerów. Do grona klu- usług sieciowych. Tutaj również firma Punkt, ze działa firma nie jest szczególnie powszechnym
czowych i strategicznych partnerów zaliczamy względu na spójny z potrzebami zakres kompe- zjawiskiem. Podsumowując, w żaden sposób nie
firmę Punkt, z którą współpracujemy właściwie tencji, okazała się pomocna. W pierwszej kolejno- żałujemy wyborów, jakich dokonaliśmy na dro-
od początku powstania Vegas Sp. z o.o. Począt- ści zleciliśmy firmie Punkt administrację zasoba- dze historii współpracy z firmą Punkt, byłyby
kowo działalność firmy skupiała się na produkcji mi hostingowymi (serwery, routery, firewall, po- one identyczne, gdyby przyszło nam raz jeszcze
multimediów i aplikacji prezentacyjnych dystry- lityka bezpieczeństwa) naszych serwerów oraz się z nimi zmierzyć. Bezdyskusyjnie, przyzna-
buowanych na nośnikach CD. Wraz z rozwojem obsługę techniczną. Po jakimś czasie zdecydowa- jemy firmie najwyższą z możliwych ocen, czyli
rynku usług internetowych działalność firmy liśmy się całkowicie przekazać Punkt obsługę ho- pięciogwiazdkowa.
została rozszerzona o produkcję witryn inter- stingu, tym bardziej że ówczesne standardy ob-
netowych, w początkowej fazie typowo statycz- sługi wymagały zapewnienia panelu administra- Ocena: «««««

76 4/2007
Recenzja

Macromedia Fireworks 8
Oficjalny podręcznik
Wydawnictwo: Helion
Autor: Patti Schulze
Cena: 49,00 zł
Stron: 296 + CD
ISBN: 83-246-0314-X
http://www.helion.com.pl

Fireworks 8 jest programem graficznym o dużych możliwościach, nia. W formie wypunktowanej listy wyszczególnione są zagad-
za pomocą którego możemy zaprojektować zarówno: cały layout nienia które powinniśmy opanować po przerobieniu danej lek-
witryny www, jak i poszczególne jej elementy takie jak: animowa- cji, oraz czas potrzebny na wykonanie ćwiczenia. Na dołączo-
ne banery, przyciski czy ikony. Fireworks i Dreamweaver to popu- nej do książki płycie, znajdziemy również materiały dodatko-
larne narzędzia używane przez webmasterów, które wzajemnie się we, czyli materiały źródłowe potrzebne do nauki.
uzupełniają. Trudność jest stopniowana, i tak pierwsze lekcje opisują
Książka Macromedia Fireworks 8. Oficjany podręcznik to podstawy, m.in.: palety narzędziowe oraz menu programu.
nieocenione źródło wiedzy skierowane do początkujących Najczęściej używane narzędzia zostały omówione na podsta-
osób, które pragną poznać obsługę i użytkowanie programu wie konkretnych przykładów, tak więc nawet laik, nie powi-
Fireworks 8, a być może później zostać projektantem stron nien mieć trudności w przyswojeniu materiału zawartego w
WWW. Dobrą rekomandacją może być fakt, że książka poleca- tej książce.
na przez firmę Macromedia, czyli twórcę tego programu. Po skończeniu lektury, będziemy mogli spróbować zapro-
Przystępny język, logiczny podział całego materiału na 11 lek- jektować własną stronę www, wygenerować jej kod HTML do
cji, sprawia że raczej nikt nie powinien mieć problemów ze zro- Dreamwevera, zoptymalizować grafikę, tak by przyspieszyć jej
zumieniem i wykonaniem poszczególnych ćwiczeń. Każda z wczytywanie, a także w jaki sposób zautomatyzować niektóre
lekcji poprzedzona jest krótkim wprowadzeniem do ćwicze- czynności w Fireworks 8.

CMS. Jak szybko i łatwo


stworzyć stronę WWW i zarządzać nią
Wydawnictwo: Helion
Autor: Paweł Frankowski
Cena: 34,90 zł
Stron: 256
ISBN: 978-83-246-0809-6
http://www.helion.com.pl

Bardzo często główną przeszkodą na posiadanie własnej profesjo- Pierwsze rozdziały wprowadzają do CMS, szczególnie przydatne
nalnej strony www, szczególnie dla małych firm z ograniczonym dla początkujących, a więc czym jest i czego potrzebujemy do po-
budżetem, lub osób prywatnych, może być brak odpowiednich prawnego zainstalowania i używania CMS. W kolejnych rozdziałach
umiejętności, niezbędnych do zaprojektowania i wykonania strony znajdziemy 6 najpopularniejszych systemów CMS: Quick CMS
internetowej, oraz dość wysokie koszty, jeżeli wykonanie i aktuali- Lite, WebText, SmodCMS, SmodBIP, Xoops, Joomla! i Mambo.
zację zlecimy wyspecjalizowanej firmie. Przydatne będą również informacje o ich instalacji, zarządzaniu do-
Jednak nie powinniśmy załamywać rąk z tego powodu, ponie- datkowymi modułami, czy opisem paneli administracyjnych.
waż możemy skorzystać z coraz powszechniej stosowanego syste- Ostatni rozdział porusza bardzo ciekawe zagadnienia prawne
mu zarządzania treścią CMS (ang. Content Menagement System). dotyczące materiałów publikowanych w Sieci, prawa autorskiego,
Dzięki któremu sami możemy aktualizować nasze strony w łatwy jak również licencji na podstawie których CMSy są rozpowszech-
sposób, bez znajomości HTML, czy innych języków programowa- niane. Książkę śmiało można polecić osobom które zastanawiają
nia, służących do tworzenia stron. się nad stworzeniem własnej strony www i samodzielną aktualiza-
Obecnie jest kilka różnych CMSów i tutaj z pomocą przychodzi cją jej za pomocą systemu CMS, a wiedziali który wybrać. Lektura
nam książka CMS jak szybko i łatwo stworzyć stronę WWW i zarzą- książki powinna im w tym pomóc. Na uwagę zasługuje fakt że jest
dzać nią. Należy ją traktować jako swoisty przewodnik po najpopu- to jedna z pierwszych pozycji na rynku dotyczących CMS.
larniejszych systemach CMS. Zredenzował: Sławomir Zadrożny

78
Felieton

Gotowe
rozwiązania
przeciwko
zdrowemu
rozsądkowi

W
sieci coraz częściej można natrafić na gotowe komponen- pojawiające się raz w stylu html raz w xhtml, to przecież też nor-
ty i rozwiązania dla webmasterów. Powstają specjalne malność. A jakakolwiek zgodność ze standardami W3C to już czy-
strony, na których możemy pobrać już napisane i gotowe sta abstrakcja. Przecież nie wszyscy musieli słyszeć o organizacji,
do użycia systemy news-ów, sondy, kalendarze i tym podobne rzeczy która ukradkiem wiedzie swój byt gdzieś w internecie.
bez zagłębiania się w ich strukturę. Coraz większą popularność zdo- Innym często praktykowanym rozwiązaniem podczas tworzenia
bywają również CMS-y (systemy zarządzania treścią). Dzięki takim „profesjonalnej” strony jest korzystanie właśnie z gotowych roz-
rozwiązaniom przy niewielkiej wiedzy i w stosunkowo krótkim czasie wiązań, które zasadniczo zostały stworzone dla osób, które ro-
można stworzyć funkcjonalną stronę, w której konstrukcję zmienia- bią stronę dla siebie (w domyśle domową) a nie stronę „firmo-
my bez ingerencji w kod, a jedynie przy pomocy administracyjnego wą”. Przecież jak można potraktować poważnie osobę , która de-
menu. Ale czy dostępność tego typu rozwiązań wywiera dobry wpływ klaruje się jako twórca stron internetowych, gdy korzysta np. z za-
na osoby, które dopiero zaczynają swoją przygodę z programowa- implementowanego przez kogoś systemu news-ów gdzie od razu
nie i projektowaniem stron internetowych? Czy te systemy nie są rów- rzuca się w oczy napis informujący, przez kogo ten system został
nież wykorzystywane przez niektórych profesjonalistów – w sposób wykonany.
karygodny – do wykorzystywania niewiedzy klientów i nabijania so- Po tych atrakcjach pozostają nam jeszcze profesjonalni entuzja-
bie kabzy ich kosztem? ści Open Source-owych CMS-ów, rozpowszechniających je jako swo-
Nieraz spotkałem się już z prywatnymi ogłoszeniami typu: Wy- je dzieła sztuki. Wydaje mi się, że zrobienie swojej reklamowej stro-
konam profesjonalnie stronę internetową - tanio! Za każdym ra- ny to nie jest aż tak duże wyzwanie, że trzeba do niego zaprzęgać
zem z zainteresowaniem zaglądałem na stronę takiej osoby i bar- od razu rozbudowany CMS. Poza tym znacznie ładniej wygląda w
dzo często musiałem mocno trzymać się krzesła, żeby pozostać w stopce napis informujący, że strona została wykonana przez naszą
pozycji sprzed jej wyświetlenia. Najczęściej pierwszy rzut oka da- firmę, a nie w oparciu o np. Joomla czy Mambo.
wał do zrozumienia, że to jakaś prowizorka mało doświadczonej Ludzie traktujący ten interes poważnie mogliby pokusić się o na-
osoby, która może ma pomysł, ale nie umie go poprawnie wpro- pisanie swojego CMS-a, co wcale nie jest trudne w przypadku two-
wadzić w życie. rzenia go z myślą o niewielkich stronach, więc nawet jednoosobowe
Każdemu niezaprzeczalnie zdarzają się błędy, ale są pewne gra- firmy powinny dać sobie z tym radę. Niestety natrafiłem też na fir-
nice niedoskonałości, z których większość webmasterów zdaje so- mę i tutaj mam na myśli prawdziwą instytucję, która rozpowszech-
bie sprawę. Jedno pikselowe przesunięcia w grafice mogą się prze- niała Mambo dodając swoją grafikę i pomagając w konfiguracji za
cież zdarzyć każdemu. Źle dobrana kolorystyka, to przypuszczalnie naprawdę grube pieniądze.
kwestia gustu. Strona wyglądająca inaczej pod każdą przeglądar- Podejrzewam, że oferta tej firmy była raczej skierowana do ludzi,
ką – to wina Microsoftu i Billa Gatesa. Problem z kodowaniem zna- którzy nie mają zielonego pojęcia o tworzeniu stron internetowych
ków – przecież każdy i tak odczyta, co jest napisane. Ale najwięk- i nie są zorientowani w całym rynku usług www – niestety parę ta-
szy szok, zawsze przeżywam, gdy ciekawość zaprowadzi mnie do kich osób się znalazło.
kodu strony. Teraz zastanówmy się, jak wyglądałoby to wszystko, gdyby zamiast
W tym miejscu możemy spotkać ogromną liczbę różnorodnych gotowych skryptów były rozpowszechniane tutoriale pokazujące krok
i „nowoczesnych” rozwiązań, które z pewnością poprawią humor po kroku czy też bardziej intuicyjnie jak napisać dany skrypt, dajmy na
i podbudują nasze ego. Zaglądamy w to nieszczęsne źródło stro- to pojawiający się już w tym artykule system news-ów.
ny i co widzimy? Przed naszymi oczami ukazuje się istna magia ge- Skopiowanie i bezmyślne korzystanie z czyjejś pracy byłoby wtedy
neratorów stron z FrontPage na czele. Kod zaśmiecony do granic niemożliwe, a jednocześnie mobilizowałoby do nauki i myślenia. A nie-
możliwości, z pojawiającymi się w każdym tagu właściwościami, stety coraz częściej ludzie mają problemy z myśleniem, bo przecież,
które Bóg jeden wie, po co się tam znalazły, jeżeli właściwie nie są wszystko zawsze dostają podane na tacy, bez większego wysiłku, za
potrzebne. Ale żeby to dostrzec trzeba jeszcze rozszyfrować po- darmo lub za pieniądze.
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. ŁUKASZ SKOWROŃSKI
Zapewne, taki profesjonalny webmaster odpowiedziałbym nam: Autor jest studentem III roku informatyki na Uniwersytecie w Białymstoku.
Style? A po co mi one, przecież mogę zrobić stronę i bez nich. Tagi Kontakt z autorem: szeryfek@gmail.com

www.phpsolmag.org 79
www.buyitpress.com

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!
zamówienie prenumeraty

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: pren@software.com.pl. 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)............................................................................................................................................................................


automatyczne przedłużenie prenumeraty

Tytuł
2 Ilość Od numeru Opłata
Ilość
zamawianych pisma lub w zł
numerów
prenumerat miesiąca z VAT
Software Developer’s Journal (1 płyta CD)
– dawniej Software 2.0 12 250/1801
Miesięcznik profesjonalnych programistów
SDJ Extra (od 1 do 4 płyt CD lub DVD)
– dawniej Software 2.0 Extra! 6 150/1352
Numery tematyczne dla programistów

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

Suma

Jeżeli chcesz zapłacić kartą kredytową, wejdź na


stronę naszego sklepu internetowego:
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
www.buyitpress.com
W następnym numerze PHP Solutions 5/2007 (22)

W sprzedaży od kwietnia

NA CD UWAGA KOLEJNY TEST KONSUMENCKI


n Kurs Code Igniter – stwórz własny serwis n Statystyki zewnętrzne

NARZĘDZIA NOWE ARTYKUŁY W DZIAŁACH:


n Code Igniter n dla początkujących
aplikacja wykorzystująca bazę danych
n dla zaawansowanych
n PHP i Flash
łączymy aplikacje z bazą danych n bezpieczeństwo

I wiele innych artykułów, których nie możesz przeoczyć!

Redakcja zastrzega sobie możliwość zmiany zawartości pisma.

You might also like