84

Php Solutions 1 2006 PL

  • Upload
    yahuto

  • View
    1.890

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Php Solutions 1 2006 PL
Page 2: Php Solutions 1 2006 PL
Page 3: Php Solutions 1 2006 PL
Page 4: Php Solutions 1 2006 PL

Spis treści

PHP Solutions Nr 1/2006www.phpsolmag.org4

Spis treści

PHP Solutions Nr 1/2006 www.phpsolmag.org 5

Nie odkrywajmy Ameryki na nowo!

Znam wielu programistów PHP, którzy piszą swoje apli-kacje bazując wyłącznie na własnych rozwiązaniach

– rozwijają frameworki, tworzą proste narzędzia do debu-gowania, czy próbują sami walczyć z niedopasowaniem relacyjno-obiektowym (narzędzia ORM) w aplikacjach bazo-danowych. Za nic nie określiłbym ich mianem domorosłych programistów webowych – to deweloperzy z kilkuletnim

doświadczeniem, którzy PRAWIE profesjonalnie tworzą CRM-y czy dedyko-wane CMS-y. Kiedy opowiadają mi o swoich problemach (programistycznych), rozwiązaniach i pomysłach, przyznaję – ich twórczość i innowacyjność robi na mnie wrażenie. Z reguły jednak odpowiadam im następująco: słuchaj, przecież pisaliśmy już o tym w PHP Solutions.

Ich praca jest często mało wydajna, gdyż sami odkrywają i implementują rzeczy już wcześniej wymyślone i zbudowane. Dzieje się tak dlatego, gdyż są nieufni i nieświadomi wielu pożytecznych i istniejących już rozwiązań. Z tego powodu użyłem sformułowania PRAWIE profesjonalnie.

Aby tę tendencję odwrócić, regularnie oddajemy w Wasze ręce magazyn PHP Solutions. Projekty i technologie, które opisujemy w obecnym numerze, na pewno pomogą Wam w codziennej pracy.

Szczególnie zachęcamy do budowania aplikacji w oparciu o technologię AJAX, która – dzięki wykorzystaniu JavaScriptu i XML-a – pozwala na two-rzenie wydajnych i wyjątkowo interaktywnych aplikacji WWW. Zastosowanie AJAX uwolni użytkownika od irytującego klikania i zbędnego oczekiwania – teraz dane mogą być przekazywane bez przeładowywania strony.

Gorąco polecam też artykuł o narzędziu PHPUnit (odpowiednik Junit dla Javy) służącym do testowania modułów aplikacji. Dzięki niemu zbudujecie stabilny i pozbawiony błędów kod w dużo krótszym czasie.

W numerze weźmiemy również pod lupę kilka absolutnych nowości, m.in. PHP-GTK2, które oferuje rewolucyjne możliwości budowania aplikacji okienkowych. SDO to kolejne rozwiązanie ze świata Javy przeniesione do PHP przez IBM i Zend Technologies, które zapewniając jednolity dostęp do różnego typu danych (bazy danych, XML). Drupal to rewolucyjny CMS po-zwalający na tworzenie wielodomenowych, wielojęzycznych i modularnych portali z wykorzystaniem takich technologii, jak AJAX.

Zapraszam do lektury kolejnego numeru PHP Solutions. Satysfakcja gwarantowana!

Dariusz PawłowskiRedaktor prowadzący

POCZĄTKIOtwarty format OASIS dla dokumentów biurowych i CMS-ów 16

Bård FarstadWklejanie czystego tekstu do CMS-a i jego ręczne formatowanie jest zadaniem żmudnym i podatnym na błędy. Gdyby tak można było stworzyć odpo-wiedni dokument w swoim ulubionym pakiecie biu-rowym, a potem po prostu skopiować plik i wkleić go do CMS-a... Taką właśnie możliwość daje połą-czenie trzech nowatorskich produktów: uniwersal-nego formatu OpenDocument, CMS-a eZ publish i pakietu biurowego OpenOffice.org 2.0.

NARZĘDZIAProgramowanie sterowanetestami za pomocą PHPUnit 22

Timo HaberkernIm większy projekt programistyczny, tym trudniej wyłapywać pojawiające się w nim błędy, a usunię-cie jednych usterek powoduje często powstanie następnych, w innej części aplikacji. Ręczne tworzenie testów dla setek klas jest nieskuteczne, a poza tym przyprawia o ból głowy i paraliżuje pracę. Z pomocą przychodzi PHPUnit: narzędzie pozwalające zautomatyzować proces tworzenia i wdrażania testów.

Drupal, czyli wielodomenowe, wielojęzyczne i modularne portalew oparciu o AJAX i SEO 30

Uwe HermannCzy potrzebujesz systemu zarządzania treścią (CMS) ogólnego zastosowania, będącego w stanie obsługiwać w jednej instancji kilka niezależnych serwisów WWW, z których każdy dostępny ma być w kilku wersjach językowych? Czy pełna internacjo-nalizacja powinna być możliwa za pomocą zaledwie kilku kliknięć myszą? Może chciałbyś także dodać do swojego serwisu elementy dynamiczne korzy-stające z AJAX, albo zwiększyć jego popularność dzięki zastosowaniu najlepszych technik SEO? Nie musisz dalej szukać: wypróbuj system Drupal.

TECHNIKIService Data Objects,czyli standard uniwersalnegodostępu do danych 42

Piotr SzarwasRozwiązania od dawna stosowane w Javie zale-wają świat PHP. Należy do nich SDO, czyli Servi-ce Data Objects: zunifikowany, wspierany przez takie potęgi, jak IBM, Zend i BEA standard do-stępu do danych, eliminujący potrzebę tworzenia osobnych interfejsów dla każdego ich źródła.

niemieckim włoskimfrancuskimpolskim

Nasz magazyn ukazuje się w czterech językach!

Jeśli jesteś zainteresowany zakupem licencji na wydawanie naszych pism prosimy o kontakt:Monika Godlewska [email protected] tel.: 48 22 887 12 66, fax: 48 22 887 10 11

Page 5: Php Solutions 1 2006 PL

Spis treści

PHP Solutions Nr 1/2006www.phpsolmag.org4

Spis treści

PHP Solutions Nr 1/2006 www.phpsolmag.org 5

AJAX – wyjątkowo interaktywnei wydajne aplikacje WWW 48

Joshua Eichorn, Werner M. KraußPHP zawdzięcza swój sukces nie tylko potężnym możliwościom, ale również samemu modelowi programowania. Aplikacje tworzone w PHP pozwalają osiągnąć bardzo wiele przy ograni-czonym oprogramowaniu klienckim, co oznacza łatwe wdrażanie i aktualizacje, a tym samym szybkie efekty pracy. Architektura ta ma też dotkli-we wady, jak opóźnienia między wyświetlaniem kolejnych stron lub brak możliwości pobierania nowych danych bez wysyłania formularza. Na szczęście istnieje mechanizm AJAX.

PROJEKTYadvAJAX, czyli praktyczne zastosowanie technologii AJAX 58

Łukasz LachCiągłe przeładowywanie strony WWW przy każ-dej zmianie jej zawartości i żmudne czekanie na wyświetlenie kolejnej porcji danych jest zmorą każdego użytkownika aplikacji webowych i pro-gramisty PHP. Nie jesteśmy jednak skazani na te bolączki: wybawia nas od nich zyskująca na znaczeniu PHP technologia AJAX. Dzięki niej ładujący się w nieskończoność pasek postępu przechodzi do lamusa.

Nowe możliwości PHP-GTK2 64

Pablo Dall'OglioRozszerzenie PHP-GTK1 zapoczątkowało nowy sposób myślenia o PHP. Język przeznaczony dla aplikacji sieciowych zaczął być powszechnie stosowany przy pisaniu samodzielnych aplikacji klienckich z graficznym interfejsem użytkownika (ang. Graphical User Interface, GUI). Niemniej jednak, to właśnie pojawienie się PHP-GTK2, umożliwiającego połączenie możliwości PHP5 i biblioteki Gtk-2.6, może dać początek prawdzi-wej rewolucji.

VARIAPorównanie ofert polskich firm hostingowych 74

Paweł GrzesiakRynek usług hostingowych w Polsce rozwija się dynamicznie. Jeżeli planujemy zakup własne-go skrawka miejsca w sieci, warto zapoznać się z przygotowanym przez nas porównaniem usług najpopularniejszych polskich providerów internetowych.

Aktualności 6

Opis CD 8

Wszystkie listingi z artykułów zostały zamieszczone na naszej stronie internetowejpod adresem www.phpsolmag.org/pl

Pytania dotycząceprenumeratytel. (22) 887 14 44e-mail: [email protected] Wydawnictwo Sp. z o.o.dział prenumeratyul. Piaskowa 301-067 Warszawa

CDtel. (22) 887 14 44e-mail: [email protected] Wydawnictwo Sp. z o.o.Defekty CD/DVDul. Piaskowa 301-067 Warszawa

Zamówienia /Numery archiwalnetel. (22) 887 14 44e-mail: [email protected] on-line: www.shop.software.com.pl

Kontakt z redakcjąe-mail: [email protected] Wydawnictwo Sp. z o.o.Redakcja PHP Solutionsul. Piaskowa 301-067 Warszawa

Strona WWW/Forumstrona www: www.phpsolmag.orgTu znajdą Państwo informacjedotyczące aktualnych i przyszłychnumerów magazynu PHP Solutions.

Forum: www.phpsolmag.org/newforumZachęcamy do dyskusji na naszymforum. Czekamy na propozycjetematów, które chcieliby Państwoznaleźć w najbliższym numerze pisma. Zapraszamy także do wymianypoglądów z innymi fanami PHP.

Cena Prenumerata: 135 złPrzelew na konto nr:46 1440 1299 0000 0000 0391 8238 Nordea Bank Polska S.A.II Oddział w Warszawie

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

Dyrektor Wydawniczy: Jarosław SzumskiMarket Manager: Sylwia Tuśnio [email protected] Manager: Maciej Krawcewicz [email protected] prowadzący: Dariusz Pawłowski [email protected]: Krzysztof Sobolewski [email protected] CD: Krzysztof SobolewskiStali współpracownicy: Paweł Kozłowski [email protected], Paweł Grzesiak [email protected] produkcji: Marta Kurpiewska [email protected] okładki: Agnieszka MarchockaSkład i łamanie: Agnieszka Zadrożna [email protected]ł reklamy: [email protected]: Marzena Dmowska [email protected]ład: 6 000 egz.

Adres korespondencyjny: Software-Wydawnictwo Sp. z o.o., ul. Piaskowa 3, 01-067 Warszawa, Polskatel. +48 22 887 10 10, fax +48 22 887 10 11www.phpsolmag.org [email protected]

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

Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących mu nośnikach informacjei programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantujetakż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 firmi zostały użyte wyłącznie w celach informacyjnych.

Redakcja używa systemu automatycznego składu Do tworzenia wykresów i diagramów wykorzystano program firmy

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

Druk: ArtDruk

Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy technicznej w instalowaniui 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ą.

Pismo ukazuje się w następujących wersjach językowych: polskiej , francuskiej , niemieckiej oraz włoskiej .

Page 6: Php Solutions 1 2006 PL

Aktualności

PHP Solutions Nr 1/2006www.phpsolmag.org6

PHPAuditPHPAudit to rozbudowany i bardzo funkcjonal-ny dedykowany system dystrybucji i licencjono-wania oprogramowania, które tworzymy w PHP. Zapewnia wiele gotowych rozwiązań w zakresie licencjonowania skryptów, pozwalając ogra-niczać ich wykonywanie do jednej instalacji, określonej domeny lub podanych adresów IP. PHPAudit może współpracować z koderem IonCube.http://phpaudit.com/

PEAR 1.4.0Wraz z wersją 1.4.0, instalator PEAR osiągnął dojrzałość. Najważniejszą nowością jest wprowadzenie obsługi i możliwości tworzenia własnych kanałów (PEAR Channels), czyli niezależnych od serwera pear.php.net repo-zytoriów pakietów, które możemy instalować używając polecenia pear. Pozwala to na wy-godną dystrybucję własnego oprogramowania. PEAR 1.4.0 potrafi też rozpakowywać archiwa, w których umieszczono kilka aplikacji (jest to tzw. bundling). Wydzielono również osobne polecenie do obsługi archiwów PECL-a, a także poprawiono wiele błędów z poprzednich wersji. http://pear.php.net/

Zend Core dla OracleWynikiem współpracy firm Oracle i Zend Technologies jest wypuszczenie na rynek wersji beta silnika Zend Core dla Oracle. Jest on cer-tyfikowanym, łatwym w instalacji środowiskiem PHP ze zintegrowaną obsługą bazy Oracle. Oprogramowanie zawiera uaktualniony ste-rownik OCI8, dzięki czemu udało się uzyskać większą stabilność i wydajność współpracy z produktami bazodanowymi Oracle. Zamiarem obu firm było stworzenie gotowego do użycia środowiska PHP do zastosowań korporacyj-nych, ułatwiającego rozwijanie oprogramowania opartego o PHP i bazę Oracle.http://zend.com

KPHPDevelopKPHPDevelop to środowisko programistyczne (IDE, ang. Integrated Development Environ-ment) pracujące pod KDE. Jest udostępniane bezpłatnie i oferuje standardową funkcjo-nalność, jak na aplikację tego typu. Koloruje składnię, podpowiada nazwy funkcji oraz parametry wejściowe oraz pozwala na sprawne zarządzanie wszystkimi plikami, które składają się na projekt. Godna uwagi jest obsługa baz danych, z analizatorem zapytań SQL na czele.http://kphpdev.sourceforge.net

Net_CurlUkazała się wersja 1.2.2 biblioteki Net_Curl, która wprowadza obiektowy interfejs do rozsze-rzenia cURL. Przyda się głównie programistom tworzącym aplikacje zorientowane obiekto-wo. Wszystkie nazwy funkcji i ich parametry wejściowe pozostają bez zmian w stosunku do cURL. Jedyna różnica polega na tym, ze odwołujemy się do nich jak do metod.http://pear.php.net/package/Net_Curl

HTML_Safe 0.9.0alpha1Wciąż rosnące zagrożenie ze strony ataków XSS powoduje powstawanie coraz większej ilości bibliotek do walidacji wprowadzanych przez użytkownika danych. XHTML_Safe to narzędzie należące do repozytorium PEAR, pozwalające dokładnie sprecyzować, jakie dane mają prawo być kontrolowane, a jakie nie (możliwość stworzenia dokładnej listy tagów). Parser biblioteki usunie potencjalnie niebez-pieczne części kodu HTML, w tym niezamknię-te znaczniki, skrypty JavaScript oraz wszystkie inne tagi, które mogą się okazać zagrożeniem.http://pear.php.net/package/HTML_Safe/

Pro-PHP Podcast

Chcesz posłuchać, co mają do powie-dzenia czołowi programiści PHP na

świecie? Zacznij słuchać podcastów o te-matyce związanej z PHP. Słowo podcast powstało z połączenia słów broadcasting (transmisja) oraz iPod (znany wszystkim przenośny odtwarzacz plików mp3). W na-szym przypadku podcastami będą audycje zapisane w plikach MP3.

PHP podcast to najbardziej udane przedsięwzięcie tego typu dla świata PHP. W rozmowach, wywiadach i debatach biorą bowiem udział pionierzy PHP, czyli ludzie najbardziej aktywni w środowisku. Za pośrednictwem audycji usłyszymy ich komentarze, a także myśli i pomysły odnoszące się do PHP. Tematyka kon-centruje się zdecydowanie wokół zaawan-sowanych aspektów programowania.

Jeżeli więc chcemy posłuchać, co ma do powiedzenia Greg Beaver na temat no-wego PEAR-a, czy Paul M. Jones, twórca Savanta i SOLAR-a, to nic nie stoi na przeszkodzie. Wystarczy wejść na stronę, pobrać odpowiednią audycję i uruchomić ją na komputerze albo na przenośnym odtwarzaczu, np. w drodze do pracy czy podczas przerwy w zajęciach. Wszyst-

kie audycje są bezpłatne i dostępne dla każdego, bez konieczności rejestracji lub wykonywania jakichkolwiek dodatkowych czynności. Podcast to doskonała metoda na odświeżenie słownictwa używanego w środowisku programistów PHP, która może okazać się szczególnie przydatna podczas prezentacji konferencyjnej w ję-zyku angielskim.

Nowe audycje ukazują się z częstotli-wością jednej na dwa tygodnie.

http://www.pro-php.com/

MySQL 5.0RC

Ukazała się prawdopodobnie najważ-niejsza odsłona systemu bazodano-

wego MySQL w historii: 5.0 RC. Poprze-dziły ją liczne wersje beta. Liczba pobrań przekroczyła ponad dwa miliony.

Piąta odsłona MySQL-a szykuje wie-le możliwości, które będą interesujące przede wszystkim dla zaawansowanych programistów. Istotę nowości wprowadzo-nych w tej wersji dobrze oddają trzy sło-wa: widoki (ang. views), wyzwalacze (ang. triggers) i transakcje (ang. transactions).

Widoki tworzymy w celu ogranicze-nia dostępu do danych zgromadzonych w tabelach. Każdy widok może zawierać dane umieszczone w różnych tabelach, a użytkownik ma wrażenie, że pracuje na normalnej, rzeczywistej tabeli. Stanowiące drugą nowość wyzwalacze są proce-durami uruchamianymi pod warunkiem wystąpienia jakiegoś zdarzenia. Przykła-dowo, gdy użytkownik spróbuje usunąć dane z którejś z tabel, wyzwalacz wykona zaprogramowaną wcześniej procedurę. Można w ten sposób zapobiec rozher-metyzowaniu danych. Trzeci element wprowadzony w MySQL 5.0, transakcja,

to nierozerwalny blok operacji (zapytań), cechujący się tym, że gdy choć jedno z nich nie będzie wykonane poprawnie, w systemie nie zostanie zapisany rezultat żadnego z nich.

W MySQL 5.0 wprowadzono ponadto wiele usprawnień wydajności (w szcze-gólności InnoDB), obsługę kursorów, zaawansowane zarządzanie procedurami i funkcjami użytkownika. Rozszerzono również rozmiar danych typu VARCHAR do 65532 bajtów. Należy wspomnieć także o implementacji dwóch nowych silników do obsługi danych: ARCHIVE (rozległe bloby) i FEDERATED (dla rozwiązań zdalnych).

Podsumowując: zmiany dokonane w wersji 5.0RC MySQL-a są poważnym argumentem na rzecz migracji na tę plat-formę bazodanową.http://mysql.org

Page 7: Php Solutions 1 2006 PL

Aktualności

PHP Solutions Nr 1/2006 www.phpsolmag.org 7

lchash 0.9.1LCHASH to mała biblioteka, która zapewnia dostęp do natywnych tablic rozproszonych (ang. Hash Tables), dostępnych w bibliotece libC. Korzystając z tego mechanizmu można bardzo szybko i efektywnie tworzyć oraz przechowywać duże porcje danych, używając przy tym jedynie pamięci podręcznej. Rozwią-zanie to jest co prawda trochę wolniejsze od tablic PHP, lecz wykorzystuje znacznie mniej pamięci. http://pecl.php.net/package/lchash

File 1.2.2Ukazała się wersja 1.2.2 narzędzia File umożli-wiającego obiektowy dostęp do plików. Zawiera ona zestaw metod, które w znaczący sposób przyspieszają wykonywanie operacji na plikach. Przydatny może okazać się także interfejs do obsługi plików zapisanych w formacie CSV.Licencja: PHPhttp://pear.php.net/package/File/

CodeGen_MySQL_UDFIstnieją dwa sposoby dodawania nowych funkcji do MySQL-a. Pierwszą jest wbudowanie ich do natywnego kodu MySQL-a i skompilowanie serwera bazodanowego. Drugą jest dodanie funkcji poprzez interfejs UDF (ang. user-defi-nied function). Z tej możliwości korzysta biblio-teka UDF_Gen, której zadaniem jest ułatwianie dodawania funkcji do MySQL-a. UDF_Gen czyta konfigurację, prototypy funkcji i fragmenty kodu z pliku XML i generuje gotowe do użycia rozszerzenie UDF. Przyda się każdemu, kto chcąc przyspieszyć swoje aplikacje, powierza niektóre zadania bazie danych.http://pear.php.net/package/CodeGen_MySQL_UDF/

DB_QueryTool 1.0.1DB_QueryTool to narzędzie pozwalające tworzyć zapytania bazodanowe w oparciu o paradygmat obiektowy. Umożliwia budowanie kwerend przy pomocy metod takich, jak setWhere(), setGroup(), setJoin(), itp. W ten sposób rozległe zapytania wyglądają na bardzo uporządkowane i takimi w istocie są. Dokonywanie późniejszych zmian w kodzie staje się znacznie łatwiejsze. Warto jeszcze dodać, że trendem w tworzeniu modułów działających pod PHP5 jest całkowite przejście wszystkich bibliotek na model obiektowy.http://pear.php.net/package/DB_QueryTool/

PHPRunnerPHPRunner to narzędzie do zautomatyzowane-go tworzenia interfejsów bazodanowych w PHP. Twórcy zapewniają, że za jego pomocą można całkowicie uniknąć własnoręcznego programo-wania. Generuje strony WWW na podstawie danych wprowadzonych w panelu i pozwala zabezpieczyć je hasłem oraz dodać formularz logowania. Stworzony interfejs może być wielojęzyczny. Wbudowany do PHPRunnera klient FTP pozwala automatycznie zamieszczać stronę WWW na serwerze.http://www.xlinesoft.com/phprunner/

phpHtmlLib 2.5.4Pojawiła się wersja 2.5.4 phpHtmlLib – zbioru klas i bibliotek służących do budowy, debugo-wania i przetwarzania dokumentów zapisanych w formatach XML, HTML, XHTML, WAP/WML oraz SVG (Scalable Vector Graphics). Do phpHtmlLib dochodzi zaawansowany analizator formularzy, który pozwala budować złożone formularze HTML/XHTML. W wersji 2.5.4 po-prawiono wiele błędów i dodano parę nowości, takich jak możliwość szeregowania w klasie FEComboListBox czy całkowicie nowe klasy (DataObjectDataListSource i FEColorPicker).Licencja: LGPLhttp://phphtmllib.newsblob.com/

Zend Platform 2

Firma Zend Technologies ogłosiła nową wersję swojej platformy do

zarządzania aplikacjami PHP. Zend Plat-form 2 ma łączyć w sobie takie cechy jak niezawodność, skalowalność i zgodność wymaganą w ważnych aplikacjach biz-nesowych. Dla bardzo obciążonych ser-werów przewidziano Klastrowanie Sesji (ang. Session Clustering), czyli efektywną wymianę danych sesyjnych pomiędzy serwerami pracującymi w strukturze kla-stra. W ten sposób serwery pracujące w klastrze mogą skuteczniej wyrównywać obciążenie pomiędzy sobą. Wg oficjalnych danych Zend, Klastrowanie Sesji powodu-je nawet dziesięciokrotny wzrost wydajno-ści aplikacji.

Kolejną ważną funkcjonalnością Zend Platform 2 jest PHP Intelligence: system oparty na zdarzeniach, służący do prze-prowadzania analizy aplikacji PHP w cza-sie rzeczywistym. Jego wykorzystanie pozwoli nam na skuteczniejsze odnajdy-wanie błędów spowodowanych ciągłymi zmianami dokonywanymi w kodzie pro-gramów. Zaprezentuje nieużywane funk-

cje, błędy zaistniałe podczas połączeń, czy też błędy w samym kodzie. Teraz będzie można prześledzić problemy, do-cierając do ich źródła.

Nowa wersja platformy Zend to rów-nież szybsze wykonywanie aplikacji PHP. PHP Performance Managment odpo-wiada za akcelerację kodu, dynamiczne buforowanie danych wyjściowych oraz kompresję danych, która pozwala ograni-czyć do 10% nominalny transfer danych.

PHP/Java Integration Bridge to ko-lejna ciekawa cecha Zend Platform 2. Jak sama nazwa wskazuje, jest to most pomiędzy światami PHP i Javy, umożli-wiający m.in. korzystanie z bibliotek i klas Javy z poziomu PHP (w tym bezpośred-nie wywoływanie metod tych klas).

Podsumowując: opisane rozwiąza-nia dają ogromne możliwości i powinny zainteresować korporacje, które tworzą i korzystają ze złożonych aplikacji napisa-nych w języku PHP.

http://zend.com/

Roundcube Webmail Project

Choć bezpłatnych programów do ob-sługi poczty przez WWW jest wiele,

w Roundcube jest coś, co zwraca uwagę. Narzędzie to ma szczególnie estetyczny i funkcjonalny wygląd, charakterystyczny dla aplikacji pracujących na platformie Macintosh.

Roundcube jest łatwy w instalacji i konfiguracji. Działa w oparciu o PHP oraz systemy bazodanowe, takie jak: MySQL, PostgreSQL oraz SQLite (któ-rego popularność rośnie wraz z rozwo-jem PHP5).

Motywy graficzne aplikacji stwo-rzone zostały w oparciu o standardy projektowania stron WWW, takie jak XHTML i CSS 2.0. Roundcube jest aplikacją dostępną w różnych wersjach językowych, obsługuje typy MIME i wia-domości w formacie HTML. Pozwala również wysyłać załączniki (ang. at-tachments) do wiadomości. W aplikację wbudowano prostą książkę adresową, możliwość tworzenia katalogów i sys-tem buforowania, przyspieszający pra-cę całej aplikacji. Ponieważ Roundcube wciąż jest w stadium rozwoju alfa, wiele opcji nie zostało jeszcze zaimplemento-wanych.

Wśród funkcji, które producent planu-je, znajduje się przekazywanie wiadomo-ści wraz z załącznikami, wyszukiwarka wiadomości, obsługa filtrów i reguł, wspar-cie dla standardu VCard (wizytówki), moż-liwość importu oraz eksportu maili, edytor wiadomości HTML (typu WYSIWYG), narzędzia do sprawdzania pisowni czy wsparcie dla GPG/PGP.

Produkt udostępniany jest na licencji GPL. Jego działanie przetestowano na przeglądarkach Firefox 1.0, Safari 2.0, Opera 8.0 oraz Internet Explorer 6.0. Ro-undcube działa w nich prawidłowo.

http://roundcube.net/

Page 8: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org8

Opis CD

GregariusAgregator RSS to aplikacja, która automa-tycznie pobiera i wyświetla aktualności z wielu kanałów RSS (również RDF i ATOM) jednocze-śnie. Gregarius to kompletny skrypt pełniący rolę agregatora. Pobiera z wielu wskazanych wcześniej źródeł internetowych świeże informa-cje, aby je następnie przetworzyć i wyświetlić na stronie głównej. Program oferuje sprawny mechanizm przeszukiwania wiadomości i generuje strony wynikowe w oparciu o XHTML i CSS. Do poważnych zalet narzędzia Grega-rius zalicza się również łatwa instalacja i prosty w obsłudze panel administracyjny. Licencja: GPLhttp://gregarius.net

LibchartTworzenie wykresów w PHP nie należy do najprzyjemniejszych czynności. Biblioteka Lib-chart próbuje to zmienić, oferując bardzo prosty interfejs do tworzenia wykresów słupkowych i kołowych. Produkt współpracuje z PHP4 i PHP5, a do pracy wymaga zainstalowanej biblioteki GD obsługującej FreeType. Pozwala umieszczać etykiety danych (m.in. na osiach) oraz tworzyć legendę. Projekt ma w miarę do-brą dokumentację (w tym tutorial). Najnowsza wersja Libcharta nosi numer 1.0.Licencja: GNU LGPLhttp://naku.dohcrew.com/libchart

User FilesWłasna usługa w rodzaju e-dysku (dysku internetowego, pozwalającego gromadzić swoje pliki na koncie dostępnym przez prze-glądarkę WWW)? Z User Files to bardzo pro-ste. Narzędzie to pozwala zarejestrowanym użytkownikom przechowywać pliki na dysku naszego serwera. By skorzystać z usługi, każdy użytkownik musi założyć swoje konto, podając swój prawdziwy adres e-mail. Możliwe jest jednoczesne przesyłanie wielu plików na serwer, określenie maksymalnych limitów objętości oraz ustalenie dozwolonych przez nas formatów plików. User Files potrafi zmieniać rozmiary obrazów i dodawać do nich opisy. Licencja: Freewarehttp://www.playth.com/scripts/userfiles/

HTML_Table_Matrix 1.0.8Łatwe i automatyczne tworzenie i uzupełnianie tabel staje się możliwe dzięki wykorzystaniu biblioteki HTML_Table_Matrix. Jest ona bardzo zaawansowanym rozwiązaniem i pozwala do-wolnie sortować dane, które chcemy wprowa-dzić do tabeli (rosnąco, malejąco, losowo, itd.), dbając przy tym o czystość kodu wynikowego tabeli. Podawanie wymiarów tworzonej tabeli nie jest wymagane, gdyż biblioteka sama doko-na obliczeń na podstawie umieszczanych w niej danych. Do działania HTML_Table_Matrix wymaga pakietu PEAR-owego HTML_Table.Licencja: PHP v3.0http://pear.php.net/package/HTML_Table_Matrix/

MP3_Playlist 0.5.0alpha1Były już skrypty do odczytu zawartych w pli-kach MP3 tagów ID3, a teraz przyszła pora narzędzie do obsługi list odtwarzania (ang. playlists). MP3_playlist pozwala na tworzenie i przetwarzanie tych list. Po uruchomieniu rozpocznie przeszukiwanie folderów w celu znalezienia plików MP3 i utworzenia z nich listy odtwarzania. Plik wynikowy możemy zapisać w wielu formatach: M3U, SMIL, a nawet XML i XHTML. Istnieje ponadto możliwość tworzenia kopii zapasowych list odtwarzania w oparciu o bazę SQLite.Licencja: PHPhttp://pear.php.net/package/MP3_Playlist/

HTML_Progress

Podczas przesyłania plików na ser-wer przydatny jest pasek postępu.

HTML_Progress to biblioteka należąca do repozytorium PEAR, która implemen-tuje takowy. Jej możliwości są naprawdę zaawansowane. Mamy do wyboru ponad 30 różnych typów paska postępu, w tym pionowe, poziome, w postaci okręgu, eliptyczne, kwadratowe i prostokątne. HTML_Progress może ponadto poka-zywać liczbowo procent przesłanych danych.

Wszystkie elementy układu paska są w pełni konfigurowalne na poziomie HTML, a biblioteka spełnia warunki zgodności ze standardami XHTML i CSS. Najmniejszych problemów nie powinna również sprawić integracja biblioteki HTML_Progress z systemami szablonów, takimi jak np. Smarty. Za generowanie kolejnych etapów postępu odpowiadają skrypty napisane w języku JavaScript.

Możemy umieszczać wiele pasków postępu na jednej stronie i nie wymaga to korzystania z wewnętrznych ramek (iframe). Użytkownik w każdej chwili może zatrzymać proces przesyłania

danych na serwer. Jedyne wymagania stawiane przez aplikację to dostęp do PHP oraz obsługa DHTML-a w przeglą-darce WWW. Biblioteka została stwo-rzona w oparciu o wzorzec projektowy Obserwator (ang. Observer), co po-zwala na dodawanie Listenerów. Pod-sumowując: HTML_Progress istotnie wzbogaci funkcjonalność naszych stron WWW.

Licencja: PHP License 3.0http://pear.php.net/package/HTML_Progress/

PhpPeanuts

Peanuts to zorientowany obiektowo framework do tworzenia aplikacji

w PHP. Programowanie z jego użyciem opiera się na architekturze kierowania modelami (ang. Model Driven Archi-tecture), która jest tworem stosunkowo świeżym, bazującym na założeniach programowania ekstremalnego (XP, ang. eXtreme Programming).

PhpPeanuts pokazuje swoje zalety już w bardzo wczesnych fazach rozwoju oprogramowania. Wystarczy stworzyć kil-ka komponentów aplikacji i tabel w bazie danych, a oprogramowanie automatycznie utworzy działający prototyp aplikacji.

Użytkownicy będą w stanie przete-stować prototyp i wyrazić swoją opinię na jego temat, co w rezultacie pozwoli efektywnie dopracować i uzupełnić pro-gram. Twórcy frameworka przygotowali łatwe w użyciu komponenty do genero-wania tabel, zakładek, formantów, okien dialogowych oraz wyszukiwania stron w bazach danych.

Kiedy tylko dokonamy zmian, phpPe-anuts błyskawicznie zaktualizuje interfejs użytkownika. Pozwala to maksymalnie

skrócić cykl rozwoju oprogramowania. Wszystkie części frameworka są skalo-walne, każda może zostać pominięta, poszerzona lub uzupełniona.

PhpPeanuts został napisany w PHP z wykorzystaniem HTMl-a i JavaScriptu. Może pracować na dowolnych konfigu-racjach i jest łatwy w instalacji. Intefejs użytkownika phpPeanuts całkowicie opiera się na wzorcu Model-Widok-Kon-troler, czyli MVC (ang. Model-View-Con-troller). phpPeanuts pozwala na jednoczesną obsługę wielu aplikacji na jednym serwerze.

Zdecydowanie polecamy ten frame-work zaawansowanym programistom, którzy posiadają duże doświadczenie w zakresie programowania zorientowa-nego obiektowo.

Licencja: Academic Free License v. 2.0http://www.phppeanuts.org/

Page 9: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006 www.phpsolmag.org 9

Opis CD

Time ManagementTime Management to prosty, ale funkcjo-nalny skrypt, który pełni rolę terminarza zadań. Użytkownik widzi typowy miesięczny kalendarz podzielony na oznaczone datami kratki, w których wpisane są czynności do wykonania o określonej godzinie. Nowe zadania przypisujemy do konkretnych dni i godzin, korzystając z bardzo wygodnego for-mularza. Możemy także edytować i kasować zadania znajdujące się na liście. Tę pierwszą czynność wykonujemy również za pomocą formularza. Zarządzanie kalendarzem jest możliwe dla zalogowanego użytkownika. Time Management wymaga dostępu do bazy My-SQL 4+, a jego instalacja jest bardzo prosta.Licencja: GPLhttp://phptime.us/

oci8 1.1.1Pojawiła się udoskonalona wersja interfejsu do obsługi baz Oracle. Narzędzie to korzysta z Oracle Call Interface (OCI). W tym, jak również poprzedzającym je o kilkanaście dni poprzednim wydaniu poprawiono wiele błę-dów, w tym błąd naruszenia ochrony pamięci (segmentation fault) czy problemy pojawiające się po użyciu funkcji oci_error() bez argumen-tów. Wprowadzono też obsługę keszowania oraz zewnętrznych list uwierzytelniających. Dodano również nowe opcje konfiguracji stałych połączeń oraz poprawiono błędne działanie funkcji oci_close(), odpowiedzialnej za zamykanie połączenia z bazą. Licencja: PHPhttp://pecl.php.net/package/oci8

Net_IPv6 1.0.5Biblioteka Net_IPv6 pozwala na stwierdzenie czy wprowadzony adres IP jest adresem z rodziny IPv6 –protokołu, który jest następ-cą IPv4. Umożliwia też sprawdzenie, czy adres IPv4 posiada końcówkę kompatybilną z IPv6. Wśród jego funkcji jest również kompresja i dekompresja adresów IPv6. Wdrażanie protokołu IPv6 rozpoczęto w roku 2000, a jego wprowadzenie ma zaradzić pro-blemowi kończącej się puli adresów w IPv4.Licencja: PHPhttp://pear.php.net/package/Net_IPv6/

pecl_http 0.13.0Biblioteka pecl_http implementuje rozsze-rzoną obsługę protokołu HTTP. Umożliwia tworzenie bezwzględnych URI oraz spełnia-jących warunki RFC przekierowań. Zapewnia zgodną z RFC obsługę daty. Pozwala parso-wać zarówno nagłówki, jak i treść wiadomo-ści. Umożliwia też buforowanie danych przez użycie nagłówka Last-Modified, a także wysyłanie danych, plików i potoków danych w różnych zakresach obsługi. Funkcjonal-ność biblioteki jest bardzo szeroka i przyda się twórcom zaawansowanych aplikacji internetowych.Licencja: PHPhttp://pecl.php.net/package/pecl_http

Math_Fraction 0.4.0Biblioteka Math_Fraction pozwala na wyświetlanie i manipulowanie ułamkami zwykłymi. Przy jej użyciu możemy dokony-wać podstawowych operacji arytmetycznych na ułamkach: porównywać je, odnajdywać największy wspólny dzielnik lub największą wspólną wielokrotność dwóch liczb całkowi-tych. Biblioteka pomoże przy upraszczaniu (redukcji) ułamków, zwróci także jego odwrot-ność. Pozwala również przekształcić liczbę całkowitą na ułamek. Math_Fraction znajduje się obecnie w stadium rozwoju beta.Licencja: PHPhttp://pear.php.net/package/Math_Fraction/

PHP121 Instant Messenger

PHP121 Instant Messenger to komu-nikator internetowy na stronie WWW,

nie różniący się wyglądem od komunikato-rów działających po stronie klienta.

Osoba, która chce korzystać z PHP121 Instant Messengera na naszej witrynie, musi się najpierw zarejestrować, podając swój identyfikator (login), hasło oraz adres e-mail. Po zalogowaniu się może rozmawiać z innymi użytkownikami, którzy w tym czasie przebywają w sieci.

Ciekawym zastosowaniem programu może być ułatwienie obsługi klientów, którzy aktualnie znajdują się na naszym sklepie internetowym i chcieliby nas o coś zapytać. Jego głównym przeznaczeniem jest jednak umożliwienie rozmów między zarejestrowanymi użytkownikami serwisu internetowego.

Istnieje osobne wydanie PHP121 IM, stworzone z myślą o użytkownikach pakietu PHPNuke. Integruje się ono z po-zostałą częścią portalu.

Wymagania, jakie stawia PHP121 Instant Messenger to parser PHP i baza MySQL. Po stronie przeglądarki musi być włączona obsługa JavaScriptu. W przy-

padku, gdy wybierzemy wydanie PHP-Nuke, potrzebny będzie również system PHPNuke w wersji nowszej niż 6.0.

Produkt dostępny jest w zasadzie bezpłatnie, lecz aby otrzymać jego naj-nowszą wersję, należy wesprzeć opro-gramowanie odpowiednim datkiem (co stanowi pewne kuriozum, gdy weźmiemy pod uwagę jego licencję). Tym niemniej, poprzednia wersja programu jest zawsze darmowa.

Licencja: GNU GPLhttp://www.php121.com/

DreamWeaver 8

DreamWeaver to nazwa znana każdemu chyba webmasterowi

i twórcy stron WWW. W ósmej odsłonie tego produktu odnajdziemy sporo zmian. Oprogramowanie zaoferuje nam większą stabilność, wydajność, nowe narzędzia oraz łatwiejszą obsługę.

W DreamWeaver 8 spotkamy się z nowym pomysłem na menu, które z rozwijalnego zamieniło się na zakład-kowe. Dla programistów przewidzianio nowy pasek narzędziowy usprawniają-cy formatowanie. Tam, gdzie chcemy lepiej zorganizować sobie duże partie kodu, przyda się możliwość rozwijania i zwijania jego fragmentów. Zaznaczając wybrane linie, grupujemy je, co pozwala na ich zwinięcie (schowanie), a następ-nie rozwinięcie.

Pomyślano również o twórcach desi-gnu, dodając opcję powiększania. Funk-cja ta, w połączeniu z linijką, pozwala na bardzo precyzyjne ustalanie takich parametrów, jak np. marginesy przygo-towywanej strony. Usprawniono również nawigator pozwalający poruszać się po stylach CSS, który jest teraz łatwiej do-stępny i posiada swój własny panel. Zaś

ulepszony rendering powoduje, że wy-gląd strony stworzonej w edytorze jest bardzo zbliżony do tego, co zobaczymy w oknie przeglądarki internetowej. Po-prawiono również obsługę XML-a, CSS, PHP, WebDAV, ColdFusion 6.0 MX i Flasha 8.0. Wciąż brakuje natomiast wsparcia dla AJAX-a. Udoskonalono za to synchronizację danych pomiędzy edytowanym kodem a serwerem FTP. Wszystkie operacje odbywają się w tle, dzięki czemu nie trzeba czekać, aż pro-ces się zakończy.

Licencja: komercyjnahttp://www.macromedia.com/software/dreamweaver/

Page 10: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org10

Opis CD

File_Find 1.0.1Jeżeli potrzebujemy biblioteki do przeszuki-wania dużej ilości plików, powinniśmy zwrócić uwagę na bibliotekę File_Find. Obsługuje poszukiwanie rekurencyjne (ang. recursi-ve), co oznacza, że zagląda do wszystkich katalogów podrzędnych. Biblioteka pozwala na odnajdywanie plików, których nazwy spełniają postawione założenia. Możemy również szukać ciągu znaków wewnątrz plików podając określony szablon. File_Find sporządzi ponadto mapę plików w katalogu oraz rekursywną mapę wszystkich plików i katalogów podrzędnych.Licencja: PHPhttp://pear.php.net/package/File_Find/

HTTP_Session 0.5.1Prezentowana biblioteka jest interfejsem obiektowym dla funkcji z rodziny session_*. Oprócz typowej zamiany nazw funkcji na nazwy metod, mamy do czynienia z paroma dodatko-wymi możliwościami, takimi jak składowanie danych o sesjach w bazach danych przy użyciu pakietów (Pear) DB, MDB, MDB2. Pojawiają się również nowe metody, w tym: isNew(), useCookies(), setExpire(), setIdle(), isExpired(), isIdled() i inne.Licencja: PHPhttp://pear.php.net/package/HTTP_Session/

crack 0.4Ukazała się w pełni stabilna wersja narzędzia crack, nosząca nxumer 0.4. Zadaniem cracklib jest sprawdzanie jakości haseł. Dokonuje ono setek testów, mających na celu ustalenie, czy wybrane przez nas hasło jest trudne do odgadnięcia, czy też nie. Wykorzystuje do tego słownik, sprawdzając czy jako hasła nie używa-my powszechnienie znanego słowa. Biblioteka próbuje też znaleźć podobieństwo hasła do nazwy użytkownika. Ostatecznie uzyskuje-my informację, czy wybrane przez nas hasło spełnia podstawowe zasady bezpieczeństwa. Crack bazuje na bibliotece libcrack, która jest standardowo dostępna w większości systemów unixowych. W wersji 0.4 narzędzia crack, za-pewniono zgodność z PHP 4.1 oraz współpracę z PEAR 1.4.0. Dodano także wersję binarną dla Windows.Licencja: PHPhttp://pecl.php.net/package/crack

html2ps 0.7.1Biblioteka html2ps oferuje funkcjonalność zbliżoną do jej odpowiednika napisanego w Perlu. Jej zadanie polega na konwertowa-niu dowolnego dokumentu HTML (również zawierającego DHTML) lub XHTML do formatu PostScript. Pozwala ustawiać m.in. orientację strony (pozioma lub pionowa) i rozmiar papieru w dokumencie wynikowym. Biblioteka radzi sobie z obrazkami, skomplikowanymi tabelami (również tymi używającymi tagów rowspan i colspan), warstwami, znacznikami <div> oraz stylami CSS. W nowej wersji dokonano wielu udoskonaleń w metodzie odpowiedzialnej za zwracanie dokumentu wynikowego (biblioteka PDFLIB), m.in. poprawiono obsługę bloków.Licencja: GPLhttp://www.tufat.com/script19.htm

PHPlist 2.10.1PHPList to jeden z najpopularniejszych i naj-lepszych programów do masowego rozsyłania poczty elektronicznej (mailingu) i tworzenia newsletterów. Aplikację przeznaczono do obsługi wielu list mailingowych, wzbogacając ją o mecha-nizm pozwalający gościom naszej strony zapisy-wać się na wybrane listy. W nowej wersji (2.10.1) dodano wiele nowych funkcji. Najważniejszą z nich jest edytor WYSIWYG, którego rolę pełni znany produkt o nazwie FCK Editor 2, pracujący zarówno pod przeglądarką Firefox, jak i Mozilla.http://www.phplist.com

PHP/Java Bridge

PHP/Java Bridge, czyli most pomiędzy PHP a Javą to moduł PHP, który po-

zwala na połączenie systemu obiektowe-go PHP z systemem Javy lub ECMA. Jest dostępny jako java.so (pod Linuksa) lub php_java.dll (pod Windows). Tam, gdzie to możliwe, implementuje JSR 223 (język skryptowy Javy) i może być używany do połączenia z językami CLR (wspólnego środowiska uruchomieniowego, stanowią-cego podstawę frameworka Microsoftu .NET), takimi jak VB.NET, czy C#.

Podstawowym środowiskiem, z któ-rym moduł ten umożliwia połączenie, jest Java, włączając w to również takie rozwiązania, jak KAWA czy Jruby. Aby zapewnić efektywną wymianę informacji, most pomiędzy PHP, a Javą komunikuje się z wirtualną maszyną Javy (ang. Java Virtual Machine) przy użyciu lokalnych portów. Dzięki PHP/Java Bridge możemy odwoływać się bezpośrednio do Javy, korzystając z typowej składni PHP. Ten fakt w znaczący sposób ułatwia pracę z zewnętrznymi aplikacjami tworzonymi w języku Java.

PHP/Java Bridge przyda się fir-mom, które doceniając możliwości PHP

chcą powoli rezygnować z rozwiązań opartych o Javę oraz integrować swoje oprogramowanie z PHP.

Już dziś obserwujemy wzrastającą tendencję migracji z Javy na PHP. Wi-dać to choćby po coraz liczniejszych projektach, próbujących przenieść funk-cjonalność Javy do PHP, co jest w dużej mierze spowodowane nowym, ulepszo-nym modelem (i silnikiem) obiektowym PHP5.

Problemem PHP/Java Bridge może się jednak okazać jego jego niewystar-czająca wydajność. Zaleca się więc sto-sowanie tego rozwiązania wszędzie tam, gdzie nie istnieje zagrożenie przeciążenia serwera, czyli głównie w rozwiązaniach intranetowych oraz ekstranetowych. Pod-sumowując: kolejny dobrze pomyślany projekt, który przysparza popularności PHP i pozwala temu językowi zdobywać następne zastosowania i przełamywać kolejne bariery.

Licencja: PHP Licensehttp://php-java-bridge.sourceforge.net/

PHPBeans

PHPBeans jest serwerem obiektów i zgodnie z aktualną tendencją, sta-

nowi kolejne rozwiązanie przeniesione z Javy. Jest oparty o specyfikację RMI, czyli Remote Method Invocation (zdalne wykonywanie metod). Jego działanie opiera się na relacji klient-serwer. W roli tego drugiego występuje PHPBeans Object Server, stanowiący repozytorium, w którym umieszczamy wszystkie nasze klasy przeznaczone do udostępnienia aplikacjom klienckim.

Interfejsem klienta jest z kolei Php-Beans Client API. Może on połączyć się zdalnie z serwerem w celu wykona-nia zgromadzonych tam metod. Przyda się to szczególnie tam, gdzie istnieje wiele rozproszonych instancji jednej aplikacji. Istnieją dwie wersje oprogra-mowania klienckiego: jedna z nich jest przeznaczona dla PHP, a druga dla Ruby'ego (niezależny skryptowy język obiektowy). Oprogramowanie serwera i klienta pobieramy oddzielnie.

Do wymiany informacji między serwerem a klientem służy phpBeans Protocol. Nie został on oparty na po-

pularnych protokołach dla Web Servi-ces, takich jak SOAP czy XML-RPC. Twórcy phpBeans Protocol wykorzystali własne, dedykowane rozwiązania, by komunikacja była łatwa, szybka i efek-tywna.

PhpBeans to jednak nie tylko opro-gramowanie klienta i serwera. To przede wszystkim metoda dostępu do klas ulokowanych poza naszym środowi-skiem pracy. PHPBeans to rozwiązanie kierowane do twórców zaawansowa-nych, komercyjnych rozwiązań na dużąskalę.

Licencja: GNU GPL lub komercyjna (ser-wer) oraz GNU LGPL (klienci dla PHP i Ruby'ego)http://www.phpbeans.com/

Page 11: Php Solutions 1 2006 PL
Page 12: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org12

Opis CD

GraPHPite

Wykresy w PHP możemy budować od podstaw, ale znacznie prostsze

i wydajniejsze jest skorzystanie z goto-wych, rozbudowanych narzędzi, takich jak obiektowo zorientowana biblioteka GraPHPite.

Pod względem swojej funkcjonal-ności, biblioteka znacząco wyróźnia się ponad przeciętność. GraPHPite pozwala na szybkie generowanie wykresów linio-wych, słupkowych, kołowych, opartych o mapę geograficzną czy mających kształt pajęczyny. Do tego dochodzą wa-riacje poszczególnych typów wykresów. Możliwe jest również łączenie paru typów wykresów z legendą na jednej grafice, a nawet rysowanie wykresu na wykresie. GraPHPite obsługuje antialiasing, półprze-zroczystość i potrafi tworzyć gradientowe tła. Pozwala na stosowanie skali logaryt-micznej.

Bibliotekę można w pełni dostosować do własnych potrzeb. Dlatego też moż-liwa jest zmiana wszystkich elementów wyświetlanych jako grafika, od koloru linii, aż po czcionkę używaną do opisów.

GraPHPite korzysta z czcionek TrueType. Otrzymane wykresy możemy zapisać w formacie PNG lub JPEG.

Docenieniem funkcjonalności bibi-lioteki GraPHPite jest umieszczenie jej w repozytorium PEAR. Będzie tam do-stępna pod nazwą Image_Graph. Twórcy GraPHPite planują dodanie obsługi więk-szej ilości formatów wyjściowych, tj. SVG, SWF i PDF oraz zapewnienie możliwości

tworzenia trójwymiarowych wykresów kołowych.

GraPHPite korzysta z biblioteki GD lub GD2 i może współpracować z PHP4 i PHP5. Do biblioteki dołączana jest rozle-gła dokumentacja. Podsumowując: projekt bardzo przydatny każdemu, kto chce two-rzyć zaawansowane wykresy w PHP. Licencja: GNU LGPLhttp://graphpite.sourceforge.net/

eyeOSeyeOS to niecodzienne rozwiązanie:

CMS przypominający swoim wyglą-dem i zachowaniem okienkowy system operacyjny, taki jak Windows czy Linux z zainstalowanym środowiskiem X-Win-dow. Działa w przeglądarce internetowej i umożliwia wykonywanie typowych czyn-ności biurowych, takich jak liczenie na kal-kulatorze, tworzenie podręcznych notatek czy edytowanie dokumentów tekstowych. Obecnie w dystrybucji systemu znajduje się 10 tego rodzaju aplikacji.

Przykładowo, aby dokonać obliczeń, uruchamiamy pod eyeOS-em swój kal-kulator, a gdy na chwilę nie będzie nam potrzebny, minimalizujemy go i np. uru-chamiamy edytor tekstu, który przypomina Worda lub OpenOffice.org Writera. Każda aplikacja działa w osobnym oknie, które możemy dowolnie przesuwać w oknie przeglądarki, a także minimalizować, po-większać lub zamykać.

Aplikacja dysponuje ponadto własnym komunikatorem oraz przeglądarką stron WWW. Nie zabrakło również narzędzia do zarządzania plikami. Cały system sprawia wrażenie funkcjonalnego i intuicyjnego, bazując przy tym na nowoczesnym de-signie. eyeOS jest również wielojęzyczny

(ma m.in. wersję polską, francuską, wło-ską i niemiecką).

Produkt znajduje się jeszcze w fazie rozwoju, a aktualną wersją pozostaje 0.8.3. EyeOS ma pewne problemy z obsługą przeglądarek, choć nie szkodzi to zbytnio jego funkcjonalności. Z założenia jest rów-nież rozbudowywalny, a jego twórcy zachę-

cają do przenoszenia do niego kolejnych aplikacji ze świata PHP. Podsumowując: bardzo ciekawe rozwiązanie, które może zrewolucjonizować nasze podejście do kwestii związanych ze środowiskiem pracy oraz interfejsami użytkownika w PHP.Licencja: GNU GPLhttp://www.eyeos.org

Page 13: Php Solutions 1 2006 PL
Page 14: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org14

Opis CD

Jeżeli szukamy systemu do zarządza-nia kontaktami z klientami (CRM),

bardzo możliwe, że to właśnie Sugar-CRM spełni wszystkie nasze wymagania. Oprogramowanie oferowane jest w dwóch wersjach. Pierwsza z nich jest bezpłatna i dostępna na opensourcowej licencji SPL (bazującej na MPL). Druga wersja SugarCRM-a jest komercyjna i ma nieco większą funkcjonalność oraz zapleczew postaci pomocy technicznej.

SugarCRM to aplikacja webowa pracująca po stronie serwera. Jest prze-znaczona na platformę LAMP (Linux, Apache, MySQL, PHP), ale urucho-mimy ją wszędzie tam, gdzie jest PHPi MySQL, niezależnie od typu serwera WWW i systemu operacyjnego. Sugar-CRM działa w oknie przeglądarki WWW i nie potrzebuje żadnych dodatkowych modułów. Współpracuje ze wszystkimi przeglądarkami internetowymi. Niestety, praca pod Internet Explorerem nie jest pozbawiona mankamentów, gdyż dane przychodzące z serwera są szyfrowane, a IE ma mniej wydajny algorytm deszy-frujący niż Firefox.

SugarCRM przeznaczony jest dla działów sprzedaży, marketingu i wspar-cia, w firmach, w których potrzebna jest bardziej efektywna komunikacja z klien-tami. W odróżnieniu od innych systemów tej klasy, SugarCRM zrywa z konwencją systemu o wysokich kosztach, słabej skalowalności i małych możliwościach rozszerzania funkcjonalności. Zamiarem jego autorów było stworzenie aplikacjio przystępnej, modułowej architekturze,

która obalałaby dotychczasowe przeko-nanie, że CRM-y to rozwiązania prze-znaczone wyłącznie dla najbogatszych firm.

Jak już powiedzieliśmy, SugarCRM to narzędzie opensourcowe. System skupia wokół siebie społeczność progra-mistów, dla których stworzono repozyto-rium dodatków i udoskonaleń o nazwie SugarForge (analogia do SourceFor-ge.net). W jego ramach swoje projekty rozpowszechnia ponad 2000 programi-stów. Znajdziemy tam zarówno pakiety lokalizujące, jak i oprogramowanie po-zwalające zintegrować naszego CRM-az systemami CMS takimi, jak Mambo.

SugarCRM pozwoli obsłużyć całą armię ludzi, ograniczając jednocześnie ich uprawnienia. Wszystkim spośród swoich pracowników możemy utworzyć osobne konta, nadając im prawa do prze-glądania wyłącznie własnych materiałów. Będąc szefem firmy, mamy możliwość przeglądania i nadzorowania efektów pracy wszystkich naszych podwładnych. Panel aplikacji zaprojektowano bardzo funkcjonalnie. Poziomo rozmieszczono zakładki, które stanowią menu całej aplikacji. Główna strona panelu pozwala szybko zorientować się, jakie w danym dniu mamy spotkania i obowiązki, czym aktualnie się zajmujemy, jakie sprawyi zadania aktualnie prowadzimy. Tym, co rzuca się w oczy, jest wykres możliwych

do uzyskania przychodów. Pokazuje, jakie mamy możliwości zarobków w róż-nych dziedzinach naszej pracy. Przydatny będzie też z pewnością kalendarz, peł-niący jednocześnie funkcję terminarza przypominającego o ważnych sprawach (spotkaniach, zadaniach, telefonach).

Podstawowym zadaniem każdego systemu CRM jest składowanie pełnej korespondencji z danym klientem. Tak stworzone archiwum spotkań, rozmów, notatek i korespondencji emailowej po-zwala w szybki sposób prześledzić za-chowania klienta lub znaleźć potrzebne informacje na jego temat. Bez wątpienia przyda się możliwość szybkiego dodawa-nia i zarządzania kontaktami. SugarCRM pozwala importować kontakty zapisane w formacie vCard, CSV, jak również całe bazy, z programów typu Microsoft Out-look czy Act!2005.

Pozyskiwanie nowych klientów ułatwi moduł Przesłanki handlowe, a zakład-ka Okazje sprzedaży przyczyni się do wzrostu obrotów w firmie. Obsługę spraw pozasprzedażowych ułatwi moduł Spra-wy, pozwalajacy obsłużyć np. reklamacje gwarancyjne.

SugarCRM oferuje znacznie więcej funkcji i nie sposób ich tu wszystkich wymienić. Narzędzie znajduje się na bardzo zaawansowanym etapie rozwoju i jest praktycznie pozbawione większych błędów projektowych. Gdy dodamy do tego możliwość rozszerzania systemu, uzyskamy znakomity, bezpłatny produkt. Jeśli i to nam nie wystarczy, zawsze możemy sięgnąć po komercyjną wersję programu SugarCRM.

Licencja: GPLCena wersji komercyjnej (Sugar Professio-nal): 239,00$http://www.sugarcrm.com

SugarCRM 3.5.0

Page 15: Php Solutions 1 2006 PL

Na CDNa CDNarzędziaUltraEdit-32 11.20UltraSentry v2.0UltraCompare Professional v3.00Roadsend Compiler for PHP 1.6 – 21-dniowy trialSimpletest 1.0.0 – GPLphp-time – GPLphp-java-bridge-2.8.0 – GPLphp-mono-bridge-2.8.0 – GPLEyeOS 0.8.4 – GPL

W

razieproblemów z płytą proszę napisać pod adres: [email protected]

IDEDreamWeaver 8 – 30-dniowy trialMaguma Workbench 2.6 – 30-dniowy trialUltraStudio 05 – 45-dniowy trial z możliwością przedłużenia na zasadach takich jak UltraEdit, Sentry oraz ComparePHPDesigner – freewarePhpwScite – GPL

14 książek elektronicznych w tym 4 noweSamba-3 by exampleThe Rise of Open Source LicensingLinux in the WorkplaceLinux Device Drivers 3rd Edition

Wsz

ystk

ie lis

tingi

z a

rtyku

łów

zos

tały

zam

iesz

czon

ena

nas

zej s

troni

e in

tern

etow

ej p

od a

dres

em www.phpsolmag.org/pl

Programy z serii Ultra są 45-dniowymi trialami. Triale mogą być przedłużone na prośbęczytelników, którzy wyślą w tej sprawie mail na adres: [email protected]

e-biznesSugarCRM 3.5 – System do zarządzania kontaktami z klientami na GPL!

CMSDrupal 4.6 – GPLeZ Publish 3.7.0 – GPLBitrix Site Manager 4.0.5 – 30-dniowy trial. Czytelnicy PHP Solutions mają 5% zniżki na pełną wersję programu. Szczegóły na www.bitrixsoft.com/phpsolutionsContent Manager 2.2.07 – Specjalna wersja – niewygasające demo

PEARHTML_AJAX-0.2.3SDO-0.6.0PHPUnit2-2.3.2pecl_http-0.16.0PDO

Wsz

ystk

ie lis

tingi

z a

rtyku

łów

zos

tały

zam

iesz

czon

ena

nas

zej s

troni

e in

tern

etow

ej p

od a

dres

em www.phpsolmag.org/pl

Page 16: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org16

Początki Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006 www.phpsolmag.org 17

Początki

Format OpenDocument, czyli otwar-ty format dla aplikacji biurowych, został opracowany przez kon-

sorcjum OASIS (Organization for the Advancement of Structured Information Standards, czyli Organizację ds. Rozwoju Strukturalizowanych Standardów Informa-cyjnych) i jest propozycją standardowego formatu zapisu i wymiany dokumentów tworzonych w pakietach biurowych, a więc arkuszy kalkulacyjnych, prezen-tacji, wykresów czy też tekstów. W tym artykule zajmiemy się przede wszystkim dokumentami tekstowymi.

Pierwsza wersja specyfikacji Open-Document powstała w wyniku współpra-cy organizacji zrzeszonych w ramach OASIS. Podstawą dla specyfikacji był XML-owy format plików OpenOffice.org, jednak specyfikacja wprowadza też wiele istotnych zmian. Format OpenDocument został zatwierdzony jako standard OASIS pierwszego maja 2005 roku. Celem stan-dardu jest dostarczenie wspólnej metody

Wklejanie czystego tekstu do CMS-a i jego ręczne formatowanie jest zadaniem żmudnym i podatnym na błędy. Gdyby tak można było stworzyć odpowiedni dokument w swoim ulubionym pakiecie biurowym, a potem po prostu skopiować plik i wkleić go do CMS-a... Taką właśnie możliwość daje połączenie trzech nowatorskich produktów: uniwersalnego formatu OpenDocument, CMS-a eZ publish i pakietu biurowego OpenOffice.org 2.0.

zapisu dokumentów, niezależnej od wewnętrznych formatów poszczególnych aplikacji. Wprowadzenie wspólnego for-matu oznacza dla użytkownika swobodę wyboru aplikacji, a dla producentów opro-gramowania zwiększoną konkurencję, a zarazem konieczność współpracy.

Od strony technicznej, specyfikacja OASIS jest dokumentem określającym metody opisu tekstu i treści multime-dialnych w typowych dokumentach pakietów biurowych. Standard definiuje schemat XML pozwalający opisywać

Otwarty format OASISdla dokumentów biurowych i CMS-ówBård Farstad

W SIECI

1. http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=office – standard OASIS OpenDocument

2. http://en.wikipedia.org/wiki/OpenDocument – wpis w Wikipedii na temat formatu OpenDocument

3. http://www.ez.no – strona projektu eZ publish

4. http://www.ez.no/community/contribs/import_export/oasis_open_document_extension – rozszerzenie OASIS dla eZ publish

5. http://www.ez.no/documentation – dokumentacja eZ publish

Powinieneś wiedzieć...Powinieneś znać podstawy pracy z PHP i eZ publish.

Obiecujemy...Po przeczytaniu artykułu będziesz wiedział jak przekazywać treść mię-dzy programem OpenOffice.org Writer a systemem eZ publish oraz jak dołą-czać obsługę formatu OpenDocument do aplikacji PHP.

Page 17: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org16

Początki Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006 www.phpsolmag.org 17

Początki

strukturę tekstu, nagłówków, list, tabel, obiektów osadzonych i innych elemen-tów dokumentu. Wynikowy plik jest zwykłym archiwum ZIP, zawierającym pewną liczbę plików XML i ewentualnie osadzonych w dokumencie obrazów lub obiektów multimedialnych.

Format OASIS OpenDocument jest standardem otwartym i prawdopodobnie stanie się w przyszłości standardem ISO. Ponieważ jest to format otwarty, można go używać do zapisu i wymiany informacji w dowolnych aplikacjach.

Aplikacje obsługujące format OpenDocumentOd czasu oficjalnego ogłoszenia standar-du OpenDocument w maju 2005 r. pojawi-ło się już kilka aplikacji ten format obsługu-jących. Coraz szerszej obsłudze standar-du w aplikacjach towarzyszy jego rosnąca popularność wśród użytkowników.

Według Wikipedii, do aplikacji obsłu-gujących format OpenDocument należą obecnie:

• Abiword,• eZ publish,• IBM Workplace,• Knomos,• KOffice,

• OpenOffice.org 1.1.5 i 2.0,• Scribus,• TextMaker,• Visioo Writer.

Migracja z formatów poszczególnych aplikacjiIstniejące dokumenty zapisane we wła-snych formatach aplikacji (na przykład dokumenty MS Word) można konwerto-wać do formatu OpenDocument za po-mocą oprogramowania Open Source, na przykład pakietu OpenOffice.org – darmowej aplikacji obsługującej wiele różnych formatów, w tym OpenDocument. Konwersję dokumentów w OpenOffice.org dodatkowo ułatwia możliwość wywoływa-nia makr z linii poleceń. Oznacza to, że wykorzystanie OpenOffice.org pozwala nie tylko ręcznie konwertować dokumenty do formatu OpenDocument, ale również automatyzować ten proces i wbudowywać go w inne aplikacje. Niektóre produkty (na przykład eZ publish) już teraz obsługują tę metodę konwersji, choć korzystanie z ich możliwości wymaga zainstalowania wersji 2 pakietu OpenOffice.org.

Praktyczny przykładWykorzystanie standardu OpenDocu-ment i oprogramowania Open Source do

Rysunek 1. Dokument edytowany w MS Word

Rysunek 2. Kopiowanie dokumentu do systemu eZ publish za pośrednictwem interfejsu WebDAV Rysunek 3. Dokument importowany do eZ publish

Page 18: Php Solutions 1 2006 PL

Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006www.phpsolmag.org18

Początki

tworzenia, konwersji i udostępniania danych prześledzimy na przykładzie. Zaczniemy od stworzenia zwykłego do-kumentu MS Word w formacie DOC. Do-kument ten importujemy następnie do eZ publish za pośrednictwem WebDAV, po czym z pomocą pakietu OpenOffice.org 2.0 konwertujemy go do własnego forma-tu danych eZ publish. Opisywany tu eZ publish (http://www.ez.no) jest systemem zarządzania treścią (CMS-em) klasy en-terprise, napisanym w PHP i dostępnym na zasadach Open Source.

Pierwszą czynnością będzie utworze-nie w Wordzie zwykłego dokumentu, za-wierającego sformatowany tekst i obrazek. Ostateczny dokument powinien wyglądać mniej więcej tak, jak na Rysunku 1 i po-winniśmy go zapisać gdzieś na lokalnym dysku. Następnym krokiem będzie prze-niesienie zawartości tego dokumentu do systemu eZ publish uruchomionego na in-nym komputerze. Do samego przekazania dokumentu posłużymy się obsługiwanym przez eZ publish interfejsem WebDAV, pozwalającym w prosty sposób kopiować i publikować dokumenty. W tym przykła-dzie użyjemy menedżera plików Konqu-eror uruchomionego w linuksowym środo-wisku graficznym KDE – dzięki WebDAV wystarczy jedynie przeciągnąć dokument z dysku windowsowego udostępnianego poprzez SMB i „upuścić go” do eZ publish. Rysunek 2 przedstawia widok interfejsu WebDAV dla eZ publish z poziomu Ko-nquerora – widoczny jest również plik dokumentu przeciągany z dysku Windows.

eZ publish automatycznie rozpoznaje format plików Worda publikowanych za pośrednictwem interfejsu WebDAV i za pomocą pakietu OpenOffice.org konwer-tuje je na format OpenDocument. Zawar-tość dokumentu po konwersji jest impor-towana już bezpośrednio do systemu za-rządzania treścią dzięki rozszerzeniu eZ publish obsługującemu format OASIS. Po zakończeniu importu, dokument jest od razu dostępny jako artykuł opublikowany w eZ publish – Rysunek 3 przedstawia widok takiego artykułu.

Podstawowa wersja operacji importu danych z formatu OpenDocument pobiera całą sformatowaną treść, ale bez definicji układu – importowane są na przykład wszystkie nagłówki, ale już nie zdefiniowa-ny w Wordzie rozmiar czy kolor czcionki.

Załóżmy, że chcemy taki artykuł edy-tować za pośrednictwem standardowego interfejsu administracyjnego eZ publish

Rysunek 4. Edycja importowanego dokumentu w eZ publish

Rysunek 5. Eksport dokumentu z eZ publish

Page 19: Php Solutions 1 2006 PL

Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006 www.phpsolmag.org 19

Początki

– Rysunek 4 przedstawia ekran edycji dokumentu. Jak widać, zachowywane jest formatowanie zdefiniowane w ory-ginalnym dokumencie, więc nagłówek, lista wypunktowana i obraz pozostają na swoich miejscach.

Teraz chcemy się zająć dalszą edy-cją dokumentu, ale tym razem w progra-mie OpenOffice.org Writer. W tym celu wystarczy wyeksportować artykuł z eZ publish do pliku w formacie OASIS Open-Document. Rysunek 5 pokazuje, jak eks-portować artykuł z eZ publish.

Po eksporcie dokument, możemy do-wolnie modyfikować jego styl, na przy-kład nakładając zwykły szablon Open-Office.org. Pozwala to, w bardzo prosty sposób, utrzymywać jednolitą stylistykę dokumentów, a podstawowy szablon można rozbudować na przykład o nagłów-ki i stopki stron. Rysunek 6 przedstawia podgląd wydruku naszego dokumentu po

zakończeniu edycji w programie Open-Office.org Writer. W porównaniu z pierwot-nym dokumentem, dodaliśmy nagłówek i stopkę strony oraz zdefiniowaliśmy styl czcionki – elementy opisane w warstwie prezentacji formatu OpenDocument.

Po zapisaniu zmodyfikowanego do-kumentu w OpenOffice.org możemy go ponownie importować do systemu eZ pu-blish z pomocą funkcji zastępowania (do-kadnie funkcja Repleace OpenOffice.org w menu kontekstowym). Pozostaje już tylko podziwiać efekt końcowy, czyli arty-kuł eZ publish po edycji w OpenOffice.org i ponownym imporcie (Rysunek 7).

W tym przykładzie skorzystaliśmy z bardzo prostego dokumentu. Rysunek 8 przedstawia dokument o znacznie bar-dziej złożonym formatowaniu, importowa-ny bezpośrednio z pliku OpenDocument stworzonego w OpenOffice.org. Import treści do eZ publish zachowuje formato-wanie dokumentu, ale szczegóły wyglądu artykułu są zależne od aktualnych usta-wień (Rysunek 9).

Poznaliśmy więc przykład podstawo-wych możliwości wykorzystania otwartych standardów, pozwalających bezproble-mowo wymieniać treści między różnymi aplikacjami i systemami.

Struktura pliku OpenDocumentBez większego wysiłku można rozbudo-wać dowolną aplikację PHP o obsługę standardu OpenDocument – format pliku jest szczegółowo udokumentowany, a do generowania i zapisu dokumentów wystar-czają standardowe narzędzia PHP. Sam plik OpenDocument (o rozszerzeniu .odt) jest zwykłym archiwum ZIP, więc wystar-czy go po prostu rozpakować, by przyjrzeć się jego zawartości (Rysunek 10).

Jak sama nazwa wskazuje, plik me-ta.xml zawiera metadane dokumentu, a więc datę utworzenia, czas edycji, sta-tystyki (np. liczbę słów i akapitów) itd. Plik mimetype zawiera po prostu typ MIME dokumentu – w naszym przypadku bę-dzie to application/vnd.oasis.opendocument.text. W pliku styles.xml znajdują się definicje czcionek, wyrównania kolorów i innych atrybutów stylu. Wreszcie plik settings.xml zawiera ustawienia interfejsu użytkownika dla aplikacji, w której ostat-nio edytowano dokument, a manifest.xml wyszczególnia wszystkie pliki składające się na dokument.

W tym przypadku będzie nas intere-sować plik content.xml oraz wszelkie pliki znajdujące się w podkatalogu Pictures

Rysunek 6. Podgląd wydruku naszego dokumentu w programie OpenOffice.org Writer

Rysunek 7. Aktualizacja artykułu importowanego do eZ publish

Rysunek 8. Wygląd bardziej złożonego dokumentu w programie OpenOffice.org Writer

Page 20: Php Solutions 1 2006 PL

Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006www.phpsolmag.org20

Początki

– plik content.xml zawiera faktyczną treść dokumentu, więc tam będziemy szukać danych, natomiast w katalogu Pictures spodziewamy się znaleźć plik osadzonego w dokumencie obrazu w formacie JPEG.

Schemat XML używany w ramach formatu OpenDocument wykorzystuje przestrzenie nazw, więc stosowany do przetwarzania dokumentów parser musi je obsługiwać. Listing 1 przedstawia uproszczoną wersję pliku content.xml (usunąłem z niego znaczniki niezwiązane z podstawową strukturą dokumentu). Opi-sywany dokument składa się z nagłówka i akapitu tekstu. Treść tą ujęto w znacznik <office:text>, który zawiera się kolejno w znacznikach <office:body> i <office:document-content>.

Tu uwaga: oglądanie plików XML generowanych przez OpenOffice.org jest znacznie wygodniejsze po wyłączeniu ich optymalizacji (menu Narzędzia -> Opcje -> Ładuj/Zapisz -> Ogólne) – pliki bez optymalizacji są dużo bardziej czytelne.

Wykorzystanie formatu OpenDocument w aplikacjach PHPWiemy już, na czym polega wymiana danych OpenDocument między klien-tem i serwerem, pora więc zająć się implementacją obsługi tego formatu w naszych aplikacjach PHP. Napisze-my skrypt pobierający treści tekstowe z pliku ODT i przekształcający je na stronę XHTML. Najpierw musimy się zaopatrzyć w parser DOM XML – w tym przykładzie wykorzystamy wchodzącą w skład środowiska eZ publish bibliote-kę eZ xml, ale równie dobrze sprawdzi się dowolny inny parser XML.

Spójrzmy na przykładowy kod z Li-stingu 2. Zaczynamy od wypisania tekstu HTML informującego o teście importu XML-a z pliku OpenDocument, po czym wstawiamy poziomą linię. Kod PHP za-czynamy od dołączenia biblioteki XML, której nakazujemy następnie wczytanie danych XML i utworzenie dla nich drze-wa DOM. Potrzebne nam dane znajdują się wewnątrz znacznika <body>, więc próbujemy pobrać zawartość węzła body, podając jego nazwę i URI przestrzeni nazw. Warto zwrócić uwagę, że identyfi-katorem przestrzeni nazw nie jest tu sam przedrostek office, ale pełna nazwa za-sobu (URN), czyli urn:oasis:names:tc:opendocument:xmlns:office:1.0. Jest to konieczne, gdyż przedrostek przestrzeni

Rysunek 9. Bardziej złożony dokument po imporcie do eZ publish

Listing 1. Dokument XML opisujący nagłówek i akapit tekstu

<office:document-content>

<office:body>

<office:text>

<text:h text:style-name="Heading_20_1" text:outline-level="1">To jest

nagłówek</text:h>

<text:p text:style-name="Text_20_body">

To jest zwyczajny akapit.</text:p>

</office:text>

</office:body>

</office:document-content>

Listing 2. Parsowanie zawartości pliku .odt w PHP

<h1>Test importu XML z pliku OpenDocument</h1>

<hr />

<?php

include_once('lib/ezxml/classes/ezxml.php');// $xml jest instancją eZXML, a $dom - modelem obiektowym dokumentu XML

$xml = new eZXML();$dom =& $xml->domTree(file_get_contents("documents/simpledoc/content.xml"));

$bodyNodeArray = $dom->elementsByNameNS( 'body',

'urn:oasis:names:tc:opendocument:xmlns:office:1.0' );

// sprawdzenie, czy w pliku występuje pojedynczy znacznik ciała dokumentu

if ( count( $bodyNodeArray ) == 1 ){ $bodyNode =& $bodyNodeArray[0];

$xhtmlTextBody = "";

foreach ( $bodyNode->children() as $childNode ){ $xhtmlTextBody .= handleNode( $childNode ); // dopisywanie wynikowego kodu XHTML

}

print( $xhtmlTextBody );}

Page 21: Php Solutions 1 2006 PL

Otwarty format dokumentów OASIS

PHP Solutions Nr 1/2006 www.phpsolmag.org 21

Początki

nazw jest jedynie aliasem dla pełnej na-zwy zasobu i może ulec zmianie.

Sprawdzamy, czy znaleźliśmy dokład-nie jeden pasujący węzeł drzewa DOM, co pozwala dodatkowo zweryfikować popraw-ność dokumentu (powinien być tylko jeden znacznik <body>). Gdy już mamy węzeł body, możemy przejść po wszystkich jego węzłach potomnych w pętli foreach. Do przetwarzania węzłów potomnych stwo-rzyłem funkcję handleNode(), zwracającą wyświetlany na końcu kod HTML.

Kod funkcji handleNode() przedstawia Listing 3. Zaczynamy od sprawdzenia nazwy bieżącego węzła (czyli znacznika) w bloku switch. Dla potrzeb tego przy-kładu obsłużymy jedynie <h> oraz <p> – napotkanie dowolnego innego znacz-nika spowoduje wyświetlenie komunikatu Nieobsługiwany element.

W przypadku znacznika <h> (czyli na-główka), zaczynamy od pobrania atrybutu level, na podstawie którego generujemy

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

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

��������

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

�����������

��������

��������

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

����������

Rysunek 10. Zawartość pliku .odt – struktura plików i katalogów

kod nagłówka HTML odpowiedniego poziomu. Potem wystarczy już tylko do-pisać tekst nagłówka wraz ze stosownymi znacznikami do zmiennej $htmlTextCon-tent, w której przechowujemy zwracany przez funkcję kod HTML.

Przetwarzanie znacznika <p> jest nie-co bardziej skomplikowane. Węzeł akapitu może mieć węzły potomne, po których przechodzimy w pętli foreach. W bloku switch sprawdzamy nazwę bieżącego węzła – w naszym prostym przykładzie obsługiwane są jedynie węzły o nazwach #text i image, a napotkanie dowolnej innej nazwy znów kończy się komunika-tem Nieobsługiwany element. Zawartość węzła #text jest doklejana do zmiennej przechowującej treść akapitu, natomiast w przypadku węzła image (czyli obrazu), będzie nas interesować tylko ścieżka do pliku obrazu, więc pobieramy wartość atrybutu href węzła obrazu i używamy jej do zbudowania HTML-owego znacznika

<img>. Dodatkowo usuwamy pierwszy znak ciągu pobranego z href, dzięki czemu otrzymujemy względną ścieżkę do pliku, nadającą się do bezpośrednie-go użytku. Po przetworzeniu wszystkich węzłów potomnych dopisujemy ich zawar-tość oraz zamykający znacznik </p> do zmiennej przechowującej wynikowy kod HTML akapitu.

PodsumowanieW tym artykule starałem się pokazać moż-liwości wykorzystania standardu OASIS OpenDocument w codziennej pracy i wy-mianie informacji. Aplikacje Open Source dają tu ogromne możliwości, w tym łatwe przechodzenie z własnych formatów aplikacji (np. Worda) na formaty otwarte oraz możliwość bezpośredniej edycji konwertowanego dokumentu. Prześledzi-liśmy też przykład edycji treści w różnych aplikacjach i kontekstach, przekonując się, że dane mogą równie dobrze występować w postaci tradycyjnych dokumentów, jak i artykułów publikowanych w Internecie. Wszystko to pokazuje, jak wiele mogą zdziałać producenci oprogramowania, gdy ustalą wspólny standard i zaimplementują go w swoich aplikacjach. n

Listing 3. Kod funkcji handleNode()

function handleNode( $node ){ $xhtmlTextContent = "";

switch ( $node->name() ){ case 'h' : { $level = $node->attributeValueNS( 'level',

'urn:oasis:names:tc:opendocument:xmlns:text:1.0' );

if ( $level >= 1 && $level <= 6 ){ $xhtmlTextContent.="<h$level>".$node->textContent()."</h$level>";

}

else print( "Nieobsługiwany poziom nagłówka" ); }break; case 'p' : { $paragraphContent = "";

foreach ( $node->children() as $childNode ){ switch ( $childNode->name() ){ case "#text" : { $paragraphContent .= $childNode->content();

}break; case "image" : { $href = ltrim( $childNode->attributeValueNS( 'href',

'http://www.w3.org/1999/xlink' ), '#' );

$paragraphContent .= "<img src='$href' alt=''/>";

}break;

default: {

print( "Nieobsługiwany element: " . $childNode->name() .

"<br>" );

}break; }

}

$xhtmlTextContent .= '<p>' . $paragraphContent . '</p>';

}break; default: { print( "Nieobsługiwany element " . $node->name() . "<br/" ); }

}

return $xhtmlTextContent;

}

?>

Bård Farstad jest jednym z założycieli i głównym deweloperem eZ systems. CMS-ami profesjonalnie zajmuje się od 1999 roku. Jest autorem wielu projek-tów oraz bibliotek dla PHP (np. ez XML – parser XML-a).Kontakt z autorem: [email protected]

O autorze

Page 22: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org22

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org 23

Wyobraźmy sobie fikcyjną, obiektowo zorientowaną apli-kację PHP, która składa się

z bardzo wielu klas. Między tymi klasami istnieją oczywiście zależności, co oznacza również, że błędy występujące w klasie bazowej powodują kolejne w klasach po-tomnych. W aplikacji zawierającej kilkaset klas może to doprowadzić do poważnych problemów, gdyż nie możemy po każdej zmianie w klasach bazowych testować od nowa całej aplikacji. Przynajmniej dotychczas tak było! W świecie Javy od dawna możemy przeprowadzać testy zwane jednostkowymi (ang. unit tests). Są one wykonywane automatycznie przez framework testowy, a ich rezultatem jest m.in. liczba testów zakończonych powo-dzeniem i niepowodzeniem. Stworzone przez Sebastiana Bergmanna narzędzie PHPUnit jest frameworkiem zapewniają-cym tę funkcjonalność w PHP.

Zapytacie pewnie, jak to możliwe, że jeden program testuje automatycznie dzia-

Im większy projekt programistyczny, tym trudniej wyłapywać pojawiające się w nim błędy, a usunięcie jednych usterek powoduje często powstanie następnych, w innej części aplikacji. Ręczne tworzenie testów dla setek klas jest nieskuteczne, a poza tym przyprawia o ból głowy i paraliżuje pracę. Z pomocą przychodzi PHPUnit: narzędzie pozwalające zautomatyzować proces tworzenia i wdrażania testów.

łanie innego? Odbywa się to za pomocą predefiniowanych testów. W każdym z nich sprawdzana jest konkretna funkcjonalność wybranej klasy, a zwrócony rezultat funkcji jest porównywany z wartością oczekiwaną. Jeżeli oba wyniki są równe, to znaczy, że badana funkcja działa poprawnie. W przeciwnym wypadku mamy do czynie-nia z błędem. PHPUnit pozwala na łatwe pisanie testów i gromadzenie ich większej liczby w tzw. zbiorach testów (PHPUnit: TestSuites). PHPUnit sprawdza wszyst-kie testy w zbiorze i zwraca nam liczbę

Programowanie sterowane testami za pomocą PHPUnitTimo Haberkern

W SIECI

1. http://www.phpunit.de – stro-ny projektu PHPUnit

2. http://www.testdriven.com – witryna o TDD

3. http://www.junit.org – projekt jUnit

Co należy wiedzieć...Powinieneś znać podstawy programo-wania obiektowego w PHP.

Co obiecujemy...Po przeczytaniu artykułu będziesz wie-dział, jak automatycznie i bez zbytniego wysiłku sprawdzać działanie aplikacji PHP za pomocą testów jednostkowych i frameworka PHPUnit. Artykuł bazuje na wersji 2.2.1 PHPUnit.

Page 23: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org22

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org 23

przeprowadzonych bezbłędnie oraz listę tych, które nie zostały zakończone pozy-tywnie (Rysunek 1). Rysunek 2 pokazuje jeszcze raz zależności między opisanymi tutaj komponentami (testami i metodami).

Ogromną zaletą testów jednostkowych w porównaniu do testów przeprowadza-nych ręcznie przez programistę jest ich szybkość i możliwość dowolnej liczby powtórzeń. Wykonanie takiego zbioru testów wymaga bardzo niewiele czasu i (w zależności od liczby testów) i pokrywa dużą część naszego kodu. Umożliwia nam to sprawdzenie funkcjonowania naszej aplikacji w najdogodniejszym czasie, np. pod koniec dnia pracy czy po wprowadze-niu zmian.

Pierwszy testTyle teorii – teraz czas na przyjrzenie się tworzeniu i wykonywaniu testów. Dla tego i następnych przykładów będziemy testo-wać klasę, która implementuje słownik polsko-angielski. Powinna ona zawierać metody umożliwiające dodawanie, ka-sowanie i odczytywanie tłumaczeń słów. W dalszej części artykułu rozszerzymy tę klasę o pewne właściwości, jak np. połą-czenie bazodanowe. Na Listingu 1 przed-stawiamy interfejs klasy Dictionary, której używamy w przykładach.

W naszym pierwszym teście chcemy sprawdzić, czy metoda isEmpty() naszej klasy Dictionary działa poprawnie. Każ-dy test utworzony za pomocą PHPUnit

dziedziczy po klasie PHPUnit_Framework_TestCase. Na Listingu 2 pokazujemy nasz przykładowy test. Przy pomocy dwóch te-stów jednostkowych chcemy się upewnić, czy funkcja ta pracuje tak, jak oczekujemy. Aby wykonać test z Listingu 2, musimy przejść do katalogu z testem i wykonać na konsoli następującą komendę:

phpunit FillTest

Wynikiem testu jest krótkie zestawienie pokazujące, ile testów zostało przepro-wadzonych oraz czy zakończyły się one sukcesem. Oprócz łącznej liczby testów otrzymujemy ilość bezbłędnych i błędnych sprawdzeń. PHPUnit rozróżnia tutaj Fa-ilures oraz Errors. Errors to błędy, które nastąpiły w czasie przetwarzania samego PHP (np. wyjątki). Failures to z kolei testy, przy których klasa zwróciła wartości inne od oczekiwanych. Rysunek 3 pokazuje każdorazowo przykład bezbłędnego i błędnego przebiegu testu. Widzimy, że w naszym przypadku zostały przeprowa-dzone dwa testy. Po starcie testu PHPUnit wykonuje każdą metodę, której nazwa zaczyna się od test. Właściwe testo-wanie odbywa się za pomocą obecnych w PHPUnit metod assert. W metodzie testIsEmptyWithoutFill() używamy assertTrue(). Jeśli wywołanie funkcji isEmpty() zwraca wartość true, to znaczy, Rysunek 1. Strona z wynikami zbioru testów

Instalacja przy użyciu PEAR-aPHPUnit jest częścią repozytorium PEAR, więc aby go zainstalować, wpisujemy w linii poleceń: pear install --alldeps phpunit2. Dzięki użyciu parametru --alldeps zainsta-lowane zostaną także wszystkie wymagane przez PHPUnit biblioteki.

Instalacja bez PEAR-aInstalacja PHPUnit jest możliwa również bez PEAR-a. W tym celu pobieramy go spod adresu http://pear.php.net/package/PHPUnit. Potrzebujemy również pakietów Log(http://pear.php.net/package/Log) i Benchmark (http://pear.php.net/package/Benchmark). Wszystkie pakiety rozpakowujemy w wybranym katalogu naszego serwera, a następnie dopisujemy ścieżkę tego folderu do parametru include_path w pliku php.ini. Jeżeli nie mamy dostępu do pliku php.ini, możemy podawać ścieżkę include_path w każdym skrypcie za pomocą wyrażenia:

ini_set("include_path",

"path/to/phpunit/library".PATH_SEPARATOR.ini_get("include_path"));

Ręczna instalacja nie jest, niestety, identyczna z PEAR-ową. Brakuje na przykład konso-lowej komendy phpunit, której używamy w tym artykule do wykonywania testów. Bez niej musimy się ograniczyć do skryptów PHP, które działają na serwerze WWW. Dlatego, o ile to możliwe, powinniśmy zawsze wybierać instalację PEAR-ową.

Instalacja XdebugW celu uzyskiwania informacji o działaniach zachodzących w kodzie, PHPUnit używa rozszerzenia PHP o nazwie Xdebug (http://www.xdebug.org). Aby je zainstalować pod Windows, wystarczy je pobrać (w postaci pliku DLL) spod adresu http://www.xdebug.org/link.php?url=xdebug200b1-50-win, a następnie zapisać w katalogu rozszerzeń PHP (php/ext). Później dodajemy nazwę tego pliku do listy rozszerzeń PHP, dopisując w php.ini na-stępującą linijkę: zend_extension_ts="c:\php\ext\xdebug-5.0-2.0.0beta1.dll".

Po restarcie serwera Xdebug jest do naszej dyspozycji. Ważne jest, aby zainstalować Xdebug jako rozszerzenie Zend, gdyż w przeciwnym razie nie będziemy mogli go stoso-wać wraz z PHPUnitem. Jeśli więc w naszym pliku php.ini jest już wpis: extension=php_xdebug.dll, to musimy go usunąć lub zablokować znakiem komentarza. Instalacja Xdebuga pod Linuksem jest nieco bardziej skomplikowana, a jej dokładny opis znajdziemy pod adresem http://www.xdebug.org/install.php.

Listing 1. Interfejs klasy słowni-kowej Dictionary dla pierwszych przykładów

<?php

class Dictionary{ public function addTranslation($strEnglish,

$strTranslated){

}

public function getTranslation($strEnglish){

}

public function removeTranslation($strEnglish){

}

public function isEmpty(){ }

public function loadFromDb(){ }

public function saveToDb(){ }

private $m_hashTranslations;}

?>

Page 24: Php Solutions 1 2006 PL

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org24

że nasza klasa pracuje prawidłowo, jako że nie mamy żadnych słówek w naszym słow-niku. Jeżeli jednak isEmpty() zwróci false, to mamy do czynienia z błędem. Założenie assertTrue() będzie niespełnione i PHPU-nit stwierdzi błąd. Zadaniem metod assert jest porównywanie oczekiwanego wyniku ze zwróconym przez funkcję. Do dyspo-zycji mamy kilka rodzajów tych metod, niektóre z nich przedstawiamy w Ramce Metody assert. Będziemy z nich korzystać w następnych przykładach.

Metoda testująca może zawierać więcej metod typu assert. Można to wy-korzystać, by sprawdzać wartości zależne od siebie.

Ulepszonekomunikaty o błędachKomunikaty zwracane przez PHPUnit w razie zakończenia testu niepowodze-niem mówią czasami niewiele. Załóżmy, że metoda getTranslation() zwraca nieprawidłowy rezultat, co spowoduje, że nasz test z Listingu 3 zakończy się nastę-pującym komunikatem:

F

Time: 0.012339

There was 1 failure:

1) testTranslation(TranslateTest)

FAILURES!!!

Tests run: 1, Failures: 1, Errors: 0,

Incomplete Tests: 0.

Informacje tego rodzaju nie są zbyt po-mocne, zwłaszcza gdy mamy do czynienia z dużą liczbą testów. Dlatego wszystkim metodom assert możemy przekazywać Rysunek 3. Bezbłędne i błędne przebiegi testów w PHPUnit

���������

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

������

�������

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

���

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

��������

�������

��������

��������

������

������

������

Rysunek 2. Zasada działania zautomatyzowanych testów

(jako parametr) własne komunikaty, które zostaną wyświetlone w przypadku nie-powodzenia testu. Jeżeli zastąpimy linię z metodą assert na Listingu 3 zapisem:

$this->assertTrue("samolot" == $strResult,

"Tłumaczeniem 'plane' jest

'$strResult'. Oczekiwano: 'samolot'")

to w przypadku niepowodzenia testu otrzy-mamy następujący komunikat:

F

Time: 0.004560

There was 1 failure:

1) testTranslation(TranslateTest)

Tłumaczeniem 'plane' jest 'error'.

Oczekiwano: 'samolot'.

FAILURES!!!

Tests run: 1, Failures: 1, Errors: 0,

Incomplete Tests: 0.

Ponieważ komunikaty zwracane przez nie-które metody assert, np. assertEqual() są wyczerpujące, więc dodawanie własnych informacji nie zawsze jest konieczne.

Gromadzenie testów w zbioryZ reguły nie chcemy wywoływać pojedyn-czego testu. Postępowanie, które opisa-liśmy nie sprawdziłoby się w przypadku dużej liczby testów. Na szczęście również tutaj PHPUnit oferuje nam wygodne me-chanizmy. Większą liczbę testów możemy umieścić w zbiorze testowym (TestSuite), a następnie wywołać pojedynczym po-leceniem. Listing 4 pokazuje, jak można dodawać pojedyncze testy do TestSuite za pomocą metody addTest(). TestSuite możemy następnie wykonać poleceniem:

phpunit DictionaryTestSuite

Wynik, który zobaczymy na ekranie, odpo-wiada temu, co znamy z dotychczasowych pojedynczych wywołań.

setUp() i TearDown()Jeśli przyjrzymy się uważnie Listingowi 1, zwrócimy uwagę na funkcje loadFromDb() i saveToDb(). Jak sugerują nazwy, odpo-wiadają one za ładowanie (load) i zapisy-wanie (save) słownika do bazy danych. Załóżmy, że w bazie znajduje się kilka tysięcy słów, więc ich ładowanie trochę potrwa. Ponieważ wiele testów korzysta z wypełnionego słownika, więc ładowanie danych dla każdego pojedynczego testu

Page 25: Php Solutions 1 2006 PL

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org 25

miałoby niewielki sens. Również z tego po-wodu klasa PHPUnit2_Framework_TestCase oferuje metodę setUp(). Metoda ta jest wywoływana przed wykonaniem testu, stanowi więc idealne miejsce na załado-wanie słownika z bazy. Musimy ją jedynie nadpisać w naszej własnej klasie PHPUnit_Framework_TestCase i dokonać inicjalizacji. Użycie tej funkcji ma sens wszędzie tam, gdzie chcemy mieć dostęp do tych sa-mych danych z różnych testów lub gdzie inicjalizacja używanych klas jest uciążliwa, a chcemy je stosować w wielu testach. Rzadziej niż setUp() używamy metody tearDown(). Jest ona przeciwieństwem setUp(), gdyż jest wywoływana po zakoń-czeniu testów. Możemy w niej np. zwalniać użyte zasoby, takie jak połączenia bazo-danowe, wskaźniki do danych, itp. Użycie obu metod przedstawiamy na Listingu 5.

Analiza pokrycia koduSkąd mamy wiedzieć, czy napisaliśmy wystarczającą liczbę testów dla naszej aplikacji? PHPUnit oferuje nam możliwość sprawdzenia, czy nasze testy obejmują cały kod. Uruchomiony z parametrem linii komend --coverage-html PHPUnit two-rzy plik HTML, który pokazuje kompletne źródło przetestowanej klasy. Linie, które zostały przetestowane, są podświetlone. Na Rysunku 4 przedstawiamy tego rodza-ju plik dla pierwszego przeprowadzonego w tym artykule testu. Korzystając z konsoli, uruchamiamy phpunit z następującymi parametrami:

Metody assertPHPUnit oferuje szeroką paletę metod assert:

• assertTrue() – oczekuje ona, że wyrażenie zwróci wartość true, w przeciw-nym wypadku mamy do czynienia z niepowodzeniem testu. Przykład: $this->assertTrue($expected == $result).

• assertFalse() – metoda przeciwna wobec assertTrue(). Oczekuje, że wyrażenie zwróci wartość false.

• assertEquals() – za jej pomocą możemy sprawdzić równość dwóch wyników. Wywo-łanie $this->assertEquals($expected, $result) odpowiada wywołaniu $this->assertTrue($expected == $result). Ma jednak tę przewagę nad assertTrue(), że w przypadku niepowodzenia otrzymujemy bardziej szczegółowy komunikat.

• assertSame() – ta metoda sprawdza identyczność dwóch obiektów. Odpowiada wywołaniu $this->assertTrue($expected === $result). Również w tym wy-padku mamy metodę przeciwną – assertNotSame().

• assertNull() – sprawdza, czy wynik jest równy null. Jeśli nie, test kończy się niepowodzeniem. Metodą przeciwną jest assertNotNull().

• assertRegExp() – ten assert używa wyrażenia regularnego do sprawdzenia wy-niku. Niepasujący wzór jest traktowany jako niepowodzenie. Za pomocą $this->assertRegExp('/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,5})+$/', $result) możemy na przykład sprawdzić, czy został zwrócony adres e-mail i czy jego for-mat jest prawidłowy.

• assertType() – sprawdza, czy wynik jest wskazanego typu. Jeżeli zwrócony typ nie odpowiada oczekiwanemu, porównanie kończy się niepowodzeniem. Przykładowo, $this->assertType('string', $result) pozwala sprawdzić, czy wynik jest typu string. Metodą przeciwną jest assertNotType().

• assertContains() – sprawdza, czy dany łańcuch (string) jest zawarty w innym stringu. Jeżeli nie, zostaje zwrócone niepowodzenie. Przykładowe wywołanie: $this->assertContains('f','foo'). Metoda przeciwna to assertNotContains().

R E K L A M A

phpunit --coverage-html

FillTest.html FillTest

Na podstawie utworzonego pliku HTML łatwo widzimy, czy potrzebujemy dal-szych testów, czy też te przeprowadzone dotychczas wystarczają, aby w pełni przetestować nasz kod źródłowy. Niestety, braki w dokumentacji utrudniają używanie tej opcji.

Musimy przygotować dwie rzeczy. PHPUnit tworzy wprawdzie plik HTML ze wszystkimi koniecznymi informacjami o pokryciu kodu, jednak używa zewnętrz-nego pliku CSS (codecoverage.css). Plik ten nie jest tworzony, ani też nie znajduje się w katalogach instalacyjnych PHP-Unit. Na Listingu 6 przedstawiamy więc plik CSS, którego można używać jako codecoverage.css. Kolejną przeszkodą

Page 26: Php Solutions 1 2006 PL

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org26

w używaniu tej opcji jest zależność od rozszerzenia xdebug, które jest zainsta-lowane na niewielu serwerach. W ramce Instalacja opisujemy więc, jak można owe rozszerzenie zainstalować, aby PHPUnit mógł z niego korzystać.

PHPUnit potrafi też zapisywać infor-macje o pokryciu kodu także w plikach tekstowych (--coverage-text) oraz w formacie, który może być łatwo używany przez inne programy (--coverage-data).

Funkcje pomocniczeJak widzimy, tworzenie testów wymaga pisania sporej ilości kodu. Aby ułatwić nam to zadanie, PHPUnit pozwala generować szkielety testów, które następnie uzupełnia-my o właściwą funkcjonalność. Aby to zre-alizować, wywołujemy polecenie phpunit z parametrem będącym nazwą pliku, dla którego powinien być utworzony szkielet:phpunit --skeleton Dictionary. Szkielet wynikowy dla naszej klasy Dictionary przedstawiamy na Listingu 7.

Zwrócenie wyników testu na konsoli może się niekiedy okazać niewystarcza-jące. W przypadku większych zespołów programistycznych testy są przeprowa-dzane o określonej porze, z reguły w nocy. Następnie wykonywany jest często sze-reg procesów towarzyszących. Tak więc oprócz testów jednostkowych tworzona jest dokumentacja API (np. za pomocą phpDocumentora), a także bekap danych i synchronizacja systemu działającego live. Dlatego ważne jest, aby wyniki testów były pokazywane nie tylko na ekranie, ale także zapisywane do pliku, ażeby można było w późniejszym czasie obejrzeć rezultaty. Aby coś takiego zrealizować, wywołujemy phpunit z parameterem --log-xml oraz nazwą pliku docelowego.

phpunit --log-xml result.xml

DictionaryTestSuite

Przykład pliku XML utworzonego przy takim wywołaniu przedstawiamy na Ry-sunku 5. Plik ten może być użyty także do automatycznej generacji dokumentacji testowej w formacie HTML lub PDF za pomocą XSLT.

Organizacja testów jednostkowychTeraz, gdy dysponujemy całą wiedzą po-trzebną nam do pisania testów jednostko-wych, możemy się zająć ostatnią otwartą sprawą: jak organizować własne testy?

Listing 2. Pierwszy test (FillTest.php)

<?

require_once ("Dictionary_inc.php");require_once ("PHPUnit2/Framework/TestCase.php");class FillTest extends PHPUnit2_Framework_TestCase {

function testIsEmptyWithoutFill() { $objDictionary = new Dictionary(); $this->assertTrue($objDictionary->isEmpty());

}

function testIsEmptyWithFill() { $objDictionary = new Dictionary(); $objDictionary->addTranslation("car", "samochód");

$this->assertFalse($objDictionary->isEmpty());

}

}

?>

Listing 3. Test zwracający niewiele mówiące komunikaty o niepowodzeniu.

<?php

require_once ("dictionary_inc.php");require_once ("PHPUnit2/Framework/TestCase.php");class TranslateTest extends PHPUnit2_Framework_TestCase { function testTranslation() { $objDictionary = new Dictionary(); $objDictionary->addTranslation("car", "samochód");

$objDictionary->addTranslation("plane", "samolot");

$strResult = $objDictionary->getTranslation("plane");

$this->assertTrue("samolot" == $strResult);

}

}

?>

Listing 4. Gromadzenie pojedynczych testów w TestSuite

<?php

require_once "PHPUnit2/Framework/TestSuite.php";require_once "FillTest.php";require_once "TranslateTest.php";class DictionaryTestSuite { public static function suite() { $suite = new PHPUnit2_Framework_TestSuite; $suite->addTest(new FillTest("testIsEmptyWithoutFill")); $suite->addTest(new FillTest("testIsEmptyWithFill")); $suite->addTest(new TranslateTest("testTranslation")); return $suite; }

}

?>

Metoda test-firstW tym artykule pisaliśmy testy, które sprawdzają funkcjonalność klas już istniejących: najpierw utworzyliśmy kod źródłowy w PHP, a potem odpowiedni test. Można jednak postępować inaczej. Ze świata Extreme Programming (XP) pochodzi metoda test-first, czasem zwana również Test-Driven Development (TDD). Inaczej niż w dotychczasowych przykładach, w których pisaliśmy testy do już istniejących klas, tutaj najpierw definiujemy interfejs klasy jako pustą funkcję z listą parametrów (podobnie jak na Listingu 1). Następnie tworzymy testy dla wszystkich możliwych zastosowań. Co się stanie, gdy wykonamy taki zbiór testów? Wszystkie testy zakończą się niepowodzeniem, ponieważ testowana klasa nie zawiera żadnego kodu. Potem implementujemy wszystkie metody. Jeżeli żaden test nie zakończy się niepowodzeniem, to klasa jest gotowa.

Zaletą tej metody jest to, że przed implementacją funkcji możemy przemyśleć jej prze-bieg i napisać dla niego test. Dzięki temu, gdy klasa zostanie zaimplementowana, będziemy już dysponowali solidnym i obszernym zbiorem testów pozwalających stwierdzić, czy pra-cuje ona poprawnie. To, którą metodę postępowania wybierzemy, zależy od indywidualnych upodobań.

Page 27: Php Solutions 1 2006 PL

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org 27

Jak to często bywa, nie ma tutaj jedno-znacznej odpowiedzi. W praktyce najczę-ściej stosujemy dwa wzorce. Nazywają się one Inline-Testing i Outline-Testing. Róż-nica leży w miejscu zapisywania testów. W przypadku Inline-Testing kod testu jest zapisywany w samej testowanej klasie. Dzięki temu zawsze wiemy, gdzie znajduje się kod testowy danej klasy i możemy go łatwiej dopasować, gdy zmienimy samą klasę.

Kolejna zaleta takiego podejścia ujawnia się, gdy używamy systemu kon-troli wersji, jak np. CVS czy Subversion, bowiem test jest zawsze dopasowany do odpowiedniej wersji klasy. Wspólne zapisywanie kodu testującego i klasy funkcjonuje tylko dlatego, że pliki klas zazwyczaj nie są bezpośrednio wywoły-wane, lecz dołączane w innych plikach za pomocą include. Możemy z tego skorzystać, aby umieścić kod testujący w pliku PHP. Trzeba jeszcze tylko dopi-sać zapytanie, które rozstrzyga, czy plik będzie dołączany przez include, czy też wywołany przez PHPUnit. Listing 8 poka-zuje ów warunek.

W przeciwieństwie do Inline-Testing, w przypadku Outline-Testing, kod te-stujący jest zapisywany oddzielnie od testowanej klasy. Outline-Testing omija niektóre problemy, które tam się pojawia-ją. Jeżeli kod testujący jest zapisywany razem z kodem klasy, to znajduje się rów-nież w późniejszej wersji produkcyjnej, jeśli klasy zostaną umieszczone na ser-werze w Internecie. Ponieważ PHP jest

Listing 5. Zastosowanie metody setUp() dla wspólnie używanych danych

<?php

require_once ("dictionary_inc.php");require_once ("PHPUnit2/Framework/TestCase.php");class TranslateTest extends PHPUnit2_Framework_TestCase { function setUp() { $this->m_objDictionary = new Dictionary(); $this->m_objDictionary->loadFromDb();}

function testTranslation() { $strResult = $this->m_objDictionary->getTranslation("plane");

$this->assertTrue("samolot" == $strResult,

"Tłumaczeniem 'plane' jest '$strResult'. Oczekiwano 'samolot'");}

function testIncorrectWord() { $strResult=$this->m_objDictionary->getTranslation("not in dictionary");

$this->assertNull($strResult);}

function testResultType() { $strResult = $this->m_objDictionary->getTranslation("plane");

$this->assertType("string", $strResult);}

function testSize() { $this->assertTrue($this->m_objDictionary->getSize() != 0);}

private $m_objDictionary;}

?>

Rysunek 5. Wynik testów w formacie XML

Rysunek 4. Analiza pokrycia kodu za pomocą PHPUnit. Linie, które zostały przetesto-wane, są podświetlone

językiem interpretowanym, kod testujący jest przy każdym wywołaniu parsowany na nowo, co zajmuje czas. Dlatego może okazać się, że oddzielenie kodu testują-cego od klas testowanych ma sens – po-stępujemy tak we wszystkich przykładach

w tym artykule. Pliki z testami możemy oddzielać na kilka sposobów. Rysunek 6 pokazuje trzy możliwości zapisywania testów. Wielu programistów zapisuje pliki testowe w tym samym katalogu, co klasy. Jest to najprostsze, ale niestety mało przejrzyste rozwiązanie. Innym, bardzo często stosowanym wyjściem jest utworzenie osobnego, przeznaczonego dla testów folderu tests w danym podka-talogu z klasami. Pozwala to na wyraźne

Listing 6. Arkusz stylów CSS (co-decoverage.css) do formatowania pliku z informacjami o pokryciu kodu

td.ccLineNumber, td.ccCoveredLine,

td.ccUncoveredLine,

td.ccNotExecutableLine{

font-family: Verdana, Arial,

monospace;

font-size: 10pt;

white-space: pre;}

td.ccLineNumber {

background-color: #aaaaaa;}

td.ccCoveredLine {

background-color: #F0F7B9;}

td.ccNotExecutableLine {

color: #aaaaaa;}

Page 28: Php Solutions 1 2006 PL

PHPUnit

PHP Solutions Nr 1/2006

Narzędzia

www.phpsolmag.org28

oddzielenie testów od właściwego kodu. Najbardziej radykalnym posunięciem jest całkowite oddzielenie kodu od aplikacji. Możemy wówczas przy jej ładowaniu na serwer internetowy wysłać wszystko poza wybranym katalogiem z testami, a więc nasza aplikacja nie posiada plików, które nie są jej konieczne do funkcjonowania. Organizacja testów pozostaje tak czy in-aczej w gestii programisty. W zależności od wielkości projektów każda z metod ma swoje wady i zalety.

Listing 7. Część automatycznie utworzonego szkieletu testowego dla klasy słow-nikowej

<?php

if (!defined("PHPUnit2_MAIN_METHOD")) { define("PHPUnit2_MAIN_METHOD", "DictionaryTest::main");

}

require_once "PHPUnit2/Framework/IncompleteTestError.php";require_once "PHPUnit2/Framework/TestCase.php";require_once "PHPUnit2/Framework/TestSuite.php";require_once "Dictionary.php";// Test class for Dictionary.

// Generated by PHPUnit2_Util_Skeleton on 2005-09-11 at 18:09:24.

class DictionaryTest extends PHPUnit2_Framework_TestCase { public static function main() { require_once "PHPUnit2/TextUI/TestRunner.php";

$suite = new PHPUnit2_Framework_TestSuite("DictionaryTest"); $result = PHPUnit2_TextUI_TestRunner::run($suite);

}

// @todo Implement testAddTranslation().

public function testAddTranslation() { throw new PHPUnit2_Framework_IncompleteTestError; }

// @todo Implement testGetTranslation().

public function testGetTranslation() { throw new PHPUnit2_Framework_IncompleteTestError; }

// @todo Implement testRemoveTranslation().

public function testRemoveTranslation() { throw new PHPUnit2_Framework_IncompleteTestError; }

// @todo Implement testIsEmpty().

public function testIsEmpty() { throw new PHPUnit2_Framework_IncompleteTestError; }

}

if (PHPUnit2_MAIN_METHOD == "DictionaryTest::main") { DictionaryTest::main();

}

?>

Listing 8. Umiejscowienie testu wewnątrz pliku klasy

<?php

class example { // some class code here

}

if ( strstr($_SERVER['PHP_SELF'], "TextUI/TestRunner.php") != false ) { require_once ("PHPUnit2/Framework/TestCase.php"); class exampleTest extends PHPUnit2_Framework_TestCase { // your test cases here

}

}

?>

Rysunek 6. Możliwości oddzielenia testów od klas testowanych

PodsumowaniePHPUnit jest interesującym projektem, który bardzo ułatwia kontrolowanie bez-błędności naszej aplikacji w trakcie jej pisania. Drastyczne zmniejszenie nakła-dów pracy odczujemy przede wszystkim dzięki automatycznemu dodawaniu testów dla każdej metody, które uwalnia nas od żmudnego, ręcznego wykonywania tych operacji. W polączeniu z łatwością obsłu-gi PHPUnita, możliwości te zadają kłam pokutującemu przekonaniu, że z powodu konieczności dotrzymania terminów nie ma czasu na testowanie programu w czasie jego powstawania.

Przyszłość PHPUnita rysuje się jesz-cze ciekawiej. Niedługo ukaże się wersja dla PHP 5.1, korzystająca z jego nowych możliwości, a także (co nie ma związku z PHP 5.1) oferująca funkcjonalność taką, jak atrapy obiektów (ang. mock objects) – to drugie zbliża ją do pierwo-wzoru ze świata Javy, którym jest jUnit. Autorzy zapowiadają również możliwość tworzenia testów przy użyciu interfejsu graficznego (GUI) działającego pod GTK. Ma on zostać napisany, gdy pojawi się GTK dla PHP5. W odległej przyszłości planowana jest integracja PHPUnita ze środowiskami programistycznymi, takimi jak Eclipse, Zend Studio czy Maguma Workbench. Jak będzie, pokaże czas, a na razie warto zacząć korzystać z do-stępnych możliwości PHPUnita, wdraża-jąc go w swoich projektach. n

Timo Haberkern jest architektem opro-gramowania biznesowego w firmie EME-DIA OFFICE. Poza tym bierze aktywny udział w rozwijaniu wielu projektów open source w językach PHP, Java i Java-script.

O autorze

Page 29: Php Solutions 1 2006 PL
Page 30: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org30

Narzędzia Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 31

Narzędzia

Drupal to opensourcowy, napisany w PHP CMS. Opiera się na rela-cyjnej bazie danych (MySQL lub

PostgreSQL). Jest modularny, elastyczny i skalowalny. Rdzeń systemu Drupal, po-dobnie jak większość modułów i motywów graficznych przygotowanych przez jego użytkowników, udostępniany jest na licen-cji GNU General Public License.

Drupal ma potężne możliwości w porównaniu z rozwiązaniami konkuren-cyjnymi, a jednocześnie jest wystarczająco elastyczny, by mógł być wykorzystywany na serwisach WWW dowolnego rodzaju: portalach, stronach osobistych, forach dyskusyjnych, blogach, fotoblogach czy podcastach – możliwości jest wiele.

Pokażemy, jak wykorzystać Drupala do zbudowania złożonego serwisu portalo-wego, koncentrując się na najbardziej za-awansowanych komponentach systemu, takich jak wielowitrynowość, czyli instalacja dla wielu serwisów (ang. multi-site installa-tion), wielojęzyczność, kategoryzacja (ang.

Czy potrzebujesz systemu zarządzania treścią (CMS) ogólnego zastosowania, będącego w stanie obsługiwać w jednej instancji kilka niezależnych serwisów WWW, z których każdy dostępny ma być w kilku wersjach językowych? Czy pełna internacjonalizacja powinna być możliwa za pomocą zaledwie kilku kliknięć myszą? Może chciałbyś także dodać do swojego serwisu elementy dynamiczne korzystające z AJAX, albo zwiększyć jego popularność dzięki zastosowaniu najlepszych technik SEO? Nie musisz dalej szukać: wypróbuj system Drupal.

categorizing) i znakowanie (ang. tagging) treści, optymalizacja pod kątem wyszuki-warek (ang. Search Engine Optimization, SEO) oraz użycie technologii AJAX w in-terfejsie użytkownika. W artykule zajmuje-my się przyszłą, jeszcze niewydaną wersją Drupala o numerze 4.7, która będzie ofe-rowała wiele ciekawych rozszerzeń w sto-sunku do bieżącej wersji stabilnej.

Drupal, czyli wielodomenowe, wielojęzyczne i modularne portale w oparciu o AJAX i SEOUwe Hermann

W SIECI

1. http://drupal.org – oficjalna strona domowa Drupal

2. http://cvs.drupal.org – repo-zytoria CVS Drupal

3. http://drupaldocs.org – doku-mentacja API programistycz-nych Drupal

4. http://opensourcecms.com – strona o CMS

Powinieneś wiedzieć...Powinieneś znać PHP, Apache'a i My-SQL-a. Przydatna będzie również wiedza ogólna o systemach CMS oraz o SEO.

Obiecujemy...Po przeczytaniu artykułu będziesz wie-dział, jak za pomocą Drupal stworzyć wielodomenowy, wielojęzyczny serwis WWW. Skupimy się przy tym na niektó-rych spośród jego najbardziej zaawanso-wanych elementów, takich jak instalacja dla wielu serwisów, internacjonalizacja, interfejsy użytkownika AJAX oraz Search Engine Optimization.

Page 31: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org30

Narzędzia Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 31

Narzędzia

Koncepcjanaszego portaluPokażemy możliwości Drupala budu-jąc prosty portal dla społeczności osób interesujących się darmową, legalnie dostępną w Internecie muzyką. Witryna będzie ukierunkowana na fanów i artystów niezależnych. Ma zapewniać fora dysku-syjne, blogi, cotygodniowe głosowanie i wiele więcej. Planujemy stworzenie odrębnego serwisu dla każdego gatunku muzyki, gdzie wykorzystamy wielowitry-nowość Drupala. Każdy z tych serwisów będzie miał poddomenę w ramach naszej wspólnej domeny example.com. Główny serwis będzie dostępny pod adresem http://www.example.com; osobne poddomeny dla gatunków będą nosiły nazwy takie, jak http://rock.example.com, http://blues.exam-ple.com czy http://electronica.example.com. Witryna dla każdego gatunku będzie miała własne ustawienia, motywy graficzne, blo-ki, treść, fora itd. Z drugiej jednak strony chcemy, by nasi użytkownicy mogli założyć pojedyncze konto i wykorzystywać je do lo-gowania się we wszystkich serwisach (ang. single sign-on). Z tego względu poszcze-gólne serwisy będą korzystały ze wspólnej bazy użytkowników.

Instalacja wielowitrynowa (wieloserwisowa)Instalacja wielowitrynowa pozwala nam tworzyć wiele serwisów, dostępnych pod osobnymi domenami lub poddomenami czy podkatalogami pojedynczej domeny. Każdy z tych serwisów może mieć własne ustawienia, moduły i motywy graficzne pomimo, że korzysta z tej samej co inne instalacji systemu Drupal. Ponadto w za-leżności od potrzeb, poszczególne serwisy mogą korzystać z całkowicie niezależnych, częściowo wspólnych, bądź całkowicie wspólnych tabel w bazie danych.

Jak działa instalacja wielowitrynowaPodstawowym mechanizmem stojącym za instalacją wieloserwisową jest sposób

wyszukiwania przez system Drupal pli-ków konfiguracyjnych, modułów oraz in-nych elementów. W przypadku instalacji jednoserwisowej, pełna ścieżka do pliku settings.php to sites/default/settings.php. W przypadku scenariusza wielowitry-nowego musimy natomiast stworzyć odpowiedni podkatalog dla każdego serwisu w sites, a następnie umieścić w nim dostosowany do tej witryny plik setttings.php.

Nazwy tych podkatalogów zawierać muszą nazwę poddomeny (vhost) dome-ny, numer portu (tylko w przypadku, gdy jest on inny niż 80) oraz nazwy folderów na danym serwisie. Poszczególne części składające się na taką nazwę oddzielone są kropkami. Dotyczy to również numeru portu, który zazwyczaj oddzielamy dwu-kropkiem.

InstalacjaPoniższe instrukcje dotyczą bieżącej wersji HEAD Drupal w CVS, więc po pojawieniu się wydania 4.7 konieczna będzie zmiana numeru wersji w kilku miejscach.

� Pobierz i rozpakuj archiwum Drupala do katalogu /var/www/testsite:

mkdir /var/www/testsite

wget http://drupal.org/files/projects/drupal-cvs.tar.gz

tar xfvz drupal-cvs.tar.gz

mv drupal-cvs/* drupal-cvs/.htaccess /var/www/testsite

� Stwórz bazę danych dla Drupala i załaduj odpowiednie skrypty bazodanowe:

mysqladmin -u database_user_name -p create dbtestsite mysql -u

database_user_name -p dbtestsite < database/database.mysql

� Zmodyfikuj odpowiednio zmienne $db _ url i $base _ url w sites/default/settings.php:

$db_url = "mysql://nazwa_użytkownika:hasło@serwer_bazodanowy/dbtestsite";

$base_url = "http://www.example.com/testsite";

� I to wszystko. Nasz serwis jest dostępny pod adresem http://www.example.com/testsite.

Kroki opcjonalne, ale zalecane:

� Stwórz katalog files/ z prawem zapisu przez serwer WWW. W katalogu tym system Drupal będzie przechowywał przesyłane przez klientów obrazki oraz inne pliki:

mkdir /var/www/testsite/files

chmod 777 /var/www/testsite/files

� Stwórz zadanie crona pytające regularnie o plik cron.php. Przykładowo, aby wywo-ływać tę czynność co godzinę, należy dodać do /etc/crontab następującą linijkę:

0 * * * * wget -O - -q http://www.example.com/testsite/cron.php

WymaganiaMinimalne wymagania instalacyjne Drupala to: PHP (PHP4 od wersji 4.3.3 lub PHP5), system relacyjnych baz danych (MySQL lub PostgreSQL) oraz serwer HTTP (Apache lub IIS). Opcjonalne, ale zalecane są: rozszerzenie XML dla PHP, obsługa mod_rewrite i plików .htaccess.

Etymologia DrupalProjekt Drupal został powołany do życia przez Driesa Buytaerta w roku 2000. Jego nazwa pochodzi od holenderskiego słowa druppel, które znaczy kropla (ang. drop). Dries Buytaert wybrał taką nazwę, ponieważ przypadkowo wpisał drop.org zamiast dorp.org (dorp to po holendersku wioska) szukając domeny dla serwisu społeczności, na którym planował korzy-stać z Drupala. Nazwa drop przyjęła się i tak narodził się Drupal.

Listing 1. Definicja naszych poddo-men dla Apache'a

<VirtualHost *:80>

DocumentRoot /var/www

ServerName www.example.com

</VirtualHost>

<VirtualHost *:80>

DocumentRoot /var/www

ServerName rock.example.com

</VirtualHost>

<VirtualHost *:80>

DocumentRoot /var/www

ServerName blues.example.com

</VirtualHost>

Page 32: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006www.phpsolmag.org32

Narzędzia

W przypadku naszego przykładowego portalu, struktura katalogów i plików dla serwisów www.example.com, blues.exam-ple.com i rock.example.com powinna wy-glądać następująco:

� sites/example.com/settings.php,� sites/rock.example.com/settings.php,� sites/blues.example.com.subdir/

settings.php.

Jeżeli serwis ma być dostępny zarówno ja-ko example.com jak i www.example.com, zaleca się utworzenie katalogu o nazwie example.com.

Konfiguracja poddomenPrzejdźmy teraz do stworzenia opisanych poddomen. W tym celu zmodyfikujemy konfigurację naszego serwera WWW tak,

by działały w nim hosty wirtualne. Ponie-waż używamy Apache'a, którego drzewo dokumentów znajduje się w /var/www, mu-simy dodać do naszego pliku /etc/apache/httpd.conf zawartość Listingu 1.

Spowoduje to skierowanie poddomen: www, rock oraz blues do naszego drzewa dokumentów, w którym zainstalujemy pojedynczą kopię kodu Drupal, mającą obsługiwać wszystkie nasze serwisy. Opi-sany scenariusz wieloserwisowy powinien działać także w przypadku większości dzielonych kont hostingowych. Konieczne może okazać się jednak pozostawienie konfiguracji poddomen administratoro-wi, albo skorzystanie z udostępnionego przez niego w tym celu interfejsu webo-wego, gdyż przeważnie nie będziemy mieli dostępu do pliku httpd.conf. Jeżeli żadne z tych rozwiązań nie jest możliwe,

zamiast poddomen wykorzystamy pod-katalogi.

Tworzenie tabel w bazie danychKolejnym krokiem jest stworzenie tabel dla każdego serwisu w bazie danych. Mamy tutaj kilka możliwości. Jeżeli chcemy, by żadna z tabel nie była dzielona między serwisami, tj. żeby były one od siebie cał-kowicie niezależne, po prostu tworzymy osobną bazę dla każdego serwisu:

mysql -u dbuser -p database1 § < database/database_1.mysql

mysql -u dbuser -p database2 § < database/database_2.mysql

W przeciwnym przypadku dzielone będą wszystkie tabele, a wszystkie serwisy bę-dą miały identyczne ustawienia, motywy graficzne, treść itd. Wystarczy nam wtedy pojedyncza baza dla wszystkich serwisów:

mysql -u database_user_name -p § db_for_all < database/database.mysql

W przypadku naszego portalu muzycznego skorzystamy z oferowanych przez Drupal możliwości pracy z prefiksami tabel. Tabele dla wszystkich podserwisów naszej witryny będą przechowywane w jednej bazie, ale ich nazwy będą się zaczynały odpowied-nimi przedrostkami. Pozwoli to wyraźnie określić, do którego serwisu należy dana tabela. Chcąc uniknąć zbędnych kompli-kacji, nadamy tabelom głównego serwisu przedrostek shared_ (jako, że część z nich będzie dzielona z innymi serwisa-mi). Tak więc, serwis rock.example.com otrzyma prefiks rock_, a blues.exam-ple.com – blues_. Aby uzyskać taki re-zultat, użyjemy najpierw skryptu prefix.sh z katalogu scripts/, który nada odpowiednie przedrostki nazwom tabel z pliku database/database.mysql, a następnie załadujemy tabele do bazy danych:

./prefix.sh "shared_" database.mysql § > database.mysql.shared

./prefix.sh "rock_" database.mysql § > database.mysql.rock

oraz:

./prefix.sh "blues_" database.mysql § > database.mysql.blues

Patrząc na polecenia SQL, plik databa-se.mysql.shared zawiera teraz linijki takie,

Terminologia Drupal� Węzeł (ang. node) – zawartość naszego serwisu przechowywana jest w węzłach; ist-

nieje szereg typów węzłów, takich jak: strona, wpis w blogu, ankieta czy też zdarzenie.� Blok (ang. block) – niewielki fragment zawartości, umieszczany zwykle po lewej lub

prawej stronie strony serwisu. Jako przykłady można wymienić Kto jest zalogowany lub Najświeższe komentarze.

� Moduł (ang. module) – rozszerzenie Drupala (napisane w PHP), dodające do nasze-go serwisu określoną funkcjonalność.

� Taksonomia (ang. taxonomy) – pozwala porządkować zawartość naszego serwisu według kategorii bądź znaczników.

� Motyw (ang. theme) – przesłania możliwe do modyfikacji funkcje Drupal, zapewnia-jąc unikalny wygląd naszego serwisu.

� Silnik motywów (ang. theme engine) – każdy motyw wymaga odpowiedniego silnika motywów. Domyślnym jest PHPTemplate, ale możemy skorzystać z innych, jak np. XTemplate czy Smarty.

Rysunek 1. Strona ustawień Drupal pozwala nam modyfikować rozmaite aspekty naszego serwisu

Page 33: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 33

Narzędzia

jak CREATE TABLE shared_users zamiast wcześniejszej CREATE TABLE users, pod-czas gdy w database.mysql.rock znajduje się polecenie CREATE TABLE rock_users, itd. Teraz, kiedy nazwy tabel w każdym pli-ku mają odpowiednie przedrostki, możemy załadować je do naszej bazy MySQL:

mysql -u dbuser -p dbname § < database.mysql.shared

mysql -u dbuser -p dbname § < database.mysql.rock

oraz:

mysql -u dbuser -p dbname § < database.mysql.blues

Konfiguracja serwisówOstatnim krokiem instalacji wieloserwiso-wej jest edycja każdego pliku settings.php tak, by jego treść odpowiadała wyma-ganiom danego serwisu. W wariancie minimalnym oznacza to konieczność

podania w tych plikach odpowiednich wartości zmiennych $base_url, $db_url i $db_prefix. Zmienna $base_url zawiera główny URL danego serwisu (np. http://rock.example.com), podczas gdy $db_url wskazuje na miejsce przechowywania pa-rametrów serwisu w bazie.

W przypadku naszego portalu, wszystkie serwisy korzystają z tej samej bazy, więc wartość $db_url jest identycz-na we wszystkich plikach settings.php. Zmienna $db_prefix zawiera tablicę asocjacyjną kojarzącą nazwy tabel z ich przedrostkami (patrz ramka Zawartość plików settings.php). Jeżeli nie chcemy dzielić żadnych tabel, $db_url zamiast tablicy będzie zawierać łańcuch, np. prefix_, albo "" (pusty tekst), jeżeli nie chcemy w ogóle stosować przedrostka. Należy pamiętać, że chcemy zaim-plementować wspólne logowanie do wszystkich serwisów naszego portalu, a więc część tabel będzie dzielona. Decyzja o tym, które tabele powinny być dzielone nie jest łatwa, ponieważ wymaga ona bliższej znajomości we-wnętrznych mechanizmów działania sys-temu Drupal i w dużym stopniu zależy od jego docelowej konfiguracji. Dla naszych potrzeb będziemy dzielić następujące ta-bele: users, users_roles, sessions, role, authmap, sequences, profile_fields oraz profile_values.

Oprócz zdefiniowania zmiennych$base_url, $db_url i $db_prefix, w odpo-wiednich plikach settings.php możemy

na sztywno ustawić pewne parametry po-szczególnych serwisów. W szczególno-ści, Drupal pozwala nam na przesłonienie dowolnych spośród swoich zmiennych konfiguracyjnych (przechowywanych zwykle w tabeli variable w bazie da-nych) przy wykorzystaniu następującej konstrukcji:

$conf = array(

'site_name'=>

'Rock music discussion site',

'theme_default'=>'pushbutton',

'comment_preview'=>'1'

);

W powyższym przykładzie definiujemy własną nazwę serwisu oraz jego domyśl-ny motyw graficzny, a także ustawiamy funkcjonalność podglądu publikowanych komentarzy na wymaganą. Oprócz wła-snego pliku settings.php, każdy serwis może mieć swoje katalogi modules/ i themes/. Pozwala to powiązać określone moduły i motywy graficzne z konkretnymi serwisami. Wymienione foldery zakładamy w odpowiednim dla danego serwisu kata-logu konfiguracyjnym, na przykład:

� sites/rock.example.com/settings.php� sites/rock.example.com/modules� sites/rock.example.com/themes

Teraz, kiedy już zakończyliśmy instalację wieloserwisową, przejdziemy do konfigu-rowania naszego portalu.

Rysunek 2. Strona parametrów motywów pozwala nam włączyć jeden lub więcej motywów, a także wybrać jeden z nich jako domyślny dla danego serwisu

Zawartość plikówsettings.phpOto istotne ustawienia znajdujące się w pliku sites/www.example.com/settings.php:

$base_url="http://www.example.com";

$db_url="mysql://database_user:

database_password@database_host/

database_name";

$db_prefix = "shared_";

Dla odmiany, w sites/rock.example.com/settings.php będziemy mieli:

$base_url="http://rock.example.com";

$db_url= ...;

$db_prefix = array(

'default' =>'rock_',

'users' =>'shared_',

'users_roles' =>'shared_',

'sessions' =>'shared_',

'role' =>'shared_',

'authmap' =>'shared_',

'sequences' =>'shared_',

'profile_fields' =>'shared_',

'profile_values' =>'shared_',

);

Podczas gdy w sites/blues.example.com/settings.php musimy ustawić:

$base_url=

"http://blues.example.com";

$db_url = ...;

$db_prefix = array(

'default' => 'blues_'

...

);

Page 34: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006www.phpsolmag.org34

Narzędzia

Podstawowa konfiguracjaCzas utworzyć naszego pierwszego użytkownika. Po wejściu na stronę http://www.example.com, klikamy na Utwórz nowe konto w bloku Logowanie po lewej stronie ekranu. Pierwszy stworzony przez nas użytkownik, niezależnie od nadanej mu nazwy, będzie administratorem po-siadającym uprawnienia do wykonywania wszelkich operacji na serwisie.

Po zalogowaniu się na to konto, pod zakładką zarządzaj –> ustawienia zmieni-my kilka podstawowych ustawień, takich jak nazwa serwisu (Portal muzyczny). Ustawimy też opcję Raportowanie błędów na Zapisuj błędy do dziennika, nie chcemy bowiem pokazywać użytkownikom na-szych wewnętrznych błędów.

Uaktywnimy także opcję Czyste URL-e, aby uzyskać ładniej wyglądające adresy URL i włączymy wbudowany mechanizm pamięci podręcznej, aby zwiększyć wy-dajność. Warto pamiętać, że ponieważ dzielimy między bazami tylko tabelę users oraz tabele z nią powiązane, parametry te nie będą wspólne dla wszystkich serwi-sów. Nasze ustawienia przedstawiamy na Rysunku 1.

Motywy graficzneDo dystrybucji systemu Drupal dołączono kilka motywów graficznych. Więcej może-my znaleźć pod adresem http://drupal.org/project/Themes. Procedura ich instalacji jest całkiem prosta: należy pobrać odpo-wiedni plik spod adresu drupal.org i rozpa-kować go do katalogu themes/. W naszym głównym portalu wykorzystamy domyślny motyw graficzny, za to dla podstron dla poszczególnych gatunków muzyki pobie-rzemy i zainstalujemy inne; przykładowo, na rock.example.com wykorzystamy mo-tyw FriendsElectric, rozpakowując go do katalogu sites/rock.example.com/themes/friendselectric. Następnie wybierzemy odpowiedni motyw za pomocą menu zarządzaj –> motywy graficzne (patrz Rysunek 2).

Korzystając z zarządzaj –> motywy graficzne –> konfiguruj możemy też zała-dować własne logo oraz obraz favicon dla naszego serwisu. Natomiast aby wyświe-tlać linki O ..., FAQ i Kontakt (patrz Rysu-nek 3) wykorzystamy listę podstawowych odnośników, podając ich nazwy i względne URL-e. Oczywiście, musimy stworzyć od-powiednie strony! Wreszcie, o ile chcemy, by we wpisach w blogach i komentarzach

pojawiał się komunikat napisany przez użytkownika <nazwa> dnia <data>, nie chcemy widzieć go na stronach statycz-nych, takich jak O .... W tym celu wyłączy-my opcję Włącz wyświetlanie informacji nt. wypowiedzi dla węzłów typu strona.

ModułyRozszerzymy teraz funkcjonalność nasze-go portalu, włączając na stronie zarządzaj -> moduły (patrz Rysunek 4) kilka dodat-kowych, dołączonych do pakietu Drupal modułów:

� profile – pozwala nam określić jakie pola powinien zawierać profil użytkow-nika, np. imię, dzień urodzenia, e-mail, ulubione zespoły, itd.

� blog – daje każdemu z zarejestrowa-nych użytkowników możliwość posia-dania bloga. Przykładowo, URL-em bloga użytkownika naszego serwisu o nazwie 23 to http://www.example.com/blog/23. Dodatkowo, automatycznie i bez żadnych dodatkowych działań otrzymujemy blog grupowy (gdzie agregowane są posty wszystkich użyt-

Rysunek 3. Korzystając z podstawowych odnośników definiujemy menu w prawym górnym rogu serwisu

Rysunek 4. Strona przeglądu modułów Drupal pokazuje wszystkie zainstalowane moduły

Page 35: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 35

Narzędzia

kowników naszego serwisu): http://www.example.com/blog. Rzecz jasna, każdy blog posiada własny strumień RSS, np. http://www.example.com/blog/23/feed. Uaktywniając blogi dajemy naszym artystom platformę, na której mogą oni mówić o swojej muzyce, natomiast fanom zapewniamy miejsce wyrażania opinii o dziełach twórców.

� ping – automatycznie powiadamia serwisy takie, jak technorati.com czy pingomatic.com o zmianach treści naszej witryny, co jest bardzo istotne i wygodne dla naszych blogo-wiczów.

� upload – pozwala użytkownikom prze-syłać na naszą witrynę pliki, np. obraz-ki lub MP3.

� forum – pozwala nam stworzyć jedno lub więcej forów dyskusyjnych w ra-mach naszego serwisu.

� poll – pozwala nam tworzyć cotygo-dniowe ankiety (możliwe są pytania z wieloma odpowiedziami), w których nasi użytkownicy mogą głosować.

� search – uaktywnia wbudowaną w sys-temie Drupal wyszukiwarkę, pozwa-lającą przeszukiwać nasz serwis pod kątem konkretnych treści lub użytkow-ników.

Istnieje wiele innych, stworzonych przez użytkowników modułów; znajdziejmy je pod adresem http://drupal.org/project/Module. W naszym portalu wykorzystamy następujące spośród nich:

� image – pozwala nam przesyłać obrazy na serwis, porządkować je w galerie oraz wstawiać we wpisach w blogach. Automatycznie tworzy mi-niaturę każdego obrazka.

� audio – pozwala naszym użytkowni-kom przesyłanie plików MP3 na ser-wis i zarządzanie nimi. Artyści mogą go wykorzystywać do publikowania swoich utworów albo do podcastin-gu. Wraz z modułem dostarczany jest napisany we Flashu odtwarzacz, pozwalający nam odtwarzać MP3 w przeglądarce WWW.

� trackback – pozwala blogowiczom na naszym serwisie wysyłać i otrzymy-wać trackbacki.

� spam – potężny zestaw narzędzi auto-matycznie radzący sobie ze spamem w komentarzach i trackbackach na naszym serwisie.

Użytkownicy,role i uprawnieniaKolejnym krokiem będzie zdefiniowanie na stronie zarządzaj –> reguły dostępu pewnych ról i nadanie im pożądanych przez nas uprawnień (patrz Rysunek 5). W tym momencie stworzymy role: artysta (otrzymuje dodatkowe upraw-nienie do przesyłania plików na serwis) oraz opiekun serwisu, dla zaufanych użytkowników pomagających nam opiekować się serwisem (rola ta otrzy-muje dodatkowe uprawnienia do ad-ministracji forami, itd.). Skorzystamy ponadto z automatycznie zdefiniowa-nych ról zarejestrowany użytkownik (zalogowani użytkownicy) i anonimowy użytkownik (użytkownicy niezalogowani), które przypiszemy wszystkim pozostałym użytkownikom. Wreszcie, musimy przypi-sać właściwe role naszym użytkownikom, klikając na stronie zarządzaj –> użytkow-nicy na odnośniku edytuj dla interesują-cego nas użytkownika. Końcowy zestaw uprawnień użytkownika to skumulowane uprawnienia wszystkich ról, do których użytkownik został przypisany.

Tworzenie zawartościNadeszła pora, by rozpocząć tworzenie zawartości naszego serwisu. Będzie to statyczna strona O ... informująca, jaką

Rysunek 5. Drupal pozwala na implementację w naszym serwisie precyzyjnej kontroli dostępu

Rysunek 6. Tworzymy prostą stronę z treścią

Page 36: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006www.phpsolmag.org36

Narzędzia

funkcję pełni nasz portal muzyczny. Dru-pal udostępnia nam do wykorzystania szereg rodzajów węzłów (np. strona, wpis w blogu czy wątek na forum). My wykorzystamy typ strona. Po kliknięciu na utwórz zawartość –> strona naszym oczom ukaże się prosty formularz, w któ-rym określimy nazwę węzła oraz jego zawartość (patrz Rysunek 6). Jako, że uruchomiliśmy moduł path, możemy tak-że określić ścieżkę, pod którą nowa stro-na będzie dostępna. Tym razem użyjemy tutaj about, w wyniku czego adresem tej strony będzie http://www.example.com/about. Dla nowej strony (lub innego wę-zła) możemy ustawić szereg opcji, np. zablokować na niej komentowanie, nie publikować jej na stronie głównej, itd. Możemy także, zaznaczając odpowied-nie pole, stworzyć nową wersję węzła. Spowoduje to zapisanie zarówno jego starej, jak i nowej wersji, co umożliwi nam ewentualny powrót do starszej wer-sji bądź porównanie jej z nową.

RozszerzeniaAJAX i JavaScriptAJAX, czyli Asynchroniczny JavaScript z XML (ang. Asynchronous JavaScript and XML) to zyskująca coraz większą popularność metoda tworzenia inte-raktywnych serwisów WWW. Piszemy o niej szerzej w artykule AJAX – porząd-kowanie aplikacji w tym numerze PHP Solutions. Drupal 4.7 będzie zawierał

niewielką, wbudowaną bibliotekę pod-stawową AJAX, która już teraz wykorzy-stywana jest w niektórych (aczkolwiek nie wszystkich) obszarach do polepsze-nia obsługi serwisów na niej opartych. Biblioteka ta oferuje API dla modułów zewnętrznych, które dzięki temu mogą wykorzystywać funkcjonalność AJAX i JavaScript do własnych potrzeb.

Jednym z ciekawszych elementów AJAX/JavaScript jest zwijalne pole for-mularza, znacznie podnoszące wygodę korzystania ze stron zawierających formularze. Przykładem jego użycia są strony utwórz zawartość –> wpis do dziennika. Rzadko używane części formularza i całe formularze na takiej stronie są domyślnie zwinięte (zamiast całego formularza widoczny jest tylko jego tytuł), dzięki czemu cała strona staje się krótsza i bardziej zwięzła. Klik-nięcie lewym przyciskiem na zwiniętym formularzu spowoduje jego rozwinięcie z wykorzystaniem JavaScript (patrz Ry-sunek 7) bez potrzeby pobierania przez przeglądarkę kolejnej strony z serwera. W naszym portalu zwijalne pola formu-larza przydałyby się np. w formularzu pozwalającym wysłać list do artysty, zamieszczonym na jego (lub jej) stro-nie, lub umożliwiającym wyświetlenie bardziej szczegółowych informacji bio-graficznych.

Kolejną przydatną możliwością AJAX jest autouzupełnianie zawartości, póki co dostępne tylko w polach z nazwą użytkownika i znacznikami (kategoria-mi). Przykładowo, jeżeli chcemy zmienić właściciela/twórcę węzła w naszym ser-wisie, musimy zmienić zawartość pola Stworzony przez dla odpowiedniego węzła. Jeżeli teraz w tym polu wpisze-my li, Drupal automatycznie pokaże nam wszystkie nazwy użytkowników za-wierające ciąg znaków li, np. Antonio Salieri, Franz Liszt czy Georg Philipp

Telemann. Dzięki temu, jednym kliknię-ciem możemy wybrać odpowiedniego użytkownika. Ten sam mechanizm wy-korzystywany jest w przypadku znaczni-ków (patrz Rysunek 8).

Kolejnym mechanizmem korzystają-cym z AJAX-a jest pasek postępu, który jest wykorzystywany podczas przesyłania plików na naszą witrynę. Informuje on użytkownika o tym, jaka część pliku zosta-ła przesłana (patrz Rysunek 9).

Edycja WYSIWYGAby ułatwić użytkownikom formatowanie tekstu w naszym serwisie, zainstalujemy prosty edytor typu WYSIWYG (What You See Is What You Get). W tym celu możemy skorzystać z jednego spośród stworzonych przez użytkowników mo-dułów, takich jak HTMLarea, TinyMCE czy FCKeditor. Wybierzemy FCKeditor, który został oparty na opensourcowym edytorze o tej samej nazwie, dostępnym pod adresem http://www.fckeditor.net. Oferuje on naszym użytkownikom szeroki wachlarz możliwości formatowania tekstu (Rysunek 10).

Kategorie i znakowanieWbudowany w systemie Drupal system taksonomii jest bardzo potężnym narzę-dziem pozwalającym na porządkowanie dowolnych treści w kategorie. Pod zarzą-dzaj –> kategorie możemy zdefiniować dowolną liczbę słowników (np. gatunek muzyki), z których każdy zawierać będzie tzw. terminy taksonomiczne, czyli kate-gorie (np. rock, pop albo trance). Każda kategoria ma własną stronę (np. http://www.example.com/taxonomy/term/1), na której wyświetlana jest lista wszystkich na-leżących do niej węzłów, a użytkownikom udostępniany jest strumień RSS (np. http://www.example.com/taxonomy/term/1/0/feed).

Nową możliwością w systemie Drupal 4.7 są słowniki wolnego znakowania (ang. free tagging), pozwalające użytkownikom wprowadzać w odpowiednim formularzu li-sty oddzielonych przecinkami znaczników.

Rysunek 7. Zwijalne pole formularza

Rysunek 8. Automatyczne uzupełnianie nazwy użytkownika przy pomocy AJAX-a

Rysunek 9. Oparty na JavaScript pasek postępu przesyłania plików na serwis

Page 37: Php Solutions 1 2006 PL
Page 38: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006www.phpsolmag.org38

Narzędzia

W chwili zapisu edytowanego przez użytkownika węzła, wszystkie znaczniki automatycznie staną się normalnymi kategoriami systemu Drupal. Pozwala to blogowiczom korzystającym z naszej wi-tryny znakować swoje wpisy, podobnie jak ma to miejsce w innych serwisach “znako-wania społecznego” (ang. social tagging), takich jak del.icio.us, flickr czy technorati. Na stronie zarządzaj –> kategorie –> do-daj słownik tworzymy słownik Znaczniki Blogów i oznaczamy go jako słownik wolnego znakowania (patrz Rysunek 11). Możliwości w tej dziedzinie znacząco zwiększa zewnętrzny moduł tagadelic, oferujący nam tzw. chmury znaczników (ang. tag clouds)– zbiory nazw znaczni-ków łączących się z odpowiednimi katego-riami (np. kliknięcie na znacznik muzyka wyświetli stronę kategorii/znacznika o tej samej nazwie). Rozmiar czcionki każde-go znacznika zależy od jego popularno-ści. Moduł tagadelic oferuje nam jedną chmurę znaczników na słownik (np. http://www.example.com/tagadelic/chunk/1) oraz jedną dodatkową chmurę łączącą znaczniki ze wszystkich słowników. Aby wyświetlić chmurę o nazwie Znaczniki Blo-gów w bloku, należy włączyć możliwość używania znaczników w Znacznikach Blo-gów na stronie zarządzaj –> bloki (patrz Rysunek 12). Chmury znaczników ofe-rują gościom naszego serwisu wygodną możliwość przeglądania jego zawartości pod kątem kategorii, które ich najbardziej interesują.

Serwisy międzynarodoweChcemy, aby nasz portal był wielojęzycz-ny. System Drupal pomaga nam tutaj na kilka sposobów: do kodowania znaków wykorzystuje Unicode oraz ułatwia nam tworzenie osobnych wersji językowych interfejsu i zawartości.

JęzykiWbudowany moduł locale pozwala na tłumaczenie interfejsu użytkownika sys-temu Drupal na dowolny język. Możemy

dodawać bądź usuwać języki na stronie zarządzaj –> języki –> dodaj język oraz oznaczyć jeden z nich jako język do-myślny (patrz Rysunek 13). W naszym przypadku językiem domyślnym będzie angielski, udostępnimy jednak również polski, niemiecki, francuski i włoski.

Tłumaczenie interfejsu możemy przeprowadzić na dwa sposoby. Pierw-szym jest skorzystanie z wygodnego interfejsu webowego, dostępnego pod zarządzaj –> języki –> zarządzaj na-pisami. Możemy przeszukiwać nasz serwis pod kątem pewnych łańcuchów znaków (przetłumaczonych bądź nie) i tłumaczyć je na dowolny z dodanych przez nas języków lub modyfikować już dostępne tłumaczenie. Drugim sposobem obsługi tłumaczeń są możli-wości importu oraz eksportu dostępne w module locale. Tłumaczenia Drupala mogą być importowane z plików Porta-ble Object (.po) systemu gettext, bądź eksportowane do tego formatu. Jest on bardzo popularny i istnieje mnóstwo narzędzi ułatwiających manipulowanie plikami z niego korzystającymi, takich jak popularne aplikacje tłumaczące kba-bel czy poEdit.

Warto jednak wiedzieć, że w przy-padku większości języków nie ma ko-nieczności tłumaczenia wszystkich tekstów. Pod adresem http://drupal.org/project/Translations znaleźć można wiele gotowych, przygotowanych przez użytkowników tłumaczeń. Do tej pory

Rysunek 11. System taksonomii pozwala nam korzystać z szerokiego zakresu różnych słowników i konfiguracji

Rysunek 10. Moduł FCKeditor zastępuje standardowe formularze wprowadzania tekstu przyjazną dla użytkownika wersją graficzną

Page 39: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 39

Narzędzia

Drupal zyskał ponad 40 wersji języ-kowych. Na potrzeby naszego portalu pobierzemy z drupal.org tłumaczenia na polski, niemiecki, włoski i francuski, a następnie zaimportujemy pliki pl.po, de.po, it.po i fr.po korzystając z opcji zarządzaj –> języki –> importuj. Może-my tutaj wybrać, czy chcemy nadpisać już przetłumaczony tekst, czy też dodać tylko te łańcuchy znaków, które nie mają jeszcze swoich tłumaczeń. Warto zauważyć, że moduł locale pozwala nam zmodyfikować praktycznie każdy tekst w naszym serwisie. Przykładowo,

możemy w menu zarządzaj –> języki –> zarządzaj napisami znaleźć tytuł bloku Kto jest aktywny i zmienić go np. na Ak-tywni użytkownicy.

Internacjonalizacja(tłumaczenie zawartości)Ostatnim elementem, którego potrzebu-jemy do stworzenia prawdziwie między-narodowego portalu muzycznego jest zewnętrzny moduł Internationalization (i18n). Daje on nam możliwość tłuma-czenia zawartości naszego serwisu na inne języki. Moduł i18n oparty jest na

następującej architekturze: tłumacze-nia modelowane są przez zwyczajne węzły, zawierające wskaźnik do wę-złów, do których należą (których są tłumaczeniem). Informacja o języku przechowywana jest w URL-u danego węzła (zamiast w cookie sesji), np. http://www.example.com/fr/about w przypadku węzła francuskiego.

Aby uczynić nasz serwis wielo-języcznym, skonfigurujemy najpierw wspomniany wyżej moduł pod zarządzaj –> ustawienia –> i18n (patrz Rysunek 14). Uaktywnimy opcję detekcja języka przeglądarki, pozwalającą wybrać język, w którym wyświetlana będzie zawartość serwisu w oparciu o ustawienia prze-glądarki gościa portalu. Jest to zwykle najwygodniejszy sposób. Jeżeli nie włączymy tej opcji, wybór języka będzie następował kolejno na podstawie URL-a, ustawień użytkownika, konfiguracji przeglądarki bądź domyślnego języka systemu Drupal.

Pod zarządzaj –> ustawienia –> i18n mamy także możliwość ogranicze-nia tłumaczenia treści do konkretnych typów węzłów. Chcemy jednak, aby na naszym portalu tłumaczone były wszyst-kie rodzaje zawartości. Przykładowo, przetłumaczymy teraz stronę O ... na język niemiecki, klikając na odnośnik tłumacz węzła http://www.example.com/about. Zobaczymy listę języków zde-finiowaną przez nas wcześniej dla modułu locale. Możemy przetłumaczyć ten węzeł na dowolny z nich. Kliknię-cie odnośnika utwórz tłumaczenie dla niemieckiego przywołuje standardowy dialog tworzenia węzła, wzbogacony o nowe pole o nazwie Język (w tym przypadku domyślnie ustawione na niemiecki). Możemy teraz wprowadzić przetłumaczony tekst w treści węzła, wybrać de/about jako ścieżkę dla prze-tłumaczonego węzła – i gotowe.

Węzeł O ... będzie odtąd widoczny w języku określonym albo na podstawie URL-a, albo konfiguracji przeglądarki (tak, jak opisaliśmy powyżej). Ponadto, u dołu strony widnieć będzie jedna lub więcej małych flag. Kliknięcie na jedną z nich po-zwoli nam przejść do odpowiedniej wersji językowej.

Moduł i18n oferuje nam także możli-wy do uaktywnienia blok wyboru języka, zawierający listę wszystkich zdefinio-wanych języków. Kliknięcie na jednym z nich powoduje zmianę bieżącego Rysunek 13. Dialog parametrów języków

Rysunek 12. Chmurka znaczników „znaczniki blogów” (ang. „Blog Tags”) dla naszego serwisu, pokazana w bloku

Page 40: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006www.phpsolmag.org40

Narzędzia

języka (działa to również w przypadku użytkowników anonimowych). Moduł ten posiada jednak pewne ograniczenia: nie ma możliwości tłumaczenia zawartości bloków czy też menu.

Optymalizacja pod kątem wyszukiwarekPonieważ chcemy, by nasz serwis zajmował jak najwyższe pozycje w wy-szukiwarkach internetowych, a jego po-pularność ciągle wzrastała, istotnym zagadnieniem jest dla nas optymalizacja pod kątem wyszukiwarek (SEO).

Czyste URL-e i moduł pathBiorąc pod uwagę, że największe wy-szukiwarki wyżej oceniają strony, których URL-e zawierają poszukiwane frazy, zoptymalizujemy odpowiednio adresy na naszej witrynie. Z systemem Drupal jest to bardzo proste. Dysponuje on m.in. opcją Czyste URL-e, która usuwa ? z adresów na naszym serwisie. Efektem użycia tej funkcji będą adresy typu http://www.example.com/node/123 zamiast http://www.example.com/?q=node/123. Opcję Czyste URL-e możemy uaktywnić pod zarządzaj -> ustawienia, będziemy jednak potrzebowali działającego modułu Apache'a o nazwie mod_rewrite. Dalszej optymalizacji naszych URL-i możemy dokonać zastępując zawarte w nich licz-by znaczącymi słowami kluczowymi, na co z kolei pozwala wbudowany mo-duł path. Po jego włączeniu, tworząc bądź edytując węzeł, każdorazowo będziemy proszeni o podanie dla niego aliasu ścieżki. W ten sposób możemy tworzyć adresy URL wyglądające jak http://www.example.com/about-this-site, co znacznie zwiększy ilość trafień na na-sze strony w wynikach wyszukiwania.

PathautoKolejne usprawnienia w tej dziedzinie zapewnia nam zewnętrzny moduł pa-thauto, wymagający standardowego modułu path. Pozwala on na elastyczną automatyzację generacji aliasów ścieżek dla węzłów, wpisów do blogów, stron użytkowników, terminów taksonomii (ka-tegorii bądź znaczników) i wielu innych. Główną ideą tego modułu jest, by za-miast ręcznie wprowadzać alias ścieżki podczas tworzenia węzła, jednorazowo podawać wzorzec ścieżki pod zarządzaj –> ustawienia –> pathauto. Od tej pory, tworząc nowy węzeł po prostu pozosta-

wiamy pole aliasu ścieżki puste, a moduł pathauto automatycznie wygeneruje od-powiedni alias.

W naszym portalu skonfigurujemy wzo-rzec [user]/[yyyy]-[mm]-[dd]/[title] dla wpisów w dziennikach. Jeżeli użytkow-nik John Doe utworzy w Wigilię wpis o ty-tule Dlaczego lubię dobrą muzykę, moduł pathauto automatycznie wygeneruje alias ścieżki john-doe/2005-12-24/dlaczego-lu-bie-dobra-muzyke.

Google SitemapsKolejną rzeczą, którą możemy uczy-nić, by zwiększyć nasze notowania w wyszukiwarkach, jest skorzystanie z ze-

wnętrznego, dedykowanego dla Google modułu Google Sitemaps (gsitemap). Moduł ten tworzy XML-ową mapę serwisu w formacie określonym przez specyfikację Google Sitemaps (http://www.google.com/webmasters/sitemaps) i umieszcza ją pod adresem http://www.example.com/gsitemap.

Mapa serwisu to, w skrócie, lista stron naszego serwisu uporządkowana wg ich priorytetu, którą Google wyko-rzystuje, aby inteligentniej i dogłębniej przeglądać nasze strony, dając w efekcie lepsze i bardziej aktualne wyniki wyszu-kiwania. Moduł gsitemap pozwala nam określić priorytet, jaki wybrane strony

Rysunek 15. Dialog parametrów pathauto

Rysunek 14. Dialog parametrów internacjonalizacji

Page 41: Php Solutions 1 2006 PL

Drupal

PHP Solutions Nr 1/2006 www.phpsolmag.org 41

Narzędzia

powinny posiadać w wygenerowanej mapie serwisu – na przykład według rodzaju węzłów, ilości komentarzy dla węzła, jego czasu stworzenia czy aktuali-zacji lub też kwestii, czy węzeł związany jest ze stroną główną. Możemy także po-lecić, aby moduł gsitemap powiadamiał Google o zmianie mapy serwisu oraz by odnotowywał fakt odwiedzenia naszej mapy przez pająka Google.

Słowa kluczowe węzłówEfektywność słów kluczowych meta (metatagów) pod względem SEO jest wysoce niepewna: mówi się, że wiele wyszukiwarek zwyczajnie je ignoruje. Niemniej zakładając, że przynajmniej niektóre z nich korzystają ze słów kluczowych, możemy wykorzystać ze-wnętrzny moduł nodewords. Pozwala on nam określić streszczenie, opis oraz notę o prawach autorskich dla każdego węzła, jak również listę słów kluczo-wych do umieszczenia w znaczniku <meta> w nagłówkach naszych stron. Istnieje możliwość skonfigurowania globalnej noty o prawach autorskich oraz globalnej listy słów kluczowych do wykorzystania na wszystkich stronach, z wyjątkiem węzłów, dla których zostaną one przesłonięte. W naszym przypadku chcemy, by każda strona zawierała na-stępujące znaczniki meta:

<meta name="copyright" content=

"Copyright 2005 Music Community" />

<meta name="keywords" content=

"music, free, independent, genre,

artists, portal" />

Podsumowując, możemy użyć modułu nodewords, aby stworzyć zestaw meta-informacji (w szczególności słów kluczo-wych) dla każdej strony naszego serwisu i mieć nadzieję, że będą one kolejnym elementem polepszającym naszą pozycję w wyszukiwarkach.

WydajnośćW oczekiwaniu na (miejmy nadzieję) rosnącą popularność naszego portalu muzycznego, pod zarządzaj –> ustawie-nia uruchomimy mechanizm pamięci pod-ręcznej systemu Drupal oraz dołączony do tego samego pakietu moduł throttle. Moduł zablokuje niektóre bloki i część funkcjonalności serwisu, jeżeli jego ob-ciążenie przekroczy pewien (możliwy do ustawienia) pułap.

Możemy także uaktywnić tłumienie (ang. throttling) konkretnych modułów i bloków w przypadku wystąpienia tzw. efektu Slashdot. Dokonamy tego za po-mocą zarządzaj –> moduły oraz zarządzaj –> bloki, zaznaczając odpowiednie pola throttle.

PodsumowanieJak zademonstrowaliśmy w naszym przy-kładzie, Drupal jest czymś, na co użytkow-nicy systemów CMS czekali od dawna. Uwalnia administratora od zamieszania

związanego z tworzeniem i zarządzaniem osobnymi instalacjami dla każdego serwi-su i wersji językowej. Intensywnie korzysta z AJAX i włącza jego funkcjonalność do interfejsu, a także pozwala użytkownikom stosować go na własną rękę. Wreszcie, możliwości systemu Drupal w zakresie SEO oferują nam wszystko, czego potrze-bujemy, aby nasz serwis stał się widoczny dla wyszukiwarek.

Biorąc pod uwagę dynamiczną, tęt-niącą życiem społeczność skupioną wo-kół systemu Drupal oraz jego znakomitą dokumentację, możemy ze spokojem wy-próbować ten system. Jego modularność i co za tym idzie elastyczność, podobnie jak w systemach XOOPS czy Mambo, za-pewnia dużą swobodę i łatwość tworzenia rozbudowanych, wielodomenowych oraz wielojęzycznych portali. n

R E K L A M A

Uwe Hermann jest studentem informa-tyki na Technische Universität München w Niemczech oraz niezależnym progra-mistą. Pracuje na rzecz wielu projektów Open Source, takich jak Debian GNU/Linux i Drupal. Zainicjował i pielęgnuje projekt Unmaintained Free Software (http://unmaintained-free-software.org), którego celem jest znajdowanie nowych opiekunów dla opuszczonych projektów Open Source.Kontakt: [email protected]

O autorze

Page 42: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org42

Techniki SDO

PHP Solutions Nr 1/2006 www.phpsolmag.org 43

Techniki

Każdy, kto interesuje się PHP i jego rozwojem zdążył zauważyć, że wielkie firmy informatyczne, takie

jak Oracle czy IBM zaczęły traktować ten język i otaczające go środowisko progra-mistów bardzo poważnie. Świadczą o tym chociażby specjalnie przygotowane wersje PHP dla baz danych Oracle i DB2. Dzięki temu, nie tylko PHP wkracza w świat apli-kacji klasy Enterprise, ale także technolo-gie wywodzące się z rozwiązań tej klasy wkraczają do PHP. Tak też stało się z SDO. SDO to skrót od Service Data Objects. Jest nazwą architektury stworzonej przez IBM i BEA, mającej na celu ułatwić, czy wręcz ujednolicić dostęp do danych pochodzących z wielu różnych źródeł. Dzięki niej, progra-miści będą mogli, poprzez spójny interfejs, zarządzać danymi m.in. z relacyjnych baz danych, plików XML czy Web Services.

Spójrzmy na Rysunek 1, na którym przedstawiamy schemat architektury SDO.Za dostęp do źródeł odpowiedzialne sąobiekty DAS (Data Access Service). Dzię-

Rozwiązania od dawna stosowane w Javie zalewają świat PHP. Należy do nich SDO, czyli Service Data Objects: zunifikowany, wspierany przez takie potęgi, jak IBM, Zend i BEA standard dostępu do danych, eliminujący potrzebę tworzenia osobnych interfejsów dla każdego ich źródła.

ki nim programista nie musi martwić się o sposób fizycznego rozmieszczenia da-nych w różnych źródłach. Dane, wchodzą-ce do obiektów DAS i z nich wychodzące, mają postać drzewa obiektów SDO. Bez względu na fakt, czy operujemy na danych pochodzących z plików XML, czy też rela-cyjnej bazy danych, otrzymywane przez nas obiekty są identyczne.

Pokażemy, w jaki sposób wykorzystać SDO do stworzenia prostej aplikacji służą-cej do administracji i prezentacji systemu newsów na stronie WWW. Newsy będą podzielone na kategorie, a każdy z nich będzie mógł należeć do jednej kategorii.

Service Data Objects,czyli standard uniwersalnego dostępu do danychPiotr Szarwas

W SIECI

1. http://pecl.php.net/package/sdo – pakiet SDO w repozy-torium PECL

2. http://us2.php.net/manual/en/ref.sdo.php – rozsze-rzenie SDO – oficjalna dokumentacja PHP

3. http://www.zend.com/pecl/tutorials/sdo.php – tutorial o SDO

4. http://www.ibm.com/developerworks/webservices – specyfikacje technologii SDO

Co należy wiedzieć...Powinieneś znać podstawy MySQL-a i programowania obiektowego.

Co obiecujemy...Po przeczytaniu artykułu będziesz wie-dział jak wykorzystać SDO do stworzenia prostego systemu newsów.

Page 43: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org42

Techniki SDO

PHP Solutions Nr 1/2006 www.phpsolmag.org 43

Techniki

PHP i SDOSDO powstało z myślą o platformie J2EE. Jednak dzięki dużemu zainteresowaniu IBM-a technologią PHP i porozumieniu z ZEND Technologies, zostało ono włą-czone również do PHP. Obecna imple-mentacja nie jest tak dopracowana, jak wydanie dla Javy i nie osiągnęła nawet statusu wersji stabilnej. Dostępna jest jedynie jako rozszerzenie PECL (PHP Extensions Community Library). Ponad-to, do swojego poprawnego działania wymaga parsera PHP w wersji 5.1, który w czasie pisania tego artykułu również nie był dostępny w wersji stabilnej.

Mimo wczesnego stadium rozwoju, SDO dla PHP pozwala już zarządzać danymi pochodzącymi z bazy danych i plików XML. Niestety, aktualna imple-mentacja ma szereg ograniczeń, o któ-rych szczegółowo napiszemy w dalszej części artykułu.

Tajemnice drzewa obiektów SDOTajemnicę swojego działania SDO ukry-wa w koncepcji tzw. grafów danych (ang. data graphs). Mówiąc najprościej, dane są zorganizowane w postaci drzewia-stych struktur obiektów. Przykładowo, jeżeli dane, z którymi aktualnie pracuje-my, pochodzą z bazy, to każdy z obiek-tów SDO odpowiada jednemu rekordowi w określonej tabeli znajdującej się w tej bazie. Natomiast relacje pomiędzy obiektami znajdującymi się w drzewie są tożsame z relacjami w bazie danych (np. jeden-do-wielu). Pełną koncepcję drzewa SDO obrazuje Rysunek 2.

Poza drzewem danych, w osobnej gałęzi w ramach struktury obiektów SDO przechowywane są informacje o wszyst-kich zmianach wykonanych na danych. Dzięki temu, obiekty DAS mogą w prosty sposób synchronizować źródła danych z drzewami obiektów. SDO zapewnia pełne API do zarządzania zmianami w drzewie, co umożliwia nam tworzenie własnych obiektów DAS.

Drzewo SDO posiada jeszcze jedną ciekawą cechę: umożliwia przeszukiwanie wszystkich dostępnych w drzewie obiek-tów przy pomocy zapytań XPath.

Data Access ServicesJak już wspomnieliśmy, jednym z głów-nych elementów architektury SDO jest

warstwa obiektów DAS. Ukrywa ona przed programistą szczegóły implemen-tacji związane z komunikacją ze źródłami danych. W przybliżeniu, jest to rozszerze-nie koncepcji warstwy dostępu do danych, często spotykanej w korzystających z baz danych aplikacjach PHP.

Twórcy specyfikacji DAS poszli krok dalej i nie tylko ujednolicili dostęp do baz danych, ale zadbali także, aby w podobny sposób można było się komunikować z in-nymi źródłami, np. plikami XML. To ostat-nie jest szczególnie przydatne podczas eksportu danych z bazy oraz ich importu.

Wymiana danych z bazami odbywa się z wykorzystaniem rozszerzenia PDO. Do komunikacji z plikami XML zaprzęgnię-to natomiast rozszerzenie SimpleXML. My skupimy się na pokazaniu, w jaki sposób SDO komunikuje się z bazą danych.

Aktualna implementacja obiektów DAS ma, niestety, szereg ograniczeń. Najważniejsze z nich to m.in. obsługa jedynie dwóch silników bazodanowych: DB2 i MySQL, czy możliwość zdefinio-wania tylko jednego (jednopolowego) klucza głównego na tabelę oraz brak transparentnej obsługi relacji typu wiele-do-wielu. To ostatnie oznacza, że model SDO nie przewiduje przechowywania informacji o relacji pomiędzy danymi z dwóch tabel w tzw. tabeli relacji.

Instalacjarozszerzenia SDOProcedura instalacji zależy od platformy systemowej. W przypadku Windows, po-bieramy ze strony PHP ostatnią skompi-lowaną wersję PHP 5.1 (w czasie pisania artykułu była to wersja RC1) i zestaw

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

������

�����

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

Rysunek 1. Architektura SDO

������

������

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

�����

Rysunek 2. Drzewo obiektów SDO

Page 44: Php Solutions 1 2006 PL

SDO

PHP Solutions Nr 1/2006www.phpsolmag.org44

Techniki

skompilowanych rozszerzeń PECL (gdy pisałem artykuł, SDO było dostępne w wersji 0.5.1).

Jeżeli instalujemy SDO pod Linuk-sem, proces instalacji jest dużo bardziej skomplikowany, głównie dlatego, że na php.net nie ma oficjalnej dystry-bucji binarnej PHP dla tego systemu. Twórcy niektórych dystrybucji Linuksa dostarczają pakiety binarne PHP, cza-sem jednak trzeba go skompilować samemu. Źródła PHP pobieramy ze strony http://php.net. Podobnie uczy-nimy z SDO, którego źródła można pobrać z repozytorium PECL (http://pecl.php.net/package/sdo). Pamiętajmy, że do poprawnego działania SDO po-trzebuje rozszerzeń PDO i SimpleXML. Na szczęście są one dostępne standar-dowo w kodzie źródłowym PHP 5.1.

Pierwszy przykładJeżeli już zainstalowaliśmy i uruchomi-liśmy PHP 5.1 z rozszerzeniem SDO, możemy zająć się utworzeniem wspo-mnianego wcześniej systemu aktual-ności. Spróbujmy więc przekonać się na własne oczy, jak szybko i elegancko możemy przy pomocy tej technologii na-

pisać system newsów. Pracę rozpocznie-my od stworzenia prostej bazy danych. Na Listingu 1. przedstawiamy schemat bazy dla MySQL-a.

Aktualności przechowywane są w dwóch tabelach. Pierwsza z nich, o nazwie news_groups zawiera podsta-wowe informacje o grupach newsów, takie jak id grupy (ng_id), nazwa grupy (ng_name) i opis (ng_description). Same wiadomości gromadzone są w drugiej tabeli, news_contents. Każdy rekord z tej tabeli zawiera następujące infor-macje: id aktualności (nc_id), jej tytuł (nc_subject), streszczenie (nc_lead), treść (nc_content) oraz referencje do jednej z grup (ng_id). Na Rysunku 3. przedstawiony jest diagram encji dla obu tabel. Wynika z niego, że tabela news_contents znajduje się w relacji wiele-do-jednego w stosunku do tabeli news_groups.

Przejdźmy teraz do pisania pierwsze-go skryptu wykorzystującego rozszerze-nie SDO. Pierwszą rzeczą, jaką musimy uczynić, jest konfiguracja klasy DAS. Jak wiemy, klasa ta odpowiada za dostęp do źródła danych (w naszym przykładzie – MySQL). Sama klasa jest na tyle ogól-na, że nie wie, jaką strukturę ma nasza baza. Dlatego też musimy powiedzieć jej, do których tabel i kolumn ma zapisać odpowiednie elementy drzewa obiektów SDO. Aby skonfigurować DAS, należy dla każdej tabeli utworzyć mapping – tablicę PHP zawierającą następujące informacje:

� nazwę tabeli,� tablicę z nazwami pól,� nazwę pola z kluczem głównym

(klucz główny w tabeli może składać się z jednego pola),

� tablicę opisująca relacje do innej tabeli.

Dodatkowo, jeżeli nasz obiekt DAS ma obsługiwać wiele tabel, pomiędzy którymi

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

��

��������

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

�������

����������

����������

�� ������

��������

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

Rysunek 3. Diagram encji dla bazy danych newsów

Listing 1. Skrypt tworzący bazę newsów dla MySQL-a

/****************************************

* tabela z grupami newsów

*

*****************************************/

create table `news_groups` ( ng_id int(11) not null auto_increment, ng_name varchar(100) not null, ng_description text, primary key (ng_id));

/****************************************

* tabela z newsami. Zawiera relację do news_groups

*

*****************************************/

create table news_contents ( nc_id int(11) not null auto_increment, ng_id int(11) not null, nc_subject varchar(100) not null, nc_lead text, nc_content text not null, primary key (nc_id),);

Listing 2. Konfiguracja klasy DAS dla dwóch tabel (news_groups i news_contents)

$newsGroupsMap = array ( 'name' => 'news_groups',

'columns' => array( 'ng_id', 'ng_name', 'ng_description' ), 'PK' => 'ng_id'

);

$newsContentsMap = array ( 'name' => 'news_contents',

'columns' => array('nc_id','ng_id','nc_subject','nc_lead','nc_content'), 'PK' => 'nc_id',

'FK' => array ( 'from' => 'ng_id',

'to' => 'news_groups',

)

);

$newsContentsRelationsMap = array( 'parent' => 'news_groups',

'child' => 'news_contents' );

Page 45: Php Solutions 1 2006 PL

SDO

PHP Solutions Nr 1/2006 www.phpsolmag.org 45

Techniki

są relacje, potrzebna jest jeszcze jedna tablica zawierająca informacje o kie-runku tych relacji, tzn. która z tabel jest nadrzędna, a która podrzędna. Przypo-mnijmy, że obecna implementacja obsłu-guje jedynie relacje jeden-do-wielu oraz jeden-do-jednego.

Na Listingu 2. pokazujemy przykła-dową konfigurację dla tabel news_groups i news_contents.

Patrząc na tablice konfiguracyjne, zauważamy jedne z największych bolą-czek obecnej implementacji SDO: klucz główny jest jednopolowy, a tablica może

mieć tylko jedną relację (jeden klucz obcy). Na szczęście, w wielu prostych bazach danych, ograniczenia te nie mają znaczenia. Ponadto, należy zakładać, że w miarę rozwoju projektu, autorzy rozwiną jego funkcjonalność również w tych dzie-dzinach.

Skoro mamy już skonfigurowany obiekt DAS, najwyższa pora utworzyć kod, który zapisze grupę newsów do bazy danych. Odpowiedni skrypt z po-minięciem mappingu przedstawiamy na Listingu 3.

Pierwszą operacją, jaką musimy wykonać jest otwarcie połączenia do bazy danych. Pamiętajmy, że SDO korzysta w tym celu z PDO. Po nawią-zaniu połączenia tworzymy obiekt klasy SDO_DAS_Relational, który będzie odpo-wiedzialny za zapisanie grupy newsów do naszej bazy danych. Jako parametry, klasa ta musi otrzymać tablice konfi-gurujące wszystkie tabele, z którymi będziemy się komunikować poprzez SDO, a także nazwę tabeli nadrzędnej i tablicę z typami relacji pomiędzy tabe-lami. Nic nie stoi na przeszkodzie, aby dla każdej z tabel naszej bazy stworzyć osobne obiekty DAS. Pozbawiłoby nas to jednak możliwości jednoczesnego zapisywania drzew obiektów, między którymi istnieje relacja.

Wracając do przykładu: dwie naj-ważniejsze klasy są już gotowe. Mu-simy jeszcze utworzyć korzeń drzewa obiektów SDO. Służy do tego metoda createRootDataObject(), którą wywołu-jemy na obiekcie DAS. Mając korzeń, możemy teraz utworzyć obiekt news_

groups, który zapiszemy później do bazy danych. Do tworzenia obiektów w drzewie SDO, przeznaczona jest me-toda createDataObject(). Ma ona jeden parametr: nazwę tabeli, dla której należy utworzyć obiekt. W naszym przypadku jest to news_groups. Obiekt news_groups posiada atrybuty publiczne, których na-zwy są tożsame z nazwami odpowiednich kolumn w tabeli news_groups, znajdującej się w bazie danych. Informacji o nazwach tych kolumn dostarcza SDO mapping. Przypisując tym atrybutom odpowiednie wartości możemy stworzyć pożądany obiekt. Aby zapisać go do bazy danych, należy na obiekcie DAS wykonać metodę applyChanges(). Ma ona dwa parametry: obiekt PDO i drzewo obiektów SDO.

Tak oto, w siedmiu linijkach kodu, bez napisania choćby jednego polecenia

Listing 3. Skrypt dodający grupę newsów do bazy danych

<?php

require_once 'Relational.php';$dbConnection = new PDO('mysql:host=localhost;dbname=nazwa_bazy_danych', 'użytkownik','hasło');

$das = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap), 'news_groups',array( $newsContentsRelationsMap ));$root = $das->createRootDataObject();

$newsGroup1 = $root->createDataObject('news_groups');

$newsGroup1->ng_name = "Grupa Pierwsza";

$newsGroup1->ng_description = "Opis dla pierwszej grupy";

$das->applyChanges($dbConnection, $root);

?>

Listing 4. Skrypt pobierający jeden rekord z bazy danych i modyfikujący go

<?

require_once 'Relational.php';$dbConnection = new PDO ('mysql:host=localhost;dbname=nazwa_bazy_danych','użytkownik','hasło');

$das = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap), 'news_groups', array( $newsContentsRelationsMap ) );$root = $das->executeQuery($dbConnection, 'select * from news_groups where

ng_id=1', array( 'news_groups.ng_id', 'news_groups.ng_name', 'news_groups.ng_description' ) );

$root['news_groups'][0]->ng_name = 'The future of GUIs for PHP';

$das->applyChanges($dbConnection, $root);

?>

Listing 5. Skrypt pobierający jeden rekord z bazy danych i kasujący go. Drugą metodą usunięcia obiektu z drzewa jest przypisanie mu wartości null

require_once 'Relational.php';$dbConnection = new PDO ('mysql:host=localhost;dbname=nazwa_bazy_danych','użytkownik','hasło');

$das = new SDO_DAS_Relational( array($newsGroupsMap,$newsContentsMap), 'news_groups', array( $newsContentsRelationsMap ) );$root=$das->executeQuery($dbConnection, 'select * from news_groups where

ng_id=1', array( 'news_groups.ng_id', 'news_groups.ng_name', 'news_groups.ng_description' ) );

unset( $root['news_groups'][0] );$das->applyChanges($dbConnection, $root);

Listing 6. Skrypt umożliwiający jednoczesne dodanie do bazy danych grupy i związanego z nią newsa

$newsGroup = $root->createDataObject('news_groups');

$newsGroup->ng_name = "PHP-related news";

$newsGroup->ng_description = "The best news around the world of PHP";

$newsContent1 = $newsGroup->createDataObject('news_contents');

$newsContent1->nc_subject = 'SDO is becoming popular';

$newsContent1->nc_lead = 'SDO or Service Data Objects is gaining more and more';

$newsContent1->nc_content = 'the content of article on SDO';

$newsContent2 = $newsGroup->createDataObject('news_contents');

$newsContent2->nc_subject = 'AJAX and PHP';

$newsContent2->nc_lead = 'AJAX is a solution for the interactive web pages';

$newsContent2->nc_content = 'the content of the article';

$das->applyChanges($dbConnection, $root);

Page 46: Php Solutions 1 2006 PL

SDO

PHP Solutions Nr 1/2006www.phpsolmag.org46

Techniki

SQL, zapisaliśmy rekord w bazie da-nych. Warto wspomnieć, że za jednym razem możemy zapisać wiele obiektów. Nic nie stoi bowiem na przeszkodzie, aby metodę createDataObject() wy-wołać wiele razy, tworząc tym samym wiele obiektów news_groups. Możemy nawet wielokrotnie zapisywać te obiek-ty w bazie danych: SDO samo zadba o to, co powinno zostać w niej zapisa-ne. Możliwe jest to dzięki opisanemu już mechanizmowi, który zapamiętuje każdą zmianę stanu drzewa obiektów. Jeżeli więc cokolwiek dodamy, skasuje-my lub zmienimy, drzewo będzie miało informacje na ten temat.

Każda operacja zapisu zmian zeruje rejestr zmian, dlatego nawet po dwukrot-nym wykonaniu operacji applyChanges dane zostaną zapisane tylko raz.

Skoro potrafimy już zapisać dane do bazy, spróbujmy je teraz odczytać, zmo-dyfikować i ponownie zapisać. Tak jak poprzednio, posłużymy się przykładem. Na Listingu 4. przedstawiamy kod, który potrafi wykonać te zadania.

Tak jak w poprzednim przykładzie, skrypt rozpoczyna się od inicjalizacji klasy SDO_DAS_Relational i nawiązania połączenia. W następnym kroku, przy użyciu metody executeQuery() po-bieramy obiekty SDO z bazy danych. Warto w tym miejscu zwrócić uwagę na fakt, że mimo iż składnia polece-nia zawiera zapytanie SQL, wynikiem jego działania jest drzewo obiektów

SDO. Na otrzymanym drzewie może-my wykonywać dowolne operacje, np. dodać do niego nowy element (metoda createDataObject), a także zmienić czy skasować istniejący element. Procedu-ra kasowania obiektu pokazana jest na Listingu 5. Tak jak w poprzednim przy-

padku, aby zapisać dokonane zmiany, należy wykonać na obiekcie DAS me-todę applyChanges().

Drugi przykładSpróbujmy teraz napisać skrypt, który będzie potrafił dodać jednocześnie grupę newsów i kilka związanych z nią wiado-mości. Kod prezentujący ten przykład przedstawiamy na Listingu 6. Dla uprosz-czenia pokazujemy tam tylko kod cha-rakterystyczny dla tej operacji, pomijając początkową inicjalizację obiektów.

Zwróćmy uwagę, że po utworze-niu obiektu SDO dla grupy newsów, wywołujemy na tym obiekcie metodę createDataObject(), która tworzy obiekt SDO dla konkretnej wiadomości. Jeżeli chcemy utworzyć więcej niż jedną wiado-mość, to wystarczy po raz kolejny wywo-łać metodę createDataObject(). Warto zauważyć, że nie musimy martwić się o przekazanie obiektowi newsa id grupy, gdyż SDO zrobi to za nas. Ponadto nic nie stoi na przeszkodzie, aby za jednym razem stworzyć wiele grup i przypisać im wiele newsów.

Kolejnym zadaniem jest pobranie z bazy drzewa z grupami i związanymi z nimi newsami przy pomocy jednego

Rysunek 4. Wynik działania zapytania, które za jednym razem wyciąga z bazy grupy newsów i same wiadomości

Listing 7. Kwerenda pobierająca z bazy danych drzewo z grupami i newsami

$root = $das->executeQuery($dbConnection, 'select * from news_groups,

news_contents where news_groups.ng_id=news_contents.ng_id',

array( 'news_groups.ng_id', 'news_groups.ng_name',

'news_groups.ng_description','news_contents.nc_id',

'news_contents.nc_subject', 'news_contents.nc_lead',

'news_contents.nc_content'

));

Listing 8. Kasowanie grupy wraz z newsami

$root = $das->executeQuery($dbConnection, 'select news_groups.ng_id,

news_contents.nc_id from news_groups, news_contents where

news_groups.ng_id=news_contents.ng_id',

array( 'news_groups.ng_id',

'news_contents.nc_id'

));

unset( $root['news_groups'][0] );$das->applyChanges($dbConnection, $root);

object(SDO_DataObjectImpl)[12] public 'news_groups' => object(SDO_DataObjectList)[11]

object(SDO_DataObjectImpl)[14] public 'ng_id' => '10' public 'ng_name' => 'Grupa Pierwsza' public 'ng_description' => 'Opis dla pierwszej grupy' public 'ng_contents' => object(SDO_DataObjectList)[13]

object(SDO_DataObjectImpl)[15] public 'nc_id' => '4' public 'nc_subject' => '10' public 'nc_lead' => 'Jakiś tytuł' public 'nc_content' => 'Jakaś zajawka'

object(SDO_DataObjectImpl)[16] public 'ng_id' => '11' public 'ng_name' => 'Grupa Pierwsza' public 'ng_description' => 'Opis dla pierwszej grupy' public 'ng_contents' => object(SDO_DataObjectList)[18]

object(SDO_DataObjectImpl)[17] public 'nc_id' => '5' public 'nc_subject' => '11' public 'nc_lead' => 'Jakiś tytuł' public 'nc_content' => 'Jakaś zajawka'

Page 47: Php Solutions 1 2006 PL

SDO

PHP Solutions Nr 1/2006 www.phpsolmag.org 47

Techniki

zapytania. Jego rozwiązanie pokazujemy na Listingu 7.

Pomijając oczywiście operacje związa-ne z konfiguracją połączenia i klasy DAS widzimy, że wszystko, co musimy napisać, zawiera się w jednej linii kodu!

Metoda executeQuery() potrzebuje dwóch parametrów: połączenia do bazy danych i zapytania SQL. Trzeci para-metr jest opcjonalny, wymagany jedynie w sytuacjach, gdy nazwa którejkolwiek kolumny występuje dwa razy w mappin-gu. Taka sytuacja ma miejsce w naszym przykładzie: kolumna ng_id pojawia się zarówno w tabeli news_groups, jak i news_contents. Fakt, że są to inne ta-bele, nie ma znaczenia. Jeżeli więc nie chcemy podawać trzeciego parametru, musimy pamiętać, aby w naszym mo-delu nie powtarzała się nazwa żadnej kolumny. Wystarczy więc przyjąć odpo-wiednią strategię nazewnictwa. Rezul-tatem wykonania tego kodu jest drzewo obiektów SDO, które przedstawiamy na Rysunku 4.

Na zakończenie pokażemy jeszcze, jak skasować grupę i związane z nią newsy. Jest to bardzo proste, ponie-waż wystarczy pobrać grupę wraz ze związanymi z nią newsami (wszystkimi) i wykonać na niej funkcję unset() lub przypisać do niej wartość null. Jeżeli pobierzemy samą grupę, to SDO będzie próbowało skasować jedynie ją. Nie jest to oczywiście problemem, gdy pracuje-my na bazie wyposażonej w mechanizm kluczy obcych. Jeżeli jednak nasza baza danych to np. MySQL, a tabele na których operujemy, są w formacie MyISAM, to usunięcie samej grupy powiedzie się, ale dane w bazie będą niespójne. Skrypt ilustrujący kasowanie grupy wraz z newsami pokazany jest na Listingu 8.

PodsumowanieBudując prostą bazę danych dla sys-temu newsów, pokazaliśmy możliwości drzemiące w SDO. Mimo, że rozszerze-nie to znajduje się ciągle w fazie rozwo-

ju, jego funkcjonalność jest imponująca. Miejmy nadzieję, że już wkrótce jego autorzy wydadzą wersję stabilną, która będzie pozbawiona obecnych manka-mentów. Warto pamiętać, że pomijając wymienione ograniczenia, już obecnie kod biblioteki SDO jest bardzo solidny. Zachęcamy więc do własnych ekspe-rymentów i zapraszamy do następnego artykułu o technologiach SDO i XML, który ukaże się w kolejnym numerze PHP Solutions. n

Piotr Szarwas jest pracownikiem SU-PERMEDIA Interactive i doktorantem na wydziale Fizyki Politechniki War-szawskiej. Od 2003 roku projektuje aplikacje WWW w oparciu o PHP4/5. Obecnie zajmuje się tworzeniem frame-worka dla PHP opartego na rozwiąza-niach Hibernate i Spring.

O autorze

Jestem nieco znudzony ofertą polskich wydań książek o PHP, pewnie dlatego również po tę pozycję sięgałem niechętnie. Przypuszcza-łem, że będzie to materiał podobny do bardzo dobrej książki PHP Zaawansowane programowanie. Vademecum profesjonalisty autor-stwa Georga Schlossnagle’a, tyle że z większym naciskiem na PHP5. Na szczęście PHP5 Zaawansowane programowanie okazało się inne. Dużo inne. Książka nie stanowi vademecum profesjonalisty – nie przeczytamy w niej (w sposób encyklopedyczny) o wszystkich zaawansowanych cechach języka PHP. Przeczytamy w niej o profesjonalnym podejściu do tworzenia złożonych aplikacji w PHP5. Autorzy skupili się na dogłębnym opisaniu modelowania w UML, korzystania ze wzorców projek-towych, testowania aplikacji (PHPUnit) czy tworzenia własnego warsztatu programisty – narzędzi które będzie można wielokrotnie wykorzystać w każdym projekcie.

Bardzo ciekawa jest część (ponad 200 stron) opisująca Studium przypadku – automatyzacja działu sprzedaży. Dowiemy się, jak podejść do dużego projektu informatycznego i jak nim zarzą-dzać. Omówione zostaną pojęcia planowania i architektury systemu. Razem z autorami stworzymy aplikację automatyzującą pracę zespołu sprzedaży i solidną platformę raportującą.

Szczerze poleciłbym tę książkę programistom PHP, którzy mają już za sobą kilka projek-tów w PHP, ale chcą zacząć tworzyć aplikacje w sposób bardziej profesjonalny – przemyślany, solidny i wydajny. Jeśli planujesz wykonanie większego projektu lub nie wierzysz (nie znasz)w PHP5, a szukasz dobrej platformy programistycznej do tworzenia aplikacji WWW – ta lektura jest dla Ciebie.

Dariusz Pawłowski

R E C E N Z J A

PHP5 Zaawansowane programowanieAutorzy: Ed Lecky-Thompson, Heow Eide-Goodman, Steven D. Nowicki, Alec CoveWydanie: Helion 2005 Cena: 79,00 zł

«««««

Page 48: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org48

Techniki AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 49

Techniki

AJAX pozwala stworzyć dodatkowy kanał komunikacji między klientem a serwerem PHP, a tym samym

wysyłać i odbierać dane bez przeładowy-wania strony. Otwiera to zupełnie nowe możliwości, a w połączeniu z operacjami na modelu DOM z poziomu JavaScriptu, oznacza nadejście ery bogato wyposażo-nych, interaktywnych aplikacji PHP, wol-nych od irytującego klikania i czekania.

W tym artykule przedstawimy prak-tyczne wprowadzenie do techniki AJAX na przykładzie dwóch bibliotek PHP i nie-wielkiej aplikacji o działaniu podobnym do Google Suggest.

Czym jest AJAX?AJAX (skrót od Asynchronous JavaScript And XML) jest nazwą nowej metody pro-gramowania, łączącej kilka różnych tech-nik: (X)HTML i CSS do tworzenia interfej-su użytkownika, DOM (Document Object Model) do obsługi elementów dynamicz-nych i interakcji oraz XMLHttpRequest do

Aplikacje tworzone w PHP pozwalają osiągnąć bardzo wiele przy ograniczonym oprogramowaniu klienckim, co oznacza łatwe wdrażanie i aktualizacje, a tym samym szybkie efekty pracy. Architektura ta ma też dotkliwe wady, jak opóźnienia między wyświetlaniem kolejnych stron lub brak możliwości pobierania nowych danych bez wysyłania formularza.Na szczęście istnieje mechanizm AJAX.

asynchronicznej wymiany danych. Techni-ki te są łączone w jedną całość za pomocą JavaScriptu, odpowiedzialnego za logikę aplikacji i dynamiczną aktualizację interfej-su użytkownika stosownie do potrzeb.

Pomimo XML w nazwie, AJAX nie-koniecznie wymaga używania formatu XML do wymiany danych. Poza XML-em obsługiwane są między innymi zwykły tekst, sformatowany HTML (dodawany do bieżącej strony poprzez właściwość innerHTML) oraz format JSON (JavaScript

AJAX – wyjątkowo interaktywne i wydajne aplikacje WWWJoshua Eichorn, Werner M. Krauß

W SIECI

1. http://sourceforge.net/projects/jpspan/ – strona główna projektu JPSpan

2. http://pear.php.net/package/HTML_AJAX/ – strona głów-na pakietu HTML_AJAX

3. http://www.google.com/webhp?complete=1&hl=en – Google Suggest

4. http://www.ajaxpatterns.org/ – serwis poświęcony wzor-com aplikacji AJAX

5. http://www.ajaxpatterns.org/Suggestion – opis wzorca w stylu Google Suggest

6. http://blog.joshuaeichorn.com/archives/category/php/ajax – blog Joshuy Eichorna poświęcony AJAX-owi

Powinieneś wiedzieć...Powinieneś się dobrze orientować w zasadach programowania obiektowe-go w PHP4 lub PHP5. Przyda się też pewna znajomość JavaScriptu.

Obiecujemy...Po przeczytaniu artykułu będziesz znał zasadę działania i stosowania techniki AJAX oraz śledzenia kodu. Pokażemy też możliwości bibliotek implementują-cych tę technikę.

Page 49: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org48

Techniki AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 49

Techniki

Object Notation), który można przepuścić przez eval() w celu uzyskania typów JavaScript. Można też korzystać z dowol-nego innego formatu danych dającego się obsłużyć w JavaScripcie i PHP.

AJAX-a można najprościej zde-finiować jako metodę wykorzystania JavaScriptu do komunikacji z serwerem niezależnie od tradycyjnych żądań POST i GET. Strona techniczna jest tu jednak mniej istotna – najważniejsze są zupełnie nowe możliwości tworzenia aplikacji inter-netowych.

Podstawą pracy AJAX-a jest obiekt XMLHttpRequest, stanowiący standar-dowy element wielu przeglądarek. Jeśli postanowisz dodać obsługę AJAX-a do swojej aplikacji za pomocą biblioteki, to nie musisz wiele wiedzieć o samym XMLHttpRequest, gdyż wszystkim zajmie się biblioteka. Fizyczna implementacja obiektu XMLHttpRequest zależy od kon-kretnej przeglądarki – w Internet Explo-rerze jest to wbudowany obiekt ActiveX, natomiast w Firefoksie, Safari i większości innych przeglądarek jest on wewnętrznym obiektem JavaScriptu.

XMLHttpRequest udostępnia proste API, pozwalające wysyłać do serwera żądania HTTP metodami GET i POST. Dla serwe-ra są to zwyczajne żądania przeglądarki, zawierające nawet wszystkie pliki cookie dla bieżącej domeny oraz autoryzację HTTP (jeśli oczywiście jest włączona). Od strony JavaScriptu, XMLHttpRequest daje dostęp do treści i nagłówków podczas wysyłania i odbioru żądań. Możliwość ta jest często używana do poinformowania serwera, że żądanie nie zostało zgłoszo-

możliwość uzyskania znacznie wyższego poziomu interaktywności w aplikacjach internetowych. Reakcje programu na dzia-łania użytkownika są dużo szybsze, bez nużącego klikania i czekania, przez co ob-sługa całego programu znacznie bardziej przypomina pracę z tradycyjną aplikacją stacjonarną.

Rysunek 1 przedstawia przepływ da-nych w typowej aplikacji internetowej. Użyt-kownik wypełnia formularz i wysyła go na serwer WWW, który przetwarza formularz i odsyła dane do czekającego użytkownika. Zwracanym wynikiem jest pełna strona HTML, którą przeglądarka klienta musi za-ładować w całości (treść i strukturę). Mar-nuje się w ten sposób czas i pasmo, gdyż kod strony wynikowej najczęściej niewiele się różni od kodu poprzedniej strony.

Aplikacja AJAX wysyła do serwera wyłącznie żądania pobierające nowe, po-trzebne dane, a odpowiedź serwera jest przetwarzana przez JavaScript po stronie klienta. Dzięki wprowadzeniu tej dodatko-wej warstwy JavaScriptu, przetwarzanie danych nie spowalnia działania interfejsu użytkownika. Cała aplikacja działa znacz-nie szybciej, gdyż między serwerem, a klientem przesyłanych jest nieporów-nanie mniej danych, a spora część prze-twarzania odbywa się po stronie klienta (Rysunek 2).

Praktycznie rzecz ujmując, stworze-nie aplikacji AJAX wymaga zatem dwóch

���

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

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

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

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

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

���

����

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

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

Rysunek 1. Przepływ danych w tradycyjnej aplikacji internetowej

���

������

���

����

����

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

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

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

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

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

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

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

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

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

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

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

Rysunek 2. Przepływ danych w aplikacji AJAX

ne bezpośrednio przez użytkownika, lecz poprzez XMLHttpRequest. Odebraną treść można traktować jako zwykły tekst, ale w przypadku treści typu text/xml można też stworzyć obiekt XML DOM. Obsługa modelu DOM przyczyniła się do popular-ności XML-a jako formatu wymiany da-nych między klientem a serwerem, nato-miast utrzymanie obsługi zwykłego tekstu pozwala korzystać z dowolnego formatu dającego się przetworzyć na poziomie JavaScriptu.

Dlaczego AJAX?Najważniejszym argumentem przema-wiającym za korzystaniem z AJAX-a jest

Page 50: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org50

Techniki

elementów: odpowiednich skryptów po stronie klienta i specjalnego kanału komu-nikacji z serwerem.

Zalety techniki AJAXAJAX ma wiele zalet, z których najbardziej zauważalną jest znaczące rozszerzenie zakresu możliwości interfejsu użytkowni-ka. Jednak samo w sobie to nie wystar-czy – w końcu istnieje też wiele innych technologii o zbliżonych możliwościach. O wyjątkowości AJAX-a stanowi przede wszystkim to, że bazuje on na uznanych standardach, więc w przeciwieństwie do innych narzędzi do tworzenia interaktyw-nych aplikacji internetowych (na przykład Flasha) można go z łatwością wpasować w istniejące procesy deweloperskie. Moż-na więc dalej korzystać ze swojego ulu-bionego edytora czy środowiska programi-stycznego, bez konieczności poznawania nowych narzędzi.

Istnieje też wiele darmowych zesta-wów narzędzi Open Source ułatwiających tworzenie i rozwijanie aplikacji AJAX, a przy okazji redukujących objętość kodu JavaScriptu, jaki trzeba wpisywać ręcznie. W dalszej części artykułu zobaczymy, jak dołączać obsługę AJAX-a do własnych aplikacji z pomocą popularnych bibliotek.

Wady AJAX-aOpisywana metoda interakcji z klientem ma też swoje wady. Nie można przewi-dzieć, z jakiej przeglądarki korzysta użyt-kownik, więc aplikacja może nie działać na niekompatybilnych przeglądarkach lub przy wyłączonej obsłudze JavaScrip-tu. Oznacza to, że dobrą praktyką jest uwzględnienie awaryjnej metody obsługi, na przykład poprzez stworzenie bazowej aplikacji z wykorzystaniem tradycyjnych technik, a następnie rozbudowanie jej o opcjonalne usprawnienia używające AJAX-a.

Trzeba też pamiętać, że aplikacje z AJAX-em nie będą działać w Internet

Listing 1. Serwer JPSpan

<?php

session_start();

// Klasa powitania

class HelloWorld { function HelloWorld() { if (!isset($_SESSION['strings'])) { $_SESSION['strings'] = array('Hello','World','Hello World'); }

}

function addString($string) { $_SESSION['strings'][] = $string;

return $this->stringCount(); }

function randomString() { $index = rand(0,count($_SESSION['strings'])-1); return $_SESSION['strings'][$index]; }

function stringCount() { return count($_SESSION['strings']); }

}

// Ustawienie stałej JPSPAN

require_once 'jpspan-0.4.3/JPSpan.php';// Załadowanie serwera PostOffice

require_once JPSPAN . 'Server/PostOffice.php';

// Utworzenie serwera PostOffice

$S = & new JPSpan_Server_PostOffice();// Rejestracja klasy w serwerze

$S->addHandler(new HelloWorld());

// Obsługa wyświetlania JavaScriptu po dodaniu

// ciągu ?client do URL-a serwera

if (isset($_SERVER['QUERY_STRING']) && strcasecmp($_SERVER['QUERY_STRING'], 'client')==0) {

// Wyłączenie kompresji wynikowego JavaScriptu

// (m.in. usuwania białych znaków) z powodu

// problemów wydajnościowych

define('JPSPAN_INCLUDE_COMPRESS',false);

// Wyświetlenie klienckiego JavaScriptu

$S->displayClient();

}else { // Początek faktycznej obsługi żądań

// Dołączenie obsługi błędów

// błędy, ostrzeżenia i komunikaty serializowane do JS

// Obsługiwanie żądań

$S->serve();

}

?>

JPSpan i PEARWersja biblioteki JPSpan dla repozy-torium PEAR jest dostępna w serwisie http://www.pearified.com. Do instalacji będzie potrzebny PEAR w nowej wersji 1.4, obsługujący inne kanały niż tylko http://pear.php.net. Poleceniem pear channel-discover pearified.com na-leży dodać kanał do repozytorium, po czym można już zainstalować JPSpan poleceniem pear install pearified/JavaScript_JPSpan.

Explorerze z wyłączoną obsługą ActiveX, co często dotyczy na przykład kafejek internetowych. Może się także zdarzyć, że aplikacja będzie działać nieco inaczej w różnych przeglądarkach i na różnych platformach, choć to samo dotyczy tworzenia tradycyjnych aplikacji interne-towych.

AJAX oferuje spore możliwości inte-rakcji, ale do wielu zadań po prostu się nie nadaje, na przykład do dynamicznego rysowania elementów czy obsługi anima-cji – w takich sytuacjach lepiej korzystać

z Flasha. Warto w tym miejscu zaznaczyć, że pomimo teoretycznej możliwości połą-czenia zalet AJAX-a i Flasha w ramach jednej aplikacji, złożoność takiego rozwią-zania jest na tyle duża, że lepiej używać tych technik osobno.

Wykorzystanie bibliotekIstnieje wiele bibliotek narzędziowych mających na celu ułatwienie integracji Ja-vaScriptu i PHP. Wszystkie uwzględniają jakąś metodę przesyłania danych, ale większość oferuje dodatkowe możliwości,

Page 51: Php Solutions 1 2006 PL

AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 51

Techniki

od bezpośredniego odwzorowania metod klas PHP na pośrednika JavaScriptu, po środowisko tworzenia elementów inter-fejsu użytkownika. Przyjrzyjmy się bliżej dwóm popularnym pakietom: bibliotekom JPSpan i HTML_AJAX.

JPSpanNajpierw zajmiemy się pakietem JPSpan – jedną z bardziej dojrzałych bibliotek AJAX dla PHP, dostępną od listopada 2004 r. Podstawową funkcją biblioteki jest niezależna od przeglądarki obsłu-ga mechanizmu AJAX bazująca na XMLHttpRequest, z możliwością wyboru pracy synchronicznej lub asynchronicz-nej. Dostępne jest wspólne, obiektowe API dla JavaScriptu i PHP. JPSpan obsłu-guje też wiele innych funkcji, na przykład przezroczyste odwzorowania obiektów z bardzo dobrą serializacją danych, po-

zwalającą odwzorowywać tablice PHP na obiekty JavaScriptu. Strona z serwera jest dołączana do wynikowych stron HTML ze znacznikiem client, generując pośrednie klasy JavaScript o takim samym API, jak klasy PHP. Ze względu na ograniczenia PHP4, wszystkie nazwy klas i metod są zapisywane małymi literami. Domyślny serwer JPSpan nosi nazwę JPSpan_

Server_PostOffice i może służyć do odwzorowywania na JavaScript zarówno całych klas, jak i ich części. Korzystając z serwera w dużym serwisie można rozważyć dodanie znacznika class, co pozwoli ograniczyć liczbę klas dołącza-nych i rejestrowanych na serwerze, a tym samym zmniejszy koszt przetwarzania. Osobiście nie doświadczyłem jednak żadnych problemów wydajnościowych nawet przy pięciu stale zarejestrowanych klasach integracyjnych.

Wywołania polegają na utworzeniu instancji odpowiedniej klasy JavaScrip-tu, a następnie wywoływaniu jej metod. W chwili utworzenia instancji w trybie asynchronicznym, określana jest klasa zwrotna, po czym wyniki są przesyłane jej metodom o takich samych nazwach, jak metody pierwotnie wywoływane. JPSpan dodatkowo obsługuje złożone ty-py danych, w tym wielowymiarowe tablice i obiekty, jak również serializację i prze-kazywanie błędów PHP do JavaScriptu z możliwością konfiguracji obsługi błędów po stronie klienta.

Strona serweraPrzyjrzyjmy się działaniu JPSpan nieco bliżej na prostym przykładzie typu Hello World, wyświetlającym losowy napis w reakcji na kliknięcie i pozwalającym dodawać nowe napisy. Zaczynamy od utworzenia klasy helloworld, zawierającej proste metody PHP do obsługi dodawania napisów do tablicy sesyjnej, zwracania długości tablicy i wyświetlania losowe-go napisu z tablicy. Są to odpowiednio metody addString(), stringCount() i randomString(), a ich kod przedstawia Listing 1.

Praca z klasami JPSpan nie różni się niczym od obsługi zwykłych klas. Trzeba tylko pamiętać, że klasa ta jest odtwa-rzana przy każdym wywołaniu ze strony JavaScriptu, więc utrzymywanie danych składowych między wywołaniami wymaga pamiętania instancji klasy w ramach sesji.

Musimy jeszcze dołączyć JPSpan i odpowiedni plik serwera PostOffice, po czym możemy stworzyć nową instancję serwera i zarejestrować w niej naszą klasę wywołując $S->addHandler(new

Listing 2. Klient JPSpan

<html>

<head>

<title>Hello World w JPSpan</title>

<script type='text/javascript' src='jpspan_server.php?client'></script>

<script>

// Klasa JavaScript zawierająca metody zwrotne

var hwCallback = { randomstring: function(result) { document.getElementById('canvas').innerHTML += '<p>'+result+'</p>'; },

stringcount: function(result) { document.getElementById('count').innerHTML = result; },

addstring: function(result) { document.getElementById('count').innerHTML = result; }

}

// Utworzenie obiektu zdalnego. Jego nazwa jest odwzorowana małymi literami,

// gdyż w nazwach klas i funkcji PHP4 wielkość liter nie jest rozpoznawana.

// Rejestrując każdą klasę na serwerze można przywrócić rozróżnianie

// wielkości liter.

var remoteHW = new helloworld(hwCallback); function do_addString() { remoteHW.addstring(document.getElementById('string').value); document.getElementById('string').value = ''; }

</script>

</head>

<body onLoad="remoteHW.stringcount()">

<input type="button" name="check" value="Pokaż losowy napis" onclick=

"remoteHW.randomstring(); return false;">

<div>Liczba losowych napisów: <span id="count"></span></div>

<div id="canvas" style="border: solid 1px black; margin: 1em; padding: 1em;"></div>

<div>

Podaj nowy napis:

<input type="text" name="string" id="string" size="20">

<input type="button" name="check" value="Dodaj nowy napis" onclick=

"do_addString(); return false;">

</div>

</body>

</html>

HTML_AJAXa nazwy klasNazwy klas zwracane przez PHP4 są zawsze zapisane małymi literami. Jeśli koniecznie chcesz zachować rozróż-nienie wielkości liter lub potrzebujesz zgodności między PHP4 i PHP5, musisz skorzystać z dodatkowych pa-rametrów metody registerClass(), określających nazwę klasy rejestrowa-nej w JavaScripcie oraz tablicę ekspor-towanych metod:

$server = new HTML_AJAX_Server();

$hello = new HelloWorld();

$methods = array('foo','bar');

$server->registerClass($hello, § 'Example', $methods);

Page 52: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org52

Techniki

HelloWorld()). Pozostaje jeszcze tylko określić, czy chcemy wysłać kliencki kod JavaScript, czy też obsługiwać żądania. Jak widać na Listingu 1, obiektowe API JPSpan bardzo ułatwia przygotowania po stronie serwera.

Strona klientaTeraz zajmiemy się stroną kliencką naszej prostej aplikacji – Listing 2 przedstawia kod klienta. Od razu zwraca uwagę wyraź-ne rozdzielenie kodu HTML i PHP podczas pracy z JPSpan. Wystarczy tylko umieścić w ramach strony HTML poniższy, automa-tycznie generowany kod, odpowiedzialny za faktyczne połączenie HTML i PHP:

<script type='text/javascript'

src='jpspan_server.php?client'>

</script>

Przy odrobinie pracy nagłówkami po-zwala to wygodnie obsłużyć składowanie znanych informacji po stronie klienta, co bardzo przydaje się na przykład przy dodawaniu do istniejącego serwisu pola autouzupełniania.

Następnie tworzymy klasę JavaScriptu o nazwie hwCallback, zawierającą metody zwrotne zastępujące treść odpowiednich elementów <div> wartościami podanymi przez serwer z wykorzystaniem właści-wości innerHTML. Pozostaje już tylko utwo-rzyć zdalny obiekt:

var remoteHW=new helloworld(hwCallback);

Klasa helloworld jest wyeksportowaną klasą PHP, którą wcześniej utworzyliśmy po stronie serwera. Nazwa klasy zawie-ra wyłącznie małe litery, gdyż PHP4 nie rozróżnia wielkości liter w nazwach klas i funkcji. Reszta kodu z Listingu 2. to już tylko dodanie formularza HTML z odpo-wiednimi metodami obsługi – i już może-my się pobawić naszą pierwszą aplikacją stworzoną w technologii AJAX.

HTML_AJAXBiblioteka HTML_AJAX daje znacznie większe możliwości niż JPSpan, ale dla uproszczenia przykładu skorzystamy z po-dobnej konfiguracji, co w przypadku po-przedniego przykładu: zewnętrzna stro-na serwera generuje kod pośredni Java-Scriptu, który jest dołączany i faktycznie wykonywany na stronie HTML. HTML_AJAX potrafi też generować cały kod po-średnika i serwera w jednym skrypcie, ale

Listing 3. HTML_AJAX może posłużyć do pobierania treści z innej strony na tym samym serwerze

<html>

<head>

<script type='text/javascript' src="server.php?client=main"></script>

<script type='text/javascript' src="server.php?client=dispatcher"></script>

<script type='text/javascript' src="server.php?client=HttpClient"></script>

<script type='text/javascript' src="server.php?client=Request"></script>

<script type='text/javascript' src="server.php?client=json"></script>

</head>

<body>

<script type="text/javascript">

function clearTarget() { document.getElementById('target').innerHTML = 'clear'; }

// Operacja 'grab' jest najprostszym zastosowaniem HTML_AJAX, polegającym na

// wysłaniu żądania do strony i pobraniu wyników. Można jej używać w trybie

// synchronicznym lub asynchronicznym (z wywołaniem zwrotnym).

var url = 'README'; function grabSync() { document.getElementById('target').innerHTML = HTML_AJAX.grab(url); }

function grabAsync() { HTML_AJAX.grab(url,grabCallback);

}

function grabCallback(result) { document.getElementById('target').innerHTML = result; }

// Operacja 'replace' może działać albo na adresie (tak jak grab), albo na

// zdalnej metodzie. W tym drugim przypadku trzeba ustawić defaultServerUrl na adres

// eksportujący wywoływaną metodę. Obecnie replace używa wyłącznie synchronicznych

// wywołań AJAX - wywołania asynchroniczne mogą się pojawić w przyszłości.

function replaceUrl() { HTML_AJAX.replace('target',url);

}

</script>

<ul>

<li><a href="javascript:clearTarget()">Czyszczenie pola docelowego</a></li>

<li><a href="javascript:grabSync()">Przykład pobrania synchronicznego</a></li>

<li><a href="javascript:grabAsync()">Przykład pobrania asynchronicznego </a></li>

<li><a href="javascript:replaceUrl()">Zastąpienie zawartości treścią pobraną

spod wskazanego adresu</a></li>

</ul>

<div style="white-space: pre; padding: 1em; margin: 1em; width: 600px; height:

300px; border: solid 2px black; overflow: auto;" id="target">Pole docelowe</div>

</body>

</html>

Listing 4. Klasa implementująca serwer podpowiedzi (plik suggest.class.php)

class suggest { function suggest() { require_once 'pear_array.php'; $this->strings = $aPear;

}

function getString($input='') { if ($input == '') return ''; $input = strtolower($input); $suggestStrings=array(); foreach ($this->strings as $string) { if (strpos(strtolower($string),$input) === 0) { $suggestStrings[] = $string;

}

}

return $suggestStrings; }

}

Page 53: Php Solutions 1 2006 PL

AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 53

Techniki

nie polecałbym tej metody, gdyż tracimy wtedy możliwość lokalnego składowania wcześniej wygenerowanego kodu Java-Scriptu.

Instalacja pakietu HTML_AJAX jest bardzo prosta – wystarczy wykonać po-lecenie pear install HTML_AJAX-alpha. Jeśli na serwerze nie masz narzędzia PEAR, możesz po prostu pobrać pakiet http://pear.php.net/package/HTML_AJAX, rozpakować go i ręcznie umieścić w wy-branym katalogu, wymienionym oczywi-ście w ramach parametru include_path w php.ini.

Rysunek 3. Serwer podpowiedzi w akcji

R E K L A M A

SerwerStrona HTML_AJAX działająca na serwe-rze jest bardzo prosta – jej działanie polega na utworzeniu instancji serwera HTML_AJAX_Server, zarejestrowaniu wszystkich ekspor-towanych klas (zwanych tu stubs, czyli na-miastkami) i obsługiwaniu nadchodzących żądań. Istnieją trzy możliwe rodzaje żądań:

� Żądanie klienckie, zawierające ?client=all w ciągu zapytania. Zamiast all można też podać jedną z części składowych klienta. Obecnie obsługiwanych jest pięć części (Ma-

in, Dispatcher, HttpClient, Request i JSON), a w przyszłości zostanie do-dana obsługa dodatkowych, opcjonal-nych części.

� Żądanie generowanej namiastki, za-wierające ?stub=nazwaklasy w ciągu zapytania (można też podać wartość all).

� Żądanie AJAX, zawierające w ciągu zapytania ?c=nazwaklasy&m=nazwametody.

Pierwsze dwa rodzaje żądań można łączyć w jednym żądaniu, lecz trzeba pamiętać, że wiąże się to z pewnym kompromisem: mniej żądań to mniej po-łączeń z serwerem, ale z drugiej strony generowane namiastki zmieniają się częściej od danych klienckich, co może negatywnie wpłynąć na efektywność lokalnego składowania kodu. Ostrożnie należy też korzystać z żądań stub=all, gdyż namiastka dla, na przykład, dzie-sięciu klas może już być spora. W ko-lejnej wersji biblioteki HTML_AJAX po-jawi się możliwość podawania wielu klas w ramach jednego żądania namiastki w postaci listy rozdzielanej przecinkami, a więc stub=test,test2.

Page 54: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org54

Techniki

Łatwa aktualizacjatreści bez AJAX-aHTML_AJAX pozwala też korzystać z pod-stawowych możliwości AJAX-a wyłącznie po stronie klienckiego JavaScriptu, dzięki czemu można bardzo szybko dodać do strony proste elementy używające AJAX-a lub włączyć HTML_AJAX do istniejącego środowiska. Typowym zastosowaniem jest aktualizacja zawartości elementu HTML za pomocą treści wygenerowanej przez inną stronę PHP, co daje elastyczność ramek <iframe> bez ich wad (patrz Listing 3).

Po dołączeniu do strony niezbędnego kodu JavaScriptu można pobierać treść ze wskazanego adresu na serwerze w trybie synchronicznym za pomocą HTML_AJAX.grab(url) lub w trybie asynchronicz-nym za pomocą HTML_AJAX.grab(url,grabCallback), gdzie argument grabCallback wskazuje funkcję zwrotną automatycznie wywoływaną przez HTML_AJAX po po-braniu treści. Można też wywołać HTML_AJAX.replace('target',url), by zastąpić

zawartość elementu o identyfikatorze podanym jako target treścią pobraną z adresu url. Ze względów bezpieczeń-stwa można w ten sposób pobierać treści wyłącznie z adresów na tym samym serwerze. Nie jest to jednak ograniczenie biblioteki HTML_AJAX, lecz ograniczenie przeglądarki, mające na celu zapobieganie atakom cross site scripting (XSS).

Przykład w stylu Google Suggest z HTML_AJAXPora na nieco bardziej zaawansowany przykład: pole podpowiedzi podobne do mechanizmu Google Suggest (http://www.google.com/webhp?complete=1&hl=en), ale służące do wyszukiwania pakie-tów PEAR (patrz też Ramka Wzorzec AJAX Suggest).

HTML_AJAX pozwala zarządzać inte-rakcją klienta z serwerem w kilku prostych wierszach kodu. Jak widać na Listingu 4., klasa obsługująca stronę PHP jest dość prosta. Dla potrzeb przykładu korzystamy

z tablicy zawierającej możliwe hasła wy-szukiwania, choć w rzeczywistej aplikacji byłyby one prawdopodobnie pobierane z bazy danych. Lista wyszukiwania wy-maga tylko jednej metody getString(), która porównuje przekazany ciąg znaków z kolejnymi pozycjami tablicy. Pasujące elementy są następnie kopiowane do tablicy wyników, która jest ostatecznie zwracana.

Teraz uruchamiamy serwer usługi (Li-sting 5). W tym przykładzie skorzystamy z klasy AutoServer, która rozszerza pod-stawową klasę serwera i dodaje metodę inicjalizacyjną dla każdej klasy. Pozwala to zarządzać eksportem kilku klas PHP za pomocą jednego serwera – wystarczy ustawić wartość zmiennej $initMethods na true i nadać metodom inicjalizacyjnym nazwy w postaci initNazwaKlasy, co dla naszej klasy oznacza utworzenie meto-dy initSuggest(). Wykorzystanie klasy AutoServer w tak prostym przykładzie to oczywiście strzelanie z armaty do muchy, ale pokazuje ciekawe możliwości biblio-teki HTML_AJAX, które mogą się bardzo przydać w większych projektach.

I to by było na tyle po stronie PHP. Jeśli nasza metoda działa poprawnie i nie generuje żadnych błędów, to nie musimy jej więcej zmieniać i możemy się zająć implementacją po stronie klienta. Rzut oka na Listing 6 pokazuje, że za-czynamy od dołączenia JavaScriptu dla serwera:

<script type='text/javascript'

src='auto_server.php?client=

all&stub=suggest'></script>

Następnie tworzymy kod obsługi żądania w postaci metody do_suggest() oraz funk-cję zwrotną do wyświetlania wyników, a na koniec tworzymy nową instancję zdalnej wyszukiwarki AJAX. Reszta kodu to po prostu formularz z jednym polem teksto-wym i elementem <div> do wyświetlania wyników. Dodanie do pola tekstowego ob-sługi zdarzenia onkeyup="do_suggest();

return false;" powoduje wywołanie funkcji do_suggest() po każdym zwolnie-niu klawisza (zdarzenie onkeypress byłoby obsługiwane zbyt wcześnie).

Jak to działa?Każda zmiana wartości pola tekstowego powoduje wywołanie funkcji do_suggest(), która z kolei wywołuje metodę remoteSuggest.getstring() javascriptowej klasy

Wzorzec AJAX SuggestPodpowiadanie użytkownikom możliwych sposobów uzupełnienia tekstu wprowadzanego w polu tekstowym uatrakcyjnia stronę i ułatwia korzystanie z niej – wystarczy zapropono-wać kilka słów lub wyrażeń, które mogą pasować do danych wprowadzanych przez użyt-kownika. Do implementacji mechanizmu uzupełniania służy najczęściej połączenie pola tekstowego z listą rozwijaną wraz z synchronizacją tych elementów.

Użytkownik może podać dowolny tekst, a bieżąca pozycja na liście będzie odpowia-dać dotychczas wprowadzonemu ciągowi. Możliwe jest również wybranie elementu z listy, co spowoduje zastąpienie zawartości pola tekstowego wybranym hasłem.

Implementacja tego wzorca wiąże się z reguły z wykorzystaniem zwykłego pola tek-stowego i stworzeniem niewidocznej z początku warstwy (elementu <div>), w której będą umieszczane kolejne podpowiedzi. Do pola tekstowego trzeba dołączyć funkcję obsługi zdarzenia, kontrolującą zawartość pola w celu zapewnienia poprawnego wyświetlania pasujących podpowiedzi na liście.

Nie będziemy oczywiście wysyłać żądania po każdym naciśnięciu klawisza – lepiej sko-rzystać z techniki dławienia zgłoszeń. W tym przypadku przeglądarka sprawdza co (na przy-kład) 350 milisekund, czy zawartość pola uległa zmianie – jeśli tak, to do serwera wysyłane jest odpowiednie żądanie. Pozwala to ograniczyć liczbę żądań (i tym samym zaoszczędzić nieco pasma), a przy okazji nie będzie przeszkadzać szybko piszącemu użytkownikowi.

Serwer odpowiada na żądanie wysyłając uporządkowaną listę pasujących podpowie-dzi, którą po stronie klienta odbiera funkcja zwrotna. Funkcja ta wprowadza w modelu doku-mentu odpowiednie zmiany, by użytkownik mógł przejrzeć nowe podpowiedzi i ewentualnie wybrać jedną z nich. Z każdą pozycją listy skojarzona jest funkcja obsługi kliknięcia, odpo-wiadająca za aktualizację pola tekstowego treścią wybranej przez użytkownika pozycji.

Tryb synchroniczny i asynchronicznyBiblioteki JPSpan i HTML_AJAX obsługują pracę zarówno w trybie asynchronicznym(z wywołaniami zwrotnymi), jak i synchronicznym (z bezpośrednim zwracaniem wartości).

Ogólnie lepiej jest stosować operacje asynchroniczne, gdyż wywołania synchroniczne mogą wstrzymywać pracę interfejsu użytkownika w oczekiwaniu na odpowiedź drugiej strony. Oczywiście niekiedy jest to zachowanie pożądane, ale przesyłając większe ilości danych trzeba wtedy zawsze pamiętać o wyświetleniu komunikatu typu proszę czekać.

Wywołania synchroniczne są znacznie łatwiejsze do oprogramowania, ale mimo to lepiej oprzeć się pokusie bezkrytycznego ich stosowania. Żądania AJAX w sieci lokalnej najczęściej trwają nie dłużej niż 50 ms, ale w przypadku przesyłania danych przez Internet czas ten najczęściej wzrasta do ponad 250 ms. Oznacza to, że użytkownik nie będzie w stanie skorzystać z żadnego elementu strony czy nawet przełączyć się na inną zakładkę przeglądarki przez ćwierć, a często i pół sekundy.

Page 55: Php Solutions 1 2006 PL

AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 55

Techniki

HTML_AJAX. Ta komunikuje się z ser-werem, który odsyła tablicę pasujących podpowiedzi, przekazywaną następnie funkcji zwrotnej, która kończy cały proces dokonując niezbędnych zmian w struktu-rze dokumentu i wyświetlając podpowiedzi w ramach elementu <div>.

W ten sposób mamy już działający, choć nie najpiękniejszy przykład. Po pierwsze, funkcja autouzupełniania prze-glądarki w tym przypadku tylko przeszka-dza. Możemy ją jednak łatwo wyłączyć dodając do pola tekstowego atrybut autocomplete="off". Po drugie, sposób wyświetlania podpowiedzi pozostawia bardzo wiele do życzenia. Spróbujmy więc ulepszyć funkcję zwrotną – Listing 7. przedstawia poprawiony kod.

Po usunięciu poprzedniej zawartości elementu resultDiv, wyświetlającego wy-niki, opakowujemy każdy wynik w osobny znacznik <span> dla uzyskania lepszej kon-troli nad formatowaniem, po czym w pętli for dodajemy kolejne wyniki do warstwy resultDiv. Etap opakowania wykonujemy wywołując metody JavaScriptu document.createElement("span") i appendChild(). Dla zwiększenia czytelności można popra-cować nad stylem (Listing 8). Najważniej-szy jest tu wpis powodujący wyświetlanie podpowiedzi jedna pod drugą zamiast w jednym wierszu:

#suggestions span {

display: block;

}

Listing 8. Style CSS dla klienta podpowiedzi

* {

padding: 0;

margin: 0;

font-family : Arial, sans-serif;

}

#suggestions {

max-height: 200px;

width : 306px;

border: 1px solid #000;

overflow : auto;

margin-top : -1px;

float : left;

}

#string {

width : 300px;

font-size : 13px;

padding-left : 4px;

}

#suggestions span {

display: block;

}

Listing 5. Serwer podpowiedzi w HTML_AJAX (plik auto_server.php)

session_start();require_once 'HTML/AJAX/Server.php';class AutoServer extends HTML_AJAX_Server { // Ustawienie tego znacznika jest konieczne, by korzystać z metod inicjalizacyjnych

var $initMethods = true;

// Metody inicjalizacyjne dla klasy podpowiedzi

function initSuggest() { require_once 'suggest.class.php'; $suggest = new suggest(); $this->registerClass($suggest);

}

}

$server = new AutoServer();$server->handleRequest();

Listing 6. Prosty klient podpowiedzi

<html>

<head>

<title>HTML_AJAX Suggest</title>

<script type='text/javascript' src='auto_server.php?client=all&stub=suggest'>

</script>

<script>

function do_suggest() { remoteSuggest.getstring(document.getElementById('string').value); }

// Stworzenie tablicy asocjacyjnej do składowania metod zwrotnych

var suggestCallback = { getstring: function(result) { document.getElementById('suggestions').innerHTML = result; }

}

// Utworzenie obiektu zdalnego. Jego nazwa jest odwzorowana małymi literami,

// gdyż w nazwach klas i funkcji PHP4 wielkość liter nie jest rozpoznawana.

// Rejestrując każdą klasę na serwerze można przywrócić rozróżnianie

// wielkości liter.

var remoteSuggest = new suggest(suggestCallback); </script>

</head>

<body>

<div>

Podaj nazwę pakietu PEAR:

<input type="text" name="string" id="string" size="20" onkeyup="

do_suggest(); return false;">

<input type="button" name="check" value="Podpowiedz..." onclick="do_suggest();

return false;">

</div>

<div id="suggestions">&nbsp;</div>

</body>

</html>

Listing 7. Ulepszona metoda zwrotna

var suggestCallback = { getstring: function(resultSet) { var resultDiv = document.getElementById('suggestions'); resultDiv.innerHTML = '';

for(var f=0; f<resultSet.length; ++f){ var result=document.createElement("span"); result.innerHTML = resultSet[f];

resultDiv.appendChild(result);

}

}

}

Page 56: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org56

Techniki

Warstwa wyników powinna początkowo być ukryta, więc w pliku CSS podajemy dla niej atrybut display: none, który po otrzymaniu wyników przełączamy na war-tość block w ramach metody zwrotnej:

resultDiv.style.display='block';

if (!resultSet)

resultDiv.style.display='none';

Dodatkowe sprawdzenie zapobiega wy-świetleniu warstwy, gdy serwer nie zwróci żadnych podpowiedzi.

Pora dodać do wyników nieco interak-cji – na razie tylko widzimy podpowiedzi, ale nie możemy wybierać pozycji z listy. Efekt wybierania osiągniemy dodając obsługę zdarzeń do elementu <span> każ-dego wyniku:

result.onmouseover = highlight;

result.onmouseout = unHighlight;

result.onmousedown = selectEntry;

Spowoduje to dodanie funkcji Java-Script do każdego zdefiniowanego zdarzenia. Działanie funkcji highlight() i unHighlight() polega po prostu na zmianie klasy CSS elementu <span>:

function highlight (){

this.className='highlight';

}

Klasa CSS highlight wygląda tak:

.highlight {

background-color: 0000ff;

color: fff;

}

Minimalna wersja naszej wyszukiwarki powinna obsługiwać zastąpienie zawar-tości pola tekstowego podpowiedzią klikniętą przez użytkownika. Pole ma identyfikator string, więc podmiana jego treści jest prosta:

function selectEntry () {

document.getElementById('string')

.value = this.innerHTML;

}

Wartość pola tekstowego jest zastępowa-na zawartością danego elementu <span>, czyli jednym z wyników zwróconych przez serwer AJAX.

Całość wygląda już znacznie lepiej (Rysunek 3). Przykład działa poprawnie,

Listing 9. Ostateczna wersja klienta podpowiedzi

<html>

<head>

<title>Podpowiedzi HTML_AJAX</title>

<link rel="StyleSheet" type="text/css" href="suggest3.css" />

<script type='text/javascript' src='auto_server.php?client=all&stub=suggest'>

</script><script>

var string = ''; var oldstring = ''; var timeout= 1000; /* czas w ms między sprawdzeniami - dobrą wartością jest 250*/ function do_suggest() { string = document.getElementById('string').value; if (string != oldstring) { /* Przy pustym polu nie wysyłaj żądania... */

if (string) { remoteSuggest.getstring(string);

}

/* ... tylko ukryj warstwę */

else { document.getElementById('suggestions').style.display = 'none'; }

oldstring = string;

}

window.setTimeout('do_suggest()', timeout); }

// Stworzenie tablicy asocjacyjnej do składowania metod zwrotnych

var suggestCallback = { getstring: function(resultSet) { var resultDiv = document.getElementById('suggestions'); resultDiv.innerHTML = '';

resultDiv.style.display = 'block';

if (!resultSet) resultDiv.style.display = 'none'; else{ for(var f=0; f<resultSet.length; ++f){ var result=document.createElement("span"); result.innerHTML = resultSet[f];

result.onmouseover = highlight;

result.onmouseout = unHighlight;

result.onmousedown = selectEntry;

resultDiv.appendChild(result);

}

}

}

}

// Utworzenie obiektu zdalnego

var remoteSuggest = new suggest(suggestCallback); // Funkcje obsługi interakcji

function highlight () { this.className = 'highlight'; } function unHighlight () { this.className = ''; } function selectEntry () { document.getElementById('string').value =this.innerHTML; }

</script>

</head>

<body onload="do_suggest()">

<h1>HTML_AJAX Example: Suggest</h1>

<p>Uwaga: czas między sprawdzeniami jest ustawiony na 1000ms dla celów

demonstracyjnych. W praktyce lepiej korzystać z wartości rzędu 350ms.</p>

<div id="error"></div>

Podaj nazwę pakietu PEAR:

<form method="get" id="suggest">

<input type="text" name="string" id="string" size="20" autocomplete="off">

<input type="button" name="check" value="Podpowiedz..." onkeyup="do_suggest();

return false;">

<div id="suggestions">&nbsp;</div>

</form>

</body>

</html>

Page 57: Php Solutions 1 2006 PL

AJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 57

Techniki

ale do serwera wysyłanych jest zbyt wie-le żądań – jeśli użytkownik wpisze coś bardzo szybko, a korzysta z powolnego łącza, to może dochodzić do wysyłania kolejnego żądania podpowiedzi przed otrzymaniem odpowiedzi na żądanie poprzednie. Spróbujmy jakoś temu za-pobiec.

Skorzystajmy z techniki zwanej dławieniem zgłoszeń (ang. submission throttling). W tym przypadku kliencki JavaScript będzie co jakiś czas (na przy-kład co 350 milisekund) sprawdzał, czy wartość pola tekstowego uległa zmianie – jeśli tak, to zostanie wysłane żądanie do serwera (patrz Listing 9). Dodatkowo sprawdzimy też, czy pole nie jest przy-padkiem puste – w takiej sytuacji nie wysyłamy żądania i ukrywamy warstwę wyników.

Jak widać, dodanie imponującej in-terakcji do formularzy i aplikacji nie jest wcale trudne. Nasz prosty przykład moż-na oczywiście rozbudować, dodając na przykład możliwość przechodzenia po li-ście wyników klawiszami kursora czy też obsługę lokalnego składowania danych, pozwalającego oszczędzić sporo pasma.

Śledzenie kodu AJAXPodczas eksperymentów z AJAX-em zauważysz zapewne, że technika ta wymaga nowego podejścia do śledzenia kodu. Nie wystarczy już śledzić kodu PHP – trzeba jeszcze pilnować JavaScriptu i obsługiwanej przez AJAX-a komunikacji między klientem i serwerem. Na szczęście nie jest to trudne.

Przede wszystkim, każdy moduł kodu należy testować osobno. Pracując w JavaScripcie dobrze jest stworzyć funk-cję pomocniczą, na przykład prościutki odpowiednik print_r() z PHP:

function print_r(input) {

var ret;

..for(var i in input) {

....ret += "["+i+"] = "+input[i]+"\n";

..}

..alert(ret);

}

Możliwości obserwacji w bibliotece JPSpan pozwalają też rejestrować między innymi błędy i udane wywołania funkcji AJAX. W domyślnej konfiguracji serwera błędy PHP są przekazywane jako ostrze-żenia JavaScript. Niekiedy można też na-trafić na ostrzeżenia wynikające z błędów

JavaScriptu, co wynika z tego, że JPSpan przechwytuje również te błędy i zgłasza je jako ostrzeżenia.

Podczas pracy z HTML_AJAX można dodać własną funkcję obsługi błędu, która będzie podmieniać zawartość elementu <div> o identyfikatorze error:

HTML_AJAX.onError = function(e) {

msg = "\nn";

for(var i in e) {

msg += i + ':' + e[i] +"\n";

}

document.getElementById('error').

innerHTML += msg;

}

Pozwoli to przechwytywać wszystkie błę-dy AJAX – najczęściej będą to zwyczajne błędy PHP, ale mogą się też pojawiać błę-dy 404, błędy wygaśnięcia i inne.

Na koniec zalecałbym tworzenie apli-kacji dla przeglądarki Firefox, a dopiero potem testowanie ich w Internet Explo-rerze. Firefox ma nieporównanie lep-sze narzędzia programistyczne od IE, a w dodatku oferuje bardzo wiele przydat-nych rozszerzeń.

PodsumowanieWiedząc już czym jest AJAX i jak z niego korzystać, możesz rozważyć zastosowa-nie tej techniki w swoich stronach. Prawi-dłowe używanie AJAX-a pozwala często osiągnąć imponujące wyniki, ale nie zna-czy to, że należy bezkrytycznie stosować tę technikę we wszystkich witrynach. Za-wsze trzeba mieć na uwadze podstawowe przeznaczenie danego serwisu – być mo-że w konkretnym przypadku lepiej byłoby dopracować nawigację lub prezentację

treści, niż dodawać interakcję korzystającą z AJAX-a. Koniecznie trzeba też uwzględ-niać docelowych odbiorców – jeśli więk-szość użytkowników z różnych względów ma wyłączoną obsługę JavaScriptu, to wprowadzenie AJAX-a raczej nie będzie dobrym pomysłem. Podobną rolę odgrywa skala – aplikacja wyposażona w AJAX-a znacznie lepiej sprawdzi się w przypadku niewielkich serwisów intranetowych (gdzie łatwo rozwiązać problemy konfiguracyjne i ujednolicić przeglądarki) niż w przypadku rozbudowanych, publicznie dostępnych witryn. Krótko mówiąc, wprowadzenie AJAX-a może dać dobre wyniki pod warunkiem, że nadrzędnym celem pozo-stanie uzyskanie jak najlepszych walorów użytkowych. n

Joshua Eichorn tworzy serwisy PHP od siedmiu lat. Jest autorem phpDocu-mentor – wielokrotnie nagradzanego i szeroko używanego narzędzia doku-mentującego kod PHP. Jest też szefem projektu HTML_AJAX, dostarczającego implementację techniki AJAX dla repozy-torium PEAR. Obecnie pracuje jako star-szy architekt oprogramowania w firmie Uversa Inc., gdzie tworzy dla klientów unikatowe rozwiązania. Technikę AJAX stosował jeszcze przed jej oficjalnym opracowaniem i popularyzacją. Mieszka w Phoenix w stanie Arizona (USA).Kontakt: [email protected]

Werner M. Krauß programuje w PHP od 1999 r. Gdy nie gra na gitarze, zajmuje się tworzeniem dokumentacji dla frame-worka Seagull.Kontakt: [email protected]

O autorze

Komunikat ładowaniaUruchamiając przykłady z HTML_AJAX zauważysz, że przy każdym wywołaniu AJAX po-jawia się czerwone okienko z komunikatem loading. Powiadomienie to jest automatycznie wyświetlane przez HTML_AJAX i jest po prostu warstwą o określonym identyfikatorze, tworzoną jeśli wcześniej nie istniała. Jeśli więc chcesz zmienić ten komunikat, wystarczy gdzieś w kodzie HTML umieścić na przykład taki fragment:

<div id="HTML_AJAX_LOADING" style=

"background-color : blue; color : white; display : none; position : absolute;

right : 50px; top : 50px;">

Ładowanie nowego napisu...</div>

Wyświetlania komunikatu nie da się w obecnej wersji wyłączyć po stronie serwera, ale w przyszłych wersjach HTML_AJAX taka możliwość już będzie. Aby zapobiec wyświetla-niu komunikatu trzeba nadpisać generującą go funkcję JavaScriptu:

HTML_AJAX.onOpen = function(){

// nic

}

Page 58: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org58

Projekty advAJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 59

Projekty

O technologii AJAX pisaliśmy już w tym numerze PHP Solutions, w artykule AJAX – wyjątkowo

interaktywne i wydajne aplikacje WWW. Teraz zajmiemy się jej praktycznym wy-korzystaniem i stworzymy kilka przykła-dów obrazujących jej możliwości. Jak już wiemy, główną zaletą AJAX-a jest to, że pozwala on na dokonywanie zmian w in-terfejsie użytkownika po stronie przeglą-darki, bez potrzeby przeładowywania całej strony i ponownego wczytywania arkuszy CSS czy plików graficznych.

Zyskuje na tym atrakcyjność serwisu, gdyż możemy uczynić go dynamicznym, jak i jego wydajność, ponieważ AJAX umożliwia nam przesyłanie jedynie niewielkiej porcji danych (zamiast całej strony WWW) pomiędzy serwerem, a klientem. To z kolei oznacza skrócenie czasu ich dostarczania i zmniejsza ob-ciążenie serwera. Przesyłane za pomocą AJAX-a dane mogą mieć dowolny format, np. CSV albo XML.

Ciągłe przeładowywanie strony WWW przy każdej zmianie jej zawartości i żmudne czekanie na wyświetlenie kolejnej porcji danych jest zmorą każdego użytkownika aplikacji webowych i programisty PHP. Nie jesteśmy jednak skazani na te bolączki: wybawia nas od nich wkraczająca do świata PHP technologia AJAX. Dzięki niej ładujący się w nieskończoność pasek postępu przechodzi do lamusa.

Do stworzenia naszych przykładów wykorzystamy napisany przez autora tego artykułu obiekt języka JavaScript o nazwie advAJAX (ang. Advanced AJAX, http://advajax.anakin.us). Obiekt advAJAX uła-twia korzystanie z opisywanej technologii i znacznie rozszerza jej możliwości, doda-jąc m.in. pełną obsługę formularzy HTML, przedawnień czasu połączeń, kontrolę nad pamięcią tymczasową przeglądarki czy kontrolę nad kilkoma wywołaniami AJAX jednocześnie, za pomocą systemu

advAJAX,czyli praktyczne zastosowanie technologii AJAXŁukasz Lach

W SIECI

1. http://advajax.anakin.us/ – projekt advAJAX

2. http://www.ajaxpatterns.org/ – strona o wzorcach AJAX-a

3. http://www.w3schools.com/jsref/default.asp – dokumen-tacja języka JavaScript

Powinieneś wiedzieć...Powinieneś znać języki JavaScript i PHP. Pomocna w zrozumieniu technologii adv-AJAX będzie również lektura artykułu AJAX – wyjątkowo interaktywne i wy-dajne aplikacje WWW.

Obiecujemy...Po przeczytaniu artykułu będziesz wie-dział, jak korzystać z obiektu advAJAX i z jego pomocą tworzyć aplikacje inter-netowe wykorzystujące AJAX-a.

Page 59: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org58

Projekty advAJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 59

Projekty

grupowań. Dzięki niemu, pobranie doku-mentu z serwera sprowadzi się do wywo-łania jednej funkcji, a my będziemy mieli pełną kontrolę nad odbieraniem danych, obsługą błędów czy dołączeniem funkcjo-nalności AJAX-a do formularzy. Przejdźmy więc do pierwszego przykładu.

Systembezpiecznego logowaniaNiemal każdy serwis tworzony w PHP zawiera panel administracyjny, za pomocą którego zarządzamy jego zawartością. Nie-odłączną częścią panelu administracyjnego jest formularz logowania, który umożliwia dostęp wyłącznie uprawnionym użytkowni-kom. Potrzebujemy więc przesyłać nazwę użytkownika i hasło, co pociąga za sobą ryzyko przechwycenia tych danych przez osoby niepowołane. Stosowanie połączeń szyfrowanych SSH zmniejsza to zagroże-nie. My postąpimy inaczej: wykorzystując AJAX-a stworzymy system bezpiecznego logowania, który nie używa SSH.

Jak już wiemy, zastosowanie techno-logii AJAX uwalnia nas od konieczności przeładowywania całej strony. W przypad-ku systemu logowania, potrzebujemy jedy-nie wysłać na serwer kilkadziesiąt bajtów, które składają się na nazwę użytkownika i hasło. Odpowiedź serwera również bę-dzie krótka: zamiast całego dokumentu HTML, otrzymamy jeden bajt. Jest to idealny przykład, pokazujący możliwości optymalizacyjne AJAX-a.

Podstawą naszej pracy jest formularz logowania, podobny do przedstawionego na Listingu 1. W nagłówku widocznego tam dokumentu HTML dołączamy trzy skrypty w języku JavaScript. Pierwszy, o nazwie advajax.js zawiera obiekt adv-AJAX. W drugim, md5.js, umieszczone zostały funkcje tworzące hash MD5, które pozwolą nam na zakodowanie hasła przed wysłaniem. Ostatni skrypt, 1.js, zawiera funkcję updateObjects(), uruchamianą po załadowaniu dokumen-tu. Umieszczony na stronie formularz, któremu nadaliśmy unikalną nazwę loginForm, przesyła dane do pliku 1.php. Z pozoru jest to typowa strona logowania, jednak po wywołaniu wspomnianej funkcji updateObjects() wszystko się zmienia.

Funkcja ta wywołuje wewnętrzną metodę obiektu advAJAX (patrz Listing 2) o nazwie assign(), która powoduje włączenie funkcjonalności AJAX-a do for-

mularza. Jej pierwszym parametrem jest obiekt formularza, który ma zostać zmo-dyfikowany – w naszym przypadku jest

to loginForm. Drugim jest nieposiadają-cy nazwy obiekt definiujący wywołanie – zestaw parametrów obiektu advAJAX.

Rysunek 1. System bezpiecznego logowania

Rysunek 2. Stronicowanie danych

Page 60: Php Solutions 1 2006 PL

advAJAX

PHP Solutions Nr 1/2006www.phpsolmag.org60

Projekty

Należy w tym miejscu wspomnieć, że nie musimy nigdzie podawać adresu URL dokumentu, który ma zostać wywołany, jak również metody jego wysłania (POST lub GET), ponieważ są one automa-tycznie pobierane z atrybutów action i method znacznika form. Omawiany obiekt zadba także o to, żeby zabloko-wać wszystkie pola formularza aż do za-kończenia zapytania, aby użytkownik nie mógł dokonywać żadnych zmian w trak-cie wykonywania i pobierania wyniku.

Przyjrzyjmy się elementom wspo-mnianego już obiektu, będącego dru-gim parametrem metody assign(). Pierwszym z nich jest funkcja on-

Initialization() – pozwala ona okre-ślić akcję, która ma zostać wykonana przed rozpoczęciem głównych procedur pobierania dokumentu. Dostęp do obiek-tu możliwy jest poprzez jedyny parametr tej funkcji o nazwie obj.

W naszym skrypcie, funkcja onInitialization() tworzy skrót (hasz)

hasła algorytmem MD5 oraz informuje użytkownika, że pobierany jest wynik lo-gowania, umieszczając opis proszę cze-kać na przycisku służącym do wysyłania formularza. Również w tej funkcji odczy-tujemy hasło. Jest ono przechowywane przez pole password obiektu parameters (obj.parameters), z którego korzystamy podobnie, jak z tablic asocjacyjnych w PHP.

Następnym elementem jest on-

Complete(). Powinien on wskazywać funkcję, która zostanie wywołana po zakończeniu pobierania dokumentu. W tym miejscu bardzo istotne jest to, że wewnątrz tej funkcji nie wiemy, czy wy-wołanie zakończyło się powodzeniem.

Funkcja, uruchamiana po udanym wywołaniu, znajduje się pod elemen-tem onSuccess(). Sprawdzamy w niej, czy logowanie zakończyło się sukce-sem: jeśli tak, to wartością zmiennej obj.responseText powinien być znak 1 (obiecany jeden bajt). W takim wypad-ku, przekierowujemy użytkownika na stronę przeznaczoną dla administrato-ra, a w innym wyświetlamy odpowied-ni komunikat i proces się powtarza. Warto wspomnieć, że ciasteczka są obsługiwane przez advAJAX, tak więc można bez problemu stworzyć sesję po stronie serwera i będzie ona dostępna tak samo, jak w sytuacji niekorzystania z AJAX-a.

Ostatni element o nazwie onError tak-że wskazuje na funkcję, która ma zostać wywołana w przypadku problemu z pobra-niem dokumentu (nie z połączeniem), np. kiedy plik nie istnieje i serwer zwróci kod 404 Not Found.

Jak widzimy, cały proces dołączenia możliwości AJAX-a do naszego formula-rza sprowadził się do wykorzystania jednej metody. W efekcie otrzymaliśmy przyjaź-niejszy dla użytkownika i bardziej opty-malny i – co najważniejsze – bezpieczny system logowania. Przedstawiamy go na Rysunku 1.

Stronicowanie danychJeśli w naszym serwisie umieszczamy większe ilości danych, to koniecznością staje się ich wyświetlanie z podziałem na strony zawierające po kilka lub kilkanaście rekordów. W tradycyjnej aplikacji webowej, każdorazowa zmiana strony tej listy pociąga za sobą przełado-wanie całego dokumentu HTML, mimo, że modyfikacji ulega tylko jego główna

Listing 1. Formularz logowania

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/

DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">

<head>

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

<script type="text/javascript" src="advajax.js"></script>

<script type="text/javascript" src="md5.js"></script>

<script type="text/javascript" src="1.js"></script>

</head>

<body onload="updateObjects()">

<form method="post" action="1.php" id="loginForm">

<label for="username">Nazwa użytkownika:</label>

<input type="text" name="username" id="username" />

<br />

<label for="password">Hasło:</label>

<input type="password" name="password" id="password" />

<br />

<input type="submit" value="OK" id="submitBtn" />

</form>

</body>

</html>

Listing 2. Dołączenie funkcjonalności AJAX-a do formularza HTML

function updateObjects() { advAJAX.assign(document.getElementById("loginForm"), {

onInitialization : function(obj) { obj.parameters["password"] = hex_md5(obj.parameters["password"]); document.getElementById("submitBtn").value = "Proszę czekać..."; },

onComplete : function() { document.getElementById("submitBtn").value = "OK"; },

onSuccess : function(obj) { if (obj.responseText == "1") document.location = "/admin"; else { alert("Nieprawidłowa nazwa użytkownika lub hasło."); document.getElementById("password").value = ""; window.setTimeout("document.getElementById('password').focus();", 100);

}

},

onError : function(obj) { alert("Nie można nawiązać połączenia z serwerem, spróbuj później."); }

});

Page 61: Php Solutions 1 2006 PL

advAJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 61

Projekty

część, a nagłówek czy menu nawigacyj-ne pozostają niezmienione. Posługując się AJAX-em unikniemy tej uciążliwej konieczności – pozwala on wszak mody-fikować zawartość otwartej w przeglądar-ce strony WWW.

Jako przykład jego wykorzystania, stworzymy prostą książkę telefoniczną z podziałem na strony zawierające po 10 rekordów. Będzie ona wyświetlała odczy-tane z serwera i przesłane w postaci do-kumentu XML imiona, nazwiska i numery telefonów. Dla uproszczenia, w naszym przykładzie nie implementujemy komuni-kacji z serwerem.

Zacznijmy od tabeli, w której będzie-my umieszczać rekordy pobrane z ser-wera. Jej kod źródłowy przedstawiamy na Listingu 3. W nagłówku znajdują się nazwy kolumn, otoczone hiperłączami wskazującymi na funkcję changeSort(), która zmienia sposób sortowania da-nych. Na początku, tabela jest pusta: zostanie wypełniona zawartością pobra-ną poprzez wywołanie AJAX. W stopce umieściliśmy pole, które będzie zawie-rało dane o aktualnie przeglądanych danych oraz przyciski nawigacyjne. Znacznik tbody otrzymał ponadto uni-kalny identyfikator dataTable, do któ-rego będziemy się odwoływać podczas wpisywania danych.

Spójrzmy teraz na kod źródłowy przedstawiony na Listingu 4. Metodą wywoływaną podczas zakończenia ładowania strony oraz przy zmianie strony jest getRecords. Jak w poprzed-nim przykładzie, tak i teraz wywołuje on tylko jedną, wewnętrzną metodę obiektu advAJAX. Tym razem jest to metoda advAJAX.get(), która wykonuje wywoła-nie typu GET na ustalony w parametrach adres URL. advAJAX pozwala korzystać zarówno z POST, jak i GET, którym odpowiadają nazwy metod obiektu adv-AJAX.

Opisywana metoda przyjmuje jeden parametr, którym jest lista parametrów obiektu. Element url jest wymagany, a jego wartością może być zarówno pełny adres URL, jak i nazwa pliku. W na-szym skrypcie wywołujemy skrypt 2.php z parametrami p (któremu przypisana jest wartość zmiennej globalnej currentPage, czyli numer pobieranej strony), oraz s, wskazująca na kolumnę i tryb sorto-wania pobieranych rekordów. Następ-nym elementem jest znany nam już onInitialization(), którego wywołanie

Listing 3. Tabela książki telefonicznej

<table>

<thead>

<tr>

<td>ID</td>

<td><a id="nameSort" href="javascript:changeSort('name')" title="Sortowanie

po imieniu">Imię</a></td>

<td><a id="surnameSort" href="javascript:changeSort('surname')"

title="Sortowanie po nazwisku">Nazwisko</a></td>

<td><a id="telephoneSort" href="javascript:changeSort('telephone')"

title="Sortowanie po numerze telefonu">Numer telefonu</a></td>

</tr>

</thead>

<tbody id="dataTable"></tbody>

<tfoot>

<tr>

<td colspan="4">

<span id="dataStats" style="float: left; margin-top: 2px"></span>

<span style="float: right">

<a id="btnFirst" href="javascript:changePage(-currentPage)"

title="Pierwsza strona">&laquo;&laquo;</a>

<a id="btnPrev" href="javascript:changePage(-1)" title="Poprzednia

strona">&laquo;</a>

<a id="btnNext" href="javascript:changePage(1)" title="Następna strona

">&raquo;</a>

<a id="btnLast" href="javascript:changePage(maxPage-currentPage-1)"

title="Ostatnia strona">&raquo;&raquo;</a>

</span>

</td>

</tr>

</tfoot>

</table>

Rysunek 3. Prosty edytor tekstu na stronie WWW

Page 62: Php Solutions 1 2006 PL

advAJAX

PHP Solutions Nr 1/2006www.phpsolmag.org62

Projekty

powoduje ukrycie przycisków nawigacyj-nych i wyświetlenie informacji, że trwa pobieranie żądanych danych. Kiedy nastąpi wywołanie funkcji zapisanejpod onSuccess() powoduje uruchomienie metody parseRecords(), z parametrem

będącym instancją obiektu XMLDocument, której kod również znajduje się na Li-stingu 4. Aby dostać się do danych za-wartych w pobranym dokumencie XML, korzystamy z wbudowanych metod DOM (ang. Document Object Model).

Całość jest już w pełni funkcjonalna, jednak nic nie szkodzi na przeszkodzie, aby przedstawiony przykład rozbudować. Można dodać jeszcze jedną kolumnę, w której umieścimy hiperłącza pozwala-jące na usunięcie czy edycję wybranego rekordu. Możliwości jest wiele, gdyż po-tencjał AJAX-a jest ogromny. Ostateczny wynik zależy zaś wyłącznie od naszych potrzeb.

Szybka edycja danychOstatnim, równie przydatnym i efek-tywnym przykładem będzie stworzenie edytora pozwalającego na zmianę tre-ści dokumentu bez przeładowywania strony, na której jest on wyświetlany. Jego interfejs oprzemy na warstwach. Edytor będzie uruchamiany po dwu-krotnym kliknięciu na wybraną warstwę. Wówczas utworzona zostanie warstwa zawierająca obiekt pola tekstowego (textarea), do którego wpisana zo-stanie treść edytowanego tekstu oraz dwa przyciski, służące do zapisywania i anulowania wprowadzanych zmian. Oczywiście edytor tego typu powinien być dostępny jedynie, gdy zaloguje-my się jako administrator, dlatego też postaramy się maksymalnie ułatwić dołączenie jego kodu do istniejącej już strony. W tym celu stworzymy funkcję o nazwie assignEditor(), której para-metrem jest unikalna nazwa identyfiku-jąca warstwę, wpisana w atrybucie id dowolnego znacznika HTML. Pełny kod omawianej funkcji, jak i całego skryptu edytora znajduje się na Listingu 5.

Istotną funkcją, którą stworzymy jest wywoływana w celu zapisania zmodyfikowanych danych na serwerze saveData(). Tym razem korzystamy z metody advAJAX.post(), ponieważ przesyłane dane mogą mieć większy rozmiar, niż pozwala na to metoda GET. Również ta metoda przyjmuje jeden ar-gument – parametry wywołania obiek-tu advAJAX. Pierwszym elementem jest url, wskazujący na skrypt 3.php, który zapisze wyedytowane dane po stronie serwera. Następnie mamy ele-ment parameters, omawiany już przy skrypcie bezpiecznego logowania. Tym razem przekazujemy unikalny identy-fikator edytowanego tekstu oraz jego nową treść. Dostęp do tych zmiennych uzyskamy poprzez tablicę $_POST ($_POST['id'] oraz $_POST['value']) w skrypcie PHP. Funkcja zapisana

Listing 4. Główny skrypt dynamicznej tabeli

var maxPage;

function $(id) { return document.getElementById(id); }

// Funkcja konwertująca dokument XML na kolejne wiersze tabeli

function parseRecords(xml) { // Zapisanie danych bieżącej strony

with (xml.getElementsByTagName("records").item(0)) { page = getAttribute("page")*1;

maxPerPage = getAttribute("max_per_page");

startId = maxPerPage*page+1;

total = getAttribute("total")*1;

maxPage = Math.ceil(total/maxPerPage);

// ...wpisanie danych do stopki tabeli

}

// Wpisanie danych rekordów do tabeli

d = $("dataTable");

for (i = d.rows.length-1; i >= 0; i--) d.deleteRow(i);

record = xml.getElementsByTagName("record");

result = "";

for (i = 0; i < record.length; i++) { tr = document.createElement("tr");

td = document.createElement("td");

td.innerHTML = startId + i;

tr.appendChild(td);

for (j = 0; j < 3; j++) { td = document.createElement("td");

td.innerHTML = record[i].childNodes[j].childNodes[0].nodeValue;

tr.appendChild(td);

}

d.appendChild(tr);

}

return result;}

// Główna funkcja wywołująca skrypt PHP i pobierająca dokument XML

function getRecords() { advAJAX.get({

url : "2.php?p="+currentPage+"&s="+currentSort+"%20"+currentSortOrder,

onInitialization : function() { $("dataStats").innerHTML = 'Pobieranie danych...';

$("btnPrev").style.visibility = $("btnNext").style.visibility =

$("btnFirst").style.visibility = $("btnLast").style.visibility =

"hidden";

},

onSuccess : function(obj) { parseRecords(obj.responseXML);

}

},

onError : function(obj) { alert("Nie można nawiązać połączenia z serwerem, spróbuj później."); });

}

Page 63: Php Solutions 1 2006 PL

advAJAX

PHP Solutions Nr 1/2006 www.phpsolmag.org 63

Projekty

pod onInitialization() spowoduje wyłączenie kontrolek edytora, aby użyt-kownik nie mógł modyfikować danych podczas ich przesyłania na serwer. W przypadku błędu, obiekt advAJAX korzysta z funkcji umieszczonej pod na-zwą onError(), która w tym przypadku wyświetla komunikat o błędzie i odblo-kowuje kontrolki, zezwalając jednocze-śnie użytkownikowi na podjęcie kolejnej próby zapisania danych. W przypadku powodzenia, wywołana zostaje funkcja zapisana pod onSuccess(), a skrypt PHP powinien zwrócić znak 1 (jak wi-dzimy, znowu jeden bajt zamiast całego dokumentu HTML po przeładowaniu!). Następnie edytor zostaje usunięty i od tej pory każdy użytkownik odwiedzający tę stronę zobaczy już nową, zapisaną przed chwilą, treść warstwy. Nic nie stoi na przeszkodzie, aby wykorzystać pole typu input, jeśli mamy do czynie-nia z małą, zawierającą się w jednej linijce porcją danych. Możemy również stworzyć edytor graficzny, pozwalający dodatkowo na zmianę stylu czcionki czy dodawanie hyperlinków i plików graficznych – wszystko znowu zależy od potrzeb, a przedstawiony skrypt jest idealną podstawą do dalszej rozbudo-wy.

PodsumowanieAJAX nie jest nową technologią, ale dopie-ro teraz został w pełni zaimplementowany w najpopularniejszych przeglądarkach internetowych, dzięki czemu krąg jego użytkowników rośnie.

Zastosowanie obiektu advAJAX po-zwala natomiast na proste i efektywne wykorzystanie jego możliwości, co sta-nowi klucz do tworzenia prawdziwie inte-raktywnych aplikacji internetowych. n

Łukasz Lach jest studentem informa-tyki. Od kilku lat zajmuje się progra-mowaniem serwisów internetowych z wykorzystaniem technologii takich, jak XHTML, PHP czy JavaScript. Jest autorem wielu publikacji dotyczących szeroko pojętego programowania stron internetowych. Obecnie pracuje nad projektem advAJAX.Kontakt: [email protected]

Listing 5. Kod źródłowy edytora

function assignEditor(objectId) { // Stworzenie edytora w przypadku podwójnego kliknięcia

document.getElementById(objectId).ondblclick = function() { runEditor(this) }}

function saveData(objectId) { advAJAX.post({

url : "3.php",

parameters : {

id : objectId,

value : $(objectId + "_editor_ta").value },

onInitialization : function() { $(objectId+"_editor_ta").disabled=$(objectId+"_editor_save").disabled=

$(objectId + "_editor_cancel").disabled = "disabled";

},

onError : function() { alert("Nie można nawiązać połączenia z serwerem, spróbuj później."); $(objectId + "_editor_ta").removeAttribute("disabled");

$(objectId + "_editor_save").removeAttribute("disabled");

$(objectId + "_editor_cancel").removeAttribute("disabled");

},

onSuccess : function(obj) { if (obj.responseText == "1") $(objectId).innerHTML = $(objectId + "_editor_ta").value; removeElement(objectId + "_editor");

}

});

}

function runEditor(obj) { // Pobranie współrzędnych położenia edytowanej warstwy

l = t = 0;

obj2 = obj;

while (obj2.parentNode) { l += obj2.offsetLeft;

t += obj2.offsetTop;

obj2 = obj2.parentNode;

}

// Stworzenie warstwy edytora i jego komponentów

editor = document.createElement("div"); h = obj.offsetHeight >= 70 ? obj.offsetHeight : 70;

with (editor.style) { position = "absolute";

zIndex = "100";

top = t + "px";

left = l + "px";

width = obj.offsetWidth + "px";

height = h + "px";

backgroundColor = "#ffffff";

}

editor.id = obj.id + "_editor";

editor.innerHTML = "<textarea id='" + obj.id + "_editor_ta'></textarea>

<br /><button id='" + obj.id + "_editor_save' onclick=\"saveData('" +

obj.id + "')\">Zapisz</button>&nbsp;<button id='" + obj.id +

"_editor_cancel' onclick=\"removeElement('" + obj.id + "_editor')">

Anuluj</button>";

document.body.appendChild(editor); ta = $(obj.id + "_editor_ta");

with (ta.style) { width = "100%";

height = (h - 25) + "px";

}

ta.value = obj.innerHTML;}

O autorze

Page 64: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org64

Projekty PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 65

Projekty

PHP-GTK2 umożliwia połączenie funkcjonalności PHP5 i bibliote-ki Gtk-2.6. W artykule przyjrzy-

my się bliżej niezwykłym możliwościom tej technologii na przykładzie aplikacji umożliwiającej proste zarządzanie przedmiotami (produktami) w sklepie. Będziemy korzystać zarówno z nowo-ści, które pojawiły się w PHP-GTK2, jak i tych, które oferuje PHP5 (np. nowy model obiektowy czy obsługa wyjątków). Dane będziemy składować w bazie SQL.

IdeaZastanówmy się, czego potrzebujemy, aby stworzyć nasz przykładowy program. Podstawowym elementem aplikacji GUI jest okno, w którym znajdują się kontrolki (widgety). W nim umieścimy trzy rozwijane menu: Plik, Edycja oraz Pomoc. Poszcze-gólne pozycje w menu będą opisane za pomocą tekstu oraz towarzyszących mu odpowiednich ikon.

Rozszerzenie PHP-GTK1 zapoczątkowało nowy sposób myślenia o PHP, otwierając przed językiem przeznaczonym do tworzenia aplikacji sieciowych świat wyposażonych w graficzny interfejs użytkownika (GUI) programów klienckich. Jednakże dopiero pojawienie się PHP-GTK2 może dać początek prawdziwej rewolucji...

Tak więc, w pierwszym menu bę-dziemy mogli dodawać nowe produkty (Dodaj), edytować już istniejące (Edytuj), wyczyścić całą bazę (Wyczyść), bądź zakończyć działanie programu (Wyjdź). Korzystając z drugiego otworzymy prosty edytor tekstu, potencjalnie przydatny np. do robienia notatek na temat naszych zapasów. Trzecie natomiast będzie zawie-rało jedną opcję: Pomoc, wyświetlającą okno dialogowe O programie.

Będziemy również potrzebowali okien dialogowych m.in. dla opcji Wyczyść

Nowe możliwości PHP-GTK2Pablo Dall'Oglio

W SIECI

1. http://gtk.php.net – strona domowa projektu PHP-GTK

2. http://www.agata.org.br – Agata Project – CRM/ERP korzystający z PHP-GTK

3. http:///tulip.solis.coop.br –Tu-lip – edytor dla programisty PHP oparty na PHP-GTK

Powinieneś wiedzieć...Powinieneś znać PHP5, a w szczególno-ści nowy model obiektowy oraz wyjątki. Przydatna będzie również ogólna wiedza o graficznych interfejsach użytkownika.

Obiecujemy...Po przeczytaniu artykułu będziesz wie-dział, jak napisać przykładową aplikację wykorzystującą nowe możliwości PHP-GTK2.

Page 65: Php Solutions 1 2006 PL

PHP Solutions Nr 1/2006www.phpsolmag.org64

Projekty PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 65

Projekty

(pytanie oraz informacja), Dodaj i Edytuj (formularz umożliwiający dodawanie nowych i edycję istniejących produktów), a także dialogu plików i niezależnego okna dla naszego edytora tekstu.

Zabieramy się do pracyNasze zadanie zaczniemy od napisania głównej klasy Application, którą przed-stawiamy na Listingach 1 i 2. Najpierw stworzy ona obiekt klasy GtkWindow, który będzie głównym oknem aplikacji i ustawi jego podstawowe parametry (rozmiar, położenie i tytuł). Następnie stworzymy kontener porządkujący pozycjonowanie naszych widgetów: wykorzystamy w tym celu klasę GtkVBox, tworząc jej instancję o nazwie $vbox.

Przejdźmy do menu rozwijanych. Zaczniemy od utworzenia menu głów-nego, zakładając obiekt $MenuBar klasy GtkMenuBar. Następnie za pomocą klasy GtkMenuItem stworzymy poszczegól-ne sekcje menu o nazwach Plik, Edycja oraz Pomoc. Będą to osobne obiekty, których póki co nie dodamy jeszcze do menu.

Menu główneKolejnym krokiem będzie stworzenie odpowiednich menu, otwieranych klik-nięciem na wymienione sekcje. W tym celu użyjemy klasy GtkMenu, tworząc jej instancję o nazwie $SubMenuFile... ale zaraz, chcieliśmy, by opcje w tych menu posiadały ikony! Na szczęście nie musimy tworzyć ich sami, gdyż PHP-GTK2 oferuje nam Obrazy Standardowe (Stock Ima-ges), czyli zbiór podstawowych, często używanych ikon dla przycisków, menu, list itd. Przedstawiają one operacje takie, jak zapis, otwieranie, zamykanie, kasowanie, dodawanie, czyszczenie, wychodzenie z programu, opcje TAK i NIE, itd. Nazwy ikon przestrzegają przejrzystej konwencji, co znacząco ułatwia korzystanie z nich.

Każda pozycja należąca do GtkMenu będzie obiektem klasy GtkImageMenuItem. Ikonę będziemy przekazywać przez argu-ment konstruktora tej klasy. Jeżeli nie po-damy nazwy ikony, to pozycja nie będzie posiadała obrazka.

W menu Plik dodajemy pozycje o nazwach: Wyczyść, Dodaj, Edytuj oraz Wyjdź. Kliknięcie na pierwszej spowoduje uruchomienie bazy, a następnie usunięcie tabeli produktów i ponowne jej stworzenie.

Druga, Dodaj, pokaże użytkownikowi dialog zawierający formularz pozwalający dodać nowy produkt, podczas gdy trzecia, Edytuj, wyświetli listę produktów, pozwala-jąc na edycję wybranej pozycji. Wreszcie, kliknięcie na pozycji Wyjdź spowoduje zakończenie działania aplikacji.

W menu Edycja umieścimy tylko jedną opcję, Edytor – będzie ona uruchamiała wspomniany już edytor tekstu. W menu Pomoc znajdzie się również jedna opcja, Pomoc, której zadaniem będzie wyświe-tlenie okna dialogowego O programie. Wszystkie menu przedstawiamy na Ry-sunku 1.

Kolejnym punktem programu jest połączenie sygnałów wysyłanych przez elementy menu w chwili wystąpienia zda-rzenia clicked z metodami callbackowymi wykonującymi odpowiednie operacje. Metody te nosić będą nazwy: onClear(), onAdd(), onList(), onEdit() i onHelp(). Powiązania tworzymy natomiast wy-wołując dla każdego elementu metodę connect(). Dodamy teraz elementy do odpowiednich menu. Ostatnią operacją, jaką musimy przeprowadzić na menu rozwijanych jest dodanie ich do paska

głównego menu. Czynność ta przebiegnie dwuetapowo: najpierw dla każdej pozy-cji w pasku menu zastosujemy metodę set_submenu(), która połączy tę pozycję z odpowiadającym jej podmenu, a następ-nie dodamy te trzy pozycje do głównego paska ($MenuBar).

Pozostałymi operacjami w konstruk-torze są: wstawienie kontenera $vbox w okno, dodanie do niego widgetów oraz wyświetlenie całej zawartości okna za po-mocą metody $window->show_all().

Metody callbackowei dialogi wiadomościNajwyższy czas rozpocząć tworzenie metod callbackowych dla poszczegól-nych elementów menu. Zaczniemy od onClear(). W pierwszej kolejności meto-da ta sprawdzi, czy baza, którą chcemy wyczyścić, istnieje. Potem poprosi nas o potwierdzenie skasowania wszystkich zawartych w bazie rekordów. W tym celu użyjemy okna dialogowego GtkMessage-Dialog. Znajduje ono zastosowanie

Rysunek 1. Menu naszej aplikacji

Rysunek 2. Dialog pozwalający nam zdecydować, czy chcemy zrestartować bazę danych

Rysunek 3. Wiadomość, że baza została wyczyszczona

Page 66: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006www.phpsolmag.org66

Projekty

w bardzo wielu sytuacjach, m.in. przy wyświetlaniu ostrzeżeń, komunikatów o błędach, dialogów potwierdzenia, okien do wprowadzania danych, itd. Użyjemy tego okna w trybie MODAL, co oznacza, że dopóki nie zostanie ono zamknięte, będzie cały czas widoczne na ekranie, a wykonywanie innych operacji w ramach aplikacji nie będzie możliwe. Chcemy, aby w obrębie dialogu widniał znak zapytania – żaden problem, użyjemy tych samych standardowych ikon, co wcześniej. Za-stosujemy również standardowe przyciski YES i NO. Całość przedstawiamy na Rysunku 2.

Po wyświetleniu okna, aplikacja będzie czekać na reakcję użytkownika. Jeżeli zezwoli on na skasowanie danych, nawiążemy połączenie z naszą bazą SQLite, a następnie usuniemy tabelę produktów i ponownie ją utworzymy. O po-prawnym wyczyszczeniu bazy informuje użytkownika kolejne okno dialogowe, któ-re pokazujemy na Rysunku 3.

Dodawanie nowych produktów: formularz produktówKolejną metodą odwoławczą jest onAdd(), która pozwala na dodanie nowego pro-duktu. Wyświetla ona na ekranie dialog widoczny na Rysunku 4. Właściwie jedy-nym zadaniem tej metody jest wykorzy-stanie klasy ProductNew, która znajduje się w pliku ProductNew.class.php (patrz Li-sting 3). Pełne opisanie tej klasy zajęłoby zbyt wiele miejsca i mogłoby być nużące dla czytelnika. Skoncentrujemy się więc jedynie na najważniejszych zagadnieniach z nią związanych.

Po pierwsze, w konstruktorze ProductNew tworzymy taki sam obiekt kla-sy GtkWindow, z jakim mieliśmy do czynie-nia wcześniej. Po drugie, do wyświetlania opisów wykorzystamy etykiety (GtkLabel). Najbardziej interesującym aspektem ich użycia jest możliwość formatowania ich zawartości. W PHP-GTK2 jest to dużo ła-twiejsze i bardziej elastyczne niż w PHP-GTK1, gdzie trzeba było wiele wysiłku, by nadać tekstowi pożądany przez nas wygląd (nawet w przypadku tak prostych efektów, jak pogrubienie, kursywa, pod-kreślenie bądź kolory). PHP-GTK2 wyko-rzystuje Pango, opensourcowy framework GTK zajmujący się wszystkimi szczegó-łami związanymi z układem i rendero-waniem. Pango umożliwia formatowanie tekstu do wyświetlenia za pomocą wywo-dzącego się z SGML języka znaczników.

Listing 1. Główny interfejs: główne okno naszej aplikacji; kod zawarty w pliku product.php

<?php

// Klasa Application – zawiera w sobie główny interfejs

class Application{ private $window; function __construct(){ // tworzy nowe okno i ustawia jego parametry

$this->window = new GtkWindow;...

$vbox = new GtkVBox; // tworzy listwę menu

$MenuBar = new GtkMenuBar; // opcje menu

$MenuFile = new GtkMenuItem('_Plik');...

// podmenu Plik, z elementami standardowymi

$SubMenuFile = new GtkMenu; $ItemFile1= new GtkImageMenuItem(GTK::STOCK_CLEAR);...

$ItemFile4= new GtkMenuItem; $ItemFile5= new GtkImageMenuItem(GTK::STOCK_QUIT); // połącz opcje menu z metodami

$ItemFile1->connect('activate', array($this, 'onClear'));...

$ItemFile5->connect('activate', array($this, 'onQuit')); // dodaj obiekty do podmenu

$SubMenuFile->append($ItemFile1);

...

// podmenu Edycja

$SubMenuEdit= new GtkMenu; $ItemEdit1= new GtkImageMenuItem(GTK::STOCK_EDIT); $ItemEdit1->connect('activate', array($this, 'onEdit')); $SubMenuEdit->append($ItemEdit1);

// podmenu Pomoc

...

$MenuFile->set_submenu($SubMenuFile);

...

$MenuEdit->set_submenu($SubMenuEdit);

...

$this->window->add($vbox);

$vbox->pack_start($MenuBar, false, false); $this->window->show_all();

}

// Metoda onClear – tworzy struktury w bazie danych

function onClear(){ if (file_exists('data.db')){ $dialog = new GtkMessageDialog(null, Gtk::DIALOG_MODAL, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO,

'Czy chcesz dokonać ponownej inicjalizacji bazy ?');

$response = $dialog->run();

$dialog->destroy();

if ($response == Gtk::RESPONSE_YES){ // usuń tabelę products

$conn = sqlite_open('data.db');

...

}

else if ($response == Gtk::RESPONSE_NO){ return; }

}

// stwórz tabelę products

$conn = sqlite_open('data.db');

$sql = 'CREATE TABLE products (code,description,' .

'unit,amount,cost,price)';

sqlite_query($conn, $sql);

Page 67: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 67

Projekty

Pozwala też na łatwe definiowanie stylów i kolorów (patrz Rysunek 5). Chociaż nie widać tego w przykładzie, równie łatwo możemy wyświetlać tekst w pionie lub pod kątem (wyrażonym w stopniach).

Dialog dodawania nowego produktu będzie zawierał następujące etykiety: Kod, Opis, Ilość, Jednostka, Koszt i Ce-na. Pod nimi z kolei umieścimy etykietę informującą o konieczności wypełnienia pól Kod, Opis i Cena. Chcielibyśmy jednak, by nie była ona widoczna przez cały czas, gdyż nie będzie potrzebna bardziej doświadczonym użytkownikom. To ostatnie nie stanowi żadnego proble-mu dla PHP-GTK2: możemy skorzystać z komponentu GtkExpander, będącego kontenerem pozwalającym na rozwijanie i zwijanie kontrolek, które się w nim znaj-dują. Umieścimy w nim naszą etykietę pomocy. W tym celu zadeklarujemy obiekt $expander klasy GtkExpander, a następnie stworzymy etykietę pomocy o nazwie $help. Na koniec, dodamy tę etykietę do $expander. Domyślnie będzie ona roz-winięta, co zapewnia nam metoda set_expanded(true).

Kolejnym wykorzystywanym przez nas widgetem będzie pole wprowadzania tek-stu (GtkEntry). Umieścimy je przy każdej etykiecie oprócz $help. W celu ułatwienia wprowadzania tekstu, PHP-GTK2 oferuje bardzo przydatny mechanizm autouzupeł-niania. Pozwala on na połączenie widgetu GtkEntry z GtkListStore – modelem da-nych zawierającym listę wartości używa-nych przy autouzupełnianiu. Połączenia instancji obu klas dokonujemy przy użyciu obiektu trzeciej klasy, GtkEntryCompletion. Pojawiające się podpowiedzi będą się zmieniać w miarę wprowadzania przez użytkownika kolejnych znaków.

Autouzupełnianie jest rozwiązaniem powszechnie używanym w aplikacjach Gtk, szczególnie w dialogach wyboru pliku, gdzie program podpowiada nazwy pasujące do wprowadzonego wzorca (patrz Rysunek 6). W naszym dialogu zastosujemy GtkEntryCompletion w polu Jednostka, gdzie podpowiedzią będzie lista często stosowanych jednostek.

Listing 2. Główny interfejs: ciąg dalszy kodu głównego okna naszej aplikacji

// poinformuj użytkownika o sukcesie

$dialog = new GtkMessageDialog(null, Gtk::DIALOG_MODAL, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, 'Baza wyczyszczona');

$response = $dialog->run();

$dialog->destroy(); }

// Metoda onAdd – tworzy formularz produktów

function onAdd(){

include_once 'ProductNew.class.php'; new ProductNew; }

// Metoda onList– wyświetla listę produktów, zezwalając użytkownikowi

// na jej edycję

function onList(){

include_once 'ProductList.class.php'; $obj = new ProductList; $obj->Show();

$obj->showData(); }

// Metoda onEdit – Otwiera mały edytor tekstu

function onEdit(){

include_once 'TextEditor.class.php'; new TextEditor; }

// Metoda onHelp – Wyświetla dialog O programie

function onHelp(){

include_once 'AboutDialog.class.php'; new AboutDialog('Produkty', 'Jest to program open-source'); }

// Metoda onQuit – wyjście z aplikacji

function onQuit(){ Gtk::main_quit(); }

}

// tworzy nową instancję Application

new Application;Gtk::Main();

?>

Rysunek 4. Formularz do dodawania nowych produktów

Rysunek 5. Efekty wyświetlania tekstu w PHP-GTK2

Page 68: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006www.phpsolmag.org68

Projekty

W tym celu, obok obiektu $this->

entries[3] klasy GtkEntry stworzymy instancję

klasy GtkListStore o nazwie $store. Następnie używając metody append()

obiektu $store dodamy do niego po-wszechnie stosowane jednostki. Potem utworzymy obiekt $completion klasy GtkEntryCompletion, po czym wskażemy mu obiekt $store jako źródło danych dla autouzupełniania, a na koniec użyjemy metody set_completion() pola Jednostka, aby połączyć z nim cały mechanizm.

Ostatnią potrzebną nam rzeczą jest przycisk Zapisz, po naciśnięciu którego umieścimy nowo wprowadzony produkt w bazie danych. Utworzymy więc instancję klasy GtkButton, którą nazwiemy $button1. Na przycisku tym umieścimy standardową ikonę dyskietki, a następnie połączymy jego zdarzenie clicked z metodą callbackową o nazwie onSaveClick(). Metoda ta pobierze wpro-wadzone wartości z formularza, zapisze je do bazy danych i, korzystając ze zde-finiowanej przez nas metody Clear(), wyczyści formularz.

Pokaż mi produkty, czyli dlaczego lubimy drzewaKolejną metodą callbackową w klasie Application jest onList(), wywoływana po kliknięciu pozycji Edytuj w menu Plik. Korzysta ona z klasy ProductList prze-chowywanej w pliku ProductList.class.php (patrz Listingi 4 i 5). Nie musimy jej dokładnie opisywać, więc podobnie jak w przypadku poprzedniej metody, skon-centrujemy się na jej najważniejszych komponentach.

Głównym zadaniem tej klasy jest wy-świetlenie edytowalnej listy wszystkich po-siadanych przez nas produktów. W przy-padku edycji, dane mają być aktualizo-wane bezpośrednio w bazie. Za wyświe-tlanie listy będzie odpowiadał wprowa-dzony w PHP-GTK2 widget GtkTreeView.

Listing 3. Kod formularza produktów, przechowywany w pliku ProductNew.class.php

<?php

// Klasa ProductNew – formularz produktu do ich wstawiania

class ProductNew extends GtkWindow{...

// Konstruktor klasy – tworzy okno i całą jego zawartość

public function __construct(){...

// tworzy wszystkie etykiety i pola tekstowe, linia po linii

$this->labels[0] = new GtkLabel('<span foreground="red"><b>Kod </b></span>');

$this->entries[0] = new GtkEntry; $this->entries[0]->set_size_request(80,-1);

...

// Tworzy model danych

$store = new GtkListStore(Gtk::TYPE_STRING); // dodaj wartości do modelu danych

$store->append(array('UN'));...

// Tworzy EntryCompletion

$completion = new GtkEntryCompletion(); $completion->set_model($store);

$completion->set_text_column(0);

$this->entries[3]->set_completion($completion);

...

// upakuj wszystkie etykiety i pola tekstowe w pionowym boksie

...

// stwórz przycisk Zapisz i boks dla niego

$save_box= new GtkHBox(); $button1 = GtkButton::new_from_stock(Gtk::STOCK_SAVE);

$button1->connect('clicked', array($this, 'onSaveClick')); $save_box->pack_start(new GtkHBox, true);...

$expander = new GtkExpander('<b><i>Help</i></b>'); $expander->set_use_markup(true);

// Krótki tekst pomocy do umieszczenia w ekspanderze

$help = new GtkLabel; $help->set_alignment(0.2, 0.5);

$help->set_markup('<b><u>Wypełnianie formularza</u></b>

Aby być w stanie wypełnić formularz, nie możesz pozostawić pól Kod,

Opis i Cena pustymi...');

$expander->add($help);

$expander->set_expanded(true); $vbox->pack_start($expander, false, false); parent::add($vbox); parent::show_all(); }

// Metoda onSaveClick – Zapisuje dane z ekranu do bazy

public function onSaveClick(){ // odczyt danych z pól tekstowych i zapisywanie ich do bazy

$conn = sqlite_open('data.db');

$product->code = $this->entries[0]->get_text();

$sql = "INSERT INTO products (code, description, amount,

...

...

}

// Metoda Clear – czyści wszystkie pola formularza.

private function Clear(){ for ($n=0; $n<=5; $n++){ $this->entries[$n]->set_text('');

}

// ustawia kursor w pierwszym polu

parent::set_focus($this->entries[0]); }

Rysunek 6. Autouzupełnianie

Page 69: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 69

Projekty

Stanowi on olbrzymi krok naprzód wzglę-dem dostępnych już wcześniej, pro-stych komponentów w rodzaju GtkCTree czy GtkCList. O ile te poprzednie wid-gety pozwalały wyświetlać tylko drze-wa (pierwszy z nich; patrz Rysunek 7)lub tylko listy (drugi; patrz Rysunek 8), GtkTreeView umożliwia wyświetlanie obu struktur, a w dodatku znacząco rozsze-rza ich funkcjonalność. Przykładowo, po-zycje listy lub drzewa mogą teraz zawie-rać checkboksy oraz obrazki. Najciekaw-sze dla nas jest to, że zarówno drzewa, jak i listy mogą mieć kolumny, a zawarte w nich dane możemy edytować podobnie, jak w arkuszu kalkulacyjnym.

W naszym przykładzie wykorzy-stamy klasę GtkTreeView w trybie edy-towalnej listy z kolumnami. Najpierw stworzymy jej instancję, $this->list, a później dostarczymy jej dane. Po-winniśmy wiedzieć, że GtkTreeView zapewnia całkowitą separację warstw: Modelu, Widoku i Kontrolera, według wzorca MVC (Model-View-Controller). Oznacza to, że model danych jest całko-wicie odseparowany od jego reprezen-tacji na ekranie. Dane przechowywane są w Modelu, którym może być obiekt klasy GtkListStore (w przypadku list) lub GtkTreeStore (w przypadku drzew). My użyjemy GtkListStore, deklarując jej instancję o nazwie $this->model. Na-stępnie stworzymy kolumny dla Widoku, w których będziemy wyświetlali dane. Wykorzystamy do tego osobną klasę o nazwie GtkTreeViewColumn.

Dla każdej z kolumn określimy tytuł oraz stworzymy i dodamy (za pomocą metody connect()) renderer odpowiedzialny za wizualizację da-nych przechowywanych w modelu. W naszym przykładzie wykorzystamy klasę GtkCellRendererText, pozwalającą na wyświetlanie tekstu. Warto wiedzieć, że istnieją renderery pozwalające wy-świetlać inne typy danych, takie jak ob-razy czy checkboksy, a każda kolumna może zawierać co najmniej jeden z nich. Po dodaniu rendererów należy je odpo-wiednio skonfigurować, ustawiając m.in. szerokość kolumny i możliwość edycji znajdującego się w niej tekstu oraz łą-cząc funkcję callbackową onEdit() ze zdarzeniem edited, które występuje przy edycji dowolnego z elementów listy.

Kolejnym krokiem będzie doda-nie kolumn do listy reprezentowanej przez obiekt $this->list. W tym celu

Listing 4. Kod ProductList, przechowywanej w pliku ProductList.class.php

<?php

// Klasa ProductList – lista produktów

class ProductList extends GtkWindow{

private $window; private $model; private $list; public function __construct(){...

// tworzy widok drzewa

$this->list = new GtkTreeView; $scroll->add($this->list); // tworzy model, z sześcioma elementami

$this->model = new GtkListStore(Gtk::TYPE_STRING, Gtk::TYPE_STRING, Gtk::TYPE_STRING,Gtk::TYPE_STRING, Gtk::TYPE_STRING, Gtk::TYPE_STRING);

// tworzy kolumny

$column1 = new GtkTreeViewColumn();...

$column1->set_title('Code');

...

// definiuje renderery

$cell_renderer1 = new GtkCellRendererText();...

// łączy renderery z edycją danych przez użytkownika

$cell_renderer2->connect("edited",array($this,'onEdit'),1,'description');...

Rysunek 7. GtkTreeView w trybie drzewa

Rysunek 8. GtkTreeView w trybie listy

Page 70: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006www.phpsolmag.org70

Projekty

skorzystamy z metody append_column() tego obiektu.

Teraz musimy dodać Model do listy: osiągniemy to za pomocą metody set_model() obiektu $this->list. Póki co nie zawiera on żadnych danych, które zosta-ną dodane później. Przy okazji, istotną zaletą separacji warstw GtkTreeView jest możliwość wykorzystania modelu danych przez więcej niż jeden obiekt GtkTreeView, dzięki czemu te same dane mogą być wyświetlane w różnych miej-scach aplikacji.

Nasza klasa ProductList jest już prawie gotowa. Musimy jeszcze stworzyć metodę wypełniającą model danymi, którą nazwiemy showData(). Będzie ona wywoływana z naszej klasy Application, a jej działanie będzie następujące: naj-pierw nawiąże ona połączenie z bazą i pobierze dane, a następnie włączy je do modelu za pomocą metody set() obiektu $this->model.

Kolejną niezbędną metodą callbacko-wą jest onEdit(). Jej wywołanie nastąpi, gdy użytkownik zmieni jakąkolwiek komór-kę listy. Metoda ta automatycznie zaktuali-zuje dane w bazie, wyszukując właściwy wiersz w odpowiedniej tabeli na podstawie kodu produktu. I to wszystko jeśli chodzi o ProductList.

EdytorKolejnym elementem, który chcemy dodać do naszego projektu, jest prosty edytor tekstu wywoływany przy użyciu metody callbackowej onEdit() klasy Application. Oprócz edycji tekstu, po-winien on umożliwiać także jego wczy-tywanie i zapisywanie. Jego wygląd przedstawiamy na Rysunku 9.

Stworzymy klasę TextEditor i zapi-szemy ją w pliku TextEditor.class.php. Jej kod pokazujemy na Listingu 6.

Głównym komponentem tej klasy jest okno tekstowe, do implementacji którego użyjemy klasy GtkTextView i GtkTextBuffer. W PHP-GTK1 skorzy-stalibyśmy z przestarzałego już kom-ponentu GtkText. Istotną sprawą jest, że o ile w PHP-GTK1 ten sam obiekt przechowywał treść i odpowiadał za jej wizualizację, w PHP-GTK2 dane przechowujemy poza widgetem, we wspomnianej już klasie GtkTextBuffer. Co za tym idzie, ten sam tekst może być wyświetlany przez różne wid-gety GtkTextView, analogicznie jak w przypadku GtkTreeView. GtkTextBuffer

Listing 5. Kod ProductList, ciąg dalszy

// upakuj renderery

$column1->pack_start($cell_renderer1, true);...

// określ szerokość

$cell_renderer1->set_property('width', 50);

...

// zezwól użytkownikowi na edycję danych

$cell_renderer2->set_property('editable', True);...

// zdefiniuj pozycję modelu do połączenia z rendererami

$column1->set_attributes($cell_renderer1, 'text', 0);

...

$this->list->append_column($column1);...

$this->list->set_model($this->model); $this->list->show_all();...

}

// Metoda showData – wyświetla wszystkie produkty obecne w bazie danych

public function showData(){ // otwiera połączenie z bazą i czyta wszystkie dane za pomocą pętli

// while()

$conn = sqlite_open('data.db');

$query = sqlite_query($conn, 'select code, description, amount,'.

' unit, cost, price from products');

while ($data = sqlite_fetch_array($query)){ $iter = $this->model->append();

$this->model->set($iter, 0, $data['code'],

1, $data['description'], 2, $data['amount'], 3, $data['unit'],

4, $data['cost'], 5, $data['price']);

}

sqlite_close($conn);

}

// Metoda onEdit – Wywoływana, gdy użytkownik zmienia dane

public function onEdit($cell_renderer, $path, $new_text, $column_number, $column_name){

// pobierz zaznaczenie

$treeselection = $this->list->get_selection(); list($model, $iter) = $treeselection->get_selected(); // ustaw nową wartość iteratora

$model->set($iter, $column_number, $new_text);

// pobierz pierwszą kolumnę

$code = $this->model->get_value($iter, 0);

// otwiera połączenie z bazą danych i dokonuje aktualizacji

$conn = sqlite_open('data.db');

$query = sqlite_query($conn, "update products set " .

"$column_name='$new_text' where code='$code'");

sqlite_close($conn);

}

}

?>

Rysunek 9. Prosty edytor tekstu

Page 71: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 71

Projekty

udostępnia nam ponadto iteratory, czyli możliwość zaznaczania określonych miejsc w tekście.

W konstruktorze naszej klasy two-rzymy instancję GtkTextView o nazwie $this->textview. To samo uczynimy z GtkTextBufffer, tworząc obiekt $this->textbuffer. Wreszcie, połączymy model danych z widgetem za pomocą metody set_buffer() obiektu $this-

>textview.Jak już wspomnieliśmy, chcemy

mieć możliwość zapisywania i łado-wania (otwierania) plików tekstowych. Jak już pokazaliśmy na Rysunku 9, edytor będzie wyposażony w pasek narzędzi zawierający dwa opatrzone odpowiednimi ikonami elementy: Zapiszi Otwórz. W celu stworzenia tego pa-ska wykorzystamy klasę GtkToolbar, nazywając jej instancję $toolbar. Na-stępnie utworzymy przyciski do zapisu i ładowania danych, konstruując obiekty klasy GtkToolButton. Każdemu z nich nadamy odpowiedni opis i przypiszemy właściwą ikonę.

Kolejnym krokiem będzie połącze-nie wydarzenia clicked każdego z tych przycisków z odpowiadającą mu metodą: openFile() w przypadku ładowania pli-ków, saveFile() przy ich zapisie. Główna część naszego edytora jest już gotowa, zabierzmy się zatem za metody obsługu-jące zdarzenia.

W pierwszej z nich, openFile(), chcemy mieć możliwość wyboru pliku z listy. PHP-GTK2 oferuje w tym celu GtkFileChooserDialog (patrz Rysu-nek 10), zastępujący – jako bardziej użyteczny i łatwiejszy w rozbudowie – GtkFileSelection z PHP-GTK1. Kom-ponent GtkFileChooserDialog jest związany z klasą GtkFileChooser z biblioteki Gtk2, wykorzystywaną praktycznie we wszystkich aplikacjach opartych na Gnome, takich jak Evolu-tion, Gnumeric, Gaim czy Gimp. Instan-cję GtkFileChooserDialog nazwiemy $dialog, a następnie nadamy jej tytuł Otwarcie pliku i skojarzymy ją z reakcja-mi na możliwe odpowiedzi, czyli na OK i ANULUJ. Również odpowiedzi będą posiadały odpowiednie ikony stan-dardowe. Jeżeli potwierdzimy naszą chęć otwarcia pliku, bufor tekstu zo-stanie opróżniony (za pomocą $this->textbuffer->delete()), a zawartość pliku – wstawiona na bieżącej po-zycji kursora ($this->textbuffer->

Listing 6. Kod edytora tekstu, przechowywany w pliku TextEditor.class.php

<?php

// Klasa Editor – mały edytor tekstu

final class TextEditor extends GtkWindow{ private $textview; private $textbuffer; function __construct(){ // tworzy okno

...

// Tworzy pasek narzędzi

$toolbar = new GtkToolbar; // Tworzy przyciski “zapisz” i “otwórz”

$save = new GtkToolButton; $save->set_label('zapisz');

$save->set_stock_id('gtk-save');

$save->connect('clicked', array(&$this, 'saveFile'));...

// Wstawia przyciski na pasek

$toolbar->insert($open, 0);

$toolbar->insert($save, 0);

$vbox->pack_start($toolbar, false, false);...

// Tworzy parę TextView/TextBuffer;

$this->textview = new GtkTextView; $this->textbuffer = new GtkTextBuffer; $this->textview->set_buffer($this->textbuffer);

...

}

// Metoda openFile – Wyświetla FileDialog i wczytuje zawartość pliku

// do TextBuffer

public function openFile(){ // Tworzy FileChooserDialog

$dialog = new GtkFileChooserDialog('Otwarcie pliku', NULL, Gtk::FILE_CHOOSER_ACTION_OPEN,array(Gtk::STOCK_OK,Gtk::RESPONSE_OK, Gtk::STOCK_CANCEL, Gtk::RESPONSE_CANCEL));

// Wyświetla FileChooserDialog

$response = $dialog->run();

if ($response == Gtk::RESPONSE_OK){ // jeżeli użytkownik kliknął OK, //wyczyść TextBuffer i wstaw do niego zawartość wybranego pliku

$first = $this->textbuffer->get_start_iter();

$end = $this->textbuffer->get_end_iter();

$this->textbuffer->delete($first, $end);

$this->textbuffer->insert_at_cursor(file_get_contents(

$dialog->get_filename()));

}

$dialog->destroy();

}

// Metoda saveFile – Wyświetla FileDialog i zapisuje zawartość TextBuffer

// do wybranego pliku

public function saveFile(){ // Tworzy FileChooserDialog

$dialog = new GtkFileChooserDialog('Zapis do pliku', NULL, Gtk::FILE_CHOOSER_ACTION_SAVE,array(Gtk::STOCK_OK,Gtk::RESPONSE_OK, Gtk::STOCK_CANCEL, Gtk::RESPONSE_CANCEL));

// Wyświetla FileChooserDialog

$response = $dialog->run();

if ($response == Gtk::RESPONSE_OK){ // jeżeli użytkownik kliknął OK, // pobierz zawartość TextBuffer i zapisz ją do pliku

$first = $this->textbuffer->get_start_iter();

$end = $this->textbuffer->get_end_iter();

$text = $this->textbuffer->get_text($first, $end);

file_put_contents($dialog->get_filename(), $text);

}

$dialog->destroy();

}

}

?>

Page 72: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006www.phpsolmag.org72

Projekty

insertatcursor()). Po wykonaniu tych czynności dialog zostanie zniszczony.

Kolejna metoda nosi nazwę saveFile(). Wykorzystamy w niej tę samą klasę GtkFileChooserDialog, aby pobrać nazwę i położenie pliku, do którego chcemy zapisać nasz tekst. Podobnie jak w przypadku otwierania pliku, dialog będzie posiadał dwa przy-ciski: OK i ANULUJ. Jeżeli użytkownik kliknie OK, saveFile() odczyta tekst z bufora korzystając z metody $this->textbuffer->get_text(), a następnie zapisze go w pliku o wybranej (lub wpisanej) nazwie, za pomocą metody file_put_contents(). Na koniec (ana-logicznie jak w przypadku openFile()) dialog zostanie zniszczony.

Kto mnie stworzył: wykorzystanie dialogu O programieOstatnią rzeczą, która pozostała nam do zrobienia, jest dialog O programie, po-jawiający się po wybraniu opcji Pomoc z menu o tej samej nazwie. W tym celu stworzymy klasę AboutDialog i umie-ścimy ją w pliku AboutDialog.class.php. Jej kod przedstawiamy na Listin-gu 7. Będziemy w niej korzystać z wyjątków oraz możliwości manipulacjiobrazem.

Na początku swojego działania, konstruktor klasy AboutDialog ustawi (jak zwykle) podstawowe parametry okienka dialogowego. Następnie zała-dujemy obrazek o nazwie gnome.png i wyświetlimy go (patrz Rysunek 11). W tym celu wykorzystamy klasę GdkPixbuf. Obsługuje ona najpopu-larniejsze formaty obrazu, takie jak PNG, JPEG, itd., co zwalnia nas z obowiązku dodatkowej konwersji pli-ków graficznych. W PHP-GTK1 klasa ta była dostępna, jednak korzystano z niej jedynie opcjonalnie. W GTK2 stała się ona częścią zbioru klas na-tywnych i nie jest już opcjonalna. Mo-żemy ją wykorzystywać we wszystkich zadaniach związanych z manipulacją obrazkami, również w przypadku uży-wanych na paskach narzędzi i w menu ikon. Nie ma potrzeby opierania się na formacie XPM (XpixMap), który był stosowany powszechnie w PHP-GTK1 w sytuacjach, gdy nie korzystaliśmy z GdkPixbuf.

Podsumowując: stworzymy instan-cję klasy GdkPixbuf o nazwie $pixbuf,

Listing 7. Kod klasy AboutDialog, zawarty w pliku AboutDialog.class.php

<?php

// Klasa AboutDialog – Wyświetla informację o działającej aplikacji

final class AboutDialog extends GtkWindow{ public function __construct($software, $text){...

// spróbuj załadować obrazek

try{ $pixbuf = GdkPixbuf::new_from_file('images/gnome.png');

$imagem = new GtkImage; $imagem->set_from_pixbuf($pixbuf);

$vbox->pack_start($imagem);

}

catch{ (PhpGtkGErrorException $error)

// jeżeli wystąpiły jakieś błędy, wyświetl je na ekranie

$dialog = new GtkMessageDialog(null, Gtk::DIALOG_MODAL, Gtk::MESSAGE_ERROR,Gtk::BUTTONS_OK, $error->message);

$response = $dialog->run();

$dialog->destroy();

return; }

// wyświetl komunikat na temat aplikacji

$this->label = new GtkLabel($text); $vbox->pack_start($this->label);

// tworzy przycisk “Zamknij”

$this->button = new GtkButton('Zamknij'); $this->button->connect('clicked', array($this, 'onClose')); $vbox->pack_start($this->button, false, false); parent::show_all(); }

// Metoda onClose – Zamyka okno

public function onClose(){ parent::destroy(); }

...

}

?>

Rysunek 10. Wybór pliku

Page 73: Php Solutions 1 2006 PL

PHP-GTK2

PHP Solutions Nr 1/2006 www.phpsolmag.org 73

Projekty

przekazując jej konstruktorowi ścieżkę do pliku gnome.png. Następnie za po-mocą klasy GtkImage stworzymy wid-get obrazka, który nazwiemy $imagem. Korzystając z jego metody set_from_pixbuf(), przekopiujemy do niego za-wartość $pixbuf.

Chcemy jednak zapewnić także, że plik gnome.png zostanie załadowa-

ny, a w przypadku jego nieznalezienia aplikacja nie zakończy działania zgła-szając błąd. Z tego względu całość ope-racji związanych z obrazkiem zostanie zamknięta w bloku try{} konstrukcji try{}..catch{}. PHP-GTK2 współdziała z wprowadzonym w PHP5 systemem wy-jątków, generując je w sytuacjach takich, jak błędy występujące podczas konstru-owania obiektu, a także pojawiające się w metodach wykorzystujących mecha-nizm Gerror (takich jak np. statyczne konstruktory w rodzaju GdkPixbuff::

new_from_file()) oraz przy konwersji stron kodowych. W naszym przypadku, nieznalezienie logo spowoduje wygene-rowanie wyjątku obsługiwanego w kon-struktorze klasy AboutDialog.

I to wszystko. Nasza aplikacja jest już gotowa i możemy ją przetestować.

PodsumowaniePokazany przykład jest dość nieskompli-kowany, ilustruje jednak najważniejsze

nowości w PHP-GTK2. Zachęcamy do jego rozbudowy i poznawania szersze-go spektrum fascynujących możliwości tej wersji PHP-GTK na własną rękę. Na pewno nie będziecie zawiedzeni: PHP-GTK2 stanowi bowiem wielki krok na-przód w stosunku do poprzedniej wersji, a w połączeniu z nowymi możliwościami PHP5 może uczynić PHP poważnym wyborem dla programistów piszących klienckie aplikacje GUI. n

Pablo Dall’Oglio jest autorem pierwszej na świecie książki o PHP-GTK. Jest również autorem Agata Report (www.aga-ta.org.br) oraz Tulip Editor (http://tulip.solis.coop.br), a także koordynatorem projektu GNUTeca (www.gnuteca.org.br) – open-sourcowego oprogramowania do zarzą-dzania biblioteką.Kontakt z autorem: [email protected]

O autorze

R E K L A M A

Rysunek 11. Dialog O programie

Page 74: Php Solutions 1 2006 PL

Ranking

PHP Solutions Nr 1/2006www.phpsolmag.org74

Ranking

PHP Solutions Nr 1/2006 www.phpsolmag.org 75

Porównanie ofert polskich firm hostingowychPaweł Grzesiak

Rynek usług hostingowych w Pol-sce rozwija się dynamicznie. Do-wodem na to są coraz lepsze

parametry usług oferowanych przez firmy, podczas gdy średnia cena hostingu wciąż maleje. Jeżeli planujemy zakup własnego skrawka miejsca w sieci, warto zapoznać się z przygotowanym przez nas porówna-niem usług najpopularniejszych polskich providerów internetowych.

Rok 2005 z pewnością możemy na-zwać rokiem, w którym polski Internet roz-wijał się bardzo szybko. Motorem dla całej branży jest coraz powszechniejszy dostęp Polaków do łącz szerokopasmowych. Fir-my telekomunikacyjne walczą o klientów, co odbija się zarówno na cenie usług, jak i coraz wyższej jakości łączy. Dziś rynek zaspokaja potrzeby zarówno tych, którzy potrzebują szybkiego dostępu (liczonego w MBPS), jak i tych, dla których podsta-wowym kryterium jest cena (już nie prze-kraczająca 100 zł). Coraz większa liczba szybkich łącz dla klientów indywidualnych, pociąga za sobą rozwój infrastruktury tele-komunikacyjnej.

Skoro użytkownicy pobierają więcej plików z sieci, serwery muszą sprostać wzrastającemu obciążeniu. W ten sposób, w ciągu ostatniego roku obserwujemy na rynku znaczący wzrost pojemności serwe-rów WWW, większe limity transferu mie-sięcznego, a także niższe ceny za ruch dodatkowy. Powodów sytuacji, gdzie para-metry usług są coraz lepsze, a ceny usług maleją, jest co najmniej kilka. Główny impuls do zmian dały zagraniczne serwisy, oferujące konta e-mailowe o wielkościach (na tamte czasy) astronomicznych. Mniej

więcej w czasie, gdy Google ogłosiło, że planuje uruchomienie własnego serwera pocztowego Gmail, oferującego zawrotną pojemność 1 GB, stało się jasne, że szy-kuje się w Polsce wojna o klienta. Usługi hostingowe musiały bowiem nadążać za rodzimymi portalami, które zaoferowały bezpłatne skrzynki pocztowe, docelowo o pojemności 1 GB.

Co zabawne, zwiększenie pojemności kont wcale nie równało się poniesieniu ogromnych nakładów finansowych. Więk-szość użytkowników nie wykorzystuje bowiem nawet 1% swojej powierzchni na korespondencję. Zadziałał tu więc raczej marketing. Kolejnym powodem, dla które-go pośrednio obniżyły się ceny usług, było wejście usług hostingowych, z serwerami zlokalizowanymi poza Polską. Miejsce na takim serwerze było swego czasu sporo tańsze, dlatego że serwery lokowano za oceanem. Na korzyść serwerów w USA działała różnica czasu. Gdy Amerykanie spali, my korzystaliśmy z ich serwerów. Jednocześnie w Stanach ceny usług ho-stingowych i sprzętu komputerowego są niższe, więc możliwe było zaoferowanie ciekawych warunków cenowych. Wadą były długie czasy odpowiedzi serwera, czyli tzw. pingi, co wynikało z długości odległości połączenia i bariery kontynen-talnej. Dla przeciętnego użytkownika nie były jednak zauważalne opóźnienia przy ładowaniu stron.

Dziś już odchodzi się od lokowania serwera w USA, na rzecz krajów Euro-py Zachodniej, a konkretniej Holandii i Niemiec, które są nam geograficznie bliższe (stąd strony ładują się szybciej),

a jednocześnie są wciąż tańsze od na-szych krajowych dostawców. Jednak w perspektywie czasu, serwer ulokowa-ny poza granicami Polski może przestać się opłacać.

Jeszcze półtora roku temu providerzy bronili się rękami i nogami przed two-rzeniem zbyt wielkiej liczby kont e-mail, czy podpinaniem wielu domen. Dziś standardem stało się wyrażenie „bez ograniczeń”, a na serwerze za kilkaset złotych można z powodzeniem urucho-mić kilkanaście niezależnych serwisów internetowych.

Jak powstało porównanie?Tworząc swoisty ranking usług ho-stingowych, za podstawowe kryterium wzięliśmy statystyki ilości obsługiwanych domen przez każdego z providerów, ba-zując na wynikach z witryny top100.pl. Usługi hostingowe bardzo ciężko jest jednoznacznie ocenić, wyłaniając przy tym zwycięzcę. Zarówno oferty, jak i ich ceny są bardzo do siebie zbliżone. Mo-gliśmy bazować na popularności i opinii klientów. Postawiliśmy na to, sądząc, że największe zaufanie budzi ten provider, który zarejestrował dla swoich klientów najwięcej domen. Oczywiście nie powin-no to stanowić kryterium decydującego o zakupie danej usługi. Zaprezentowane 12 firm prezentuje bowiem bardzo wy-równany, wysoki poziom. Należy jesz-cze tylko dodać, że do rankingu zostały zakwalifikowane tylko te firmy, których podstawowym przedmiotem działalności są usługi hostingowe. n

Page 75: Php Solutions 1 2006 PL

Ranking

PHP Solutions Nr 1/2006www.phpsolmag.org74

Ranking

PHP Solutions Nr 1/2006 www.phpsolmag.org 75

Firm

aU

sług

aPo

wie

rzch

nia

Lim

it tr

ansf

eru

(mie

sięc

zny)

Res

tryk

cje

ilośc

iow

eO

bsłu

ga b

az d

anyc

hC

eny

(net

to)

Loka

lizac

ja

serw

era

FTP

Pocz

taBa

zyD

anyc

hKo

nt e

-mai

lD

omen

/ Su

bdom

enSe

rwis

ówKo

nt F

TPBa

zda

nych

MyS

QL

Post

gre-

SQL

Abon

amen

t R

oczn

yH

ome

(hom

e.pl

)Bu

sine

ss S

tarte

r1

GB

10 G

Bb.

o.b.

o.1

11

Tak

Tak

300

Pols

kaBu

sine

ss S

erve

r5

GB

20 G

Bb.

o.b.

o.b.

o.1

5Ta

kTa

k60

0Bu

sine

ss P

RO

10 G

B30

GB

b.o.

b.o.

b.o.

b.o.

15Ta

kTa

k90

0Pr

ogre

so (p

rogr

eso.

pl)

Bizn

es5

GB

12 G

Bb.

o.b.

o.b.

o.b.

o.b.

o.Ta

k-

300

Pols

kaBi

znes

plu

s10

GB

24 G

Bb.

o.b.

o.b.

o.b.

o.b.

o.Ta

k-

600

Live

net (

liven

et.p

l)Sm

all

100

MB

1 G

B3

51

12

Tak

Tak

32,7

8

Hol

andi

a

Med

ium

200

MB

2,5

GB

107

25

4Ta

kTa

k45

,08

Larg

e50

0 M

B5

GB

3020

510

8Ta

kTa

k72

,13

Big

1 G

B8

GB

5010

07

1012

Tak

Tak

108,

19X-

big

2 G

B10

GB

b.o.

b.o.

910

16Ta

kTa

k14

4,26

Porta

l5

GB

15 G

Bb.

o.b.

o.11

2020

Tak

Tak

198,

36Pr

iorit

aire

10 G

B30

GB

b.o.

b.o.

16b.

o.40

Tak

Tak

270,

49N

etlin

k (n

q.pl

)nQ

.STA

RT

1 G

B5

MB

4 G

B5

11

11

Tak

Tak

199

Pols

kanQ

.BIZ

NES

2 G

B25

MB

10 G

B20

53

51

Tak

Tak

399

nQ.P

RO

FESJ

A5

GB

200

MB

16 G

B50

155

152

Tak

Tak

699

nQ.V

IP10

GB

300

MB

24 G

Bb.

o.30

10b.

o.3

Tak

Tak

999

Naz

wa

(naz

wa.

pl)

Activ

e5

GB

10 G

Bb.

o.b.

o.b.

o.1

1Ta

kTa

k30

0Po

lska

Pro

10 G

B20

GB

b.o.

b.o.

b.o.

1b.

o.Ta

kTa

k60

0KE

I Pro

vide

r (ke

i.pl)

Biur

o Ex

tra5

GB

10 G

Bb.

o.b.

o.b.

o.1

1Ta

kTa

k30

0Po

lska

Lide

r10

GB

20 G

Bb.

o.b.

o.b.

o.1

5Ta

kTa

k60

0D

omen

y.or

g (d

omen

y.or

g)St

art

4 G

B4

GB

2 G

B8,

3 G

Bb.

o.b.

o.b.

o.1

5Ta

k-

220

Pols

kaC

lass

ic10

GB

10 G

B5

GB

16,7

GB

b.o.

b.o.

b.o.

b.o.

b.o.

Tak

-42

0Fu

turo

(fut

uro.

pl)

Flex

o St

art

2 G

B5

MB

1 G

Bb.

o.b.

o.b.

o.b.

o.b.

d.Ta

k-

50Po

lska

Flex

o5

GB

5 M

B10

GB

b.o.

b.o.

b.o.

b.o.

b.d.

Tak

-10

0Fl

exo

Biz

10 G

B7

MB

20 G

Bb.

o.b.

o.b.

o.b.

o.b.

d.Ta

k-

500

Ogi

com

(ogi

com

.pl)

Bizn

es 5

010

0 M

B-

1 G

B4

b.o.

11

--

-40

7

Pols

kaBi

znes

150

300

MB

-3

GB

12b.

o.1

1-

--

660

Bizn

es 2

5050

0 M

B5

GB

30b.

o.1

1b.

d.Ta

k-

880

Bizn

es 3

5070

0 M

B7

GB

50b.

o.1

1b.

d.Ta

k-

1199

Bizn

es 5

001

GB

10 G

Bb.

o.b.

o.1

1b.

d.Ta

k-

1507

Agna

t (ag

nat.p

l)Pr

ofit

5 G

B5

GB

100

b.o.

b.d.

b.d.

n.d.

*-

-29

8Po

lska

Expe

rt10

GB

10 G

Bb.

o.b.

o.b.

d.b.

d.n.

d.*

--

598

Sisc

o (s

isco

.pl)

Econ

omic

300

300

MB

5 G

B5

b.o.

b.o.

b.o.

1Ta

k-

300

Pols

kaBu

sine

ss 5

0050

0 M

B8

GB

10b.

o.b.

o.b.

o.2

Tak

-40

0Pr

o 10

001

GB

16 G

Bb.

o.b.

o.b.

o.b.

o.3

Tak

-60

0VI

P 20

002

GB

25 G

Bb.

o.b.

o.b.

o.b.

o.5

Tak

-10

00M

ax 3

000

3 G

B40

GB

b.o.

b.o.

b.o.

b.o.

8Ta

k-

1600

Alph

aNet

(alp

ha.p

l)Pr

omo

500

MB

500

MB

b.o.

5 G

Bb.

o.b.

o.1

b.o.

1Ta

kTa

k99

Pols

ka

Prim

a1

GB

1 G

Bb.

o.10

GB

b.o.

b.o.

2b.

o.2

Tak

Tak

190

Expo

5 G

B20

GB

b.o.

b.o.

4b.

o.4

Tak

Tak

290

Mul

ti3

GB

20 G

Bb.

o.b.

o.20

b.o.

20Ta

kTa

k39

9O

pti

6 G

B30

GB

b.o.

b.o.

50b.

o.50

Tak

Tak

599

Solid

+15

GB

100

GB

b.o.

b.o.

150

b.o.

b.o.

Tak

Tak

1500

AMM

-Kom

pute

r (am

m.n

et.p

l)St

art

1 G

B25

MB

2 G

Bb.

o.b.

o.b.

d.b.

d.2

Tak

-10

0

Pols

ka

Star

t+1,

5 G

B50

MB

3 G

Bb.

o.b.

o.b.

d.b.

d.3

Tak

-15

0M

ini

3 G

B75

MB

4 G

Bb.

o.b.

o.b.

d.b.

d.3

Tak

Tak

200

Stan

dard

5 G

B10

GB

b.o.

b.o.

b.d.

b.d.

4Ta

kTa

k30

0Bu

sine

ss6

GB

15 G

Bb.

o.b.

o.b.

d.b.

d.5

Tak

Tak

400

Prof

essi

onal

7,5

GB

20 G

Bb.

o.b.

o.b.

d.b.

d.7

Tak

Tak

600

b.o.

– b

ez o

gran

icze

ń; n

.d. –

nie

dot

yczy

; b.d

. – b

rak

dany

ch;

* firm

a of

eruj

e do

stęp

do

bazy

dan

ych

SQLi

te (m

oduł

PH

P5)

Page 76: Php Solutions 1 2006 PL

76

Portal aktywnych internautów

Codziennie w Polsce nowe firmy rozpo-czynają działalność, łączą się, zmie-niają nazwy. Każdy przedsiębiorca

i webmaster poszukuje sposobów, by pokazać w sieci siebie i swą ofertę z jak najlepszej strony, jak najniższym kosztem. W ostatnich latach było wiele firm oferujących usługi ho-stingowe, które po kilku miesiącach kończyły swą działalność, a nasze pieniądze i trudw budowaniu stron legł w gruzach. Dla webma-stera podstawową sprawą jest znalezienie ta-kiego usługodawcy, który zapewni stabilność strony, szybki dostęp, a także wiele usług dodanych. Jednak fundamentalnym kryterium przy wyborze miejsca, w którym będziemy przetrzymywali naszą stronę jest cena. Two-rząc strony w PHP staramy się, by czynność ich aktualizacji przełożyć na barki właścicieli stron. Korzystamy zatem z systemów umoż-liwiających użytkownikowi samodzielne za-rządzanie treścią (CMS). Niestety na naszym rynku istnieje niewielka liczba firm, których oferta odpowiadałaby naszym potrzebom. Najczęściej dostęp do serwera oferującego kilkaset megabajtów miejsca na stronę WWW, możliwość dostępu do PHP w wersji nowszej niż 4.0, gwarantującego bezpieczeństwo na-szych danych, kosztuje od kilkudziesięciu do kilkuset złotych miesięcznie.

POSZUKUJEMYDARMOWEGO HOSTINGUSzukając rozwiązania naszych problemów związanych z koniecznością uiszczania opłat za hostowanie naszych stron, można natknąć się na oferty kilku firm oferujących darmowe usługi. Jedną z nich jest oferta Ósemka.pl In-ternet Media, właściciela za.pl i friko.pl. Ósemka to jedna z najlepszych firm oferujących nie-przerwanie od 1999 roku usługi hostingowe. Obecnie w nowopowstałym Portalu Aktywnych Internautów, który połączył tradycję darmo-wych kont za.pl i friko.pl, zarejestrowanych jest 202 tysiące użytkownikow, a 66 tysięcy kont hostingowych jest aktywnych. Ze statystyk wynika, iż łącznie strony hostowane na ser-werach portalu hosting.osemka.pl w miesiącu wrześniu 2005r. obejrzało blisko 3mln użyt-kownikow, generując ponad 25 mln odsłon. Budzi zdziwienie fakt, iż nie jest to odnotowane

w żadnych zbiorczych zestawieniach firmy statystycznej Gemius SA. A wystarczy tylko sprawdzić, iż wyszukiwarka Google zaindekso-wała 2,5 mln dokumentów portalu osemka.pl – dla porówania w Google znajduje się 2,3 mln dokumentów Wirtualnej Polski (webpark.pl), czy 1,6 mln firmy Prv.pl. Świadczy to o ogrom-nej popularności usług proponowanych przez wspomniany serwis oferujący 200 MB konta na strony www oraz dostęp przez ftp. Wyróż-niającą cechą tego portalu wśród konkurencji jest wysoka pozycja stron w domenie friko.pl i za.pl w wyszukiwarkach (strona główna ma Page Rank 6), a także możliwość skorzysta-nia ze skryptów PHP 4.4.0. Niezwykle istotne jest, iż osemka.pl nie tworzy żadnych limitów miesięcznych, czy rocznych na transfery pli-ków. Ta opcja jest praktycznie niedostępna u konkurencji, a ponadto nawet serwisy płatne stosują limity.

TESTUJEMYPostanowiliśmy przetestować ofertę osem-ka.pl. Rejestracja wyglądała prosto i sprawnie – należało podać jedynie swoje dane oraz adres email, następnie wybrać domenę dla naszej strony z łatwo zapadających w pamięć – za.pl i friko.pl. Momentalnie otrzymaliśmy wygenerowany automatycznie email z potwier-dzeniem rejestracji i hasłem. Po zalogowaniu się nie napotkaliśmy jakichkolwiek problemów z edycją hasła, swoich danych itp. W panelu użytkownika znaleźliśmy nieaktywną opcję zakładania baz MySQL. Fakt jej umieszczenia może wskazywać, że programiści przewidzieli taką możliwość w przyszłości. Chwilę później po szybkim transferze plikow na serwer, mo-gliśmy się już pochwalić naszą stroną inter-netową, zbudowaną w systemie CMS, naszym znajomym i klientom, i to zupełnie za darmo! Największą wadą tego serwisu, którą napotka-liśmy był tryb działania safe mode, który nieco ogranicza funkcje, lecz jednocześnie zwiększa szansę, że nasz serwer bedzie działał dłużej. Zauważoną niedogodnością była funkcja inclu-de, którą można stosować tylko do bieżącego katalogu. Utrudnia to nieco pracę przy więk-szych ilościach podstron, lecz zważywszy na fakt, iż jest to całkowicie darmowy serwis – to i tak nieznaczne uchybienie.

SZUKAMY WIĘCEJ MIEJSCANaszą uwagę w poszukiwaniach darmowego hostingu z obsługą php przykuła inna oferta polskiej firmy Spox.pl.

Wspomniany serwis oferuje całkowicie bezpłatnie profesjonalny hosting o parame-trach zarezerwowanych do tej pory dla komer-cyjnych i często bardzo drogich serwerów www. Spox.pl proponuje aż 500 MB pamięci dysko-wej, transfer bez limitu, łatwy dostęp przez FTP, cPanel. Dodatkowo istnieje także opcja posiadania własnej domeny. Tutaj o rejestracji nie decyduje automat, a każde zgłoszenie jest osobno rozpatrywane. Na odpowiedź i potwier-dzenie zgłoszenia rejestracyjnego czekaliśmy niecałe 24h. Zaraz po zalogowaniu się i zmianie hasła mogliśmy już swobodnie umieścić naszą stronę w serwisie spox.pl. Transfer był szybki i nie zauważyliśmy jakichkolwiek problemów z funkcjonowaniem naszego site’a. Strona nadal działa bezbłędnie.

ZA GRANICĄ ZA DARMOPrzykładem sprawnego działania, bez koniecz-ności obsługi skryptów PHP, jest zagraniczny serwis happyhost.org. Przede wszystkim należy zaznaczyć, że jest to całkowicie darmowy serwis, bez limitów na przesył danych. Co prawda pingi wysyłane z Polski wracają po nieco dłuższym czasie, niż w przypadku innych rodzimych serwisów, jednak sprawdzając połączenia z ser-werów znajdujących się w USA, wyniki wyglądają rewelacyjnie.

Page 77: Php Solutions 1 2006 PL

zamów prenumeratę PHP Solutionsa otrzymasz prezent!

szczegółowe informacje: www.phpsolmag.org/prenumerata lub [email protected]

wybierz prezent:

» program PHPRunner o wartości 199$» 20% zniżki na oprogramowanie firmy Zend» dwa dowolne numery archiwalne PHP Solutions» pakiet internetowy nQ.Biznes firmy Netlink o wartości 486,70 zł» roczny abonament na Usługę Business Starter» pakiet Xtreeme SiteXpert firmy Xtreeme» Maguma Workbench Bundle Starter

* cena prenumeraty rocznej w promocji zimowejoferta ważna do wyczerpania zapasów;

nowa niższa cena:150zł 135zł

Page 78: Php Solutions 1 2006 PL

78

PHPRunner: Szybkie prototypowanie PHP na twój sposóbFirma Universal Data Solutions wydała

PHPRunner 2.0 – biznesowe rozwiąza-nie do budowania wizualnie atrakcyj-

nych interfejsów sieciowych dla najpopular-niejszych systemów baz danych, mianowicie: MySQL, PostgreSQL, Oracle, MS Access oraz MS SQL Server. Jest zaprojektowane tak, by spełniać oczekiwania wszystkich użytkowni-ków – od początkujących po doświadczonych deweloperów.

PHPRunner posiada różne zastosowania: przeszukiwanie baz danych przez sieć, wpro-wadzanie danych bądź tworzenie sieciowych raportów. Branże: samochodowa, nierucho-mości, medyczna i turystyczna to tylko kilka spośród wielu, w których można wykorzystać to rozwiązanie.

Istotnym elementem jest wykorzystywa-nie przez PHPRunner interfejsu opartego na kreatorach oraz zbioru szablonów. Oznacza to, że administrator bazy danych nie musi napi-sać ani jednej linii kodu, czy nawet posiadać doświadczenia programistycznego. Oprócz szczodrej kolekcji szablonów, dostępny jest także ich edytor, pozwalający administratorom baz danych dopasowywać wygląd stron stwo-rzonych w PHP do własnych potrzeb, przez wstawianie logo i etykiet oraz modyfikację czcionek i kolorów. Zaawansowani użytkowni-cy mają także możliwość poprawiania genero-wanego przez program kodu PHP.

Obecnie oprócz MySQL używać można także PostgreSQL, Oracle’a, MS Access i MS SQL Server, co stanowi istotny krok w dziedzinie ulepszania tego rozwiązania. Ponadto PHPRun-ner wzbogacony został o szereg przydatnych funkcji, takich jak wielopoziomowe uprawnienia dostępu do różnych tabel, wsparcie dla wielu języków (wybierać można z ponad 20), a także wiele innych możliwości.

PHPRunner jest świetnym rozwiązaniem do tworzenia chronionych hasłem serwisów tylko dla użytkowników; ponadto pozwala budować strony pozwalające przeprowadzać automatycz-ną rejestrację użytkowników. Można z jego pomo-cą tworzyć funkcje przypominania i zmieniania haseł. Operacjom wywoływanym za pomocą tych funkcji może towarzyszyć na przykład wysyłanie pocztą powiadomienia dla administratora w sytu-acji, gdy zarejestrował się nowy użytkownik.

Możliwe jest także ustawienie dla każdego użytkownika wielopoziomowych uprawnień do różnych tabel. Przykładowo: Użytkownik A może jedynie edytować i dodawać dane do tabel Orders i Customers, podczas gdy Użytkownik B może kasować dane w tabeli Orders oraz edytować ta-belę Customers. Oprócz tego, PHPRunner może tworzyć użytkowników Administrator oraz Gość. Administrator miałby dostęp do wszystkich tabeli rekordów, Gość zaś – tylko prawa odczytu.

PHPRunner czyni edycję danych dziecinnie łatwą. Zapewnia on szereg zaawansowanych kontrolek edycyjnych takich jak selektory dat, łączone rozwijane listy, możliwość przesyłania plików i obrazków na serwer, edytor tekstu z formatowaniem HTML, pola list, przyciski radio i wiele innych.

PHPRunner dostarcza także szereg funkcji walidacji danych, chroniących użytkowników

przed wprowadzeniem niewłaściwych danych do dostępnych dla nich pól. Po wygenerowaniu plików PHP, użytkownicy mogą szybko wysłać pliki na zdalny serwer WWW za pomocą wbu-dowanego klienta FTP – z możliwością wyboru, czy wysłane mają być wszystkie pliki, czy tylko zmodyfikowane.

PHPRunner jest tak prosty w obsłudze, że w pełni funkcjonalną aplikację można za jego pomocą wygenerować w zaledwie 15 minut.

PHPRunner rozpowszechniany jest elek-tronicznie przez Internet. Darmowa wersja próbna dostępna jest na stronie producenta. Cena pojedynczej kopii to 199 USD. Dystrybutorom oprogramowania oraz kupującym większe ilości kopii sugerujemy negocjację specjalnych zniżek. Wersja próbna (ważna 21 dni) może być pobrana ze strony http://www.xlinesoft.com/phprunner/download.htm

Telefon: +1 (888) 290-6617http://www.xlinesoft.com

Informacje o programie:http://www.xlinesoft.com/phprunner

Kontakt:

CO NASI KLIENCI MAJĄ DO POWIEDZENIA O PHPRUNNER:l Cóż, stało się wreszcie! Znalazłem rozwiązanie umożliwiające szybkie prototypowanie

w świecie MySQL/PHP – i wprawdzie istnieją także i inne, jednak to jest pierwsze wi-dziane przeze mnie rozwiązanie, które jest zarówno praktyczne, jak i funkcjonalne. Tym produktem jest PHPRunner – Peter B. MacIntyre.

l Korzystając z PHPRunner właśnie zbudowałem serwis dla bazy MySQL w ciągu około trzydziestu minut. FANTASTYCZNE. Po prostu nie mogę tego opisać. Kilku moich kole-gów nie może wyjść z podziwu, jak gładko to wszystko poszło – Randy Samms, SBC/Southwest-ESAC.

l Muszę Ci to powiedzieć stary, ten program to najwspanialszy wynalazek od czasu krojonego chleba. Jako obecny w sieci fotograf, piszący swoje własne galerie itp. korzystam z wielu programów, ale PHPRunner to chyba najbardziej pomocny program w mojej biblioteczce. Po prostu tak bardzo upraszcza mi życie – Stephen Jones, Australia.

l PHPRunner to prawdopodobnie najlepszy generator PHP na rynku. Zanim trafiłem na to narzędzie wypróbowałem coś koło trzech innych i mogę powiedzieć, że nie znajdziesz lepszego, ani nawet porównywalnego – Pedro Ruiz, Database Manager.

Page 79: Php Solutions 1 2006 PL

Całkowicie przebudowany serwis poświęcony skryptom. Obecnie skupia się na zbiorze skryp-tów z całego świata.

www.antraxja-skrypty.iweb.pl

Portal, który oprócz emitowania newsów czy wywiadów gromadzi bogate materiały związane z projektowaniem i pisaniem stron WWW.

www.webinside.pl

Skryptoteka to jeden z największych i najbar-dziej znanych zbiorów skryptów. Zawiera także artykuły, czcionki, szablony i podręczniki.

www.skryptoteka.pl

Serwis dla webmasterów, organizujący konkurs we współpracy z naszym magazynem, promują-cy rozwiązania bez użycia systemów CMS itp.

www.webmaster.bbsoft.pl

Serwis zawierający kompletne kursy 9 technolo-gii związanych z webmasteringiem oraz skrypty, elementy grafiki, czcionki i narzędzia.

www.tymex.org

Bogate archiwum skryptów PHP, JavaScript, CGI, Perl i ASP. Zawiera także artykuły, porady, tutoriale, książki.

www.megaskrypty.com

Młody, rozwijający się serwis związany z PHP. Zdaje się, że autorowi zależy na niestandardo-wej oprawie i zawartości.

www.sm00f.boo

Serwis stworzony z myślą o programistach PHP, który stara się prezentować także ogólne wiadomości związane Internetem.

www.compzone.org

Strona zawierająca artykuły związane z PHP napisane przez autora. Zawiera też kolekcję zdjęć oraz opisy ciekawych książek.

www.antylameriada.net

Recommended sites >>>

Recommended sites

Xklonos to serwis istniejący już od 2001 roku. Każdy użytkownik może wpływać na jego formę.

www.xklonos.cal.pl

Wortal webmastera bogaty w wiele materiałów. Związany jest z Webserv – pakietem Apache, PHP, MySQL, MySQL CC oraz NoIP.

www.webpl.org

Serwis powstał w celu związania społeczności webmasterskiej. Użytkownicy mogą wymieniać doświadczenia oraz uzyskiwać porady.

www.webmade.org

Jeśli prowadzisz ciekawą stronę internetowąi chcesz abyśmy przedstawili ją w ramach akcji Recommended sites,

skontaktuj się z nami pod adresem [email protected]

Page 80: Php Solutions 1 2006 PL

Zaprenumeruj swoje ulubione magazyny i zamów archiwalne numery!

Już teraz w kilka minut możesz zaprenumerować swoje ulubione pismo.Gwarantujemy:- preferencyjne ceny- bezpieczną płatność on-line- szybką realizację Twojego zamówienia Bezpieczna prenumerata on-line wszystkich tytułów Wydawnictwa Software!

www.shop.software.com.pl zamówienie prenumeratywww.shop.software.com.pl

Page 81: Php Solutions 1 2006 PL

www.shop.software.com.pl

Prosimy wypełnić czytelnie i przesłać faksem na numer: (22) 887 10 11 lub listownie na adres: Software-Wydawnictwo Sp. z o.o., Piaskowa 3, 01-067 Warszawa, e-mail: [email protected]. Przyjmujemy też zamówienia telefoniczne: (22) 887 14 44

Imię i nazwisko............................................................................................ ID kontrahenta..........................................................................................

Nazwa firmy................................................................................................. Numer NIP firmy.......................................................................................

Dokładny adres....................................................................................................................................................................................................................

Telefon (wraz z numerem kierunkowym)................................................... Faks (wraz z numerem kierunkowym) ....................................................

E-mail (niezbędny do wysłania faktury)............................................................................................................................................................................

zamówienie prenumeratywww.shop.software.com.pl

1 Cena prenumeraty rocznej dla osób prywatnych2 Cena prenumeraty rocznej dla osób prenumerujących już Software Developer’s Journal lub Linux+3 Cena prenumeraty dwuletniej Aurox Linux

Jeżeli chcesz zapłacić kartą kredytową, wejdź na stronę naszego sklepu internetowego:

www.shop.software.com.pl

automatyczne przedłużenie prenumeraty

Suma

Tytuł Ilość numerów

Ilość zamawianych prenumerat

Od numeru pisma lub miesiąca

Opłata w zł

z VATSoftware Developer’s Journal (1 płyta CD)– dawniej Software 2.0Miesięcznik profesjonalnych programistów

12 250/1801

SDJ Extra (od 1 do 4 płyt CD lub DVD)– dawniej Software 2.0 Extra!Numery tematyczne dla programistów

6 150/1352

Linux+ (2 płyty CD)Miesięcznik o systemie Linux 12 250/1801

Linux+DVD (2 płyty DVD)Miesięcznik o systemie Linux 12 270/1981

Linux+Extra! (od 1 do 7 płyt CD lub DVD)Numery specjalne z najpopularniejszymi dystrybucjami Linuksa 8 232/1982

PHP Solutions (1 płyta CD)Dwumiesięcznik o zastosowaniach języka PHP 6 135

Hakin9, jak się obronić (1 płyta CD)Dwumiesięcznik o bezpieczeństwie i hakingu 6 135

.psd (1 płyta CD + film instruktażowy)Dwumiesięcznik użytkowników programu Adobe Photoshop 6 140

Aurox Linux (4 płyty CD + 1 płyta DVD)Magazyn z najpopularniejszym polskim Linuksem 4 1193

Page 82: Php Solutions 1 2006 PL

W sprzedaży od 20 lutego!

W następnym numerze PHP Solutions

■ Ilia Alshanetsky, twórca FUDforum, autor książki Guide to PHP Security, a także współautor wielu projektów Open Source i rozszerzeń takich jak: PDO, SQLite czy GD prezentuje:

Ataki XSS oraz CSRF na aplikacje internetowe

■ Aaron Wormus: PEAR::Structures_DataGrid – poznajemy narzędzia tworzące datagridw formatach HTML, XML, XLS, XUL i innych. Pakiet umożliwia także łatwe implementowanie mechanizmów stronicowania i sortowania w celu limitowania wyświetlanych i przetwarzanych danych. Idea wzorowana jest na .NET Framework DataGrid control.

Ponadto planujemy:

■ SDO (Service Data Objects) i XML

■ Phalanger, czyli z .NET do PHP

■ Wzorce projektowe

Page 83: Php Solutions 1 2006 PL
Page 84: Php Solutions 1 2006 PL