Professional Documents
Culture Documents
Tematy
Usługi hostingowe
Savant – pogromca Smarty? 24
Relokacja serwerów Tomasz Garbiak
Tomasz w swoim artykule opisuje jak korzystać
Sprzęt – Serwery
z systemu Savant – zorientowanego obiekto-
Łącza internetowe wo systemu, który wykorzystuje samo PHP ja-
Statystyki zewnętrzne ko język szablonów. Przedstawia również wady
i zalety tego zorientowanego obiektowo syste-
UPC mu wyszukujacego samo PHP jako język sza-
blonów.
Zapraszamy również firmy, które chciałyby, aby ich produkty lub usługi
zostały objęte naszymi testami.
BEZPIECZEŃSTWO
RSA w PHP:
chronimy dane przy użyciu
kryptografii asymetrycznej 32
Kamil Karczmarczyk
Sylwia Pogroszewska Kamil przedstawia działanie algorytmu asyme-
phpsolmag@software.com.pl trycznego RSA, który jest obecnie najpopu-
larniejszym algorytmem szyfrowania asyme-
trycznego,używanym powszechnie np. w han-
dlu elektronicznym czy też w celu podpisywa-
nia emaili. Autor wskazuje, jak przy jego użyciu
stworzyć system bezpiecznego logowania.
Nasz magazyn ukazuje się w trzech językach!
PROJEKTY
polskim niemieckim francuskim
XML_FastCreate 38
Guillaume Lecanu
Guillame pokazuje jak tworzyć prawidłowy kod
XML za pomocą XML_FastCreate, sposób doko-
nywania transformacji znaczków XML-a, spraw-
dzania DTD , wykrywania błędów składni i two-
rzenia dokumentów w XHTML-u.
Jeśli jesteś zainteresowany zakupem licencji na wydawanie naszych pism prosimy o kontakt:
Monika Godlewska monikag@software.com.pl tel.: 48 22 887 12 66, fax: 48 22 887 10 11
Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit firmy G DATA Software Sp. z o.o.
FELIETON 78
Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu nośnikach informacje
Michał Małecki i programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantuje
także poprawnego działania programów shareware, freeware i public domain.
Uszkodzone podczas wysyłki płyty wymienia redakcja.
Wszystkie znaki firmowe zawarte w piśmie są własnością odpowiednich firm
ZAPOWIEDZI 82 i zostały użyte wyłącznie w celach informacyjnych.
Druk: ArtDruk
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
– bez zgody wydawcy – jest działaniem na jego szkodę i skutkuje odpowiedzialnością sądową.
Achievo
PHP-GTK2
dostępny w wersji alfa
Wielkimi krokami zbliża się pierwsza stabil-
na wersja PHP-GTK2. W połowie lipca autorzy
A chievo to napisany w PHP system za-
rządzania projektami, który łączy cechy
typowego PM-a, CRM-a, HRM-a i PIM-a.
podziału pracy w zespole programistów, po-
zwala też na zarządzanie umowami zawar-
tymi z pracownikami i innymi wykonawca-
udostępnili wersję zeta projektu (którą potem
Możemy go łatwo wdrożyć do systemu ob- mi czy korzystanie z list zadań do wykona-
musieli z przyczyn technicznych przemianować
na alpha). Blisko połowa z 202 klas i 2 900 me- sługi klientów, oferując im podgląd postępu nia (TODO). Do dyspozycji mamy wiele plu-
tod została już ujęta w dokumentacji. Autorzy zamówionych prac w trakcie ich wykonywa- ginów, w tym kalendarz, notatnik i genera-
nie zdradzają planowanej daty wydania pierw-
szej stabilnej wersji PHP-GTK2, ale już teraz, w nia. Narzędzie działa na każdej platformie tor statystyk pracy. Na wsparcie techniczne
oparciu o wersje testowe, możemy tworzyć wła- oferującej PHP i MySQL, jest też wieloję- projektu składa się także forum i dedykowa-
sne aplikacje graficzne i poznawać jej zapowia-
daną funkcjonalność. zyczne i całkowicie darmowe. Sam Achievo na bugzilla. Opcjonalnie możemy poprosić o
http://gtk.php.net oferuje wiele udogodnień: generowane za płatną konsultację z deweloperami Achievo,
pomocą biblioteki GD2 statystyki czasu pra- zaś postęp prac obejrzymy na blogu auto-
Planeta PHP – wszystkie
cy, wykresy postępu rozwoju projektu, czy rów (http://www.achievo.org/blog)
newsy w jednym miejscu
PHP Planet prezentuje informacje powiązane z funkcję dodawania plików, które następnie
PHP, pochodzące z różnych źródeł dostępnych może przejrzeć i skomentować nasz kon- licencja: Open Source (własna)
w sieci. Treści nowości są pobierane z dziesią-
tek kanałów RSS najpopularniejszych blogów trahent. Achievo oferuje także wspomaganie http://www.achievo.org
oraz wortali poświęconych temu językowi. Do-
datkowo, na stronie projektu Planet Feed Re-
ader (http://planetplanet.org) znajdziemy odno-
śniki do innych witryn typu Planet: traktujących
o MySQL-u, eZ publish, czy PRADO.
http://planet-php.org
Symphony Framework
Symphony to nowy framework, udostępniany
na podstawie darmowej licencji MIT,komponu-
je,zachowuje, dzieli i wykonuje meta programy
( SHA99, LOR02). Mimo, że wersja 1.0 jesz-
cze się nie ukazała, już teraz projekt zaskakuje:
jest skierowany na aplikacje klasy Enterprise,
przy czym oferuje przyjazne linki, wsparcie dla
technologii AJAX i caching. Całość została na-
pisana w OOP PHP5 (architektura MVC). Pro-
jekt rozwija się z dnia na dzień, zaś jego bardzo
mocną stroną jest obszerny manual, wsparty fil-
mami w formacie QuickTime.
http://www.symphony-project.com
n
forum dyskusyjnego phpBB, noszącej nazwę
et2ftp to bardzo popularne rozwią- gów, szukać plików, używać załączonych
kodową Olympus. Autorzy projektu udostępnili
zanie, stosowane głównie na witry- do projektu edytorów HTML i PHP i two- już kilka wersji beta produktu. Spośród nowych
nach firm hostingowych. Jego funkcjonal- rzyć nowe pliki tekstowe. Aplikacja wspiera możliwości phpBB 3.0 warto wymienić tworze-
nie własnych kodów BBCode, usprawnione ke-
ność nie ustępuje najlepszym okienkowym transfer plików pomiędzy dwoma serwera- szowanie, powiadamianie o nowych wiadomo-
klientom FTP. Net2ftp umożliwia nawigację mi FTP. Projekt możemy łatwo wdrożyć do ściach przez Jabber lub XMPP oraz wysyłanie
treści tematów emailem. Obecna wersja działa
w katalogach, upload plików (także z auto- systemu CMS: na jego witrynie znajdziemy pod PHP4 i PHP5. Produkt jest dostępny na li-
matycznym rozpakowywaniem archiwów) moduły dla Mambo, Drupala i XOOPS-a. cencji GPL.
http://phpbb.com
oraz ich pobieranie. Pozwala też na archi- Łatwy w obsłudze system szablonów za-
wizację zbiorów do formatu ZIP, ich prze- pewnia prostą implementację do gotowe- Gnope
noszenie, kopiowanie i usuwanie, zmianę go layoutu naszej strony. Cały system zo- Wraz z nadejściem PHP-GTK2, Christian We-
iske rozpoczął prace nad projektem Gnope.
nazw plików i katalogów, użycie komen- stał przetłumaczony na ponad 10 języków i Efektem jest pakiet działający na wielu platfor-
dy CHMOD (zmiana uprawnień dostępu) łatwo możemy dodawać kolejne. mach, który ułatwia pisanie aplikacji PHP-GTK
oraz ich dystrybucję na najpopularniejsze plat-
czy podgląd kodu pliku w edytorze (wraz formy systemowe. Narzędzie to, w połączeniu
z podświetlaniem składni i numerowaniem licencja: GNU GPL z Glade, stanowi absolutny niezbędnik dewelo-
linii). Możemy też obliczać rozmiar katalo- http://www.net2ftp.com pera PHP-GTK. Projekt jest rozpowszechniany
na licencji LGPL.
http://www.gnope.org
W
nich edycji jest odejście od obsługi PHP4 i My-
raz z wydaniem Mambo o numerze
SQL-a 3.23.x. Lista wprowadzonych poprawek
4.5.3, w sierpniu 2005 roku, część jest imponująca – programiści Mediawiki dokła-
deweloperów tego CMS-a odeszła, aby dają wszelkich starań, by ich produkt był bez-
konkurencyjny. Mediawiki jest dostępne na li-
stworzyć Joomlę. Rozniosła się wieść, że cencji GNU GPL.
Mambo przestało istnieć, a na jego miej- http://www.mediawiki.org
sce tworzony był nowy Multisite CMS. Nic
Shoutbox w PHP i AJA X-ie
bardziej mylnego – projekt Mambo wciąż YShout to znane z wielu witryn (w tym forów
się rozwija, a ilość jego zwolenników ro- dyskusyjnych) rozwiązanie alternatywne dla
chata: shoutbox, czyli okienko, w którym (pra-
śnie. Mambo jest bezpieczną aplikacją: wie) na bieżąco możemy się komunikować z in-
bugi zostały naprawione, a dokumentacja nymi użytkownikami. Rewolucją w rozwiąza-
niach tego typu jest użycie technologii AJAX do
rozwinięta. Na stronie projektu znajdzie- odświeżania zawartości okienka – koniec z uży-
my m.in. tutoriale wykonane w technologii file użytkowników, czy systemy zarządza- ciem ramek! Można się spodziewać, że projekt
ten szybko znajdzie uznanie i zostanie zaimple-
Macromedia Flash, obrazujące wdrożenie nia reklamami. Mambo jest wyposażone
mentowany w najpoplarniejszych CMS-ach i fo-
i wykorzystanie systemu. Ilość szablonów i w potężny system keszujący, który skraca rach dyskusyjnych.
pluginów dla Mambo jest imponująca. czas generacji dokumentów, zachodzącej http://yurivish.com/yshout
Zalety Mambo: przyjazne URL-e, przy użyciu autorskiego systemu szablo- CMS na prywatną witrynę
wątki RSS, podziały na kategorie, zarzą- nów. Łącznie ilość modułów napisanych Flux jest nowym projektem typu CMS,
opartym na frameworku Popoon (http:
dzanie użytkownikami, łatwa integracja z pod Mambo jest bliska 300, dodatkowo w //www.popoon.org) i PHP5. Oferuje wsparcie
forami dyskusyjnymi, wielość wersji języ- repozytorium znajdziemy ponad 80 dar- dla wielu języków, posiada wbudowany edytor
kowych, profesjonalny edytor WYSIWYG mowych szablonów, 400 komponentów WYSIWYG, generator dokumentów PDF i wiele
innych. Korzysta z opartego na XSLT systemu
i ogromna, liczona w dziesiątkach tysię- i dziesiątki artykułów na temat systemu. szablonów; pozwala też na instalację wielu plu-
cy społeczność użytkowników, gwaran- Jeśli mamy uprzedzenia do Mambo po ginów, takich jak m.in. blog czy galeria. Nowo-
ścią w rozwiązaniach tego typu jest użycie tech-
tują pomoc i dostępność poszukiwanych rozłamie z 2005 roku, warto drugi raz się nologii AJAX w polu wyszukiwania – wyniki wy-
rozwiązań. Dodatkowe pluginy zawiera- przyjrzeć temu rozwiniętemu projektowi. świetlane są w trakcie pisania, co bardzo ogra-
nicza czas potrzebny na znalezienie pożąda-
ją m.in. systemy ankiet, fora dyskusyjne, nej informacji. Flux jest dostępny na zasadach
galerie, systemy uwierzytelniania w opar- Licencja: GNU GPL. określonych w licencji GNU GPL.
ciu o LDAP, kalendarze, rozszerzone pro- http://www.mamboserver.org http://www.flux-cms.org
PHP w Wikibooks
Wikibooks to oparta na silniku MediaWiki wielo- MagpieRSS
P
języczna internetowa biblioteka swobodnie do-
rowadząc wortal często cytujemy in-
stępnych tekstów (m.in. książek). Dotyczy wie-
lu dziedzin (w tym informatyki) i jest tworzo- formacje o nowościach z zaprzyjaź-
na przez społeczność pasjonatów. W jej zaso- nionych źródeł. Dzięki wątkom RSS nie
bach znajdziemy m.in. ciekawy podręcznik PHP
oraz pozycje nt. technologii i rozwiązań takich, musimy już się męczyć z kopiowaniem
jak XHTML, CSS, XML Schema, CVS czy Sub- informacji na naszą stronę – możemy
version. Serwis rozwija się bardzo dynamicznie
– każdy podręcznik jest pisany przez kilku au- użyć darmowej, rozpowszechnianej na li-
torów i nic nie stoi na przeszkodzie, by dopisać cencji GNU GPL klasy MagpieRSS. Pro-
i swój rozdział.
jekt ten szybko zdobył sympatię dewelo-
http://wikibooks.org
perów PHP, głównie dzięki przejrzyste-
Biblioteka AJA X od Adobe mu kodowi i dużej szybkości działania.
Spry to AJAX-owy framework firmy Adobe.
Ułatwia on tworzenie aplikacji wykorzystują- Jego niewątpliwym atutem jest ilość ob-
cych AJAX-a, m.in. upraszczając wstawianie sługiwanych formatów wątków. Obecnie ły, co gwarantuje jego łatwe wdroże-
elementów dynamicznych do kodu HTML i w
dużej mierze zwalniając webmastera od ko-
są to: RSS 0.9, RSS 1.0, RSS 2.0 oraz nie oraz modyfikację. Na witrynie Mag-
nieczności programowania. Spry oferuje też Atom. pieRSS znajdziemy wiele odnośników
narzędzia graficzne pomocne w nawigacji i Nowatorskim rozwiązaniem uży- do aplikacji opartych o ten system, ta-
administracji na stronie WWW. Świetnie ob-
razują to przykłady dostępne na witrynie pro- tym w MagpieRSS jest zastosowanie kich jak: generator grafik PNG, agrega-
jektu, takie jak galeria ze skalowalnymi zdję- keszowania oraz nagłówków HTTP w tor wiadomości RSS, konwerter RSS
ciami, czy tabela, którą możemy sortować
– oczywiście, bez potrzeby odświeżania stro- celu rozpoznania, czy dokument zo- do JavaScript, czy specjalne edycje dla
ny. W połączeniu z PHP i bazą danych, Spry stał zmodyfikowany (ang. conditio- blogów Wordpress. Dodatkowo mamy
stanowi potężne narzędzie, pomocne zwłasz-
cza przy projektowaniu sklepów interneto-
nal GETs). Jakby tego było mało, ma- możliwość przejrzenia wielu artykułów
wych czy systemów klasy Enterprise. Frame- my możliwość korzystania z kompresji i tutoriali na temat użycia tej klasy.
work jest dostępny na licencji BSD. GZIP, uwierzytelniania HTTP oraz szy-
http://labs.adobe.com/technologies/spry
frowania transmisji za pomocą SSL. licencja: GNU GPL.
advAJA X 1.1 Cały projekt jest podzielony na modu- http://magpierss.sourceforge.net
Advanced AJAX to obiekt języka JavaScript,
pomocny przy tworzeniu dynamicznych witryn
internetowych korzystających z AJAX-a. Uła-
twia on m.in. ustawianie wartości argumen- Framework Prototype w praktyce
tów zapytania do serwera, pełną kontrolę nad
połączeniem klient-serwer i jego wznawianie
oraz korzystanie z pamięci podręcznej (ang.
cache). Możliwości advAJAX i specyfikę sa-
P rototype to darmowy framework dla
języka JavaScript, ułatwiający two-
rzenie aplikacji za pomocą technologii
mej technologii AJAX omówiliśmy w numerze
1/2006. Obecnie projekt rozwija się bardzo AJAX (a więc i PHP). Jego wszechstron-
dynamicznie; rośnie też jego dokumentacja
i przykłady zastosowań. Twórca advAJAX-a
ne zastosowania możemy zobaczyć na
pozwala zarówno na jego prywatny, jak i ko- stronie http://script.aculo.us. Ta ostatnia
mercyjny użytek. stanowi repozytorium przydatnych skryp-
http://advajax.anakin.us
tów, używanych przy tworzeniu aplikacji
Glade 3 klasy Enterprise, które z racji tego, że są
Po wielu miesiącach oczekiwania, Glade
– narzędzie pozwalające na łatwe, intuicyj-
rozbudowane i przesyłają dużo danych,
ne tworzenie graficznych interfejsów użytkow- generują poważne obciążenie serwera.
nika opartych na bibliotece GTK (dostępnej
Użycie technologii AJAX zmniejsza za- jektu o nazwie SortableFloats: użytkow-
również dla języka PHP dzięki PHP-GTK) do-
czekało się stabilnej wersji z linii 3. Znajdzie- potrzebowanie na dostęp do serwera, nik może zmienić kolejność elementów
my w niej mnóstwo nowych funkcji: obsługę gdyż – mówiąc w skrócie – dane są naj- na liście poprzez ich przeciąganie – od-
ikon, przenoszenie i możliwość skalowania
elementów GtkTable i GtkBox, nowe pale- pierw przenoszone do klienta (przeglą- wieczny problem z klikaniem “przesuń
ty kolorów, wspomaganie tworzenia pasków darki internetowej), a następnie przetwa- niżej”, występujący np. przy zmianie ko-
narzędzi (ang. toolbars) i menu oraz wiele in-
nych. Do działania, Glade 3 wymaga GTK+
rzane po jego stronie dopóki nie ulegną lejności wyświetlania wątków na forach
w wersji 2.8 oraz libxml2. Projekt jest rozpo- zmianie (można więc bez problemu np. dyskusyjnych powinien bezpowrotnie
wszechniany na licencji GNU GPL.
sortować zawartość tabeli, ale już mody- zniknąć.
fikacja zawartych w niej danych wymaga Rozwiązania zaprezentowane na
ich ponownego pobrania. script.aculo.us są stosowane m.in. na
W Prototype znajdziemy technikę stronach Apple, Digg, Feedburner, Base-
drag-and-drop, stosowaną w koszykach camp, czy Mailroom, a przede wszystkim
sklepów internetowych, automatyczne w bardzo innowacyjnym frameworku Ru-
uzupełnianie pól (używane w wyszuki- by on Rails.
warkach w celu dostarczenia wstępnych
wyników bez potrzeby przeładowania
strony), tabele, które możemy sortować
oraz mnóstwo efektów wizualnych (na- http://script.aculo.us
http://glade.gnome.org
jazdy, zanikanie, podświetlanie, itd.). Na http://prototype.conio.net
szczególną uwagę zasługuje demo pro- http://www.rubyonrails.org
2 filmy wideo: XML Development using Java oraz XML Based Web Applications
F irma KeyStone Learning przygoto-
wała specjalnie dla czytelników ma-
gazynu PHP Solutions następujące fil-
my: XML Development using Java oraz
XML Based Web Applications. Filmy
przydadzą się wszystkim deweloperom.
Pierwszy z filmów omawia zasto-
sowanie Javy w technologii XML. Au-
torzy wyjaśniają możliwości, które ofe-
ruje Java deweloperom. Dowiesz się w
jaki sposób zbudować wyszukany użyt-
kowy program szybciej i po niższych
kosztach.
Natomiast z filmu XML Based Web
Applications znajdziesz odpowiedź na
pytanie jaką rolę odgrywa XML w prze-
twarzaniu danych w formacie B2B w
aplikacjach internetowych. Życzymy
przyjemnego oglądania i nauki. Rysunek 1. XML Development using Java
Dodatkowe materiały
Testy wydajności
i profilowanie aplikacji PHP
Stopień trudności: lll
Łukasz Witczak
Z
większenie wydajności jest mo- uprawnienia administratora (środowisko
żliwe dzięki optymalizacji kodu. Linux) poleceniem:
Problem w tym, że dzisiejsze
aplikacje pisane w PHP rozrosły się pear install benchmark
do takich rozmiarów, iż ciężko przej-
rzeć cały kod i poprawić jego efektyw- PEAR::Benchmark składa się z trzech
ność. Znajdując wąskie gardło w syste- klas: Benchmark _ Iterate, Benchmark _
mie można je zoptymalizować i w mia- Profiler i Benchmark _ Timer.
rę niewielkim kosztem podnieść wy-
dajność całej witryny. W tym artyku- Benchmark_Timer
le pokażemy, jak testować wydajność Benchmark _ Timerto klasa pozwalająca
W SIECI zarówno całej aplikacji, jak i wybra- nam mierzyć czas, jaki upłynął między
nych fragmentów kodu oraz jak iden- kolejnymi tzw. markerami. Markery to
tyfikować te partie kodu, które są przy- miejsca pomiaru czasu, które ustawia-
l http://pear.php.net/package/
czyną największego narzutu czaso-
Benchmark – strona domowa
wego.
l
pakietu PEAR::Benchmark
http://www.linuxjournal.com/
Co należy wiedzieć...
article/7213 – artykuł o Powinieneś znać podstawy programo-
profilowaniu przy pomocy Testy wydajności wania proceduralnego i obiektowego
APD z PEAR::Benchmark w PHP5.
http://wiki.cc/php/Apd
Co obiecujemy...
l
my instancję tej klasy. Podobnie jak po- Analizując wyniki widzimy, że naj- Nakazuje ona uruchomić funkcję o
przednio, pomiary rozpoczynamy i koń- więcej czasu zajmuje połączenie się z nazwie podanej jako drugi argument
czymy metodami start() i stop(). Tutaj bazą danych i wstawienie nowego re- i z parametrem przesłanym jako trze-
podobieństwa z poprzednim przykładem kordu w tabeli bazodanowej. Nieste- ci argument. Liczbę iteracji (wywo-
się kończą, bowiem w przypadku Bench- ty, operacje wejścia/wyjścia są najbar- łań) określa pierwszy argument. My
mark _ Profiler zamiast markerów używa- dziej kosztowne, stąd dobrą metodą na testujemy funkcję com ments() z argu-
my sekcji. Oprócz tego, że mierzony jest zwiększenie szybkości działania apli- mentem $com ment 1000 razy. Wywo-
globalny czas wykonania między wywo- kacji jest keszowanie (ang. caching). W łanie get() zwraca nam tablicę, która
łaniami start() i stop(), osobne pomia- naszym przypadku nie możemy użyć tej zawiera czas wykonania kodu w każ-
ry dokonywane są dla sekcji oznaczo- ostatniej techniki, gdyż przyspiesza ona dej iteracji (klucze są ponumerowane
nych metodami enterSection() i leave- odczyt, a my dodajemy dane do bazy. wg kolejnych liczb naturalnych) oraz
Section() oznaczającymi początek i ko- Jeśli bardzo zależy nam na wydajności, czas średni (klucz mean) i liczbę itera-
niec sekcji. to możemy się zająć funkcjami filtrują- cji (klucz iterations). Ważną rzeczą
Argumentem każdej z tych metod cymi nr telefonu i komentarz, co powin- podczas przygotowywania testu jest
jest nazwa sekcji, którą ustalamy we- no dać nam kilka procent zysku na cza- dobór liczby iteracji. Abyśmy mogli
dług naszych upodobań. W przypad- sie wykonania. Przyjrzyjmy się więc bli- mówić o wiarygodnych testach, mu-
ku pomiaru czasu wykonania funkcji żej funkcjom telephone() i comments(). simy przeprowadzić co najmniej 1000
bądź metod można zastosować sztucz- cykli. Kod z Listingu 10 wyświetla tyl-
kę, która wyłącza z pomiarów czas po- Benchmark_Iterate ko czas średni, bo on jest dla nas naj-
trzebny na samo wywołanie funkcji i po- Czas wykonania skryptu i jego poszcze- istotniejszy:
nowne zwrócenie sterowania do miej- gólnych części zależy od wydajności
sca wywołania funkcji lub metody. W maszyny, na której odbywa się test oraz Mean time: 0.000047s for 1000
tym celu możemy wewnątrz funkcji za- jej obciążenia. Łatwo zauważyć, że cza- iterations of telephone()
deklarować, że zmienna zawierająca sy te różnią się za każdym wywołaniem, Mean time: 0.000141s for 1000
obiekt klasy Benchmark _ Profiler jest ale najczęściej oscylują wokół jakiejś iterations of comments()
globalna i utworzyć sekcje wewnątrz tej wartości, z rzadka odbiegając znaczą-
funkcji (Listing 9). Wynik działania testu co do normy. Aby pozbyć się tych nie- Teraz mamy bardziej wiarygodne wy-
uzyskamy wywołując metodę display() dogodności, powinniśmy wykonać test niki i możemy przystąpić do optymali-
pod koniec skryptu, a rezultat przedsta- w pętli i uśrednić uzyskane czasy. Kla- zacji kodu funkcji comments() (Listing
wiamy na Rysunku 1. sa Benchmark _ Iterate pozwala na wy- 11). Choć techniki optymalizacyjne nie
Patrząc na Rysunek 1 od razu za- konywanie funkcji lub metody w pę- są przedmiotem tego artykułu, to musi-
uważymy kolumnę oznaczoną znakiem tli o zadanej liczbie iteracji. Na Listin- my tu wspomnieć o kilku sposród nich,
„%”, która ilustruje procentowy udział gu 10 pokazujemy przykład wykorzysta- aby wiedzieć, jak uzyskać wzrost wy-
każdej operacji w czasie wykonania nia tej klasy wobec funkcji filtrującej ko- dajności. Nasza funkcja widoczna na
skryptu między start() a stop(). Ostat- mentarze. Listingu 4 wykorzystuje do swego dzia-
ni wiersz oznaczony jako Global ozna- Jak widać, nie jest to skomplikowa- łania wyrażenia regularne za pomocą
cza cały skrypt (a w zasadzie cześć po- ne: po stworzeniu instancji klasy Bench- funkcji ereg _ replace(). Pewnie więk-
między początkiem a końcem pomia- mark _ Iterate uzyskujemy dostęp do szość z Was wie, iż ereg _ replace()
rów), więc zajmie on 100% czasu wyko- jej metod służących testom i wyświe- jest zdecydowanie wolniejsza niż per-
nania. Kolumna #calls pokazuje, ile razy tlaniu wyników. Kluczowa jest następu- eg _ replace() – możemy więc wyko-
dana sekcja była wywołana, calls zawie- jąca linia: rzystać tę szybszą. Ponieważ jednak
ra nazwy sekcji, jakie zostały wywołane mamy tylko pozbyć się tagów, więc nie
wewnątrz sekcji odpowiedniej dla każde- $benchmark->run( 1000, 'comments', potrzebujemy w ogóle używać wyra-
go wiersza wyników. $comment ); żeń regularnych: wystarczy wbudowa-
są Benchmark _ Timer i dodaniu nowej łego skryptu. Dalej znajduje się tabela na). Ostatni wiersz naszej tabeli opisu-
funkcji apd _ set _ pprof _ trace() na podająca bardziej szczegółowe informa- je funkcję main(), a przecież na naszym
początku skryptu, które rozpoczyna cje, jak procentowy udział danej funk- listingu nie było funkcji o takiej nazwie!
śledzenie działania skryptu. APD po- cji w czasie wykonania całego skryp- Skąd więc się ona wzięła? Otóż main
siada tez kilka innych funkcji, ale my tu, rzeczywisty czas, jaki minął (kolum- oznacza tu cały skrypt od momentu roz-
wykorzystamy jedynie tę wymienioną. na Real), czas spędzony na wykony- poczęcia śledzenia.
Jak widać, aby wykonać profilowanie, waniu kodu użytkownika przez proce-
wymagana jest tylko minimalna mo- sor (kolumna User) oraz czas spędzony Przykład z życia wzięty
dyfikacja kodu aplikacji: wystarczy, że na wywołaniach systemowych (kolum- Nasz przykład jest dość prosty, więc
wywołanie na początku głównego pli- na System). W kolumnie Calls zapisana czasy wykonania są minimalne. Weź-
ku naszej aplikacji dodamy apd _ set _ jest informacja o liczbie wywołań danej my więc większą aplikację: nie będzie-
pprof _ trace(). Po wykonaniu skryp- funkcji (nazwa funkcji to ostatnia kolum- my jej tworzyć od zera, tylko skorzy-
tu wynik profilowania zostaje zapisany
w pliku o nazwie pprof.xxxxx.yy, gdzie Listing 12. Porównanie wydajności funkcji przed i po optymalizacji.
xxxxx to PID procesu serwera, który
uruchomił profilowany skrypt, a yy to <?php
require 'Benchmark/Iterate.php';
kolejny numer porządkowy. Katalog, w
require './filter.php';
którym ten plik zostanie zapisany, jest require './filter2.php';
określony przez opcjonalny parametr $benchmark = new Benchmark_Iterate();
funkcji apd _ set _ pprof _ trace (). $comment = 'Some comments <script> ... </script>,
Jeżeli ten ostatni nie został zde- Some comments <script> ... </script>
<a href="www.somedangerouslink.com"> Safe text <a
finiowany, to położenie tego folderu
href="javascript:alert("XSS")">ClickMe!</a> - <body
określa zmienna apd.dumpdir z pliku onload=alert("vulnerable")> Safe text <iframe src=
php.ini. Struktura pliku pprof jest opi- http://www.notsafe.com/script.html>';
sana w dokumentacji, ale odradzamy $benchmark->run( 1000, 'comments', $comment );
własnoręczne analizowanie jego za- $commentResult = $benchmark->get();
$benchmark->run( 1000, 'comments2', $comment );
wartości, ponieważ istnieje do tego
$comment2Result = $benchmark->get();
proste i efektywne narzędzie – skrypt
PHP o nazwie pprofp. echo '<p>Mean time: '.$commentResult['mean'] . 's for '.$commentResult[
Wywołujemy go z linii poleceń w 'iterations']. ' iterations of comments()</p>';
katalogu, w którym się on znajduje,
$percent = round( (1-($comment2Result['mean']/$commentResult['mean']))*100, 1 );
podając ścieżkę dostępu do pliku z
echo '<p>Mean time: '.$comment2Result['mean'].'s ('. $percent .'% faster) for '.
wynikami: $comment2Result['iterations'].' iterations of comments2()</p>';
?>
php pprofp –z /tmp/profiling/pprof.02596.8
Listing 13. Klasa MyIterate
Spowoduje to przeanalizowanie poda-
<?php
nego jako parametr pliku, utworzone- require_once 'Benchmark/Iterate.php';
go wcześniej przez funkcję apd _ set _ class MyIterate extends Benchmark_Iterate{
pprof _ trace(). Program pprofp ma private $overhead;
szereg flag i opcji opisanych w Ramce public function run(){
$arguments = func_get_args();
Parametry skryptu pprofp. Nam najbar-
$iterationsCount = array_shift( $arguments );
dziej przydadzą się flagi –z i –r. Wyni- $functionName = array_shift( $arguments );
kiem interpretacji naszego pliku jest ta- $arguments = array_shift( $arguments );
bela pokazana na Rysunku 2. parent::run( $iterationsCount, $functionName, $arguments );
Na Rysunku 2 pokazujemy kilka $benchmark = new Benchmark_Iterate();
for ( $i=0; $i<$iterationsCount; $i++ ){
istotnych informacji. Na górze widać
$benchmark->setMarker( '_start_'.$i );
podstawowe dane, takie jak lokalizacja $benchmark->setMarker( '_stop_'.$i );
testowanego pliku i czas wykonania ca- }
$result = $benchmark->get();
$this->overhead = $result['mean'];
Listing 11. Zoptymalizowana funkcja }
comments() public function get(){
$result = parent::get();
<?php
$result['mean'] -= $this->overhead;
function comments2( $comment ){
return $result;
$comment = strip_tags($comment);
return $comment; }
} }
?> ?>
apd_set_pprof_trace();
<?php O autorze
apd_set_pprof_trace();
function doSth(){ Łukasz Witczak
$tmp = range( 0, 999 ); Autor jest studentem piątego roku Wy-
krsort( $tmp ); działu Informatyki Politechniki Szczeciń-
return $tmp;
skiej. Programowaniem w PHP zajmu-
}
je się od 5 lat. Oprócz PHP, programu-
je jeszcze w C/C++ i Javie.
// wywołanie funkcji doSth()
$result = doSth();
Kontakt z autorem:
?>
lwitczak@wi.ps.pl
HITY
2 kursy wideo KeyStone
- XML Developing Using Java
Programy - XML Based Web Applications
PHP-Qt
XAMP
Wampserwer E-BOOKS
Auditing Your Web Site Security
PHP Power Programming
OASSIS OpenDocument Essentials
na naszej stronie internetowej pod adresem www.phpsolmag.org/pl
W
ymienionych wad pozbawio- lacji. Jeżeli skompilowanego pliku jeszcze
ny jest Savant – zorientowany nie ma, bądź jest on nieaktualny, odbywa
obiektowo system wykorzystu- się proces kompilacji.
jący samo PHP jako język szablonów. Zo- Stosując Smarty piszemy w myśl pa-
baczmy zatem, czym Savant tak napraw- radygmatu (wzorca) MVC (model-view-
dę różni się od Smarty. Spójrzmy na frag- controller). Szablony, czyli warstwa pre-
ment kodu z Listingu 1, gdzie przedstawi- zentacji, są kompletnie oddzielone od
liśmy przykładowy szablon stworzony w warstwy logiki aplikacji, co ma czynić je
Smarty. (szablony i całe aplikacje) bardziej przej-
Po kolei: Smarty najpierw wsta- rzystymi i niejako łatwiejszymi do napi-
wi odpowiednią wartość zmiennej $ti- sania – teoretycznie szablony będzie
tle, następnie, korzystając z pętli foreach mógł stworzyć grafik, który nigdy wcze-
przejdzie przez tablicę asocjacyjną $par- śniej nie miał do czynienia z PHP. Wadą
W SIECI agrahps wstawiając wartości klucza ti- takiego rozwiązania jest oczywiście do-
tle w HTML-owe znaczniki <h2>, zaś war-
tości klucza content w znaczniki <p>. Nie
• http://www.phpsavant.com/ Co należy wiedzieć...
– strona domowa Savanta ma tu ani śladu po kodzie PHP. W syste- Czytelnik powinien znać podstawy PHP
• http://smarty.php.net/ – mie Smarty szablony są kompilowane do i HTML. Przyda się też znajomość
strona domowa Smarty
tego języka. Smarty.
• http://www.phppatterns.com/
docs/design/templates_and_ Oczywiście nie za każdym razem –
template_engines – ciekawe
informacje o szablonach
system sprawdza najpierw, czy dla dane- Co obiecujemy...
Z artykułu dowiesz się, jak korzystać z
• http://www.sitepoint.com/ go szablonu nie istnieje już skompilowa-
article/smarty-php-template- systemu Savant i czy warto się na nie-
ny plik, a jeśli tak, to czy szablon nie zo- go przesiąść.
engine – artykul o Smarty
stał zmieniony od czasu ostatniej kompi-
������� ����������
���������������� ������
������ ����������
��� ���
���
���
���������������������� ���������������������
pear install
��� http://phpsavant.com/
���� ��������������������� Savant3-3.0.0.tgz.
Warstwa logiki
���
Zacznijmy od warstwy logiki, a więc od
skryptu, w którym wykonywane będą
właściwe operacje i który będzie przeka-
����������
zywał dane do szablonów. Na początek
����������
stwórzmy obiekt Savanta.
require_once 'Savant3.php';
Rysunek 2. Schemat działania systemu Savant $savant = new Savant3();
����
Szablon
– warstwa widoku
������
����
Brakuje nam już tylko samego szablo-
���� nu. Kod gotowego szablonu można zo-
���������������������
$savant->assign('title', $title);
Kilka szablonów
$savant->assign('description', $description); na jednej stronie
Obecnie mamy wspólny szablon dla cało-
$savant->assign('menu', $menu); ści wyświetlanej strony. Chcielibyśmy jed-
nak, aby inne strony wyglądały inaczej za-
$savant->assign('content', $content);
chowując jedynie wspólny nagłówek i stop-
$savant->assign('info', $info);
kę. Jak to zrobić? Szablon można podzie-
lić na mniejsze fragmenty i umieścić je w
$savant->display('template.tpl.php'); osobnych plikach, tak jak na Listingach 10
i 11. Aby umieścić te fragmenty w głównym
szablonie należy skorzystać z metody tem- resource. Otworzywszy plik Savant3_Plu- Napiszmy zatem własną wtyczkę, któ-
plate i instrukcji include, tak jak pokazano gin_ahref.php przekonamy się, że plugin ra wstawi do szablonu adres strony, z ja-
to na Listingu 12. Innym, nieco bardziej ele- to w zasadzie klasa dziedzicząca po klasie kiej wszedł użytkownik. W tym celu tworzy-
ganckim sposobem jest uzyskanie metodą Savant3 _ Plugin posiadająca zaledwie jed- my w katalogu Savant3/resources plik o na-
fetch() wyniku wyświetlenia mniejszych ną metodę o nazwie takiej jak nazwa plu- zwie Savant3_Plugin_referer.php, w którym
szablonów i przypisanie ich do zmiennych. ginu (pominąwszy początkową część: Sa- umieszczamy kod jak na Listingu 14. Mamy
Cała ta operacja odbywa się oczywiście w vant3 _ Plugin). Savant używa tu magicz- za sobą najtrudniejszy fragment, czyli stwo-
pliku warstwy logiki. W głównym szablonie nej metody _ _ call(), która odpowiada za rzenie szkieletu klasy naszej wtyczki. Pozo-
wstawiamy już same zmienne: zachowanie się klasy podczas próby wy- staje już tylko napisanie prostej funkcji, która
wołania nieistniejącej funkcji. W takim przy- zwróci odnośnik do strony, z której użytkow-
$header = $savant->fetch( padku Savant będzie próbował znaleźć od- nik wszedł do naszego serwisu – przykłado-
'header.tpl.php'); powiedni plugin (jego nazwa określana jest wa implementacja widoczna jest na Listingu
$savant->assign(' na podstawie nazwy metody) i wywołać da- 15. Gotowe! Teraz wystarczy w szablonie
header', $header); ną metodę. wpisać <?php echo $this->referer() ?> i
$footer = $savant->fetch(
'footer.tpl.php');
Listing 8. Szablon w Savancie
$savant->assign(
'footer', $footer); <?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Drobnej modyfikacji wymagać teraz bę- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
dzie szablon główny – jego kod przedsta- <head>
wia Listing 13. Sposób postępowania wy- <title><?php echo $this->title ?></title>
gląda tu zatem podobnie jak w Smarty. <meta name="description"
content="<?php $this->eprint($this->description) ?>" />
Pluginy, </head>
<body>
czyli rozbudowywanie <h1><?php echo $this->title ?></h1>
Savanta <ul><?php foreach($this->menu as $key => $val): ?>
Ogromną zaletą Savanta jest możliwość <li><?php if ($key != $this->currentPage): ?>
<a href="<?php echo $val ?>"><?php echo $key ?></a>
jego łatwej rozbudowy dzięki sprawnemu
<?php else: echo $key; endif; ?></li>
systemowi pluginów. Zanim jednak napi- </ul>
szemy własne rozszerzenie, przyjrzyjmy <p>
się, jaka jest zasada ich działania. Plugi- <?php echo $this->content ?>
ny to obiekty, które można wywołać w sza- </p>
<address><?php echo $this->info ?></address>
blonie celem automatyzacji tworzenia pew-
</body>
nych powtarzających się elementów, np. </html>
aby łatwiej było umieścić na stronie odno-
śnik. Taką możliwość daje dostarczony z Listing 9. Przykład użycia funkcji eprint()
Savantem plugin ahref, którego używa się
<input type="text" name="sampleInput"
wpisując do szablonu następujący kod:
value="<?php $this->eprint($this->variable, strip_tags,
htmlspecialchars, array($someObject, $method)) ?>" />
<?php echo
$this->ahref('Text', Listing 10. Szablon nagłówka
'http://some.dummy.address.com') ?>,
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
co w efekcie daje nam taki oto rezulat: www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<a href="http://some.dummy. <head>
<title><?php echo $this->title ?></title>
address.com">Text</a>
<meta name="description"
content="<?php $this->eprint($this->description) ?>" />
Kod pluginu znajdziemy w katalogu </head>
Savant3/resources. W tym miejscu będzie- <body>
my umieszczać nasze własne pluginy. Moż- <h1><?php echo $this->title ?></h1>
<ul><?php foreach($this->menu as $key => $val): ?>
na zdecydować się na inną lokalizację, ale
<li>
wówczas będziemy musieli podać Savanto- <?php if ($key != $this->currentPage): ?>
wi odpowiednią ścieżkę posługując się zna- <a href="<?php echo $val ?>">
nymi już metodami setPath() lub addPath(). <?php echo $key ?></a><?php else: echo $key; endif; ?>
Jedyna różnica w ich wykorzystaniu pole- </li>
</ul>
gać będzie na tym, że tym razem pierw-
szym parametrem będzie nie template a
uzyskamy zamierzony efekt. Pisanie podob- mamy tam do czynienia ze znacznie więk- Kompilacja w Savancie
nych pluginów dla systemu Smarty również szą ilością możliwych opcji (obsługa keszo- Wróćmy do wykorzystania w Savancie ze-
nie należy do rzeczy trudnych, jednakże wania, dynamiczna rejestracja pluginu, itp.). wnętrznych kompilatorów. Włączenie kom-
pilatora sprowadza się do napisania kilku
Listing 11. Szablon stopki linijek kodu, tak jak na Listingu 16.
W pierwszym kroku ładujemy pliki
<address><?php echo $this->info ?> zarówno Savanta, jak i kompilatora. Na-
</address>
stępnie tworzymy instancję kompilato-
ra i ustalamy opcje konfiguracyjne – wy-
Listing 12. Szablon główny starczy podać ścieżkę do katalogu, w któ-
rym będą przechowywane skompilowane
<?php include $this->
pliki. Trzeba pamiętać o tym, że serwer
template('header.tpl.php') ?>
<p> musi mieć możliwość zapisu w tym ka-
<?php echo $this->content ?> talogu, trzeba mu więc nadać odpowied-
</p> nie prawa. Kompilator umożliwia korzy-
<?php include $this-> stanie w szablonach ze składni zbliżonej
template('footer.tpl.php') ?>
do tej znanej ze Smarty, a więc na przy-
</body>
</html> kład, aby wyświetlić zmienną, należy wpi-
sać {$variable}.
Listing 13. Szablon główny, tym razem nagłówek i stopka jako zmienne Jeśli kompilator ustawimy w tryb re-
strykcyjny, co odbywa się przez nadanie
<?php echo $this->header ?>
<p>
parametrowi $strict wartości true, w sza-
<?php echo $this->content ?> blonach będzie można korzystać tylko z
</p> tych funkcji i statycznych metod, które po-
<?php echo $this->header ?> damy w parametrach $allowedFunctions i
</body>
$allowedStatic. Funkcjonalność ta nie jest
</html>
jeszcze w pełni sprawna, dlatego domyślnie
Listing 14. Szkielet dla naszego pluginu jest wyłączona. Trzeba pamiętać, że przed-
stawiony kompilator jest jedynie przykładem
class Savant3_Plugin_referer extends Savant3_Plugin { możliwości systemu Savant, nie zaś w pełni
public function referer() {
działającym produktem.
}
}
Podsumowanie
Listing 15. Pełny kod pluginu Czy wobec wszystkich przedstawionych
tu wad i zalet Savanta warto dla niego po-
public function referer() {
if (!$_SERVER['HTTP_REFERER']) {
rzucić Smarty? Odpowiedź zależy w dużej
return ''; mierze od indywidualnych upodobań pro-
} else { gramisty i współpracujących z nim grafików.
$html = '<a href="'; Jeżeli potrzebny jest nam lekki i elastycz-
$html .= $_SERVER['HTTP_REFERER'];
ny system, Savant będzie idealny. Jeżeli
$html .= '">You came from this page</a>';
return $html;
potrzebujemy systemu bezpieczniejszego,
} z mnóstwem możliwości, to na dzień dzi-
} siejszy lepiej pozostać przy Smarty. Bar-
dzo prawdopodobne jest jednak, że wkrót-
Listing 16. Włączenie zewnętrznego kompilatora ce Savant doścignie swojego konkurenta i
require_once 'Savant2.php'; jego funkcjonalności nie będzie można ni-
require_once 'Savant2/Savant2_Compiler_basic.php'; czego zarzucić. n
N
ieodłączną częścią każdego me- haśle. Algorytm ten (w naszym przy-
chanizmu logowania użytkowni- padku zaimplementowany w języku Ja-
ków jest przesyłanie hasła wpi- vaScript i działający na przeglądarce
sanego na komputerze klienta (w przy- internetowej) zamienia hasło na spe-
padku aplikacji webowych – w przeglą- cjalny hash, podczas generowania któ-
darce internetowej) na serwer, na którym rego używany jest również tajny klucz.
(przeważnie w bazie danych) przechowy- Następnie, otrzymany skrót jest wysy-
wane są skróty MD5 haseł (zob. Ramka łany do serwera, gdzie – podobnie jak
Podstawy MD5). Ponieważ te skróty są przy sprawdzaniu hasła przesyłanego
jednokierunkowe i odtworzenie haseł na czystym tekstem – jest porównywany
ich podstawie nie jest możliwe, więc kra- z hashami zapisanymi w bazie danych.
W SIECI
dzież bazy nie da sprawcy wielu możli- Korzystając z tej metody wyeliminuje-
wości włamania. Poważnym problemem my ryzyko podsłuchu (nie przesyłamy
1. http://pear.php.net/package/ jest natomiast wspomniane już przesyła-
Crypt_RSA/ – klasa nie hasła jako czystego tekstu: wystarczy,
Crypt_RSA (PHP)
aby intruz podsłuchał transmisję pomiędzy
Co należy wiedzieć...
2. http://pear.php.net/package/ Należy znać podstawy programowania
Crypt_Blowfish/ – klasa klientem a serwerem (np. za pomocą snif- w PHP oraz AJAX. Przydatna będzie też
Crypt_Blowfish (PHP)
fera), a będzie mógł bez problemu doko- podstawowa wiedza na temat kryptografii.
3. http://ohdave.com/rsa/ – Im-
plementacja RSA (JS) nać agresji.
4. http://en.wikipedia.org/wiki/ W poprzednim numerze PHP So- Co obiecujemy...
RSA – Opis algorytmu RSA
lutions, w artykule Kryptografia w PHP Pokażemy zasadę działania algorytmu
5. http://en.wikipedia.org/wiki/
Blowfish_(cipher) – Opis
asymetrycznego RSA i zademonstruje-
prezentowaliśmy rozwiązanie tego pro-
algorytmu Blowfish my, jak przy jego użyciu stworzyć system
6. http://advajax.anakin.us/ blemu przy użyciu algorytmu HMAC- bezpiecznego logowania.
– Obiekt advancedAJAX MD5 po stronie klienta na wpisywanym
stawie publicznego wykładnika i modu- szyfrowanie przesyłanych danych, czyli Deszyfrowanie i tworzenie konta
łu. Prywatny wykładnik nie jest nam po- wartości wszystkich pól formularza (na- Przejdźmy do omówienia zawartości
trzebny, więc wpisujemy 0. Następnie zwy użytkownika, hasła, adresu ema- wspomnianego już pliku register2.php
wdrażamy obsługę formularza za po- il, imienia i nazwiska) za pomocą al- (Listing 3). Otrzymuje on przekazane za
mocą obiektu advAJAX. Metoda assign gorytmu RSA. Funkcja onSuccess wy- pomocą advAJAX dane z formularza,
pobiera (jako parametr) nazwę formula- świetla wewnątrz znacznika <div> (o które musimy teraz odszyfrować. Posłu-
rza oraz obiekt zawierający metody je- id=”response”) dane zwrócone przez żymy się do tego zapisanym wcześniej
go obsługi. Funkcja OnInitialization plik register2.php, do którego wysłali- w sesji jako rsa obiektem $key_pair,
jest wykonywana jeszcze przed wysła- śmy wprowadzone w formularzu war- który nazwiemy $rsa_keys i zdeseria-
niem formularza. To w niej następuje tości. lizujemy (unserialize()). Następnie
wydobędziemy z tego obiektu klucz
Listing 2. Plik register.js – szyfrowanie i wysyłanie danych prywatny, który także będzie obiektem
o nazwie $priv. Potem utworzymy nowy
function updateObjects() { obiekt $rsa_obj klasy Crypt_RSA i wy-
var key; wołujemy jego metodę DecryptBinary()
key = new RSAKeyPair(enc_exp,0,modulus);
odpowiedzialną za deszyfrowanie
function $(id) { return document.getElementById(id); }
advAJAX.assign($("registerForm"), { danych (każdego z przesłanych pól for-
onInitialization : function(obj) { mularza z osobna). Metoda ta przyjmuje
// szyfrowanie danych z formularza dwa parametry: zaszyfrowany tekst oraz
obj.parameters["username"]=encryptedString( utworzony przez nas wcześniej klucz
key,obj.parameters["username"]);
prywatny $priv (obiekt klasy Crypt_RSA_
obj.parameters["password"]=encryptedString(
key,obj.parameters["password"]); KeyPair). Ponieważ dane pochodzące
obj.parameters["email"]=encryptedString(key,obj.parameters["email"]); z formularza zostały po zaszyfrowaniu
obj.parameters["name"]=encryptedString(key,obj.parameters["name"]); przekonwertowane na system szesnast-
obj.parameters["surname"]=encryptedString(key,obj.parameters["surname"]); kowy, więc musimy je przywrócić do
},
formy binarnej przy użyciu funkcji he-
onSuccess : function(obj) {
$("response").innerHTML=obj.responseText; x2bin(), którą napiszemy sami (Listing 4),
}, gdyż nie została ona zaimplementowana
onError : function() { w PHP.
alert("Can't connect to server."); Mając odszyfrowane dane użyt-
}
kownika, możemy przystąpić do jego
});
} rejestracji w serwisie. Robimy to np.
przy pomocy klasy user, której imple-
Listing 3. Plik register2.php – deszyfrowanie i zapisanie danych nowego usera mentację pominęliśmy, gdyż nie jest
ona istotna dla ukazania technik kryp-
<?php
session_start();
tograficznych.
require_once 'Crypt/RSA.php';
// odczytanie przechowywanego obiektu (kluczy) Kryptografia hybrydowa
$rsa_keys = unserialize($_SESSION['rsa']); Jako kryptografia hybrydowa rozumiane
$priv = $rsa_keys->getPrivateKey();
jest jednoczesne użycie kryptografii sy-
$rsa_obj = new Crypt_RSA;
// deszyfrowanie
metrycznej i asymetrycznej. Dotychczas
$username=$rsa_obj->decryptBinary(hex2bin($_POST['username']),$priv); szyfrowaliśmy dane tylko w jednym kie-
$password=$rsa_obj->decryptBinary(hex2bin($_POST['password']),$priv); runku: od użytkownika do serwera. Aby
$email = $rsa_obj->decryptBinary(hex2bin($_POST['email']),$priv); zrealizować nasz projekt, będziemy jed-
$name = $rsa_obj->decryptBinary(hex2bin($_POST['name']),$priv);
nak potrzebowali szyfrowania dwukierun-
$surname = $rsa_obj->decryptBinary(hex2bin($_POST['surname']),$priv);
// tworzenie nowego konta
kowego, gdyż w jedną stronę będziemy
$user = new user; wysyłali nasz login i hasło oraz dodawali
$result = $user->register($username,$password,$email,$name,$surname); nowe notatki, a w drugą – wyświetlali ist-
if ($result) { echo "Your account are successfully created."; niejące notatki. Zabezpieczenie danych
}else { echo "error: your account can't created!"; }
przy tych czynnościach za pomoca sa-
?>
mego RSA byłoby trudne, wykorzystamy
Listing 4. Funkcja hex2bin więc dodatkowo symetryczny algorytm
blowfish.
function hex2bin($hex) {
$str="";
Przygotowania
for($i=0;$i<strlen($hex);$i=$i+2) {
$str.=chr(hexdec(substr($hex,$i,2))); Będziemy więc potrzebowali implemen-
} return $str; tacji algorytmu blowfish. W PHP posłu-
} żymy się do tego klasą Crypt_Blowfish
z repozytorium PEAR. Po stronie prze-
$_SESSION['username'] = $username;
Podsumowanie
$_SESSION['password'] = $password; W przedstawionej aplikacji pokazali-
$_SESSION['blowfishKey'] = $blowfishKey; śmy, w jaki sposób można skorzystać
z dwóch metod kryptograficznych (asy-
$user = new user($username, $password); metrycznej i symetrycznej) oraz poda-
$notes = $user->getNotes();
liśmy przykładowe zastosowanie tych
$html="";
technik. Potęga RSA w połączeniu z
foreach ($notes as $note) { prostotą języka PHP jak też z całkiem
$html.="<a href=\"javascript:goto('note','".$note['id']."')\">"; niezłą funkcjonalnością JavaScrip-
$html.=$note['title']."</a><br/>"; tu umożliwia tworzenie naprawdę bez-
}
piecznych aplikacji, które będą odpor-
$blowfish = new Crypt_Blowfish($blowfishKey); ne na podsłuch i przechwytywanie da-
echo(base64_encode($blowfish->Encrypt($html))); nych.
} Zachęcamy do korzystania z krypto-
else if ($_GET['page']=="addnote") { // wyświetlanie formularza grafii we własnych projektach – zwłasz-
$html = <<<heredochtml
cza tam, gdzie poufność przesyłanych i
<form method="post" action="index2.php=addnote2" id="addNoteForm">
<label for="title">title:</label> gromadzonych danych jest szczególnie
<input type="text" name="title" id="title" /><br/> istotna, poczynając od aplikacji do gro-
<textarea name="note" id="note"></textarea><br/> madzenia prywatnych notatek i syste-
<input type="submit" value="add" id="submitBtn" /> mów przekazywania wiadomości osobi-
</form>
stych, poprzez narzędzia używane we-
heredochtml;
$blowfish = new Crypt_Blowfish($_SESSION['blowfishKey']); wnątrz firmy (np. do zarządzania pro-
echo(base64_encode($blowfish->Encrypt($html))); jektem, danymi księgowymi czy biz-
} else if ($_GET['page']=="addnote2") { // dodawanie notatki nesplanem), po dostępne dla tysię-
$user = new user($_SESSION['username'], $_SESSION['password']); cy użytkowników jednocześnie syste-
my e-commerce, takie jak sklepy inter-
// ustawienie klucza blowfish
$blowfish = new Crypt_Blowfish($_SESSION['blowfishKey']); netowe czy pasaże aukcyjne. Na pohy-
//deszyfrowanie blowfish bel intruzom! n
$title = $blowfish->decrypt(base64_decode($_POST['title']));
$noteText = $blowfish->decrypt(base64_decode($_POST['note']));
//dodawanie notki
$user->addNote($title,$noteText);
echo "new note added";
} else if (($_GET['page']=="note")&&(isset($_GET['pageid']))) {
// wyświetlanie notki O autorze
$user = new user($_SESSION['username'], $_SESSION['password']);
Kamil Karczmarczyk jest uczniem Li-
$note = $user->getNoteById($_GET['pageid']); ceum Ogólnokształcącego. Od kilku lat
$html = "<b>".$note['title']."</b><br/>"; hobbystycznie zajmuje się programowa-
$html .= "<p>".$note['text']."</p>"; niem, między innymi w PHP. Interesuje
$blowfish = new Crypt_Blowfish($_SESSION['blowfishKey']); się bezpieczeństwem sieci, kryptografią
echo(base64_encode($blowfish->Encrypt($html))); oraz matematyką.
}
?> Kontakt z autorem:
limak@mmj.pl
XML_FastCreate
Stopień trudności: lll
Guillaume Lecanu
F
ormat XML (eXtensible Markup nerowanego kodu XML z zasadami okre-
Language) jest coraz częściej uży- ślonymi przez DTD, informowanie użyt-
wany na stronach internetowych, kownika o niezgodności, szybką konwer-
gdzie zawitał przede wszystkim jako sję na XHTML oraz bardzo łatwe tworze-
XHTML – nowy, promowany przez W3C nie rozbudowanych dokumentów, również
standard zapisu stron WWW. Innym po- jeśli chcemy je składać z wielu części.
pularnym zastosowaniem XML-a są for-
maty plików pakietów biurowych, w szcze- Instalacja
gólności stosowane od dawna w OpenOf- Jak już powiedzieliśmy, XFC jest pakietem
fice.org formaty SXW czy SXC oraz nowa- należącym do repozytorium PEAR (PHP
torskie i uznane za standard przez wiele Extension and Application Repository,
firm instytucji ODT (tekst) czy ODG (grafi-
ka). XML jest również wykorzystywany ja-
W SIECI Co należy wiedzieć...
ko format eksportu i importu danych wielu Potrzebna będzie podstawowa znajo-
programów czy też komunikacji pomiędzy mość zagadnień programowania obiekto-
aplikacjami znajdującymi się na różnych wego w PHP5. Przydatna będzie również
l http://pear.php.net/ ogólna wiedza na temat standardu XML.
packages/XML_FastCreate maszynach (klient-serwer), np. w pro-
– klasa XML_FastCreate tokołach typu SOAP czy XML-RPC. Ję- Co obiecujemy...
l http://xmlsoft.org – strona Pokażemy, jak za pomocą XML_Fast-
zyk PHP dysponuje dużymi możliwościa-
główna projektu libxml Create utworzyć prawidłowy kod XML.
l http://pear.php.net/ mi tworzenia i przetwarzania dokumentów Zademonstrujemy też, jak dokonywać
packages/Cache_Lite XML. W artykule pokażemy, jak użycie transformacji znaczników XML-a, wy-
– pakiet PEAR::Cache_Lite
PEAR-owego pakietu XML_FastCreate muszać sprawdzanie DTD, wykrywać
l http://lya.fr/pear/XML_
FastCreate/tests/ – przykła- błędy składni czy tworzyć dokumenty
(XFC) poszerza tę funkcjonalność, pozwa-
dy użycia XML_FastCreate w XHTML-u.
lając m.in. na wymuszanie zgodności ge-
http://pear.php.net). Aby go zainstalować, XFC: pierwsze kroki jącą z innych tagów typowych dla HTML-a
wystarczy w linii poleceń systemu ope- Aby skorzystać z XML_FastCreate, do- i XHTML-a (<html>,<head> i <body>).
racyjnego użyć narzędzia pear. Jeżeli łączamy plik XML/FastCreate.php (zob. Patrząc na kod z Listingu 2 zauważymy,
takowego nie posiadamy, jego instalacja Listing 1) i tworzymy obiekt $x, będący że wykorzystane tam metody (oprócz
jest bardzo prosta i została szczegółowo instancją klasy XML_FastCreate (uwaga: toXML()) obiektu $x mają takie same
opisana na stronach PEAR-a. używamy w tym celu należącej do kla- nazwy, jak użyte przez nas tagi XHTML-
Mając narzędzie pear jesteśmy gotowi sy XML_FastCreate metody statycznej a. Wstawienie każdej z tych metod do
do instalacji XFC. W tym celu wystarczy factory()). Zainicjowanie $x wymaga po- skryptu powoduje automatyczne utworze-
wpisać pear install XML_FastCreate. dania dwóch parametrów: pierwszy z nich nie znacznika o takiej samej nazwie. Jest
Pamiętajmy, że instalacja niektórych pa- określa format wygenerowanego XML-a. to wielką zaletą XML_FastCreate, która
kietów opcjonalnych XML_FastCreate, My używamy formatu Text, co oznacza, ułatwia tworzenie nawet rozbudowanych
które są w wersji beta lub alpha, może że po użyciu metody toXML() (którą omó- dokumentów.
wymagać użycia dodatkowego parametru wimy później) uzyskamy XML w formie Zwróćmy też uwagę na zagnieżdżenie
narzędzia pear. Przykładowo, dla wersji tekstu (zserializowanej). Drugi parametr metod reprezentujących znaczniki: zaczy-
beta będzie to: stanowi tablicę asocjacyjną opcji, którą namy od metody:
również omówimy później.
pear -d preferred_state=beta Wspomnijmy, że jedną z najistotniej- $x->html()
install nazwa_pakietu szych spośród tych opcji jest właściwy na-
główek doctype, który zostanie następnie której parametrem jest:
Jeżeli ta składnia nie działa (co ma umieszczony w pierwszej linii pliku XML
miejsce w przypadku starszych wersji i będzie określał DTD, na którym oparto $x->head()
narzędzia pear), to musimy sprawdzić na dokument. Nagłówek ten możemy zdefi-
stronie pakietu, w jakiej fazie znajduje się niować ręcznie, ale XML_FastCreate daje która z kolei zawiera wywołania head() i
jego najnowsza wersja (stable, alpha lub nam do wyboru kilka gotowych definicji body(). W ten sposób tworzymy strukturę
beta) i uwzględnić tę fazę, jeśli jest różna odpowiadających najczęściej używanym znaczników w XML_FastCreate, która po
od stable, w sposób następujący: doctype. My użyjemy: użyciu metody toXML() zostanie przekształ-
cona na gotowy dokument XML (zob. Listing
pear install nazwa_pakietu-faza XML_FASTCREATE_DOCTYPE_ 3). UWAGA: toXML() jedynie wypisuje XML
XHTML_1_0_STRICT na ekran; aby zapisać dokument w zmien-
np.: nej, trzeba użyć metody getXML(), np.:
co w rezultacie daje nagłówek:
pear install XML_Tree-beta $xml_out=$x->getXML();
XHTML 1.0 Strict.
Wśród pakietów opcjonalnych współ- W tym przykładzie nie określiliśmy atrybutów
pracujących z XFC można wymienić np. Stwórzmy teraz najprostszy dokument znaczników. Aby je dodać do określonego
XML_Tree, XML_DTD, XML_Beautifier XML, który będzie stroną XHTML-ową znacznika, wystarczy umieścić je w tablicy
czy XML_HTMLSax. Ich użycie jest zale- zawierającą napis Hello World! w akapicie asocjacyjnej przekazanej jako pierwszy ar-
cane w celu pełnego wykorzystania możli- (<p>..</p>) oraz tekst XML_FastCreate ja- gument metody reprezentującej ten znacz-
wości XML_FastCreate. ko tytuł (tag <title>..</title>) i korzysta- nik. Przykładowo, aby utworzyć link (tag <a
href>...</a>) prowadzący do strony głównej
<?php $x->a(array(‘href’=>’http://
require_once 'XML/FastCreate.php'; pear.php.net’),’P.E.A.R.’)
$x=&XML_FastCreate::factory('Text',array(
'doctype' =>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT Efektem będzie:
)
); <a_href=”http://pear.php.net”>
?> P.E.A.R.</a>
$x->html(
$x->head(
$x->title('XML_FastCreate')), $x->body($x->p('Hello World !'))
);
Już na podstawie tych przykładów może- Jak już wiemy, użycie argumentu Bez ograniczeń możemy łączyć blo-
my się przekonać, jak łatwe i szybkie jest Text podczas tworzenia instancji klasy ki wygenerowane z użyciem parametru
tworzenie XML-a przy użyciu XML_Fast- XML_FastCreate powoduje, że skutkiem Text podczas tworzenia instancji doku-
Create. użycia metody toXML() będzie wygenero- mentu. Nie będzie również problemu, je-
wanie XML-a w formie tekstowej (zseriali- żeli format jest inny (np. XML_Tree), o ile
Wymuszanie zowanej). Gdybyśmy zamiast Text podali wszystkie bloki są tego samego formatu.
i weryfikacja XML_Tree, utworzony zostałby obiekt klasy Spójrzmy na Listing 6: łączymy na nim
zgodności z DTD XML_Tree, która jest dostępna jako osobny dwa bloki typu Text, wygenerowane przy
Tworząc lub modyfikując dowolny doku- pakiet PEAR-owy. użyciu utworzonej wcześniej instancji $x
ment XML powinniśmy się upewnić, czy Co więcej, możemy złożyć dokument klasy XML_FastCreate (nie musimy po-
będzie on zgodny ze standardem DTD, XML z kilku mniejszych bloków, co się dawać żadnych parametrów oprócz ty-
do czego często używamy dodatkowych często przydaje, np. gdy generujemy jego pu XML-a).
narzędzi. Użycie XML_FastCreate pozwa- elementy korzystając z pętli czy instrukcji
la nam zaoszczędzić czas dzięki funkcji warunkowych. Jest to wręcz zalecane, Transformacje XML
automatycznego wyświetlania błędów gdyż umożliwia zachowanie przejrzysto- XFC posiada opcję szybkiej transforma-
składni XML-a. ści – zarówno kodu aplikacji generującej cji, której zadaniem jest zamiana wy-
Aby wymusić sprawdzanie DTD, mu- XML, jak i samego XML-a. branych znaczników na inne. Przykła-
simy mieć odpowiedni plik zawierający de-
finicje DTD (niektóre z nich, np. XHTML, Listing 3. Rezultat XHTML przykładu z Listingu 2
znajdują się w katalogu dtd zainstalowane-
go XML_FastCreate) i uruchomić jego ła- <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
dowanie podczas tworzenia instancji klasy <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/
xhtml1/DTD/xhtml1-strict.dtd">
XML_FastCreate. To drugie wykonamy do-
<html><head><title>XML_FastCreate</title></head>
dając opcję dtd do wspomnianej wcześniej <body><p>Hello World !</p></body></html>
tablicy asocjacyjnej (Listing 4). My załadu-
jemy plik xhtml_1_0_strict.dtd, będący defi- Listing 4. Tworzymy instancję XML_FastCreate sprawdzającą zgodność XML
nicją standardu XHTML 1.0 w wersji strict. z jego DTD
Jeżeli w składni XML-a wystąpi nie- $x =& XML_FastCreate::factory('Text',
zgodność z DTD, komunikat o błędzie array(
zostanie wyświetlony podczas wywołania 'doctype' =>
wspomnianej już metody toXML(). Po- XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
'dtd' => 'xhtml_1_0_strict.dtd'
zwala to np. na wyświetlenie go na końcu
)
strony WWW. );
Na Listingu 5 podajemy przykład skryp-
tu generującego stronę XHTML-ową, w któ- Listing 5. Sprawdzamy zgodność XML z jego DTD
rej celowo wstawiliśmy błąd polegający na
<?php
pominięciu atrybutu alt w znaczniku <img
require_once 'XML/FastCreate.php';
src> (co było dopuszczalne w HTML-u, ale $x =& XML_FastCreate::factory('Text',
jest zabronione w XHTML-u). Po utworze- array(
niu strony, konwertujemy ją do postaci do- 'doctype' => XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
kumentu XML jako zmienną $err. Następ- 'dtd' => 'xhtml_1_0_strict.dtd'
)
nie korzystając z metody statycznej PEAR:
);
:isError() sprawdzamy, czy zmienna ta $x->html(
zawiera komunikat o błędzie: jeżeli tak, to $x->head($x->title('XML_FastCreate')),
go wypisujemy przy pomocy metody $err- $x->body(
>getMessage(). Przykład wykonania tego $x->p($x->img(array('src' => 'soleil.png'))
)
skryptu przedstawiamy na Rysunku 1.
)
);
Manipulacja if (PEAR::isError($err = $x->toXML())) {
dokumentami XML echo nl2br(htmlSpecialChars($err->getMessage()));
Przejdźmy teraz do omówienia rozmaitych }
?>
metod generowania i manipulacji doku-
mentami XML. Listing 6. Przykład konkatenacji (łączenia) dwóch tagów
$hello = $x->p('Hello');
$world = $x->p('World');
$body = $x->body($hello,$world,);
Rysunek 2. Entytki umożliwiające zako- $x->html($x->head($x->title('XML_FastCreate')),$body);
dowanie znaków specjalnych w doku-
mentach XML
dowo, możemy w ten sposób uprościć XML_FastCreate w tablicy asocjacyjnej na cały zestaw tagów (<h1><span>...</
sobie składnię XML-a czy XHTML-a, wpisujemy opcję translate, która z ko- span></h1>).
oznaczając tagi po swojemu, w spo- lei otwiera tablicę znaczników do tłuma- Gdybyśmy nie korzystali z XFC w ce-
sób dostosowany do naszych prefe- czenia.Mamy tam tagi opisujące notkę lu ułatwienia konwersji znaczników, aby
rencji czy potrzeb programu, który z informacyjną (<news>, <desc>, <title> osiągnąć ten sam efekt co na Listingu 7
tych danych korzysta. Transformacja z i <date>), które będą zamienione na musielibyśmy ręcznie wstawić wartości do
XFC przyda się również przy konwersji oryginalne znaczniki XML-a. Zwróć- odpowiednich tagów XML-a, jak na Listin-
z XML-a na HTML-a. Spójrzmy na Li- my szczególną uwagę na znacznik gu 8. Wracając do Listingu 7 zauważmy,
sting 7: przy tworzeniu instancji klasy <title>: zostanie on przekonwertowany że po zdefiniowaniu tablicy transformacji
tworzymy kod XML metodą tradycyjną.
Listing 7. Przykład zastosowania opcji ‘translate’ Tam również wystąpi znacznik <title>,
tyle że nie jest on tytułem naszej wiado-
<?php mości, lecz standardowym tagiem <title>
require_once 'XML/FastCreate.php'; oznaczającym tytuł strony WWW i znanym
$x =& XML_FastCreate::factory('Text',
z HTML-a oraz XHTML-a. Aby uniknąć je-
array(
'doctype' => XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT, go konwersji (która nastąpiłaby zgodnie
'dtd' => 'xhtml_1_0_strict.dtd', z regułami przetwarzania znaczników
'translate' => array( naszych wiadomości), poprzedzamy jego
'news' => array('div'), nazwę podkreśleniem (_title). Dzięki
'desc' => array('p'),
temu generowany będzie standardowy
'title' => array('<h1 class="title"><span>', '</span></h1>'),
'date' => array('<span class="date">', '</span>') znacznik <title>..</title>.
)
) Opcje i metody XFC
); XFC zawiera kilka dodatkowych, przydat-
$x->html(
nych metod:
$x->head($x->_title('XML_FastCreate')),
$x->body($x->news(
$x->title('News'), comment() – pozwala na dodawanie
$x->date('10-12-2005'), komentarzy w kodzie XML; ogranicz-
$x->desc('blah blah blah') nikami komentarza są oczywiście tagi
)
<!-- i -->. Przykładowo, następujące
)
); użycie tej metody:
if (PEAR::isError($err = $x->toXML())) { $x->comment($x->p(‘Hello World
echo nl2br(htmlSpecialChars($err->getMessage())); !’))
} spowoduje wygenerowanie kodu:
?>
<!-- Hello World! -->.
Listing 8. Wariant cytowany w Listing 7 bez opcji ‘translate’ cdata() –otacza wybraną zawartość
znacznikami CDATA. Jest to niezbędne,
$x->div( kiedy musimy wprowadzić zawar-
$x->h1(array('class' => 'title'),$x->span('News')),
tość, która niekoniecznie jest zgodna
$x->span(array('class' => 'date'), '10-12-2005'),
$x->p('blah blah blah')
z DTD, np. kod typu JavaScript czy
); jakiś rodzaj importu stylów w ramach
strony XHTML. Bez CDATA zwyczajnie
Listing 9. Przykład zastosowania metody cdata() nie da się umieścić takiej zawartości
w dokumencie XML. Przykład użycia
$x->style(array(
'type' => 'text/css', 'media' => 'all'), cdata() przedstawiamy na Listingu 9.
$x->cdata("@import url('example.css');") quote() – metody tej używamy, aby
); przekonwertować wybrane znaki na
entytki (ang. entities). Jest to koniecz-
Listing 10. Tworzymy instancję XML_FastCreate sprawdzającą zgodność XML
ne, gdyż umieszczenie pewnych zna-
z jego DTD poprzez program zewnętrzny
ków (np. &) w dokumentach XML jest
$x =& XML_FastCreate::factory('Text', niemożliwe i wygeneruje błąd. Metody
array( quote() możemy używać w sposób
'doctype' =>
zautomatyzowany, jeżeli zadeklaruje-
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
my ją podczas definiowania obiektu
'dtd' => 'xhtml_1_0_strict.dtd',
'file' => '/tmp/XFC.xml', klasy XML_FastCreate jako true.
'exec' => 'xmllint --valid --noout /tmp/XFC.xml 2>&1', W takiej sytuacji, jeśli nie chcemy
) używać tej opcji wobec określonych
);
części dokumentu, możemy wywołać
opcję noquote() (Rysunek 2). UWA-
GA: jeżeli tworzymy dokument znaczniki o nazwach pokrywających padku edytora vim wystarczy umieścić
XHTML, wyszukiwarka Microsoft In- się z nazwami tych metod. Aby unik- w ~/.vimrc linię:
ternet Explorer (wersja 6 i niższe) nie nąć tego problemu i zmusić XFC do
rozpoznaje encji '. Aby uniknąć traktowania metody jako odnoszącej map ,fc :!HTML2XFC.php<CR>
jej konwersji, musimy umieścić opcję się do znacznika, przed nazwą tagu
apos w false. wstawiamy znak podkreślenia, np. wybrać do konwersji kod HTML i urucho-
_quote(). mić makro wpisując ,fc.
Należy też pamiętać o tym, że:
Wygoda Podsumowanie
Kod XML jest generowany bez for- użytkowania XFC W tym artykule pokazaliśmy najciekaw-
matowania. Oznacza to, że wszystkie Aby uprościć tworzenie projektu korzy- sze spośród podstawowych zastosowań
znaczniki są wklejane i zagnieżdżane stającego z XML_FastCreate, zalecane XML_FastCreate. Jak widzimy, użycie tej
bez przechodzenia do nowej linii czy jest, aby inicjowanie instancji tej klasy biblioteki znacznie upraszcza tworzenie,
stosowania tabulacji. Jeżeli chcemy odbywało się w pliku, który będziemy do- manipulację i konwersję dokumentów
uczynić kod XML bardziej czytelnym, łączać do każdej ze stron. Inną opcją jest XML. Nie bez znaczenia jest również to,
dodajmy opcję indent do true. Takie generowanie tego obiektu wewnątrz funk- że należy ona do repozytorium PEAR,
formatowanie może jednak sprawić, cji, która będzie wywoływana na końcu do którego trafiają wyłącznie sprawdzone
że dokumenty XML będą niezgodne każdej strony. i działające projekty. Wraz z dodatkami ty-
z DTD. Pamiętajmy też, że generowanie pu XML_Tree, XML_FastCreate powinna
Niektóre nowe DTD, jak na przykład XML-a zajmuje czas, przez co korzystanie zająć miejsce wśród niezbędnych narzę-
XHTML 1.1, bazujące na kilku kar- z XML_FastCreate będzie wolniejsze, niż dzi każdego programisty, który korzysta
totekach, jeszcze nie są tolerowane. używanie gotowych, zapisanych na dysku z XML-a. n
Mimo to, za pomocą opcji file może- (czy w bazie danych) dokumentów XML.
my wydać XFC polecenie utworzenia Aby przyspieszyć dostęp do nich (tylko
pliku tymczasowego i wykonania pro- w przypadku plików), możemy użyć narzę-
gramu zewnętrznego za pomocą opcji dzia keszującego, np. PEAR::Cache_Lite. O autorze
exec, przeznaczonej do takiej analizy.
Program xmllint doskonale sobie radzi Konwersja Guillaume Lecanu jest autorem pakie-
tu programów XML FastCreate, rozwija-
z takimi problemami, a przykład jego dokumentów HTML nego od przeszło 12 lat. Jego pasja pro-
użycia w ramach naszej aplikacji pre- Konwersję dokumentu HTML na XML uła- gramowania zaczęła się od asemblera,
zentujemy na Listingu 10. twi załączony w pakiecie XML_FastCreate którego nauczył go na domowym kom-
puterze brat, twórca programów typu de-
XFC ma kilka własnych, wbudowa- skrypt HTML2XFC.php. Za jego pomo-
mo. Niedawno Lecanu stworzył własną
nych metod, co przy specyficznym cą możemy przekształcić cały plik (skrypt firmę Noovea, która prezentuje pełnię je-
sposobie traktowania znaczników (me- wywołujemy wtedy w linii poleceń) albo go możliwości.
toda ma taką samą nazwę, jak znacz- wybrany fragment – uruchamiamy wte-
Kontakt z autorem:
nik, do którego się odnosi) powoduje dy HTML2XFC.php jako makro w wybra-
guillaume@lya.fr
problemy, jeżeli chcemy zdefiniować nym edytorze programistycznym. W przy-
R E K L A M A
Dla zaawansowanych
Rozwiązywanie problemów
przekrojowych z użyciem IoC
Stopień trudności: lll
Piotr Szarwas
K
ażdą aplikację można podzielić nicznego MVC. Pojawienie się warstwy
na logiczne warstwy. Najczę- dostępu do danych wynika z zastoso-
ściej występują trzy warstwy: wania wzorca DAO, który uniezależnia
warstwa danych, logiki biznesowej i logikę biznesową od warstwy danych.
prezentacji. Wszystkie spośród nich Dzięki temu można łatwo wymieniać
powinny być nałożone na siebie tak, źródło danych. Schemat tego podziału
aby wyższa wiedziała tylko o istnie- pokazujemy na Rysunku 2.
niu jednej warstwy niższej; wszystko, Rozbicie systemu na warstwy zapew-
co znajduje się poniżej, powinno być nia szereg korzyści:
dla niej niedostępne. Z drugiej strony, Każdej z warstw można wymie-
warstwa niższa nie wymaga dla swoje- nić implementację, nie zmieniając jed-
go działania istnienia żadnej z warstw nocześnie implementacji pozostałych
wyższych. warstw. Jak już wspomnieliśmy, moż-
Podział ten ilustrujemy na Rysun- na na przykład wymienić warstwę DAO
ku 1. Można jeszcze bardziej dopraco-
wać ten schemat mówiąc, że aplikacja
powinna posiadać aż pięć warstw: war- Co należy wiedzieć...
Należy znać zasady programowania
stwę danych, dostępu do danych, logi-
obiektowego w PHP5 z wykorzystaniem
ki biznesowej/usług, kontrolerów i pre- wzorców projektowych.
zentacji. Ten drugi podział wynika bez-
Co obiecujemy...
pośrednio ze stosowania wzorców pro- Pokażemy, jak rozwiązać niektóre spo-
gramistycznych i architektonicznych. śród problemów przekrojowych (ang.
Przykładowo, kontrolery i prezentacja crosscutting concerns).
stanowią element wzorca architekto-
(dostępu do danych) tak, aby obsługi- dów. Praktycznie każda aplikacja za-
wała inne źródło danych, nie zmienia- wiera elementy kodu odpowiadające
jąc jednocześnie logiki biznesowej. za logowanie i debugowanie. Czy jed- Rysunek 2. Podział aplikacji na pięć
Każda warstwa może być traktowa- nak możemy je przydzielić do którejś logicznych warstw. Warstwa wyższa wie
na jako spójna całość. Pozwala to m.in. warstwy? Niestety nie. Ich kod jest roz- tylko o istnieniu warstwy znajdującej się
bezpośrednio pod nią. Żadna z warstw
na tworzenie każdej warstwy przez proszony po całej aplikacji i występu-
niższych nie wie nic o wyższych
osobny zespół programistów, który nie je w każdej warstwie. Pamiętajmy, że
musi znać implementacji pozostałych z punktu widzenia logicznego podziału stycznie maleje. W przypadku logowa-
warstw. na warstwy, logowanie błędów nie jest nia problem nie jest tak wielki, ale już
Jeśli zostanie dobrze zaprojektowa- ani częścią logiki biznesowej, ani innej w sytuacji, gdy w aplikacji zaszyjemy
na, każda warwstwa(warstwa) może być warstwy. Bezpośrednie zakodowanie reguły bezpieczeństwa, czy też zdefi-
wykorzystywana wielokrotnie, w różnych logiki logowania w każdej z warstw po- niujemy miejsca, w których rozpoczy-
projektach lub miejscach tego samego woduje, że niezależność, przenaszal- nają się i kończą transakcje, cały kod
projektu. ność i elastyczność tej warstwy dra- przestaje w zasadzie być przenaszal-
ny i staje się mocno związany z regu-
Listing 1. Implementacja klasy MailSender służącej do wysyłania maili. Kod klasy łami biznesowymi danej aplikacji. Ry-
pozbawiony jest reguł problemów przekrojowych: logowania i bezpieczeństwa. sunek 3 pokazuje schematycznie nasz
Reguły te będą implementowane przez odpowiednie dekoratory problem.
Skoro problemy przekrojowe mogę
interface MailSender {
sprawić takie trudności, czy da się je
public function send($to, $from, $subject, $message);
} wydzielić do osobnych modułów, któ-
class MailSenderImpl implements MailSender { re nie będą w ogóle powiązane z żad-
public function send($to, $from, $subject, $message) { ną z warstw? Okazuje się, że tak. Roz-
return mail($to,$subject,$message,'From: '.$from); wiązania są dwa. Pierwsze, którym się
}
zajmiemy w tym artykule, będzie pole-
}
gało na wykorzystaniu wzorca Deko-
Listing 2. Przykładowa klasa dekorująca dowolną klasę implementującą interface rator i kontenera IoC, który zbudowa-
MailSender liśmy wspólnie w poprzednim artykule.
Drugi sposób opiera się na zastosowa-
class MailSenderDecorator implements MailSender {
private $mailSender;
niu programowania aspektowego (ang.
public function __construct(MailSender $mailSender ){ aspect-oriented programming - AOP).
$this->mailSender = $mailSender; Ten drugi sposób byłby dużo lepszym
} podejściem; niestety, obecnie dla PHP
public function send($to, $from, $subject, $message) {
nie istnieje żaden framework AOP, któ-
// Kod dekoratora
$result = $this->send($to,$subject,$message,'From: '.$from);
ry w wystarczającym stopniu imple-
// Kod dekoratora mentowałby wszystkie założenia pro-
return $result; gramowania aspektowego. Tak jak po-
} przednio, cały kod zaprezentowany w
}
artykule zostanie umieszczony na stro-
nie http://flexi.sf.net/.
Wzorzec Dekorator
Zgodnie z definicją GoF (ang. Gang
of Four – termin, który określa czwór-
�������������������
kę programistów odpowiedzialnych za
zapoczątkowanie idei wzorców pro-
jektowych), zadaniem wzorca Deko-
rator jest wzbogacanie funkcjonalno- ������������������� ����������������
wiem wszystkie kluczowe metody apli- by przestać go współdzielić. Jak więc Zabierzmy się więc do pracy.
kacji, co oznacza potrzebę przetesto- widać, podejście, które wydawało się Pierwszym krokiem będzie modyfika-
wania całego projektu od nowa. Dodat- najbardziej oczywiste, spowodowałoby cja kontenera IoC tak, aby na podsta-
kowym problemem byłaby konieczność całą lawinę problemów. wie zadanego wzorca mógł połączyć
przekazania do każdej z warstw aplika- My na szczęście będziemy mądrzejsi dekorowany obiekt z dekoratorem. W
cji informacji o tym, kto aktualnie wyko- i do rozwiązania problemu wykorzystamy tym celu rozszerzymy klasę DefaultI-
nuje daną metodę. Ponadto, jeżeli mo- kontener IoC. Nasze założenie jest nastę- oCContainer i zmodyfikujemy jej meto-
dyfikowany kod był wykorzystywany w pujące: nie możemy dokonać żadnej mo- dę create(). W nowej wersji tej klasy,
innych projektach, programista musiał- dyfikacji kodu zapisującego i modyfikują- jej metoda create() najpierw wywołuje
create() klasy nadrzędnej. Następnie
Listing 4. Implementacja klasy dopasowującej dekoratory do klas na podstawie sprawdza, czy powołany obiekt nie im-
nazw klas plementuje jednego z interfejsów klas
pomocniczych dekoratorów, aby unik-
class ClassNameIoCDecoratorSupport implements IoCDecoratorSupport {
nąć dekoracji tych ostatnich. Następ-
private $decoratorName;
nie kontener sprawdza przy pomocy
private $classNameToDecorator = array();
public function __construct($decoratorName,array $classNameToDecorator){ klas pomocniczych, czy nazwa świeżo
$this->decoratorName = $decoratorName; powołanej klasy pasuje do wzorca któ-
$this->classNameToDecorator = $classNameToDecorator; regoś z dekoratorów. Jeżeli tak, to kla-
}
sa pomocnicza zwraca nazwę deko-
public function match($className,$classObject) {
ratora. Każda klasa pomocnicza mu-
return (in_array($className,$this->classNameToDecorator))?true:false;
} si implementować interfejs IoCDecora-
cego$this->decoratorName;
public function getDecoratorName() { return dane. Dlatego skonstruujemy
} kon- torSupport, który z kolei składa się z
} tener, który na podstawie odpowiednie- dwóch metod:
go wzorca składającego się z nazwy kla-
Listing 5. Implementacja klasy dopasowującej dekoratory do klas na podstawie
sy oraz implementowanego przez nią in- l match() – zwraca true, jeżeli wzorzec
dowolnego wyrażenia regularnego
terfejsu będzie umiał udekorować tworzo- dekoratora pasuje do wzorca klasy,
class RegExpIoCDecoratorSupport implements ny obiekt.
IoCDecoratorSupport { l getDecoratorName() – zwraca nazwę
private $decoratorName; dekoratora z pliku konfiguracyjnego
private $pattern;
IoC.
public function __construct($decoratorName,$pattern){
$this->decoratorName = $decoratorName;
$this->pattern = $pattern; Klasy pomocnicze dostarczane są do
} kontenera poprzez metodę setDecora-
public function match($className,$classObject) { tors(). Następnie kontener IoC powo-
return (preg_match($this->pattern,get_class($classObject)))?true:false;
łuje do życia tenże dekorator i umiesz-
}
public function getDecoratorName() { return $this->decoratorName; } cza w nim dekorowany obiekt. Dekora-
} tor musi implementować interfejs IoC-
Decorator, który posiada jedną meto-
Listing 6. Implementacja klasy dopasowującej dekoratory do klas na podstawie dę – setObject(). Zauważmy, że w ten
interfejsu
sposób możemy każdą z klas udekoro-
class InterfaceIoCDecoratorSupport wać wieloma dekoratorami. Warto jesz-
implements IoCDecoratorSupport { cze zapamiętać, że zgodnie z imple-
private $decoratorName; mentacją naszego kontenera, dekora-
private $interfaceName;
tor nie może być singletonem. To zna-
public function __construct(
$decoratorName,$interfaceName){
czy: dla każdej dekorowanej klasy musi
$this->decoratorName= być powoływany do życia nowy deko-
$decoratorName; rator. Na Listingu 3 przedstawiamy kod
$this->interfaceName= nowej wersji kontenera, a na Listingach
$interfaceName;
4, 5 i 6 – kilka przykładowych klas po-
}
public function match($className,
mocniczych implementujących interfejs
$classObject) { IoCDecoratorSupport. Pierwsza klasa
return ($classObject instanceof odnajduje klasy według pełnej nazwy,
$this->interfaceName)? druga wg wyrażenia regularnego, a
true:false;
trzecia wg konkretnego interfejsu, któ-
}
public function
ry implementuje dekorowana klasa.
getDecoratorName(){ Wróćmy teraz do naszego przykładu.
return $this->decoratorName; Załóżmy dla uproszczenia, że aplikacja,
} w której trzeba dokonać zmian, ma trzy
}
klasy modyfikujące dane: UserDAO, Order-
DAO oraz ItemDAO. Wszystkie one imple-
mentują jeden wspólny interfejs DAO za- dzie. Na Listingu 7 prezentujemy przykła- tuje dwa interfejsy: IoCDecorator i DAO (Li-
wierający metody setConnection(), find- dową konfigurację kontenera bez dekora- sting 8). Oczywiście, jej docelowa imple-
ById(), save(), update(), delete(). Me- torów. Jak widzimy, składa się ona z czte- mentacja powinna zawierać bardziej wy-
toda setConnection() ustawia połącze- rech wpisów, z których jeden dotyczy po- rafinowany kod logujący. Teraz wykorzy-
nie do źródła danych, findById() zwraca łączenia z bazą danych, a pozostałe trzy stując klasę z Listingu 6 modyfikujemy
obiekt na podstawie jego id, save() za- zawierają ustawienia klas DAO. konfigurację kontenera. Nową konfigura-
pisuje obiekt, update() go zmienia, a de- Zmodyfikujemy teraz przykład tak, cję pokazujemy na Listingu 9. Zauważmy,
lete() kasuje. Dane są modyfikowane je- aby spełniał on wymagania biznesowe że dodaliśmy tylko dwa wpisy i zgodnie
dynie przez metody save(), update() i de- naszego klienta. Nic prostszego: zada- z założeniami, kod klas UserDAO, Order-
lete(). Szczegóły implementacji klas *DAO nie rozpoczynamy od utworzenia klasy DAO oraz ItemDAO nie został zmieniony. W
nie mają znaczenia w naszym przykła- DAOLoggerDecorator. Klasa ta implemen- przykładzie pominęliśmy problem przeka-
Listing 7. Plik konfiguracji kontenera IoC dla opisanego w Listing 8. Klasa DAOLoggerDecorator jest dekoratorem
tekście przykładu bez wsparcia dekoratorów klas UserDAO, OrderDAO i ItemDAO
M
od_Rewrite to moduł Apache'a, Mod_Rewrite. Ponieważ jednak coraz
który jest domyślnie zainstalowa- więcej użytkowników oczekuje możliwo-
ny na serwerze (choć nie zawsze ści korzystania z niego, jest on powoli
włączony w konfiguracji). Jego funkcją jest wprowadzany jako standard. Na początek
przepisywanie (ang. rewriting) URL-i, czy- musimy się dowiedzieć, czy nasz serwer
li możliwość prezentowania plików i katalo- udostępnia ten moduł – możemy zapytać
gów umieszczonych na witrynie przy użyciu o to jego administratora albo sprawdzić to
innych nazw i ścieżek niż w rzeczywistości. na własną rękę. Aby wykonać to drugie,
W SIECI Pozwala nam to m.in. na dynamiczne prze- przeprowadzimy prosty test: utworzymy
pisywanie linków, przekazywanie do skryp- plik test.php, w którym umieścimy nastę-
tów PHP dodatkowych zmiennych, które nie pujący kod, po czym wykonamy go na
l http://httpd.apache.org zostały podane w zewnętrznym URL-u (me- serwerze:
– strona główna Apache'a todą GET) ani przekazane metodą POST
l http://httpd.apache.org/docs/
czy blokowanie zewnętrznych linków (zwa-
1.3/mod/mod_rewrite.html Co powinieneś
– oficjalna dokumentacja nych też HotLinkami) do wybranych treści.
Mod_Rewrite
Działanie Mod_Rewrite opiera się na sto- wiedzieć...
l http://phpnuke.org – strona Potrzebna będzie średniozaawansowana
domowa projektu PHP-Nuke sowaniu reguł opisujących sposób przepisy- wiedza na temat konfiguracji i korzysta-
http://www.postnuke.com/
wania URL-i, które umieszczamy domyślnie
l
czymy znakiem dolara ($), to oryginalna dając tę flagę do reguły możemy być z plików (a nie z bazy danych), nie musi-
ścieżka pliku, którą chcemy przepisać ja- pewni, że jeżeli ta ostatnia nie zosta- my modyfikować za każdym razem tych
ko adres_przepisany. Pamiętajmy, że jeśli nie wykonana, serwer spróbuje użyć ostatnich - wystarczy raz umieścić odpo-
w którymkolwiek adresie używamy znaków reguły znajdującej się o linijkę niżej, wiedni warunek w skrypcie PHP i wgrać
specjalnych: dolara ($), kropki (.), dasz- L – skrót od angielskiego słowa last plik .htaccess na serwer. Po zakończeniu
ka (^), gwiazdki (*), plusa (+), pytajnika (?), (ostatni). Wstawienie tej flagi powo- promocji wystarczy usunąć .htaccess
backslasha (\) czy nawiasów klamrowych, duje zatrzymanie sprawdzania kolej- albo zmienić jego nazwę, np. na promo-
okrągłych lub kwadratowych, to musimy je nych reguł w .htaccess, jeżeli reguła cja.htaccess. Przy takich rozwiązaniach
poprzedzać znakiem backslasha (\). Wyni- ją zawierająca jest poprawna i zosta- należy jednak pamiętać, że jeżeli ktoś wie,
ka to stąd, że obie ścieżki są rozpoznawa- nie użyta. od jakiej zmiennej zależy warunek, może
ne przy użyciu wyrażeń regularnych (ang. R - skrót od redirect (po ang. prze- ją dopisać do adresu URL i tym sposobem
regular expressions), w których te zna- kierowanie). Dodanie tej flagi powo- obejrzeć ukrytą część strony!
ki pełnią określone funkcje; poprzedzanie duje przekierowanie adresu na adres Aby sprecyzować zakres działania na-
tych znaków backslashem nazywamy na- przepisany. Gdybyśmy wstawili tę szego pliku .htaccess, możemy pod linijką
tomiast ich eskejpowaniem lub uwalnia- flagę w naszym drugim przykładzie, zawierającą komendę RewriteEngine On
niem (ang. character escaping), które po- w pasku adresowym przeglądarki wstawić polecenie RewriteBase, które
woduje, że każdy znak specjalny znajdują- dopisany zostałby ciąg ?menu=true, określa relatywną ścieżkę do aktualnego
cy się bezpośrednio po tym backslashu jest co w tej sytuacji nie byłoby pożądane. katalogu. Jej składnia jest następująca:
rozpoznawany jako zwykły znak. Stosując flagę R możemy też wska-
Kolejna sprawa to tzw. flagi, które zać typ przekierowania, np. słynne RewriteBase ścieżka
umieszczamy na końcu reguł. Nie użyli- przekierowanie 301 (Redirect 301)
śmy ich w dotychczasowych przykładach, zapiszemy jako R=301. Jeśli chcemy, aby nasze reguły miały
ponieważ przydają się one wtedy, gdy zasięg globalny, nie musimy wstawiać
korzystamy z większej ilości reguł. Najczę- Możemy dodać kilka flag jednocześnie RewriteBase do pliku .htaccess.
ściej używane flagi to: – wystarczy je wymienić po przecinku
między nawiasami kwadratowymi na koń- Migracja domen przy
NC – dzięki tej fladze reguła zadziała cu reguły. Przykład: [L,NC,OR]. użyciu Mod_Rewrite
bez względu na wielkość liter, jakimi W naszym przypadku ścieżka Często się zdarza, że zmieniamy dome-
został napisany URL. Gdybyśmy index.php zostanie przepisana na in- nę naszego serwisu i chcemy zachować
w opisanym przykładzie dodali fla- dex.php?menu=true. Rozwiązanie prze- starą. Przykładowo, możemy przenosić
gę NC, moglibyśmy wpisać adres kazywania zmiennych jest przydatne, ją z darmowej na płatną (np. .com), na-
w dowolny sposób, np. INDEX.PHP, gdy chcemy bez modyfikacji plików PHP tomiast likwidacja starej domeny ozna-
inDeX.pHp, IndeX.php, itd., przesłać dodatkowe wartości. Przykłado- czałaby dla nas utratę tysięcy linków do
OR – oznacza to samo, co słowo or wo, jeśli chcemy dodać promocję w na- nas zamieszczonych na innych witrynach
w języku angielskim, czyli lub. Do- szym sklepie internetowym, który korzysta oraz pozycji w wyszukiwarkach, które
zindeksowały wiele spośród naszych
Listing 2. Plik .htaccess, którego używamy wraz z test.php, aby sprawdzić podstron ze starym adresem i związane
obecność Mod_Rewrite z nimi słowa kluczowe. Na pierwszy rzut
oka, rozwiązanie tego problemu migracji
Options +FollowSymLinks wydaje się proste – wystarczy podpiąć
<IfModule mod_rewrite.c>
dwie domeny pod to samo konto. Wiążą
RewriteEngine On
RewriteRule ^(test.php)$ test.php?tester=1 [QSA] się z tym jednak kolejne trudności, np.
RewriteRule ^$ test.php?tester=1 [QSA] wyszukiwarka Google widzi takie domeny
</IfModule> jako tzw. double content, czyli dwie witryny
z identyczną treścią. Tu również pomoże
Listing 3. Sprawdzamy, jaką wartość ma zmienna $menu
nam Mod_Rewrite: w katalogu głównym
<? starej domeny umieścimy plik .htaccess
$menu2 = false; o następującej zawartości:
if (isset($menu) && $menu == true) {
?> <br /><b>Zmienna $menu istnieje, choć nie została podana w URL-u</b> <?
RewriteEngine On
$menu2 = true;
RewriteCond %{HTTP_HOST} staradomena.com
}
?> RewriteRule ^(.*)$
<br /> http://www.nowadomena.com/$1 [R=301,L]
<? if ($menu2 == true) { ?>
Dzięki poprzedniej zmiennej wartość zmiennej $menu2 została zmieniona na
Jak widać, w kodzie pojawia się nowe po-
true, dlatego ten tekst jest widoczny.
<?
lecenie RewriteCond. Określa ono zakres
} wykonywania dalszych reguł. W tym przy-
?> padku ustala warunek, że reguły będą in-
terpretowane tylko wtedy, gdy wejście na-
stąpi z adresu staradomena.com. Składnia Aby się bronić przed tym zjawiskiem, cych: następne reguły (które przekierowują
komendy RewriteCond jest następująca: należy zastosować blokadę HotLinków. wszystkie HotLinki na stronę informującą,
Dotychczas opracowano i wdrożono wiele że jest to zabronione) będą wykonywane
RewriteCond %{WARUNEK} adres tego rodzaju blokad działających na pozio- tylko wtedy, jeżeli sprawdzany przez HTTP_
mie PHP. Jednymi z najskuteczniejszych REFERER adres serwera polecającego nie
Jedyna zdefiniowana przez nas tym razem były te, które sprawdzały serwer pole- jest naszym adresem. Problem mogący
reguła przepisuje wszystkie stare adresy cający (tzn. serwer, z którego nastąpiło się pojawiać przy użyciu przedrostka www
na http://www.nowadomena.pl/[adres]. kliknięcie na link) i porównywały jego adres rozwiązuje zastosowanie wyrażenia regu-
Do rozpoznawania wszystkich znaków z adresem witryny, której właściciel umie- larnego (.+\.)?, dzięki któremu nieważne
służy wyrażenie regularne (.*) – kropka ścił swoje pliki oraz używały przepisywania jest, czy w adresie użyto tego prefiksu, czy
symbolizuje dowolny znak, a * – dowolną linków w celu ukrycia plików do pobrania, nie. Zauważmy, że przed naszym adresem
ilość znaków. zarazem uruchamiając skrypt. Niestety, (strona.com) umieściliśmy znak wykrzykni-
Użyte przez nas przekierowanie przy blokady te miały jedną wadę – jeżeli ktoś ka: w języku wyrażeń regularnych oznacza
użyciu RewriteRule i RewriteCond jest znał prawdziwe ścieżki do plików, skrypt on przeczenie.
znacznie lepsze od tradycyjnego się nie uruchamiał i plik można było spo- Umieszczona w następnej linijce re-
Redirect301 / http://www.nowadomena.com, kojnie pobrać. guła sprawdza po rozszerzeniu pliku, czy
ponieważ to drugie przekierowuje użytkow- Tu również z pomocą przychodzi wolno do niego linkować. Jeżeli rozsze-
nika od razu na nową domenę niezależnie Mod_Rewrite, pozwalając na udoskonale- rzenie to (opisane wyrażeniem regularnym
od tego, czy wpisał adres starej, czy no- nie opisanej metody. Wystarczy stworzyć .*\., czyli dowolny_znak.znaki_po_kropce;
wej. Co więcej, to stosując przytoczoną plik .htaccess, który następnie umiesz- zwróćmy uwagę na eskejpowanie znaku
instrukcję Redirect301 (którą też umiesz- czamy w katalogu przeznaczonym do kropki) należy do grupy zabronionych (u
czamy w pliku .htaccess) można łatwo zabezpieczenia: nas zip, exe, rar, gz, tar.gz i tar), to link
zapętlić serwer. Umieszczenie instrukcji do pliku nie zadziała: użytkownik, który na
Redirect301 przekierowującej ze starego RewriteEngine On niego kliknie, zostanie przekierowany na
adresu na serwerze, pod który podpięte są RewriteCond %{HTTP_REFERER} !^http:// stronę HotLink.html.
dwie domeny (staradomena.com i nowado- (.+\.)?strona\.com [NC] Opisane rozwiązanie jest bardzo przy-
mena.com), grozi tym, że serwer będzie RewriteRule ^.*\.(zip|exe|rar|gz| datne, ale ma jedną wadę: gdy wpiszemy
nas przekierowywał w nieskończoność, tar.gz|tar)$ http://www.strona.com/ adres pliku w przeglądarce (otrzymany
gdyż nie będzie wiedział, która domena HotLink.html [L] np. w mailu czy komunikatorze), blokada
jest stara, a która nowa – obie będą czytały HotLink zadziała i nie będziemy mogli
ten sam plik .htaccess. Dzięki zastosowa- Dzięki poznanej wcześniej komendzie pobrać pliku. A przecież ideą blokowania
niu przedstawionego zestawu składają- RewriteCond i wyrażeniom regularnym HotLinków nie jest utrudnianie życia zwy-
cego się z przekierowania warunkowego możemy w prosty sposób ustalić warunek kłym użytkownikom, tylko właścicielom
RewriteCond i reguły RewriteRule tego wykonywania reguł dla serwerów polecają- serwisów obciążających nasze łącza! Aby
unikniemy: serwer nie będzie miał proble-
mu z ustaleniem, która domena jest nowa,
a która stara, gdyż przekierowanie podziała
Wyrażenia regularne
W regułach RewriteRule stosowaliśmy wyrażenia regularne (ang. regular expressions).
tylko, jeżeli wejdziemy ze starej. Mówiąc najprościej, są to wzorce w postaci łańcuchów symboli, których używamy w ce-
lu zaawansowanego wyszukiwania wybranych fraz w tekście (w przypadku RewriteRule
Skuteczna przeszukiwane są nazwy plików i katalogów). Wyrażenia te odnajdują tekst pasujący do
blokada HotLinków wzorca. Ze względu na elastyczność, wyrażenia regularne stanowią wręcz standard wśród
metod przeszukiwania tekstu. Warto wiedzieć, że dzielą się na składnię uniksową i perlo-
Chyba każdy, kto zamieszcza jakiekolwiek wą (znaną jako PCRE czyli Perl Compatible Regular Expressions i stosowaną nie tylko w
pliki do pobrania na stronie WWW, wie, co Perlu, ale także w PHP, Ruby i wielu innych językach, które korzystają z utworzonej w C
znaczy termin HotLink: oznacza on podpi- biblioteki PCRE). Bez znajomości choćby podstaw wyrażeń regularnych ciężko mówić o
korzystaniu z Mod_Rewrite. Oto kilka znaczników używanych w wyrażeniach regularnych,
nanie się pod wybrane pliki (np. MP3 czy
które ułatwią nam dalszą pracę z tym modułem:
PNG) z innego serwisu. W praktyce wy-
gląda to tak, że webmaster kupuje serwer, kropka (.) – dowolny znak,
na którym umieszcza pliki, które z kolei są tekst1|tekst2 – alternatywa: tekst1 lub tekst2,
daszek (^) – rozpoczyna daną strefę znaków,
przeznaczone do pobrania z jego strony,
dolar ($) – kończy daną strefę znaków,
a osoba prowadząca inny serwis po prostu pytajnik (?) – zero lub jeden znak poprzedzający wyrażenie,
podpina te same linki u siebie na stronie, gwiazdka (*) – zero lub więcej znaków poprzedzających wyrażenie,
czego następstwem jest wzrost transferu plus (+) – jeden lub więcej znaków poprzedzających wyrażenie,
(tekst _ w _ nawiasach) – grupuje tekst tekst _ w _ nawiasach.
na koncie webmastera, który wykupił ser-
wer. Powoduje to zwiększenie obciążenia Aby podstawić w adresie docelowym znalezione nazwy, które pasują do wyrażenia uży-
łączy prowadzących do tego serwera; co tego w regule wobec adresu źródłowego, używamy oznaczającego rezultat wyszukiwa-
więcej, niektóre firmy hostingowe ustalają nia dolara ($), bezpośrednio po którym stawiamy numer wyrażenia (licząc od pierwsze-
go pozwalającego na wstawienie tekstu), czyli np. $1, $2 i $3. Numery rezultatów szuka-
górne limity miesięczne transferu z konta, nia są przyporządkowane kolejnym wyrażeniom (zawartym w nawiasach), np. wyrażeniu
po przekroczeniu których strona jest za- ^([^-]+)/([^-]+)/([^-]+)$ zostaną przypisane $1, $2 i $3.
wieszana.
Adresy przepisywane wcale jednak gallery/photo/21?PHPSESSID= lub, w przypadku linków z sufiksem .html:
nie muszą wyglądać jak katalogi. Można accfcc299077b36817dc534c90588253
tak wykorzystać Mod_Rewrite, aby adresy RewriteRule ^news-(.*)\.html$
były maskowane w postaci plików HTML, czy też: index.php?module=news&name=$1
co wygląda jeszcze bardiej efektownie.
Ogólnie wyglądałoby to tak, że schemat gallery-photo-21.html?PHPSESSID= Wyrażenie regularne (.*) pozwala na za-
wartość1/wartość2/wartość3 wyglądałby accfcc299077b36817dc534c90588253 pisanie dowolnego ciągu znaków (również
np. następująco: wartość1-wartość2-war- spacji), więc teoretycznie adres mogliby-
tość3.html, np. gallery-photo-21.html. Aby Wyszukiwarka znajduje w nich pytajnik, śmy zapisać jako news/Bolek i Lolek na
uzyskać taki efekt, należy przebudować znak równości oraz bezsensowny (dla wy- wycieczce, aczkolwiek nie jest to zalecane,
poprzedni zestaw reguł w pliku .htaccess, szukiwarki) ciąg znaków przedłużających gdyż przeglądarki i wyszukiwarki różnie
co już nie będzie trudne (Listing 6). URL-a. Problem ten oczywiście występu- interpretują spacje. Powyższy przykład
Jak widzimy, reguł jest teraz mniej, po- je tylko i wyłącznie wtedy, gdy dany serwis może już praktycznie działać, o ile system
nieważ w poprzednim przykładzie występo- korzysta z funkcji obsługi sesji w PHP. Aby CMS na naszej witrynie potrafi odnaleźć
wały dodatkowe zasady, dzięki którym adres wyszukiwarki nie doklejały numeru sesji artykuł po nazwie zawartej w zmiennej, nie
mógł się kończyć na slashu (/), ale nie mu- do linków, należy w pliku .htaccess, za- potrzebując ID. Mało który system CMS ma
siał. Tym razem slashe nie są używane: zo- raz pod RewriteEngine On, dodać nastę- jednak funkcje typu GetIdFromName(nazwa),
stały zastąpione myślnikami, a na końcu do- pujące linijki: a my nie będziemy się teraz zagłębiać
dajemy sufix .html, udający rozszerzenie pli- w ich tajniki.
ku. Jak już wspomnieliśmy, przed znakami Options FollowSymLinks Jest jeszcze jeden problem dotyczący
specjalnymi należy stawiać znak backslash php_flag session.use_trans_sid off powyższego przykładu – mianowicie znaki
(\), dlatego widnieje on przed kropką. Dzię- specjalne oraz polskie znaki diakrytyczne,
ki plikowi .htaccess z Listingu 6, adresy URL Jeżeli zamiast strony zobaczymy błąd 500 akcenty (np. włoskie czy francuskie), nie-
wyglądają jak w Tabelach 4, 5 i 6. W rezulta- (Internal Server Error), to znaczy, że opcja mieckie umlauty, itd. Znaki specjalne naj-
cie wszystko działa tak, jak w przypadku ad- use_trans_sid jest ustawiona globalnie na lepiej zamienić na myślniki, a narodowe
resów w stylu katalogowym. on w konfiguracji serwera i nie możemy jej – na wersje łacińskie. Spacje zastąpimy
lokalnie zmienić. Pozostaje nam wtedy po- znakami podkreślenia (_), zaś wszystkie
Pozbywanie się prosić administratora, aby ustawił tę opcję litery uczynimy małymi.
identyfikatora sesji lokalnie na off. Dzięki napisanej w PHP funkcji
Jak już wspomnieliśmy, nawet najlepiej replace_titles(), którą przedstawiamy na
zbudowane adresy URL nic nie dadzą Praktyczne Listingu 7, możemy zamienić zdanie Mały
(w sensie pozycjonowania stron w wy- zastosowania jeż je sobie jabłko, które jest zepsute na
szukiwarkach), jeżeli do linków dokleja- Mod_Rewrite maly_jez_je_sobie_jablko,_ktore_jest_ze-
ny będzie identyfikator sesji. W rezulta- w systemach CMS psute.
cie nasze adresy, zamiast wyglądać jak W praktyce, Mod_Rewrite ma wiele zasto- Działanie tej funkcji opisaliśmy w ko-
gallery/photo/21 czy gallery-photo-21.html, sowań w systemach typu CMS. Wymieni- mentarzach. Oczywiście, tablicę ze znaka-
będą wyglądały jak: my i opiszemy najpopularniejsze z nich. mi można powiększyć lub dostosować do
innych języków (my jako przykładu użyli- pomnijmy, że parametr $1 nie musi zostać Wspomniane systemy portalowe
śmy polskich znaków diakrytycznych). Za- użyty. Nie będziemy od nowa podawali ta- w katalogu modules/News/ mają plik
stosowanie tej funkcji w systemie CMS jest bel z przykładami przepisywania adresów, funcs.php. Odpowiada on za generowa-
proste. Załóżmy, że za wyświetlanie new- bo można to łatwo wywnioskować same- nie linków w systemie newsów. Otwie-
sów odpowiada plik news.php. Po pierw- mu. Oczywiście, użyliśmy przykładów te- ramy go i wstawiamy w nim opisa-
sze, należy umieścić tę funkcję najlepiej stowych – chcąc je wdrożyć w działających ną już funkcję zamiany tytułów (repla-
zaraz na początku tego skryptu. Po drugie, systemach CMS należy mieć jakąś wiedzę ce_titles()) z Listingu 7, zaraz po ko-
wystarczy odszukać szablon dla linku (za- na temat PHP. mentarzu autora. Następnie odnajduje-
kładamy, że CMS nie korzysta z systemu my w funcs.php komentarz:
szablonów w celu ustalenia wzorca dla Zastosowanie przyjaznych
linków, tylko ze zwykłych zmiennych PHP), linków w popularnych // Allowed to read full article?
który wygląda mniej więcej tak: systemach CMS
Pokażemy teraz, jak wdrożyć przyjazne i wstawiamy pod nim:
<a href=”index.php?module=news& URL-e w popularnych CMS-ach opartych
id=<?=$id?>”><?=$title?></a> na platformie Nuke (PostNuke, MDPro, $nazwa_newsa =
PHP-Nuke, enVolution, itp.). Są one kom- replace_titles($info[title]);
Ten szablon należy zamienić na umożli- patybilne z modułem generowania layoutu
wiający tworzenie przyjaznych URL-i przy o nazwie AutoTheme (MDPro i PHP-Nuke Zmienna $nazwa_newsa będzie wywoływa-
użyciu naszej funkcji, której dla adresów mają go nawet w standardowej instalacji). ła funkcję replace_titles() i stosowała ją
udających katalogi użyjemy w następujący Jest on obecnie najczęściej używanym wobec tytułu newsa podanego w zmiennej
sposób: systemem szablonów dla tych CMS-ów. $info[title]. Poniżej wstawionego przez
Moduł ten umożliwia już włączenie przyja- nas kodu widnieje linijka:
<a href=”news/<?=$id?>/<?= znych linków w ustawieniach. Niestety, są
replace_titles($title)?>”><?= to tylko linki w stylu plikowym – dobrze, że if (pnSecAuthAction(0, $component,
$title?></a> możemy chociaż wybrać sufix (domyślnie $instance, ACCESS_READ)) {
do wyboru mamy .html, .htm i .phtml). Po
Natomiast w przypadku tych, które udają uruchomieniu zamiany linków na przyja- Pod tym kodem powinna być umieszczo-
pliki, szablon będzie wyglądał następująco: zne, wystarczy przekopiować do katalogu na definicja zmiennej $fullarticle. Za-
głównego jeden z gotowych plików .htac- mieniamy całą linijkę z tą definicją na:
<a href=”news-<?=replace_titles( cess, które są dostarczane razem z mo-
$title)?>-id<?=$id?>/”><?=$title?></a> dułem. Nazwy tych plików zaczynają się $fullarticle = $news_name.'-id'.
od sufiksu, więc jeżeli wybierzymy .phtml, $info[sid].'.html';
Nasz schemat przy adresach katalogo- kopiujemy plik phtml.htaccess do głównego
wych będzie więc wyglądał tak: news/ katalogu strony i zmieniamy jego nazwę na Dzięki temu link do newsa będzie teraz
ID/nazwa_newsa, a przy plikowych: .htaccess. Po tym zabiegu domyślne sche- wyglądał następująco: nazwa_newsa-
news-nazwa_newsa-idID.html. Teraz, aby maty przyjaznych linków zaczną działać. id31.html, gdzie liczba 31 jest przykłado-
ukończyć nasze dzieło, dodajemy do pliku Naszym celem jest jednak opisanie, jak te wym ID newsa. Oczywiście sufix .html na-
.htaccess następującą regułę (dla sche- schematy przerobić i ustawić tak, aby w lin- leży zamienić na wybrany wcześniej przez
matu katalogowego): kach do newsów były nazwy tych ostatnich. nas. Pozostało jedynie dodanie reguły
RewriteRule ^news/([^-]+)/(.*)$
Listing 7. Funkcja replace_titles(), która zmienia wielkość liter i usuwa znaki
index.php?modul=news&id=$1 [L,NC,NS] narodowe
w naszym pliku .htaccess, która powinna Jak widzimy, w miejscu, w którym można Na koniec, aby wszystko działało po-
być ustawiona jako pierwsza: wstawić wartość zmiennej w URL-u, znaj- prawnie, należy zmodyfikować re-
duje się wyrażenie ([\w\d\.\:\_\/]+), guły w pliku .htaccess tak, aby by-
RewriteRule ^(.*)-id([0-9]+)\.html$ którego rezultat po przetworzeniu przez ły one zgodne z pozycjami pliku auto-
modules.php?op=modload&file= funkcję preg_replace() jest oznaczony urls.ext.php. Miejmy nadzieję, że nie bę-
article&sid=$2 [L,NC,NS] pod nazwą $1, którą musimy umieścić dzie z tym już problemów. Efekt zasto-
w tablicy $replace. Odpowiedni wpis sowania przyjaznych linków w systemie
Dzięki temu wszystko będzie już działać. w tablicy $replace będzie więc wyglądał CMS można zobaczyć chociażby na ofi-
Zauważmy, że w tym przypadku dla ID następująco: cjalnej stronie CMS-a PostNuke, http:
użyliśmy wyrażenia regularnego, które ze- //www.postnuke.com/ czy polskiej stro-
zwala na wprowadzenie tylko danej liczby. '”changelang-$1.'.$autourlsext.'”', nie www.underflip.pl.
Można dodatkowo zmodyfikować
domyślny schemat generowania linków Zmienna $autourlsext oznacza sufix. Podsumowanie
w AutoTheme. Standardowo są to angiel- Nie mamy jednak zamiaru opisywać Przedstawiliśmy Ci, jak w praktyce za-
skie odpowiedniki modułów działających szczegółowo modyfikacji CMSów i ich stosować reguły Mod_Rewrite i opisać
z tymi CMS-ami. Aby je zmodyfikować modułów, dlatego też nie będziemy się je za pomocą wyrażeń regularnych. Uży-
w dowolny sposób, należy otworzyć plik w to dalej zagłębiać. Ograniczymy się te przez nas przykłady powinny dać Ci
modules/AutoTheme/extras/nazwa_uży- do pokazania, jak powinny wyglądać no- wyraźne wskazówki, jak postępować.
wanego_systemu_cms/autourls.ext.php. we pozycje. Przykładowo, jeśli chcemy Wszystkie z nich zostały sprawdzone na
W pliku tym widzimydwie tablice dodać pozycję index.php?module=war- kilku serwerach i działają, dlatego jeże-
- $search i $replace oraz funkcję preg_ tość1&file=wartość2, to przed znakiem li którykolwiek z nich nie będzie zwracał
replace(), która zamienia wszystkie ad- zapytania należy wstawić slash, a znak oczekiwanego wyniku, może być to wy-
resy według wyrażeń z tablic. Zatem aby & zastąpić wyrażeniem &(?:amp;)?, które łącznie winą serwera. Wszystko zależy
zmienić schemat linków, należy zmody- jest warunkiem typu lub: zadziała i wtedy, bowiem od konfiguracji Mod_Rewrite na
fikować tablice, które sobie odpowiadają gdy w linku jest znak & i wtedy, gdy znaj- serwerze, która bywa błędna.
na zasadzie, że pierwsza pozycja z tablicy duje się tam & (poprawna wersja). Jednocześnie pamiętajmy, że moduł
$search jest zamieniana na pierwszą Wartość1 i wartość2 należy zastąpić wy- Mod_Rewrite jest na tyle potężny, że
z tablicy $replace, druga na drugą, itd.; rażeniem ([\w\d\.\:\_\/]+), a na końcu nie sposób streścić wszystkie jego moż-
dlatego też obie tablice mają tę samą ilość pozycji umieścić znaki "|. Całość powinna liwości nie tylko w jednym artykule, ale
pozycji. Sposób edycji pokażemy na przy- wyglądać następująco: nawet w całym numerze pisma. Życzymy
kładzie jednej z pozycji tablicy $search: zatem poprawnych reguł, zadowolenia
$prefix.'index.php\?module= użytkowników oraz wysokich pozycji
$prefix . 'index.php\?newlang= ([\wd\.:\_/]+)&(?:amp;)? w wyszukiwarkach dzięki zastosowaniu
([\wd\.:\_/]+)”|', file=([\wd\.:\_/]+)”|' Mod_Rewrite. n
R E K L A M A
Kasa dla
Webmastera
Tajniki freelancingu
Stopień trudności: lll
Krzysztof Trynkiewicz
J
uż na początku swojej przygody z freelancingowców. Pamiętajmy jednak, by
freelancingiem możemy dojść do nie kopiować treści, ani wyglądu – port-
wniosku, że mnogość zleceń wca- folio i resume muszą być inne – w końcu
le nie gwarantuje łatwej pracy, zaś po- każdy ma swój styl i własne dokonania.
zyskanie pierwszych klientów jest zada- Warto na wstępie wspomnieć kilka słów o
niem trudnym. W większości przypadków sobie. Niech to jednak nie będzie opis mu-
zleceniodawcy wybierają droższych, lecz zyki, której słuchamy. Istotne dla zlecenio-
bardziej doświadczonych programistów. dawcy jest: gdzie mieszkamy, dla kogo i w
Ich przewaga leży jednak nie tylko w ilo- jakich porach pracujemy, jakie mamy do-
ści ukończonych projektów. Wraz z ro- świadczenie w innych stałych pracach,
snącym doświadczeniem, wypracowali a wreszcie: jakie projekty ukończyliśmy.
oni własne schematy pisania kuszących Ukończone projekty czołowych freelan-
ofert. Przyjrzyjmy się bliżej praktykom, cingowców można liczyć w setkach, jed-
które stosują. nak żaden nie wspomina o więcej niż kilku
w swoim portfolio – powinniśmy wybrać te
Tworzymy najlepsze i najbardziej rozwinięte. Dobrze
W SIECI portfolio i resume jest załączyć fragment własnego skryptu
Pierwszą rzeczą, jaką musimy zrobić, jest lub gotową klasę, opatrzoną komentarza-
stworzenie strony informującej o naszych mi. Możemy wspomnieć nazwy naszych
• http://allfreelance.com dokonaniach. Przy tworzeniu portfolio i re- największych klientów oraz podać moż-
– kompendium linków fre-
elancingowych
sume na potrzeby freelancingowe, nale- liwe sposoby komunikacji – w grę wcho-
• http://guru.com ży zwrócić uwagę w pierwszej kolejności dzi naturalnie e-mail, ale także komuni-
• http://rentacoder.com na konkurencję. Głównym źródłem naszej katory oraz telefon. Nie zapomnijmy po-
• http://getafreelancer.com
wiedzy będą szczegóły kont wiodących chwalić się znanymi nam językami obcymi
– zleceniodawca w znakomitej większości “ty”. W treści oferty powinniśmy zamie- nić projekt. W tym celu posłużymy się
przypadków chętniej spojrzy na wykonaw- ścić coś przyciągającego – zwykłe “zro- ponownie historią ukończonych projek-
cę, z którym może porozumieć się w oj- bię to za $25” nie wystarczy. Przydatne tów zleceniodawcy. Pamiętajmy, że naj-
czystym języku. Schludną stronę informa- jest tu przedstawienie swojego pomysłu lepiej widziana jest cena najbardziej od-
cyjną jednego z czołowych freelancingow- na wykonanie projektu, naturalnie zgod- powiednia – jeżeli ustalimy za niską kwo-
ców możemy zobaczyć na Rysunku 1. nego z wytycznymi. Jeśli ukończyliśmy tę, zostaniemy wzięci za amatorów. Z ko-
podobne projekty, warto wspomnieć o lei zbyt wysoka cena skreśla nas nawet
Szukamy kilku najistotniejszych oraz wskazać od- przed przeczytaniem treści oferty. Ilość
odpowiedniego projektu nośnik do swojej historii ukończonych złożonych ofert wskaże nam, jak wyglą-
Zanim złożymy swoją pierwszą ofertę prac. Warto w tym miejscu zajrzeć do hi- da nasza konkurencja – jeśli jest ich wie-
(ang. bid), musimy znaleźć projekt ade- storii projektów zleceniodawcy – pozna- le, powinniśmy obniżyć swoją cenę.
kwatny do naszych umiejętności. W przy- my jego wymagania, a w zależności od
padku programistów PHP sprawa wyda- pośrednika freelancingowego, także styl Przekonujemy
je się prosta: interesują nas zlecenia z i treść ofert, które zaakceptował. Nie mo- do siebie zleceniodawcę
tej właśnie kategorii. Warto jednak zwró- żemy krytykować wytycznych zlecenio- Wiele pośredników freelancingowych udo-
cić uwagę także na projekty, które zosta- dawcy – zawsze mu przytakujmy, wska- stępnia różnego typu narzędzia, pomocne
ły zakwalifikowane do kategorii ASP, JSP, zując opcjonalne rozwiązania. Koniecz- w komunikacji ze zleceniodawcą. Powinni-
czy nawet Flash. Często bowiem znaj- nie musimy wspomnieć o przewidywa- śmy więc używać wbudowanych chatów
dziemy tam swoich przyszłych klientów, nym czasie wykonania zlecenia, najlepiej i for dyskusyjnych, celem sprecyzowania
którzy nie mając głębszej wiedzy o języ- krótszym niż ustalony deadline. Jeżeli zlecenia – nie bójmy się spytać o szcze-
kach webowych, błędnie zakwalifikowali składamy ofertę na zlecenie wykonania góły, w końcu zależy nam, by zlecenio-
projekt. Niektórych możemy także przeko- skryptu bądź klasy, warto umieścić odno- dawca dostrzegł nasze zainteresowanie.
nać, że dana strona jest możliwa do stwo- śnik do przykładowych fragmentów wła- W kontaktach tego typu kluczowe jest sto-
rzenia przy użyciu darmowych technik, w snego kodu. Pamiętajmy jednak, by kod sowanie stylu podobnego do zleceniodaw-
naszym przypadku najpewniej połączenia ten był opatrzony odpowiednimi komen- cy oraz bardzo szybkie, precyzyjne odpo-
PHP oraz bazy danych MySQL. Przy skła- tarzami! Również w ofercie poinformuj- wiedzi. Jeśli pośrednik umożliwia złoże-
daniu oferty zaznaczmy, że koszty wyko- my, że nasz kod będzie jasny, czytelny, nie pieniędzy do depozytu zabezpieczają-
nania będą niższe – nie musimy bowiem a co najważniejsze – będzie zawierał ko- cego zleceniodawcę (ang. Seller Guaran-
opłacać licencji za programy, w których mentarze. Dobrym pomysłem jest wspo- tee Deposit), skorzystajmy z niego! Ta-
wykonujemy projekt. mnienie o możliwości stworzenia doku- kiego typu zabezpieczenie finansowe da-
mentacji do projektu, np. przy użyciu na- je nam ogromne szanse na szybkie wybi-
Składamy rzędzia phpDocumentor. Na zakończe- cie się spośród tłumu nowych freelancin-
pierwszą ofertę nie zachęcamy do zadawania pytań i po- gowców, pieniądze zaś zostaną nam i tak
Znaleźliśmy już odpowiedni dla nas pro- zdrawiamy w adekwatnym do opisu zle- zwrócone. Dodatkowo niektórzy pośredni-
jekt, który będziemy w stanie ukończyć. cenia stylu. Pozostało nam tylko wyce- cy umożliwiają zamieszczenie w szczegó-
Przyszedł czas na złożenie oferty. Za-
poznajmy się najpierw dokładnie z wy-
tycznymi projektu oraz wszelkimi za-
łącznikami. Po treści wytycznych pozna-
my stopień zaawansowania zlecenio-
dawcy – odpowiedź napiszemy adekwat-
nym językiem. Nie możemy przecież za-
sypać laika mnóstwem skrótów i obiet-
nicami zgodności z wciąż rosnącą licz-
bą standardów. Projekt należy uważnie
przemyśleć – dobrze jest, jeśli mamy ja-
kąś wizję i ją przedstawimy w treści na-
szej oferty. Wizję może stanowić dodat-
kowa funkcjonalność, czy nawet układ i
kolorystyka wykonywanej strony. Naszą
ofertę zaczynamy, naturalnie, od przywi-
tania. Warto zwrócić już tutaj uwagę, ja-
kim stylem pisze zleceniodawca, czy jest
to poważna firma, czy też jedna osoba.
W tym drugim przypadku możemy poku-
sić się o trochę mniej formalności, tym
samym pisząc stylem internautów – per Rysunek 1. Fragment strony informacyjnej jednego z czołowych freelancingowców
łach naszego konta informacji o ukończo- tkniemy się na ich średnie wyceny pra- Ile czasu dziennie spędzasz na jej wyko-
nych kursach i posiadanych certyfikatach cy za godzinę: wahają się one od $10 nywaniu?
– z pewnością ten od firmy Zend jest wart do $70, zaś podsumowane zarobki wy- SIG: Mógłbym żyć z samego freelan-
wspomnienia. kraczają poza kwotę 100 000 USD. Z cingu, ale obecnie mam także inną pra-
kolei na Rent A Coder znajdziemy in- cę. Dziennie na freelancing przeznaczam
Szukamy wykonawcy formacje na temat samego rozwoju fre- do 12 godzin, chociaż czasem robię sobie
Wiemy już, jak złożyć kuszącą ofertę. Co elancingu: rocznie ilość zakończonych wolne – w zależności od ilości pracy oraz
jednak, jeśli to my mamy projekt, które- zleceń rośnie o 72%, obecnie miesięcz- spraw do załatwienia poza domem.
go wykonanie wymaga pomocy osoby nie zakańczanych jest około 15 000 pro- PS: Jak porównasz freelancing z pra-
trzeciej? Powinniśmy najpierw chwycić jektów, z czego aż 93% to oferty stałych cą na pełny etat?
za kartkę i ołówek. Z ich pomocą stwo- zleceniodawców. Mamy tym samym od- SIG: We freelancingu mam możliwość
rzymy wytyczne projektu oraz zarys gra- powiedź na pytanie, czy jako freelance- wyboru zleceń – mogę zwyczajnie odmó-
ficzny, który następnie możemy zeska- rzy znajdziemy stałych klientów – z pew- wić, dobierając sobie bardziej odpowiedni
nować i dodać do opisu naszego zlece- nością tak. projekt. Dodatkowo, po zakończonym zle-
nia. Istotne jest, by zastanowić się, w ja- ceniu, otrzymuję pozytywne opinie, które
kich technikach powinien być wykonany Opinia profesjonalisty pomagają mi znaleźć kolejnych klientów
nasz projekt. Jeśli jest to strona interne- Freelancing może być sposobem na ży- – zamknięte koło. Z drugiej strony, cza-
towa, pamiętajmy o problemach z dru- cie. Jednym z ludzi, którzy swój sukces sami trudno jest wygrać aukcję i nie ma
kowaniem stron z animacjami Flasha. zawdzięczają tej formie zarabiania pienię- się pewności, że wpływy będą regularne.
Co jednak istotniejsze, sprecyzujmy ja- dzy, jest Sergey I. Grachyov, z którym mie- Warto mieć zabezpieczenie w postaci dru-
kie wersje PHP i MySQL mamy dostęp- liśmy przyjemność rozmawiać. giej pracy.
ne u naszego hosting providera. Różnica PHP Solutions: Opisz siebie w kilku PS: Czy freelancing uważasz za spo-
między PHP 4 a 5 jest kolosalna, warto słowach – jakimi osiągnięciami freelancin- sób na życie, czy też jest to dla Ciebie for-
więc się dobrze zastanowić, a nawet roz- gowymi możesz się pochwalić? Jak zaczę- ma zarobku na rozpoczęcie własnej dzia-
ważyć zakup serwera z obsługą nowszej ła się Twoja przygoda z freelancingiem? łalności?
wersji PHP, by nasz projekt był rozwijal- Sergey I. Grachyov: Mam 34 lata i SIG: Nie planuję rozpoczęcia własnej
ny w przyszłości bez konieczności prze- mieszkam w St. Petersburgu, w Rosji. Swo- działalności – nie lubię kierować innymi
pisywania kodu. Pamiętajmy też, że nie ich pierwszych zleceń szukałem na Rent A ludźmi. Narazie chcę wciąż działać jako
wszystko należy bezwzględnie opierać Coder, gdzie obecnie mam 745 ukończo- freelancer, kierując swoją ofertę głównie
na klasach, a jeśli już ich chcemy, wyma- nych projektów i status Top Coder. Uzyska- na rynek amerykański – większość zlece-
gajmy dokładnego ich opisu. Przy wybo- łem także status Gold Member na GetAFre- niodawców pochodzi właśnie z tego kra-
rze oferty wykonawcy zwracajmy uwagę elancer ze średnią oceną 9,95. Korzystam ju. Oczywiście freelancing może być do-
na skończone zlecenia, a przede wszyst- także z serwisu Scriptlance, na którym mo- brym wyjściem na zarobienie pieniędzy
kim, na fragmenty przykładowych skryp- ja ocena to 10. Projekty wykonuję głównie w koniecznych do otwarcia własnej firmy,
tów. Na ich podstawie stwierdzimy, czy PHP, Visual Basic, C# oraz ASP. głównie dla studentów, nie mających cza-
będziemy w stanie samodzielnie wnosić PS: Czy freelancing jest na tyle opła- su na regularną pracę. Ja jednak już lubię
poprawki do kodu, czy też każda zmiana calny, by wystarczał jako jedyna praca? to, co robię.
będzie wymagała konsultacji (zapewne
odpłatnej). Zadajmy też przykładowe py-
tanie, np. jakimi językami posługuje się
wykonawca. Da nam to wiedzę o szyb-
kości odpowiedzi, a przy okazji mamy
szansę trafić na osobę znająca nasz ję-
zyk ojczysty, co ułatwi komunikację. Ce-
na nie jest tak istotną kwestią – nie nale-
ży oszczędzać na programistach. Najle-
piej określić pewien zakres – zbyt niska
cena może oznaczać słabe wykonanie,
zaś zbyt wygórowana wcale nie gwaran-
tuje lepszego produktu końcowego.
Odpowiadamy
na pytania
Po publikacji pierwszego artykułu o fre-
elancingu (PHP Solutions 5/2006) otrzy-
maliśmy wiele zapytań odnośnie płatno-
ści. Serwis Guru.com wskaże nam w tej
kwestii wiele odpowiedzi. Szukając de-
welopera PHP na szczycie rankingu, na- Rysunek 2. ProfilSergeya I. Graychova na Rent A Coder
PS: Jak freelancing wpływa na Twoje Mogę umieszczać trochę wyższe propo- cingowców: arbiter w pięć sekund przy-
życie prywatne? Czy nie uważasz, że zaj- zycje cenowe, ponieważ klienci mają pew- zna rację (i fundusze) zleceniodawcy, któ-
muje zbyt dużo czasu? ność, że jest to koszt zatrudnienia profe- ry zgłosi, że przekroczyliśmy ustalony de-
SIG: Freelancing nie zajmuje mi wię- sjonalisty. Zdecydowanie polecam ukań- adline, zaś otrzymany negatywny komen-
cej czasu, niż każda inna praca. Ma taki czanie kursów i zdobywanie certyfikatów tarz fatalnie wpłynie na naszą reputację.
sam wpływ na moje życie prywatne, jak wszystkim, którzy chcą być liczącymi się Terminy to kluczowa sprawa, należy ich
praca na etat. programistami. bezwzględnie dotrzymywać.
PS: Od kogo i jakiego typu zlecenia PS: Co uważasz za najważniejsze we PS: Czy sądziłeś, że freelancing bę-
najczęściej przyjmujesz? freelancingu: dobre rekomendacje, portfo- dzie trudniejszy lub łatwiejszy, niż się oka-
SIG: Przyjmuję każde zlecenia, któ- lio, korzystne wyceny, szybki kontakt, czy zał?
re potrafię wykonać. Przed zaakceptowa- może coś innego? SIG: Gdy zaczynałem, nie myślałem o
niem zadania, zawsze sprawdzam, jakie SIG: Najważniejsze, to posiadać dużą trudnościach. Z obecnej perspektywy wy-
komentarze o zleceniodawcy pozostawili ilość pozytywnie zakończonych projektów daje się, że jest to praca o stopniu trudno-
poprzedni wykonawcy – negatywne opinie u swojego pośrednika freelancingowego. ści zależnym od zlecenia, ale przynosząca
w zasadzie przekreślają szansę na zatrud- Ukończone projekty, to reputacja. Reputa- wielką satysfakcję. Nikt mnie nie zmusza,
nienie mnie. Preferuję zadania z precyzyj- cja, to nowi klienci. bym wykonywał trudne zadania – sam o
nie określonymi wytycznymi, w których PS: Posiadanie tak wielu klientów z tym decyduję, co jest ogromnym plusem.
dokładnie wiem, co mam zrobić. Zlecenio- pewnością wymaga dobrego rozplanowa- PS: Jesteś zadowolony z formy zarob-
dawca powinien wiedzieć, czego chce – ja nia czasu i zadań. Czy korzystasz z do- ku, którą wybrałeś, czy też wolałbyś ina-
wiem, co mogę zaoferować. Unikamy tym datkowych narzędzi poza tymi, które udo- czej spożytkować swój czas przeznaczo-
samym niedomówień. stępniają pośrednicy? ny na freelancing?
PS: Korzystałeś z wielu serwisów fre- SIG: Do przechowywania i zarządza- SIG: Jestem bardzo zadowolony z te-
elancingowych. Który z nich mógłbyś po- nia moimi pracami używam Visual So- go, co robię. Gdybym mógł zmienić czas,
lecić? urce Safe. Gdy chcę pokazać zlecenio- zostałbym freelancingowcem pięć lat
SIG: Zdecydowanie polecam Rent A dawcy postęp projektu, niekiedy używam wcześniej.
Coder, głównie z racji bezpieczeństwa: własnego systemu. Narzędzia oferowa- PS: Jakie rady udzieliłbyś osobie, która
wpłaty na Escrow są zobowiązujące, zaś ne przez pośredników świetnie sprawdza- planuje rozpocząć pracę jako freelancer?
w przypadku problemów, arbiter zawsze ją się do składowania kopii zapasowych SIG: Przede wszystkim: próbować.
potrafi pogodzić obie strony. Odradzam oraz dowodów wykonania pracy, w przy- Próbować i nie poddawać się. Wraz z wy-
serwisy, które wymagają wniesienia opła- padku sporu. grywaniem kolejnych zleceń, będzie ła-
ty za rejestrację, umieszczenie lub wyszu- PS: Czy musiałeś nabyć dodatkowe twiej o następne. Zalecam także intensyw-
kiwanie zleceń. umiejętności, np. w zakresie marketingu, ną naukę języka angielskiego.
PS: Czy trudno było zdobyć zaufanie czy komunikacji z klientami, by stać się PS: Dziękujemy za rozmowę.
klientów na serwisach freelancingowych? profesjonalnym freelancingowcem?
Jak dużo czasu Ci to zajęło, i co okaza- SIG: Nie, wystarczyło, że dokładnie Podsumowanie
ło się kluczem do sukcesu? Czy obecnie przeczytałem zasady i zalecenia z Rent Niezależnie od tego, czy jesteśmy wyko-
większość Twoich klientów to byli zlece- A Coder i zacząłem je stosować. Reszta nawcą, czy zleceniodawcą, naszym głów-
niodawcy? (np. zdolności komunikatywne) przyszła nym źródłem informacji są bardziej doświad-
SIG: Swoje pierwsze zlecenie wy- sama z siebie. czeni użytkownicy pośredników freelancin-
grałem dopiero po tygodniu pełnym od- PS: Brak nadzoru szefa z pewno- gowych. Warto zwrócić uwagę na podobne
powiedzi “Niestety, zleceniodawca wy- ścią nie motywuje. Jak poradziłeś so- do naszych oferty i na nich się wzorować.
brał inną ofertę”. Wynagrodzenie za to bie ze zmuszaniem siebie do codzien- Ważne jest, by wybrać jeden serwis pośred-
zadanie wynosiło zaledwie $10. Do- nej pracy? niczący i na nim zdobywać renomę oraz
świadczenie nauczyło mnie, że jako po- SIG: Nie lubię, gdy ktoś obserwu- stałych klientów. Jak widzimy na przykładzie
czątkujący freelancer, musisz próbować je moje ręce podczas pracy. Motywację Sergeya, do sukcesu niedaleko! n
pozyskiwać zlecenia, umieszczając ko- do pracy zyskałem, gdy wmówiłem sobie,
rzystne propozycje cenowe. Na dzień że jest to taka sama praca, jak na pełen
dzisiejszy, większość moich klientów to etat. Teraz już nie zmuszam się do nicze-
nowi zleceniodawcy, chociaż często tra- go – lubię to, co robię. O autorze
fiają mi się propozycje wykonania pro- PS: Jak radzisz sobie ze stresem spo-
Krzysztof Trynkiewicz od wielu lat zaj-
jektów dla byłych klientów. Sam dobie- wodowanym obowiązkowym dotrzymywa- muje się tworzeniem witryn w technolo-
ram swoje zlecenia – a wybieram tylko niem terminów, wiedząc, że kolejne zlece- gii PHP oraz Flash. Ściśle współpracuje
te pewne i jasno określone. nie może nie nadejść prędko? z magazynem PHP Solutions, wykonu-
je także zlecenia freelancingowe. Obec-
PS: Posiadasz również kilka certyfi- SIG: Jestem rozgrzany przez cały rok,
nie rozwija kilka równoległych projektów
katów – jak one wpłynęły na ilość klien- jak po opalaniu, a mieszkam przecież w autorskich dostępnych na witrynie http://
tów? Czy uważasz, że warto było je zdo- St. Petersburgu. Dotrzymywanie terminów eldoras.com
bywać? nie sprawia mi problemu, zaś w przypad-
Kontakt z autorem:
SIG: Zdobycie certyfikatów wydatnie ku braku zleceń – wciąż mam drugą pra-
chris.trynkiewicz@gmail.com
wpłynęło na moją karierę freelancingową. cę. Przestrzegam jednak nowych freelan-
PHPUnit2 w praktyce
Stopień trudności: lll
Marcin Staniszczak
P
rzypomnij sobie jak często Zanim przejdziesz do dalszej czę-
po napisaniu nawet wydawa- ści artykułu, musisz zainstalować u sie-
ło by się prostej klasy, odnaj- bie PHPUni2 – zapoznaj się w tym celu z
dywałeś w niej błąd (i to często w naj- ramką Instalacja PHPUnit2.
mniej spodziewanym miejscu)? Ile ner-
W SIECI
wów i czasu kosztowało Cię odnalezie- Krótki wstęp
nie błędnego fragmentu? Nawet jeśli Pisanie testów jednostkowych nie jest
W Internecie znajduje się spo- jesteś szczęśliwcem używającym edy- niczym innym jak stworzeniem klas ma-
ro materiałów na temat testów tora z wbudowanym debugerem PHP, jących na celu kompletne przetestowa-
jednostkowych. Oto kilka wy-
branych, interesujących odno-
zadanie odnalezienia błędu w aplikacji nie klas wchodzących w skład aplikacji.
śników: składającej się z kilkudziesięciu – kil- Przyjęło się, że na każdą klasę aplika-
kuset klas, często jest zadaniem bar- cji powinna przypadać jedna lub więcej
l http://www.phpunit.de/
– strona i wiki projektu dzo trudnym. klas testów. Zdarza się, że klasa testu-
PHPUnit; W świecie Java-y od dawna stosowa- jąca posiada więcej kodu od klasy testo-
l http://www.phpunit.de/
pocket_guide/index.en.php ne są tak zwane testy jednostkowe (ang.
– podręcznik autora frame-
worka PHPUnit;
unit tests), przeprowadzane z wykorzy- Co musisz wiedzieć
staniem wyspecjalizowanych framewor- W celu zrozumienia materiału zawarte-
l http://www.onlamp.com/
pub/a/php/2005/12/08/ ków testowych – najpopularniejszym z go w tym artykule, wymagana jest przy-
phpunit.html – krótki tutorial nich jest JUnit. Na szczęście od pewnego najmniej podstawowa znajomość PHP5
autora frameworka PHPU- oraz programowania obiektowego. Do-
nit2; czasu istnieje kilka podobnych framewor- datkowo niezbędne są chęci – tworzenie
l http://simpletest.sourceforge ków dla PHP. My zajmiemy się tu frame- testów jednostkowych początkowo może
.net/ – konkurencyjny w sto-
workiem o nazwie PHPUnit2. Jest on roz- wydawać się zbędnym traceniem cenne-
sunku do PHPUnit2 frame-
work do testów jednostko- wijany w ramach PEAR przez Sebastiana go czasu, jednak wraz ze wzrostem pro-
wych klas PHP. jektu, szybko docenia się ich siłę.
Bergmanna.
Tworzymy testy
Tyle informacji na początek wystarcza.
Zacznijmy pisać testy dla pierwszej kla-
sy. Każda klasa testu musi dziedziczyć
po klasie PHPUnit2_Framework_Test-
Case. Klasę testującą klasę Authoriza- Rysunek 1. Nieudane uruchomienie testu
tion, nazwiemy AuthorizationTest (dalej dowałem specjalną klasę odpowiedzial- toda ta nawiązuje połączenie jedynie
będziemy się trzymali tego sposobu na- ną jedynie za nawiązywanie połączenia raz, przy pierwszym jej wywołaniu. Każ-
zewnictwa): z bazą – zobacz Listing 3. Klasa ta po- de następne wywołanie powoduje jedy-
siada prywatny konstruktor, tak aby nie nie zwrócenie obiektu PDO.
<?php dało się utworzyć jej instancji. Dodatko- Klasa ta zabezpiecza nas przed ko-
class AuthorizationTest wo posiada publiczną statyczną meto- niecznością wielokrotnego nawiązy-
extends PHPUnit2_Framework_TestCase { dę, zwracającą połączenie z bazą. Me- wania połączenia w każdej z klas te-
}
?>
lecenie SQL tworzące odpowiednią ta- wy login i hasło, a może tylko login. który poda prawidłowy login i hasło po-
belę w bazie MySQL przedstawia Li- Dodajemy do naszej metody kilka li- winien być akceptowanych przez meto-
sting 5. nii – zobacz Listing 6. Pobieramy tu dę check. Musimy jeszcze dodać bloka-
Gdy istnieje już Tabela, musisz dodać użytkowników. Z taką metodą (oraz ze dę w przypadku zdefiniowanego adresu
do niej odpowiednie dane, które są wyma- zmodyfikowanymi metodami getName i IP spod którego użytkownik może się
gane przez nasz test. Przedstawia to Li- getSurname, tak aby zwracały one od- logować (kolumna ip w tabeli users).
sting 6. powiedni imię i nazwisko użytkownika), Nasza metoda wzbogaciła się o kolej-
Pierwszym etapem będzie spraw- nasza klasa przechodzi już dwa pierw- ny warunek – Listing 7. Dzięki temu kla-
dzenie czy użytkownik podał prawdzi- sze testy. Jednak nie każdy użytkownik sa poprawnie przechodzi większość te-
stów. Do rozwiązania został tylko jeden
Listing 5. Szablon klasy Authorization problem – blokowanie konta użytkow-
nika w przypadku trzykrotnego poda-
<?php nia nieprawidłowego hasła. Po krótkim
class Authorization { przemyśleniu i zapisaniu swoich myśli
w PHP, powstała klasa jak z Listingu 8.
const OK = 0;
const ERROR_UNAUTHORIZED = 1; Wydaje się że wszystko powinno działa
const ERROR_3TIMES = 2; poprawnie. W przypadku niepoprawne-
const ERROR_IP = 3; go hasła sprawdzamy ile było nieuda-
private $objDBConnection; nych prób logowania na dane konto pod
rząd. Jeśli zbyt wiele blokujemy konto.
public function __construct(PDO $objDBConnection) {
$this->objDBConnection = $objDBConnection; Jeśli konto jest zablokowane, spraw-
} dzamy czy możemy je już odblokować.
Jeśli nie możemy ustawiamy zmienną
public function check($strLogin, $strPassword) { informującą jak długo konto pozosta-
}
nie jeszcze zablokowane i zwracamy
public function getID() { błąd. Wszystko wydaje się być popraw-
} ne. Nawet w przypadku logowania, czy-
ścimy wpisy w bazie o nieudanych pró-
public function getName() { bach logowania, tak aby były one zli-
}
czane od początku. A więc uruchom-
public function getSurname() { my test. I co się stało? Okazuje się że
} klasa nadal nie przechodzi trzeciego te-
stu – metoda check w momencie poda-
public function getLastLogin() { nia prawidłowego hasła po trzech nie-
}
udanych próbach logowania na kon-
public function getLockFor() { ta zwraca wartość Authorization::OK.,
} czyli pozwala się zalogować na konto
które powinno być zablokowane. Po-
} wód? Spełnione zostały pierwsze dwa
?>
warunki – istnieje użytkownik o zada-
Listing 6. Polecenie SQL tworzące odpowiednią tabelę w bazie MySQL nym loginie, oraz podanym haśle. Me-
toda nie sprawdza więc już czy konto
CREATE TABLE users ( nie jest przypadkiem zablokowane. Zo-
iduser INT NOT NULL auto_increment PRIMARY KEY,
bacz Rysunek 4.
name VARCHAR(50) NOT NULL,
surname VARCHAR(80) NOT NULL,
Miejsce błędu zostało odnalezione
login VARCHAR(50) NOT NULL UNIQUE, bardzo szybko dzięki zastosowaniu te-
password CHAR(32) NOT NULL, stów. Na szczęście naprawienie błędu
ip BIGINT DEFAULT NULL, jest bardzo proste. Wystarczy zmodyfiko-
lastlogin INT NOT NULL DEFAULT 0,
wać warunek:
lasttry INT NOT NULL DEFAULT 0,
trycount INT NOT NULL DEFAULT 0,
); if (strcmp($arrUser['password'],
md5($strPassword)) === 0) {
Listing 7. Dodajemy dane do tabeli
metody check, tak aby sprawdzał on tak-
INSERT INTO users (iduser, name, surname, login, password, ip, lastlogin,
lasttry, trycount) VALUES (101,'Jan','Kowalski','test', że liczbę nieudanych prób logowania
'e10adc3949ba59abbe56e057f20f883e',NULL,0,0,0), (102,'Jan', oraz czy ewentualnie zablokowane kon-
'Kowalski','testIP','e10adc3949ba59abbe56e057f20f883e', to można już odblokować (czyli czy upły-
-943208505,0,0,0); nął już czas na jaki konto zostało zablo-
kowane)
if ((strcmp($arrUser['password'],
md5($strPassword)) === 0) &&
(($arrUser['trycount']
<$this->intLockAfter)
|| ($arrUser['lasttry']+$this->
intLockTime<time()))) {
Listing 10. Niemal poprawna klasa Authorization – wydawało się że klasa powinna działać poprawnie, tymczasem okazuje się,
że nie przechodzi ona trzeciego testu
Listing 10. Niemal poprawna klasa Authorization – wydawało się że klasa powinna działać poprawnie, tymczasem okazuje się,
że nie przechodzi ona trzeciego testu
<?php $this->intLockTime)<time()) {
class Authorization { $this->updateTry($arrUser['iduser']);
const OK = 0; } else {
const ERROR_UNAUTHORIZED = 1; $this->updateTry($arrUser['iduser'],
const ERROR_3TIMES = 2; $arrUser['trycount']+1);
const ERROR_IP = 3; }
private $objDBConnection; return self::ERROR_UNAUTHORIZED;
private $intLockAfter = 3; }
private $intLockTime = 180; }
private $strName = null; }
private $strSurname = null;
private $intLastLogin = null; return self::ERROR_UNAUTHORIZED;
private $intLockFor = null; }
gu 10 znajduje się pełna klasa nasze- Plik zawierający klasę z pakietem mu- Testy
go pakietu. si posiadać nazwę klasy i rozszerzenie niekompletne,
Test buduje się tworząc instancję .php. anulowanie testu
klasy PHPUnit2_Framework_TestSuite. Uruchomienie pakietu testów przebie- Jeśli niektóre z testów nie są jeszcze ukoń-
Następnie korzystając ze stworzonego ga analogicznie do uruchomienia pojedyn- czone, można poinformować o tym frame-
obiektu możemy dodawać kolejne testy czego testu: work, zwracając w metodzie testu wyjątek
do naszego pakietu. Służy do tego me- PHPUnit2_Framework_IncompleteTestError.
toda addTest(). Jako parametr tej me- phpunit UsertTestSuite W jego konstruktorze można opcjonalnie
tody podajemy obiekt testu który doda- podać dodatkową informację:
jemy (konstruktor klasy przyjmuje na- Na Rysunku 5 znajduje się przykła-
zwę metody z testem który chcemy uru- dowy wynik działania pakietu z Listin- throw new PHPUnit2_Framework_
chomić). gu 10. IncompleteTestError('
Podsumowanie
Mam nadzieję, że artykuł ten przyczynił
się do zainteresowania Cię testami jed-
nostkowymi. Mimo iż wiele osób na po-
Rysunek 5. Wynik działania pakietu testów z Listingu 10 – plik UserTestSuit.php
czątku podchodzi do nich bardzo scep-
Test ten nie został jeszcze $this->markTestSkipped tycznie i nie chce „tracić czasu” na ich
ukończony'); ('Wymagane rozszerzenie XYZ jest budowę, to jednak po kilku próbach sa-
niedostępnę!'); mi oni stwierdzają że to jest to. Aplika-
Jeśłi chcesz skorzystać z klasy wyjątku cje internetowe bardzo często szybko
PHPUnit2_Framework_IncompleteTestError, Inne możliwości się rozwijają.
musisz dołączyć do klasy testu następu- PHPUnit2 Dodawanie nowych elementów po-
jący skrypt, wchodzący w skład frame- To co zostało zaprezentowane w tym woduje wzrost prawdopodobieństwa
worka PHPUnit2 - PHPUnit2/Framework/ artykule to jedynie wycinek możliwości pojawienia się w nowych fragmentach
IncompleteTestError.php. PHPUnit2. Framework ten pozwala na błędów, które mogą się okazać trudne
przykład sprawdzić nasze testy pod kon- do odnalezienia, a co gorsze mogą po-
require_once(‘PHPUnit2/Framework/ tem pokrycia testami testowanej klasy. wodować błędne działanie innych, sta-
IncompleteTestError.php’); Wystarczy wówczas nieco zmodyfiko- rych, części aplikacji. W takich wypad-
wać wywołanie phpunit: kach testy jednostkowe bardzo często
Częściej spotykaną sytuacją jest zależ- pomagają w szybkim wyłapaniu błę-
ność wykonania testu od zainstalowa- phpunit --coverage-html coverage.html dów, które w innym wypadku mogły by
nia jakiegoś rozszerzenia do PHP, czy UserTestSuite się ujawnić po pewnym czasie dopiero
obecności w systemie dodatkowych bi- u klienta. n
bliotek, wymaganych do działania da- Dzięki temu PHPUnit2 wygeneruje podsu-
nej funkcjonalności projektowanej kla- mowanie na temat przetestowanych frag-
sy, lub od wcześniejszego, poprawne- mentów naszej klasy, w postaci strony in- O autorze
go wykonania się innych testów. Jeśli ternetowej. Jednak aby strona ta była dla
funkcjonowanie pewnych elementów nas czytelna, musimy przygotować so- Marcin Staniszczak jest studentem
pierwszego roku informatyki studiów
naszej klasy jest zależne od czynników bie plik CSS, formatujący ją w odpowied- uzupełniających magisterskich na
zewnętrznych, oraz gdy ich obecność ni sposób. WSHE w Łodzi. W PHP programuje
możemy zbadać z poziomu testów, mo- PHPUnit2 pozwala zapisać wy- od wielu lat. Jest autorem kilkunastu
żemy w razie konieczności poinformo- nik pokrycia kodu także w pliku txt, lub publikacji o tematyce PHP i Interne-
towej. Jest autorem framework MVC
wać PHPUnit2 że chcemy dany test po- w serializowanej tablicy, którą z łatwo- dla PHP5 (web.framework) oraz sys-
minąć (niestety ta metoda działa jedy- ścią można obrabiać z poziomu skryp- temu szablonów dla PHP5 (web.tem-
nie w wersji 3.0.0, która nie jest jesz- tów PHP. plate).
cze stabilna i nie jest w związku z tym PHPUnit2 pozwala także na łatwe wy-
Kontakt z autorem:
standardowo pobierana w czasie insta- generowanie prostej dokumentacji testu w marcin@staniszczak.pl
lacji z PEAR): formacie HTML lub txt:
Paskudne technologie
Michał Małecki
K
toś, kto siedział przez dłuższy czas Czytelność to przykład, i to jeszcze a rozwija się, bo ma kto w niego inwestować.
w biznesie związanym z oprogramo- bardzo praktyczny. Gorzej z kryteriami ty- Tak przecież stało się z komputerem IBM
waniem, zauważył już na pewno, ja- pu „piękno”, „estetyka”, czy „elegancja”. Co PC, który u swojego zarania (XT/AT) był naj-
ka jest różnica między informatyką, a inżynie- prawda ostatnio jak spytałem o to, czy mo- gorszym szmelcem wśród sprzętu kompute-
rią oprogramowania. Inżynieria, nie istniałaby że to być ścisłe kryterium, zostałem odesła- rowego, ale dzięki otwartości pokonał znacz-
bez nauki. Ale dopiero inżynieria oprogramo- ny do jakichś stron na Wikipedii (np. Mathe- nie lepsze od siebie komputery Amiga i Ata-
wania jest w stanie uzasadnić, czy ten rozwój matical beauty), które ze śmiertelną powagą ri ST, o których dziś chyba mało kto pamięta,
informatyki rozwojowi cywilizacji, czy też jest twierdzą, że matematycy czerpią estetycz- a i na „ogryzka” bym nie stawiał. Wcale nie
jedynie twórczym wysysaniem sobie z pal- ną przyjemność ze swojej pracy. Co prawda jest powiedziane, że rozwój tego „gorszego”
ca. W końcu środowiska naukowe potrze- już samo porównanie piękna liczb do piękna w efekcie kosztował więcej, niż kosztowałby
bują funduszy do swojego działania, a jeśli 9-tej symfonii Beethovena powinno sprowa- rozwój tego „lepszego”. Jak przemysł nie do-
nowe technologie opracowane w tych śro- dzić na ziemię tych, którym się wydaje, że te rósł do określonych rozwiązań, to widocznie
dowiskach nie dają się wykorzystać do ro- kryteria mają coś wspólnego z jakąkolwiek przemysłowi jest z tym dobrze. Tak jak to było
bienia pieniędzy, to nie ma mowy o pienią- inżynierią, ale to wielu nie przeszkadza na- z maszyną parową, która została wynalezio-
dzach na badania. To z kolei, potrafi w wie- rzekać na wszystkie współcześnie używa- na już w starożytnym Egipcie, ale praktyczne
lu wypadkach prowadzić do zaniechania ba- ne w inżynierii języki programowania, że są zastosowanie znalazła dopiero w XIX wieku,
dań nad tym, co potencjalnie mogłoby ca- paskudne. Oto na przykład czytam, jakim bo wcześniej nie było na nią zapotrzebowa-
łemu „biznesowi” przynieść korzyści, ale ja- to wspaniale eleganckim językiem jest Pro- nia. Dlatego też w technologiach stosowa-
ki jest „potencjał” tych korzyści nikt nie potra- log. Popatrzyłem na podpowiedziane przy- nych w przemyśle gorąco polecam dale-
fi ocenić. A przedsiębiorcy najczęściej ryzyku- kłady aplikacji GUI w Prologu i stwierdziłem, ko posunięty konformizm i trzymanie się z
ją wystarczająco dużo, żeby w kwestii tech- że... są straszliwie nieczytelne. Gdzie im do daleka od wszelkich ideologii. Nie oznacza
nologii pozwolić sobie na taktykę „lepszy wró- takiego np. Tk! I co, mam znów powtarzać to oczywiście, że nie należy być twórczym
bel w garści”. to banalne i oklepane stwierdzenie "kwe- i nie proponować dobrych pomysłów. Ale
W każdym zawodzie istnieje kwestia stia gustu"? Przemysłu to i tak nie interesu- trzeba pamiętać, że „każdy chce robić to,
„własnych upodobań” co do narzędzi pracy je, bo w przemyśle używa się takich techno- co chce, ale chce, żeby za to, że on robi
i informatycy nie są wyjątkiem. Prowadzi to logii, jakie przynoszą zysk, a nie takich, jakie to, co chce, płacili mu inni, którzy nie chcą,
często do dyskusji, w których rozdział mię- są „eleganckie”. A robienie interesów to nie żeby on robił to, co chce, ale chce, żeby
dzy własnym gustem a argumentami natury jest czysta i piękna sprawa, tylko kombino- robił to, czego oni chcą”. n
technicznej jest często bardzo płynny.Każdy wanie i robienie wszystkich dookoła w bam-
wie, że takie kryterium istnieje, każdy intuicyj- buko, dokładnie tak, jak to robi Microsoft,
nie wyczuwa, że jakoś-tam to jest określone, czy Sun. I wygrywa ten, komu się ta sztuka
ale na pytanie, czy można zrobić jakiś wery- uda, a nie ten, kto stworzy lepszą, czy bar- O autorze
fikator kodu, który sprawdzałby czytelność dziej elegancką technologię.
Autor interesuje się psychologią, progra-
programu, każdy programista odpowie jed- To oczywiście powoduje, że często „pa-
mowaniem, muzyką, publicystyką i ję-
noznacznie przecząco. Oczywiście, mamy skudne technologie zwyciężają” i biorą gó- zykoznawstwem, a w wolnych chwilach
wiele narzędzi do weryfikacji kodu, różne lin- rę nad tymi, które są „estetyczne” i „eleganc- pracuje etatowo jako programista.
ty, klocworki itp. bajery, ale jeśli ktoś sądzi, że kie”, a gorsze technologicznie narzędzia bio-
Kontakt z autorem:
istnieje jakiś związek pomiędzy np. złożono- rą górę nad lepszymi. Oczywiście to gorsze
ethouris@gmail.com
ścią cyklomatyczną, a czytelnością kodu... za jakiś czas staje się lepsze, bo się rozwija,
ites
Recommended s
www.buyitpress.com
Prosimy wypełnić czytelnie i przesłać faksem na numer: (22) 887 10 11 lub listownie na adres: Software-Wydawnictwo Sp. z o.o.,
Bokserska 1, 02-682 Warszawa, e-mail: pren@software.com.pl. Przyjmujemy też zamówienia telefoniczne: (22) 887 14 44
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
ROZWIĄZANIA
Wielojęzyczne
portale z wykorzystaniem eZ publish
Przedstawimy krok po kroku jak postawić 3-języczny
portal newsowy z wykorzystaniem eZ publish
ROZWIĄZANIA
XAJAX – łatwy AJAX dla programistów PHP
Pokażemy jak zrealizować formularz logowania, któ-
ry notyfikuje bez przeładowania o błędnym loginie
i/lub haśle. Wskażemy też gdzie, po kliknięciu zakład-
ki ładowania jest nowa strona. Oraz: dodaj/usuń do/z
ulubionych–realizujemy za pomocą AJAX.
NARZĘDZIA
Flashowe interfejsy WWW,
czyli PHP i Action Script w akcji
Pokażemy, jak wykorzystać najnowsze możliwości
Flasha do budowania zaawansowanych GUI dla apli-
kacji PHP. Przedstawimy zalety programowania zda-
rzeniowego i frameworka AsWing.