PHP. Zaawansowane programowanie

Zacznij tam, gdzie inni kończą! PHP jest obecnie najpopularniejszym językiem programowania aplikacji internetowych, a je

1,299 168 6MB

Polish Pages [355] Year 2012

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

PHP. Zaawansowane programowanie

Table of contents :
Spis treści
O autorach
O korektorze merytorycznym
Przedmowa
Wprowadzenie do PHP
Geneza PHP
Czym jest PHP?
Szczegółowy przegląd treści książki
Rozdział 1. Obiektowość
Rozdział 2. Wyjątki i referencje
Rozdział 3. Mobilne PHP
Rozdział 4. Media społecznościowe
Rozdział 5. Nowości technologiczne
Rozdział 6. Tworzenie formularzy i zarządzanie nimi
Rozdziały 7. i 8. Integracja z bazami danych. Część I i II
Rozdział 9. Integracja z bazami danych. Część III
Rozdział 10. Biblioteki
Rozdział 11. Bezpieczeństwo
Rozdział 12. Programowanie zwinne z wykorzystaniem Zend Studio dla Eclipse, Bugzilli, Mylyn i Subversion
Rozdział 13. Refaktoryzacja, testy jednostkowe i ciągła integracja
Rozdział 14. XML
Rozdział 15. JSON i Ajax
Rozdział 16. Konkluzja
Przyszłość PHP
Rozdział 1. Obiektowość
Klasy
Dziedziczenie i przeciążanie
„Magiczne” funkcje
Metody __get i __set
Metoda __isset
Metoda __call
Metoda __toString()
Kopiowanie, klonowanie oraz porównywanie obiektów
Interfejsy, iteratory i klasy abstrakcyjne
Kontekst klasy i elementy statyczne
Podsumowanie
Rozdział 2. Wyjątki i referencje
Wyjątki
Referencje
Podsumowanie
Rozdział 3. Mobilne PHP
Różnorodność urządzeń
Rozpoznanie urządzenia
Aplikacja kliencka
Wbudowane funkcje PHP
Rozpoznawanie możliwości urządzenia
WURFL
Tera-WURFL
Narzędzia renderujące
WALL
Reagujący CSS
Emulatory i SDK
Tworzenie dla systemu Android
Adobe Flash Builder dla PHP
Kody QR
Podsumowanie
Rozdział 4. Media społecznościowe
OAuth
Twitter
API publicznego wyszukiwania
Prywatne REST API
Wykorzystanie mechanizmu OAuth w celu powiązania strony z systemem logowania
Dodatkowe metody API i przykłady jego wykorzystania
Facebook
Dodanie linku wylogowania z Facebooka
Żądanie dodatkowych uprawnień
Graph API
Podsumowanie
Rozdział 5. Nowości technologiczne
Przestrzenie nazw
Przestrzenie nazw i autoładowanie
Przestrzenie nazw — podsumowanie
Funkcje anonimowe
Nowdoc
Lokalne instrukcje goto
Standardowa biblioteka PHP — SPL
SPL — podsumowanie
Rozszerzenie phar
Podsumowanie
Rozdział 6. Tworzenie formularzy i zarządzanie nimi
Walidacja danych
Wczytywanie plików i obrazów
Konwersja obrazów i miniatury
Wyrażenia regularne
Integracja języków
Podsumowanie
Rozdział 7. Integracja z bazami danych. Część I
Wprowadzenie do MongoDB
Zapytania w MongoDB
Modyfikowanie dokumentów w MongoDB
Agregacje w MongoDB
Podsumowanie MongoDB
Wprowadzenie do CouchDB
Wykorzystanie interfejsu Futon
Podsumowanie CouchDB
Wprowadzenie do SQLite
Podsumowanie SQLite
Podsumowanie
Rozdział 8. Integracja z bazami danych. Część II
Wprowadzenie do rozszerzenia MySQLi
Podsumowanie rozszerzenia MySQLi
Wprowadzenie do PDO
Podsumowanie PDO
Wprowadzenie do ADOdb
Podsumowanie ADOdb
Wyszukiwanie pełnotekstowe przy wykorzystaniu Sphinksa
Podsumowanie
Rozdział 9. Integracja z bazami danych. Część III
Wprowadzenie do Oracle
Podstawy. Połączenie i wykonywanie zapytań
Interfejs tablicowy
Procedury i kursory w PL/SQL
Praca z typami LOB
Inne podejście do połączeń — pule połączeń
Zestawy znaków w bazie danych i PHP
Podsumowanie
Rozdział 10. Biblioteki
SimplePie
TCPDF
Pobieranie danych ze stron internetowych
Integracja z Mapami Google
Wiadomości e-mail i SMS
gChartPHP — biblioteka wykorzystująca Google Chart API
Podsumowanie
Rozdział 11. Bezpieczeństwo
Nigdy nie ufaj danym
register_globals
Białe i czarne listy
Dane formularzy
$_COOKIES, $_SESSION i $_SERVER
Żądania Ajax
Powszechne ataki
Polityka tego samego pochodzenia
XSS (Cross Site Scripting)
CSRF (Cross-Site Request Forgery)
Sesje
Zapobieganie atakom typu SQL injection
Wyrażenia filtrujące
Plik php.ini i ustawienia serwera
Środowisko serwerowe
Zabezpieczanie pliku php.ini
Algorytmy haseł
Podsumowanie
Rozdział 12. Programowanie zwinne z wykorzystaniem Zend Studio dla Eclipse, Bugzilli, Mylyn i Subversion
Zasady programowania zwinnego
Rajd programowania zwinnego
Wprowadzenie do programu Bugzilla
Mylyn dla Eclipse
Bugzilla i Mylyn w połączeniu z Eclipse
Maksymalizowanie korzyści
Podsumowanie
Rozdział 13. Refaktoryzacja, testy jednostkowe i ciągła integracja
Refaktoryzacja
Niewielka refaktoryzacja
Większy przykład
Testy jednostkowe
Ciągła integracja
Serwer ciągłej integracji
System kontroli wersji
Analiza statyczna
Budowanie automatyzacji
Uruchomienie serwera Jenkins
Podsumowanie
Rozdział 14. XML
Podstawy XML
Schematy
SimpleXML
Parsowanie XML z tekstu
Parsowanie XML z pliku
Przestrzenie nazw
RSS
Generowanie dokumentów XML za pomocą SimpleXML
DOMDocument
XMLReader i XMLWriter
Podsumowanie
Rozdział 15. JSON i Ajax
JSON
PHP i JSON
Ajax
Tradycyjny model WWW
Model Ajax
Zdarzenia synchroniczne kontra asynchroniczne
Obiekt XMLHttpRequest
Wykorzystanie obiektu XMLHttpRequest
API JavaScript wyższego poziomu
Przykłady jQuery
Przesyłanie danych z Ajaksa do skryptu PHP
Prosty program graficzny
Utrzymanie stanu
Podsumowanie
Rozdział 16. Konkluzja
Zasoby
www.php.net
www.zend.com
devzone.zend.pl
www.phparch.com
Konferencje
Certyfikacja PHP
Podsumowanie
Dodatek. Wyrażenia regularne
Składnia wyrażeń regularnych
Przykłady wyrażeń regularnych
Opcje wewnętrzne
Chciwość
Funkcje wykorzystujące wyrażenia regularne
Zamiana ciągów — preg_replace
Inne funkcje
Skorowidz

Citation preview

Spis treści

O autorach ...................................................................................................................................11 O korektorze merytorycznym .......................................................................................................13 Przedmowa ..................................................................................................................................15 Wprowadzenie do PHP ................................................................................................................17 Rozdział 1.

Obiektowość ..........................................................................................................21 Klasy ....................................................................................................................................................... 21 Dziedziczenie i przeciążanie ............................................................................................................... 23 „Magiczne” funkcje ............................................................................................................................. 27 Metody __get i __set .................................................................................................................... 27 Metoda __isset ............................................................................................................................... 28 Metoda __call ................................................................................................................................ 28 Metoda __toString() ..................................................................................................................... 29 Kopiowanie, klonowanie oraz porównywanie obiektów ............................................................... 29 Interfejsy, iteratory i klasy abstrakcyjne ........................................................................................... 31 Kontekst klasy i elementy statyczne .................................................................................................. 35 Podsumowanie ..................................................................................................................................... 36

Rozdział 2.

Wyjątki i referencje ................................................................................................37 Wyjątki .................................................................................................................................................. 37 Referencje .............................................................................................................................................. 41 Podsumowanie ..................................................................................................................................... 45

Rozdział 3.

Mobilne PHP ..........................................................................................................47 Różnorodność urządzeń ..................................................................................................................... 47 Rozpoznanie urządzenia ..................................................................................................................... 48 Aplikacja kliencka ......................................................................................................................... 48 Wbudowane funkcje PHP ........................................................................................................... 48 Rozpoznawanie możliwości urządzenia ........................................................................................... 51 WURFL .......................................................................................................................................... 51 Tera-WURFL ................................................................................................................................. 57

PHP. ZAAWANSOWANE PROGRAMOWANIE

Narzędzia renderujące ........................................................................................................................ 60 WALL ............................................................................................................................................. 60 Reagujący CSS ............................................................................................................................... 62 Emulatory i SDK .................................................................................................................................. 62 Tworzenie dla systemu Android ................................................................................................ 62 Adobe Flash Builder dla PHP ..................................................................................................... 62 Kody QR ................................................................................................................................................ 63 Podsumowanie ..................................................................................................................................... 64

Rozdział 4.

Media społecznościowe .........................................................................................65 OAuth .................................................................................................................................................... 65 Twitter ................................................................................................................................................... 66 API publicznego wyszukiwania .................................................................................................. 66 Prywatne REST API ..................................................................................................................... 67 Wykorzystanie mechanizmu OAuth w celu powiązania strony z systemem logowania ........77 Dodatkowe metody API i przykłady jego wykorzystania ....................................................... 80 Facebook ............................................................................................................................................... 83 Dodanie linku wylogowania z Facebooka ................................................................................. 88 Żądanie dodatkowych uprawnień .............................................................................................. 89 Graph API ...................................................................................................................................... 89 Podsumowanie ..................................................................................................................................... 91

Rozdział 5.

Nowości technologiczne ........................................................................................93 Przestrzenie nazw ................................................................................................................................ 93 Przestrzenie nazw i autoładowanie ............................................................................................ 96 Przestrzenie nazw — podsumowanie ........................................................................................ 96 Funkcje anonimowe ............................................................................................................................ 96 Nowdoc ................................................................................................................................................. 97 Lokalne instrukcje goto ..................................................................................................................... 100 Standardowa biblioteka PHP — SPL .............................................................................................. 100 SPL — podsumowanie ............................................................................................................... 103 Rozszerzenie phar .............................................................................................................................. 103 Podsumowanie ................................................................................................................................... 106

Rozdział 6.

Tworzenie formularzy i zarządzanie nimi ............................................................107 Walidacja danych ............................................................................................................................... 107 Wczytywanie plików i obrazów ....................................................................................................... 113 Konwersja obrazów i miniatury ...................................................................................................... 114 Wyrażenia regularne ......................................................................................................................... 115 Integracja języków ............................................................................................................................. 118 Podsumowanie ................................................................................................................................... 119

Rozdział 7.

Integracja z bazami danych. Część I ....................................................................121 Wprowadzenie do MongoDB .......................................................................................................... 122 Zapytania w MongoDB .............................................................................................................. 126 Modyfikowanie dokumentów w MongoDB ........................................................................... 130 Agregacje w MongoDB .............................................................................................................. 132 Podsumowanie MongoDB ........................................................................................................ 134

6

SPIS TREŚCI

Wprowadzenie do CouchDB ........................................................................................................... 134 Wykorzystanie interfejsu Futon ............................................................................................... 135 Podsumowanie CouchDB ......................................................................................................... 140 Wprowadzenie do SQLite ................................................................................................................. 141 Podsumowanie SQLite ............................................................................................................... 149 Podsumowanie ................................................................................................................................... 149

Rozdział 8.

Integracja z bazami danych. Część II ...................................................................151 Wprowadzenie do rozszerzenia MySQLi ....................................................................................... 151 Podsumowanie rozszerzenia MySQLi ..................................................................................... 158 Wprowadzenie do PDO .................................................................................................................... 158 Podsumowanie PDO .................................................................................................................. 161 Wprowadzenie do ADOdb ............................................................................................................... 161 Podsumowanie ADOdb ............................................................................................................. 165 Wyszukiwanie pełnotekstowe przy wykorzystaniu Sphinksa ..................................................... 165 Podsumowanie ................................................................................................................................... 173

Rozdział 9.

Integracja z bazami danych. Część III ..................................................................175 Wprowadzenie do Oracle ................................................................................................................. 175 Podstawy. Połączenie i wykonywanie zapytań .............................................................................. 177 Interfejs tablicowy .............................................................................................................................. 180 Procedury i kursory w PL/SQL ........................................................................................................ 183 Praca z typami LOB ........................................................................................................................... 186 Inne podejście do połączeń — pule połączeń ................................................................................ 190 Zestawy znaków w bazie danych i PHP .......................................................................................... 192 Podsumowanie ................................................................................................................................... 193

Rozdział 10. Biblioteki .............................................................................................................195 SimplePie ............................................................................................................................................. 196 TCPDF ................................................................................................................................................. 199 Pobieranie danych ze stron internetowych ............................................................................. 204 Integracja z Mapami Google ............................................................................................................ 209 Wiadomości e-mail i SMS ................................................................................................................ 211 gChartPHP — biblioteka wykorzystująca Google Chart API ..................................................... 215 Podsumowanie ................................................................................................................................... 219

Rozdział 11. Bezpieczeństwo ...................................................................................................221 Nigdy nie ufaj danym ........................................................................................................................ 221 register_globals ........................................................................................................................... 222 Białe i czarne listy ....................................................................................................................... 222 Dane formularzy ......................................................................................................................... 223 $_COOKIES, $_SESSION i $_SERVER .................................................................................. 224 Żądania Ajax ................................................................................................................................ 224 Powszechne ataki ............................................................................................................................... 225 Polityka tego samego pochodzenia .......................................................................................... 225 XSS (Cross Site Scripting) .......................................................................................................... 225 CSRF (Cross-Site Request Forgery) ......................................................................................... 228 Sesje ...................................................................................................................................................... 229 Zapobieganie atakom typu SQL injection ...................................................................................... 229

7

PHP. ZAAWANSOWANE PROGRAMOWANIE

Wyrażenia filtrujące .......................................................................................................................... 230 Plik php.ini i ustawienia serwera ..................................................................................................... 233 Środowisko serwerowe ............................................................................................................... 233 Zabezpieczanie pliku php.ini .................................................................................................... 234 Algorytmy haseł ................................................................................................................................. 235 Podsumowanie ................................................................................................................................... 236

Rozdział 12. Programowanie zwinne z wykorzystaniem Zend Studio dla Eclipse, Bugzilli, Mylyn i Subversion ..............................................................................................237 Zasady programowania zwinnego .................................................................................................. 237 Rajd programowania zwinnego ....................................................................................................... 238 Wprowadzenie do programu Bugzilla ............................................................................................ 239 Mylyn dla Eclipse ............................................................................................................................... 240 Bugzilla i Mylyn w połączeniu z Eclipse ......................................................................................... 242 Maksymalizowanie korzyści ............................................................................................................. 245 Podsumowanie ................................................................................................................................... 246

Rozdział 13. Refaktoryzacja, testy jednostkowe i ciągła integracja .........................................249 Refaktoryzacja .................................................................................................................................... 249 Niewielka refaktoryzacja ............................................................................................................ 250 Większy przykład ........................................................................................................................ 253 Testy jednostkowe ............................................................................................................................. 265 Ciągła integracja ................................................................................................................................. 279 Serwer ciągłej integracji ............................................................................................................. 280 System kontroli wersji ................................................................................................................ 280 Analiza statyczna ........................................................................................................................ 281 Budowanie automatyzacji .......................................................................................................... 282 Uruchomienie serwera Jenkins ................................................................................................. 282 Podsumowanie ................................................................................................................................... 285

Rozdział 14. XML .....................................................................................................................287 Podstawy XML ................................................................................................................................... 287 Schematy ............................................................................................................................................. 288 SimpleXML ......................................................................................................................................... 289 Parsowanie XML z tekstu .......................................................................................................... 289 Parsowanie XML z pliku ............................................................................................................ 290 Przestrzenie nazw ....................................................................................................................... 294 RSS ................................................................................................................................................ 296 Generowanie dokumentów XML za pomocą SimpleXML .................................................. 298 DOMDocument ................................................................................................................................. 303 XMLReader i XMLWriter ................................................................................................................ 305 Podsumowanie ................................................................................................................................... 306

Rozdział 15. JSON i Ajax ..........................................................................................................307 JSON .................................................................................................................................................... 308 PHP i JSON .................................................................................................................................. 309 Ajax ...................................................................................................................................................... 312 Tradycyjny model WWW ......................................................................................................... 313 Model Ajax ................................................................................................................................... 313 Zdarzenia synchroniczne kontra asynchroniczne ................................................................. 315 8

SPIS TREŚCI

Obiekt XMLHttpRequest ........................................................................................................... 316 Wykorzystanie obiektu XMLHttpRequest .............................................................................. 317 API JavaScript wyższego poziomu ........................................................................................... 322 Przykłady jQuery ........................................................................................................................ 322 Przesyłanie danych z Ajaksa do skryptu PHP ........................................................................ 327 Prosty program graficzny ................................................................................................................. 328 Utrzymanie stanu ....................................................................................................................... 330 Podsumowanie ................................................................................................................................... 335

Rozdział 16. Konkluzja .............................................................................................................337 Zasoby .................................................................................................................................................. 337 www.php.net ................................................................................................................................ 337 www.zend.com ............................................................................................................................ 338 devzone.zend.pl ........................................................................................................................... 338 www.phparch.com ...................................................................................................................... 338 Konferencje ......................................................................................................................................... 339 Certyfikacja PHP ................................................................................................................................ 340 Podsumowanie ................................................................................................................................... 341

Dodatek

Wyrażenia regularne ...........................................................................................343 Składnia wyrażeń regularnych ......................................................................................................... 343 Przykłady wyrażeń regularnych ....................................................................................................... 344 Opcje wewnętrzne ...................................................................................................................... 347 Chciwość ...................................................................................................................................... 347 Funkcje wykorzystujące wyrażenia regularne ............................................................................... 348 Zamiana ciągów — preg_replace ............................................................................................. 348 Inne funkcje ........................................................................................................................................ 350

Skorowidz ..................................................................................................................................353

9

PHP. ZAAWANSOWANE PROGRAMOWANIE

10

O autorach

Peter MacIntyre ma ponaddwudziestoletnie doświadczenie w przemyśle IT, głównie w obszarze tworzenia oprogramowania. Posiada certyfikat Zend (ZCE). Opublikował wiele prac związanych z IT, między innymi: Using Visual Objects (Que 1995), Using PowerBuilder 5 (Que 1996), ASP.NET Bible (Wiley 2001), Zend Studio for Eclipse Developer’s Guide (Sams 2008), PHP5. Programowanie (Helion 2007) i PHP: The Good Parts (O’Reilly Media 2010). Był prelegentem na międzynarodowych konferencjach, włączając w to CA-World w Nowym Orleanie, CA-TechniCon w Kolonii i CA-Expo w Melbourne. Mieszka na Wyspie Świętego Edwarda w Kanadzie, gdzie piastuje stanowisko starszego konsultanta w firmie OSSCube (www.osscube.com), będącej liderem w dziedzinie tworzenia oprogramowania open source. Pomaga w prowadzeniu Centrum Doskonalenia Zend. Można się z nim skontaktować mailowo pod adresem [email protected]. Brian Danchilla jest certyfikowanym inżynierem Zend i okazjonalnym programistą Java. Posiada licencjat w dziedzinie informatyki i matematyki. Programy komputerowe pisze już ponad połowę swojego życia, włączając w to aplikacje internetowe, analizy numeryczne oraz programy VOIP (voice over IP). Szybko wdraża się w nowe technologie i API. Jest zagorzałym czytelnikiem publikacji technicznych. Pracując jako asystent na uniwersytecie, prywatny nauczyciel i kierownik zespołów PHP Danchilla, nauczył się przekazywać swoją wiedzę. Udziela się także w ramach społeczności Stack Overflow. Kiedy nie programuje, lubi spędzać czas na świeżym powietrzu albo grać na gitarze. Mladen Gogala jest bardzo doświadczonym specjalistą w dziedzinie baz danych. Może się pochwalić długą i udaną karierą. Był administratorem bazy Oracle oraz systemów Linux i Unix, administratorem VAX/VMS, a ostatnio architektem wydajności baz danych. Od roku 1990 pracował z bazami zawierającymi terabajty danych — głównie z bazami Oracle. Zna Linuksa, Perl i PHP. PHP stało się jego ulubionym językiem na początku roku 2000. Jest autorem książki Easy Oracle PHP: Create Dynamic Web Pages with Oracle Data (Rampant TechPress, 2006). Napisał także kilka artykułów dotyczących PHP, Oracle i Symfony. Urodził się w roku 1961 w chorwackim Zagrzebiu.

PHP. ZAAWANSOWANE PROGRAMOWANIE

12

„„„

O korektorze merytorycznym

Thomas Myer jest autorem, konsultantem i programistą. Większość czasu spędza, pracując nad projektami PHP (głównie nad programami CodeIgniter, ExpressionEngine, WordPress i MojoMotor), jednak zdarza mu się także pracować z Pythonem, Perlem i Objective-C. Możesz subskrybować jego kanał na Twitterze (jeśli się odważysz): @myerman. Nie zapomnij także odwiedzić strony www.tripledogs.com, aby dowiedzieć się więcej na temat założonej przez niego firmy Triple Dog Dare Media. Aktualnie mieszka w Austin (Teksas) z żoną Hope i psami Kafką i Marlowe’em.

PHP. ZAAWANSOWANE PROGRAMOWANIE

14

Przedmowa

Ponieważ PHP rozpoczynało swój żywot jako projekt hakerów — próba opracowania łatwego i przyjemnego języka pozwalającego na tworzenie stron internetowych — nikt nie przypuszczał, że zyska ono popularność, jaką cieszy się dzisiaj. Przez lata próbowano badać powodzenie PHP różnymi metodami, sprawdzając, ile stron używa tego języka, liczbę sprzedanych książek o nim w sklepie Amazon, liczbę znaczących firm, które go wykorzystują, liczbę związanych z nim projektów, wielkość społeczności itd. Wtedy pojawił się nowy, o wiele mniej naukowy sposób. W 2008 roku, kiedy byłem w podróży poślubnej z żoną Any, mieszkaliśmy w małym hotelu o nazwie Noster Bayres, w Buenos Aires. Przybyliśmy po długim locie do zupełnie nowego miejsca, pełnego twarzy, których nigdy nie widzieliśmy. Wyobraź sobie moje zdziwienie, kiedy po wypełnieniu przez nas dokumentów recepcjonista zapytał mnie, czy to ja jestem Suraski, „ten gość od PHP”. Okazało się, że tworzył w PHP sieć społecznościową dla San Telmo. Wszystkie wskaźniki udowadniały wprawdzie duży zasięg i popularność PHP, ale to zdarzenie, mające miejsce w małym hotelu po drugiej stronie globu, przekonało mnie ostatecznie. Skoro ten recepcjonista tworzył oprogramowanie w PHP, zdecydowanie byliśmy w głównym nurcie. Obecnie, prawie trzy lata później, zaawansowana znajomość PHP jest kluczowa dla twórców aplikacji internetowych i dla wszystkich innych — w związku z ogromnym wzrostem popularności usług HTTP. PHP. Zaawansowane programowanie prezentuje kilka ważnych aspektów współczesnego programowania PHP, włączając w to obiektowość, tworzenie aplikacji mobilnych oraz skalowalne źródła danych, które mogą mieć istotny wpływ na przydatność aplikacji do pracy w chmurze. Jestem pewien, że wiedza, którą zdobędziesz, będzie dla Ciebie ważnym narzędziem i pomoże Ci wykorzystać wszystkie możliwości PHP 5.3. Szczęśliwego „pehapowania”! Zeev Suraski, CTO, Zend

PHP. ZAAWANSOWANE PROGRAMOWANIE

16

Wprowadzenie do PHP

To kolejna książka dotycząca języka PHP. Jest ona unikalna, ponieważ skupia się na zaawansowanych zagadnieniach i na nowościach. Staraliśmy się, aby była tak nowoczesna, jak to tylko możliwe w szybko zmieniającym się świecie internetu. Przeprowadzamy Czytelnika z poziomu średnio zaawansowanego do wysoko zaawansowanego użytkownika języka PHP.

Geneza PHP PHP rozpoczęło swój żywot jako projekt prowadzony przez Rasmusa Lerdorfa. W czerwcu 1995 r. Lerdorf opublikował wersję 1.0 osobistych narzędzi do tworzenia stron (ang. Personal Home Page Tools — stąd nazwa „PHP”). Była to kolekcja funkcji pozwalająca na automatyzację tworzenia i utrzymywania małych stron internetowych. Od tamtej pory PHP znacznie się rozwinęło, ewoluując do aktualnej wersji 5.3.4 (gdy powstawała książka). PHP był jednym z pierwszych języków pozwalających na tworzenie stron internetowych typu open source. Lerdorf okazał się wizjonerem, który zauważył potencjał języka, który mógłby rozwijać się razem ze społecznością internetową.

Czym jest PHP? Czym dokładnie jest PHP? Jak wygląda w aktualnej wersji? Najprościej mówiąc, PHP jest generatorem kodu HTML. Jeśli spojrzysz na kod źródłowy strony wygenerowanej za pomocą PHP, zobaczysz tylko znaczniki HTML; może jeszcze trochę skryptów JavaScript, jednak żadnego kodu PHP. Oczywiście, jest to zbytnie uproszczenie definicji języka, którego udział w rynku języków wykorzystywanych do tworzenia stron internetowych obejmuje od 39 do 59% (według różnych źródeł). Bez względu na to, którą liczbę uznasz za prawdziwą, PHP jest aktualnie najpopularniejszym językiem tworzenia i utrzymywania stron internetowych. Należy także zauważyć, że PHP jest darmowe. Tak, darmowe! Jest projektem open source. A więc jak na produkt, który nie jest monitorowany ani prowadzony przez żadną instytucję, PHP poradziło sobie świetnie, jeżeli chodzi o popularność. „ UWAGA. Więcej informacji dotyczących oprogramowania open source znajduje się w publikacji The Cathedral and the Bazaar Erica S. Raymonda, dostępnej pod adresem http://www.catb.org/~esr/writings/cathedral-bazaar/. Jest tam porównanie produktów tradycyjnych i open source.

PHP. ZAAWANSOWANE PROGRAMOWANIE

Aktualnie Zend Corporation jest prawdopodobnie światowym liderem PHP. Firma opracowała wiele dodatkowych produktów wspierających PHP i rozszerzających jego możliwości. Jest także głównym graczem, jeżeli chodzi o rozwój tego języka, odkąd założyciele firmy — Zeev Suraski i Andi Gutmans — podnieśli rękawicę (od PHP3). PHP jest bardzo otwartym i wyrozumiałym językiem między innymi dlatego, że jest słabo typowany. Oznacza to, że zmienne nie muszą być deklarowane z typem danych, jaki będzie w nich przechowywany — co jest konieczne w niektórych innych językach programowania. PHP próbuje raczej „wywnioskować” typ danych zapisanych w zmiennej z kontekstu i jej zawartości. Oznacza to na przykład, że zmienna o nazwie $informacje może podczas wykonywania programu przechowywać wiele różnych wartości. W niektórych przypadkach może to być wadą, ponieważ dane mogą ulegać modyfikacjom, powodując błędy w liniach, które np. oczekują liczby całkowitej, a otrzymują tekst. Programy PHP można także tworzyć w modelu zorientowanym obiektowo (OOP). Klasy, właściwości, metody, dziedziczenie, polimorfizm i enkapsulacja są częściami języka. To zwiększa możliwości powtórnego użycia kodu tworzonego w PHP oraz ułatwia korzystanie z niego. Oczywiście podejście obiektowe istnieje od długiego czasu, a PHP adaptuje i rozszerza możliwości obiektowe od kilku lat. Kolejną cenną cechą PHP jest możliwość wykonywania skryptów z poziomu wiersza poleceń (w systemach Linux i Windows), dzięki czemu język ten może być wykorzystywany w zadaniach CRON; nie musisz uczyć się innego języka programowania w celu realizacji innych zadań w środowisku serwerowym. Możesz tworzyć strony internetowe w tym samym języku, z którego korzystasz przy manipulowaniu plikami (jeżeli będziesz chciał). PHP ma także wiele punktów integracyjnych. Jest bardzo otwartym językiem. PHP służy nie tylko do tworzenia stron internetowych — może mieć wiele innych zastosowań. Połącz go z bazą danych poprzez odpowiednie rozszerzenie, a otrzymasz interfejs webowy lub nawet aplikację webową. Wykorzystaj dodatkową bibliotekę (np. tcpdf), a będziesz mógł w locie generować dokumenty PDF. Są to tylko dwa przykłady; w książce omówimy znacznie więcej dodatkowych bibliotek.

Szczegółowy przegląd treści książki Co w takim razie znajdziesz w tej książce? Staraliśmy się, aby zawierała najświeższe informacje dotyczące PHP, tak abyś umiał korzystać z najnowszych możliwości i rozszerzeń tego języka. Nie poświęcaliśmy miejsca na proste zagadnienia związane z językiem, takie jak to, czym jest zmienna lub w jaki sposób tworzyć pętle. Chcemy, abyś stał się wysoko zaawansowanym programistą oraz aby ten materiał pomógł Ci się przygotować do egzaminu certyfikacyjnego pozwalającego uzyskać tytuł ZCE (ang. Zend Certified Engineer). Poniżej znajdziesz krótkie omówienie tematyki poszczególnych rozdziałów.

Rozdział 1. Obiektowość Celem pierwszego rozdziału jest przygotowanie Cię do tego, byś mógł zrozumieć informacje i przykłady kodu, które będą prezentowane w dalszej części książki. Przedstawiamy podstawy modelu obiektowego oraz jego implementacji w PHP, następnie od razu przechodzimy do zaawansowanych zagadnień. Ważne jest, abyś dobrze zrozumiał ten rozdział, zanim przejdziesz do kolejnych.

Rozdział 2. Wyjątki i referencje W tym rozdziale omawiamy zagadnienia związane z programowaniem obiektowym i prezentujemy sposoby obsługi błędów za pomocą bloków try i catch. Jest to elegancki sposób zarządzania błędami w aplikacjach PHP — jego opanowanie daje ogromne możliwości. Następnie omawiane są referencje i ich znaczenie w odniesieniu do klas i funkcji, z których będziesz korzystał.

Rozdział 3. Mobilne PHP Urządzenia mobilne są coraz popularniejsze, stają się coraz mniejsze i wydajniejsze. W tym powiększającym się rynku swoje udziały zdobywają firmy takie jak Apple, RIM czy HTC. Do urządzeń tych są jednak potrzebne aplikacje — pokażemy w tym rozdziale, w jaki sposób PHP może przydać się w ich tworzeniu. 18

WPROWADZENIE DO PHP

Rozdział 4. Media społecznościowe Podobnie prężnie rozwijają się media społecznościowe, a PHP znacznie się do tego rozwoju przyczynia. Wiele aplikacji dostępnych na Facebooku jest napisanych właśnie w PHP. Liczne inne strony, np. Flickr, częściowo Yahoo!, a nawet aplikacje blogowe, są zależne od PHP. W tym rozdziale omówimy niektóre z interfejsów dostępnych dla integracji z portalami społecznościowymi.

Rozdział 5. Nowości technologiczne W aktualnej (gdy powstawała ta książka) wersji 5.3.4 PHP udostępnia nowe funkcje. Wiele z nich pochodzi z długo oczekiwanej wersji 6.0, ale ponieważ niektóre funkcje zostały ukończone przed innymi, początkowa kolekcja została wydana jako wersja 5.3. W tym rozdziale przeanalizujemy najlepsze nowe funkcje oraz wyjaśnimy, w jaki sposób możesz z nich skorzystać w swoich projektach.

Rozdział 6. Tworzenie formularzy i zarządzanie nimi W tym rozdziale poświęcimy trochę miejsca na omówienie funkcjonalności i technik, które mogą zostać wykorzystane przy tworzeniu formularzy. Ponadto przybliżymy kontrolowanie wpisywanych danych, reagowanie na błędnie wpisane dane (np. błędny format daty) oraz sposób przekazywania danych do aplikacji.

Rozdziały 7. i 8. Integracja z bazami danych. Część I i II Oczywiście jednym z głównych aspektów tworzenia współczesnych stron internetowych jest możliwość przechowywania i wyświetlania danych pochodzących ze źródeł danych. W tych dwóch rozdziałach pokażemy wiele sposobów manipulowania danymi. Omówimy systemy zarządzania bazami — od mniejszych baz danych, takich jak bazy NoSQL, do dużych silników bazodanowych, takich jak MySQLi. Wyjaśnimy także, jak można skorzystać z dodatkowych narzędzi, np. PDO i Sphinx.

Rozdział 9. Integracja z bazami danych. Część III PHP i Oracle łączy wyjątkowa więź, jeżeli w grę wchodzą duże kolekcje danych. W tym rozdziale omówimy sprawy dotyczące tego związku oraz podpowiemy, jak go wykorzystać.

Rozdział 10. Biblioteki Jak już wspomniano, PHP jest bardzo otwarte na inne biblioteki. W rozdziale 10. przybliżymy niektóre z nich, te najpopularniejsze i najbardziej zaawansowane. Oprócz tego zostaną poruszone między innymi: możliwość generowania dokumentów PDF, przeglądanie kanałów RSS, tworzenie profesjonalnych wiadomości e-mail, integracja z mapami Google.

Rozdział 11. Bezpieczeństwo Książka nie byłaby kompletna, gdybyśmy nie przeanalizowali najnowszych technik z dziedziny bezpieczeństwa. Na ten obszerny temat przeznaczyliśmy rozdział 11. Omawiamy w nim najbezpieczniejszy (obecnie) algorytm szyfrujący, SHA1, oraz zagadnienia związane z ochroną danych wprowadzanych w formularzach i danych udostępnianych przez system.

19

PHP. ZAAWANSOWANE PROGRAMOWANIE

Rozdział 12. Programowanie zwinne z wykorzystaniem Zend Studio dla Eclipse, Bugzilli, Mylyn i Subversion Rozdział ten nie jest ściśle związany z PHP. Wyjaśniamy w nim, jak korzystać z jednego z najpopularniejszych środowisk programistycznych (IDE) dla PHP — Zend Studio for Eclipse. Zobaczymy, w jaki sposób może współpracować zespół programistów opierający swoje działanie na koncepcji programowania zwinnego (słyszałeś o programowaniu ekstremalnym?). Omówimy używanie narzędzi SVN, Bugzilla i Mylyn oraz ich współpracę mającą na celu zwiększenie produktywności zespołu.

Rozdział 13. Refaktoryzacja, testy jednostkowe i ciągła integracja Jest to rozszerzenie poprzedniego rozdziału. Nacisk został tu położony na zagadnienia związane z poprawianiem jakości programów PHP, aczkolwiek głównym tematem rozdziału są refaktoryzacja i testy jednostkowe. Dowiesz się ponadto, jak poprawnie z nich korzystać w swojej codziennej pracy.

Rozdział 14. XML W ostatnich latach popularność XML znacznie wzrosła. W tym rozdziale wyjaśnimy, w jaki sposób wykorzystać SimpleXML do obsługi dokumentu XML pochodzącego ze źródła zewnętrznego. Powiemy także o możliwości tworzenia dokumentów XML wewnątrz systemu.

Rozdział 15. JSON i Ajax Ponownie oddalamy się nieco od czystego PHP. Tym razem przybliżymy bibliotekę JSON. Wyjaśnimy, jak używać jej z Ajaksem, by strony były przyjazne dla użytkowników.

Rozdział 16. Konkluzja W tym rozdziale prezentujemy dodatkowe źródła wiedzy dotyczącej PHP. Wymieniamy strony internetowe, magazyny oraz konferencje, dzięki którym możesz pogłębić swoje wiadomości i lepiej zrozumieć język PHP i związaną z nim społeczność.

Przyszłość PHP Ponieważ PHP jest produktem open source, trudno przewidzieć kierunek, w którym będzie rozwijane w bliskiej i dalekiej przyszłości. Bardzo wierzę jednak w społeczność. Odkąd jestem programistą PHP, nie widziałem jeszcze błędnego kroku w wykonaniu tego kolektywu. Wiem, że urządzenia mobilne będą się rozwijały. PHP już podejmuje działania, aby nadążyć za tym rozwojem. Co jeszcze stanie się w niedalekiej przyszłości? Może zostanie poprawiona integracja z telefonią, jeśli chodzi o smartfony, i kompatybilność danych. Być może rozwinie się rozpoznawanie mowy. Kto wie? Na podstawie swojego dotychczasowego doświadczenia w programowaniu w języku PHP sądzę, że społeczność będzie trzymała rękę na pulsie i że nas nie zawiedzie. Patrzenie w przyszłość PHP jest bardzo pocieszające; jest jak patrzenie na piękny wschód słońca z przekonaniem, że kolejny dzień może być tylko lepszy.

20

ROZDZIAŁ 1 „„„

Obiektowość

Rozdział ten jest wprowadzeniem do podstawowych zagadnień obiektowości. Co właściwie oznacza stwierdzenie, że PHP jest zorientowane obiektowo? Najprościej mówiąc, PHP pozwala tworzyć i porządkować hierarchicznie typy tworzone przez użytkownika. Książka ta dotyczy PHP 5.3, które wprowadza nowe elementy do repertuaru narzędzi obiektowych. PHP przeszło radykalne zmiany od wersji 4., która także zawierała podstawowe mechanizmy obiektowości. W wersji 4. nie można było na przykład definiować widoczności metod i właściwości. W PHP 5.3 zostały dodane przestrzenie nazw. Omówimy tu klasy, dziedziczenie, tworzenie obiektów oraz definiowanie interfejsów. Przedstawimy również zaawansowane pojęcia, takie jak iteratory. Zaczynajmy.

Klasy Klasy są po prostu typami definiowanymi przez użytkownika. W językach obiektowych klasa wykorzystywana jest jako szablon do tworzenia obiektu lub instancji (kopii funkcjonalnej) tej klasy. Klasa zawiera opis standardowych właściwości wszystkich należących do niej elementów. Celem klas jest enkapsulacja definicji obiektu, jego zachowanie oraz ukrycie jego implementacji przed użytkownikiem końcowym, a także pozwolenie temu użytkownikowi na wykorzystanie obiektów klas w sposób udokumentowany i oczekiwany. Enkapsulacja zmniejsza rozmiary programów i czyni je łatwiejszymi w zarządzaniu, ponieważ obiekty zawierają potrzebną do tego logikę. Istnieje także mechanizm autoładowania, który pozwala rozbić skrypty na mniejsze, łatwiejsze w zarządzaniu części. Zanim przeanalizujemy prosty przykład klasy, zapoznaj się z terminologią. • Element klasy lub właściwość — zmienna, część danych klasy. • Metoda — funkcja zdefiniowana wewnątrz klasy. Teraz zdefiniujemy klasę dla punktu na dwuwymiarowej przestrzeni, określonego przy użyciu współrzędnych kartezjańskich (listing 1.1). Omawiana klasa została zaprojektowana wyłącznie do celów demonstracyjnych i ma poważne wady. Zalecamy, abyś nie wykorzystywał jej jako podstawy do tworzenia własnego kodu. Listing 1.1. Przestrzeń dwuwymiarowa

Przedstawiona klasa zawiera sporo elementów wartych przeanalizowania i poprawienia. Jak już wcześniej stwierdziliśmy, opisuje ona punkt na płaszczyźnie, określony współrzędnymi kartezjańskimi $x i $y. Przy zmiennych jest umieszczone słowo kluczowe public, do którego wrócimy później. Zaimplementowana została także metoda konstruktora __construct, wywoływana w momencie tworzenia w pamięci nowego obiektu (lub instancji) klasy Punkt poprzez wywołanie operatora new. Innymi słowy, kiedy wywoływana jest linia $p1=new Punkt(2,3), metoda __construct jest wywoływana automatycznie, a argumenty w nawiasach po nazwie klasy są przekazywane do metody __construct i mogą być w niej wykorzystane. Metoda __construct odwołuje się do zmiennej $this. Zmienna $this umożliwia w językach obiektowych odwołanie się do instancji klasy. Odnosi się zawsze do aktualnie obsługiwanego obiektu. Jest obiektowym odpowiednikiem „ja”. Różne odmiany tej zmiennej wykorzystywane są w niemal wszystkich językach obiektowych; w niektórych jest nazywana „self”. Konstruktor klasy jest metodą inicjalizującą (tworzącą instancje) obiekty danej klasy. W tym przypadku przypisuje koordynaty. Koordynaty (zmienne $x i $y) są właściwościami klasy. Zdefiniowane są także inne metody, dwie metody get oraz metoda odleglosc, która oblicza odległość między dwoma punktami. Kolejną rzeczą wartą zauważenia jest słowo kluczowe public. Oznaczanie elementów klasy jako „publiczne” pozwala na uzyskanie do nich pełnego dostępu. W naszym skrypcie znajduje się linia: $p2->x=5; — koordynat x jest w niej modyfikowany bezpośrednio. Taki dostęp nie pozwala na kontrolowanie go i we wszystkich przypadkach, poza najprostszymi, nie powinien mieć miejsca. Dobrą praktyką jest tworzenie akcesorów (metod get i set), które będą odczytywały i zapisywały właściwości w sposób kontrolowany. Innymi słowy, za pośrednictwem metod get i set można kontrolować wartości właściwości. Dla właściwości publicznych metody get i set są nadmiarowe, ponieważ możliwy jest bezpośredni dostęp do nich, tak jak w przypadku $p2->x=5;. Jednakże właściwości publiczne nie pozwalają kontrolować wartości właściwości. Metody get i set mogą być pisane ręcznie dla każdej właściwości, jednak PHP umożliwia wykorzystanie tak zwanych „magicznych” metod, które mogą być stosowane zamiast metod tworzonych ręcznie. Możliwe jest lepsze chronienie elementów klasy poprzez użycie słów kluczowych private i protected. Dokładne znaczenie tych dwóch słów kluczowych będzie wyjaśnione w następnym podrozdziale. Należy także zauważyć, że public jest domyślną widocznością. Jeżeli widoczność dla elementu klasy nie będzie wyszczególniona — zostanie ustawiona na public. Kod: class C { $member; function method() {...} …. }

jest równoznaczny z kodem: class C { public $member;

22

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

pubic function method() {…} …. }

W przeciwieństwie do elementów publicznych prywatne właściwości i metody klasy są widoczne tylko dla metod tej klasy. Metody, które nie są częścią klasy, nie mają dostępu do prywatnych właściwości, nie mogą także wywoływać żadnych prywatnych metod. Jeżeli dla właściwości $x i $y słowo kluczowe public zostanie zamienione na protected i nastąpi próba uzyskania dostępu, wyświetli się informacja o błędzie: PHP Fatal error: Cannot access private property Point::$x in script2.1 on line 25

Innymi słowy, nasza mała sztuczka w linii 25., czyli $p2->x=5, przestanie działać. Metoda konstruktora, podobnie jak metody get_x() i get_y(), nie będzie miała żadnego problemu z dostępem do właściwości tak długo, jak długo będzie częścią klasy. Jest to poprawna sytuacja, ponieważ nie będzie możliwości modyfikowania wartości właściwości bezpośrednio z potencjalnym zmodyfikowaniem zachowania klasy w sposób, jaki nie powinien mieć miejsca. W skrócie — klasa jest bardziej hermetyczna, podobnie jak autostrada, na której jest określona liczba wjazdów i zjazdów. Właściwości publiczne i prywatne zostały już opisane. Czym jednak są właściwości i metody oznaczone jako protected? Do takich właściwości i metod dostęp może uzyskać metoda klasy, do której one należą, oraz metoda klasy dziedzicząca po klasie bazowej, do której one należą. Przyjrzymy się temu bliżej w kolejnym podrozdziale.

Dziedziczenie i przeciążanie Zgodnie ze stwierdzeniem z początku tego rozdziału klasy mogą być organizowane hierarchicznie. Hierarchia osiągana jest poprzez dziedziczenie. W celu zademonstrowania dziedziczenia utworzymy kolejną klasę, nazwaną pracownik. Część pracowników firmy to menedżerowie — klasa menedzer będzie klasą dziedziczącą po ogólniejszej klasie pracownik. Dziedziczenie bywa także nazywane specjalizacją. Przyjrzyj się klasie z listingu 1.2. Listing 1.2. Przykład klasy pracownik

Klasa ta została utworzona do celów demonstracyjnych i nie powinna być wykorzystywana jako szablon. Warto zauważyć, że konstruktory obu klas są publiczne. Gdyby były prywatne, utworzenie nowego obiektu klasy byłoby niemożliwe. Po uruchomieniu skrypt zwróci następujący wynik: Pracownik Kowalski otrzymał podwyżkę w kwocie 50 złotych Nowa pensja wynosi 350 złotych Ten pracownik jest menedżerem Pracownik Nowak otrzymał podwyżkę w kwocie 50 złotych Nowa pensja wynosi 150 złotych Żegnaj okrutny świecie: PRACOWNIK:Nowak Żegnaj okrutny świecie: MENEDŻER:Kowalski Żegnaj okrutny świecie: PRACOWNIK:Kowalski

Na powyższym przykładzie doskonale można wytłumaczyć pojęcie dziedziczenia. Każdy menedżer jest pracownikiem. Słowo „jest” jest charakterystyczne dla dziedziczenia. W tym przypadku klasa pracownik jest klasą nadrzędną dla klasy menedzer. W przeciwieństwie do prawdziwych relacji pokrewieństwa klasa w PHP może mieć tylko jednego rodzica, wielokrotne dziedziczenie nie jest dozwolone. Ponadto metody klasy nadrzędnej mogą być wywoływane poprzez wykorzystanie konstrukcji parent::, pokazanej w klasie menedzer. Kiedy tworzony jest obiekt klasy dziedziczącej, konstruktor klasy nadrzędnej nie jest wywoływany automatycznie. Wywołanie konstruktora klasy nadrzędnej w klasie podrzędnej należy do zadań programisty. To samo dotyczy metody destruktora. Jest ona dokładnym przeciwieństwem klasy konstruktora. Konstruktor jest wywoływany w momencie tworzenia obiektu w pamięci; destruktor jest wywoływany, gdy obiekt nie jest już potrzebny lub kiedy dla obiektu zostanie wywołana funkcja unset. Jawne wywoływanie funkcji unset nie jest powszechne, zazwyczaj jest wykorzystywane w celu oszczędzania pamięci. To oznacza, że destruktor jest automatycznie wywoływany dla wszystkich obiektów w momencie zakończenia działania skryptu. Metody destruktorów są używane przeważnie do zwolnienia zasobów, na przykład zamknięcia otwartych plików lub połączeń z bazą danych. Zauważ także, że metoda destruktora w klasie klasy menedzer ma pełny dostęp do właściwości nazwisko, pomimo że jest ona właściwością klasy nadrzędnej pracownik. Jest to właściwy cel wykorzystania modyfikatora dostępu protected. Gdyby nazwisko było właściwością prywatną klasy pracownik, powyższy przykład by nie działał. Metoda daj_podwyzke istnieje w obu klasach. PHP „wie”, która metoda powinna zostać wykorzystana dla danej klasy; jest to jeden z aspektów fundamentalnej zasady obiektowości — enkapsulacja. Obiekt $x jest typu menedzer, a metoda daj_podwyzke wyświetliła tekst „Ten pracownik jest menedżerem” po wyświetleniu standardowych informacji wyjściowych. Inaczej mówiąc, metoda daj_podwyzke w klasie menedzer przeciąża lub zastępuje metodę daj_podwyzke w klasie pracownik. Zauważ, że pojęcie przeciążania w PHP jest rozumiane inaczej niż w językach C++ lub Python, w których oznacza ono funkcję (nie metodę klasy) o takiej samej nazwie, ale innych argumentach. Wracając do PHP — jeżeli metoda zostanie oznaczona słowem kluczowym final, nie będzie mogła być przeciążona. Gdyby metoda daj_podwyzke została zadeklarowana w ten sposób: final function daj_podwyzke($wartosc) { …. }

24

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

to przeciążenie w klasie menedzer nie byłoby możliwe. Polecamy poćwiczyć podstawowe zagadnienia obiektowości na małym skrypcie oraz poeksperymentować z ustawianiem dla różnych elementów klas modyfikatorów dostępu: public, protected i private, aby zaznajomić się z efektami. Mówiąc o dziedziczeniu, nie można pominąć klas abstrakcyjnych. Dla klas abstrakcyjnych nie można tworzyć instancji — nie można tworzyć żadnych obiektów tej klasy. Klasy te są wykorzystywane głównie jako szablony w celu wymuszenia na klasach dziedziczących określonej struktury. Klasa jest abstrakcyjna, jeżeli zostanie oznaczona słowem kluczowym abstract w następujący sposób: abstract class A { …. }

Żaden obiekt tej klasy nie może być utworzony. PHP zwróci błąd czasu wywoływania i zatrzyma wykonywanie skryptu. Możliwe jest także tworzenie metod abstrakcyjnych wewnątrz klasy abstrakcyjnej: abstract class A { abstract protected metoda(...); }

Metody abstrakcyjne wykorzystywane są do wymuszania implementacji metody w klasach dziedziczących. Klasy abstrakcyjne są z reguły używane jako szablony dla klas dziedziczących po nich. Dobry przykład klasy abstrakcyjnej można znaleźć w standardowej bibliotece PHP (SPL — Standard PHP Library). Klasy dla sterty sortowanej (SplMinHeap, SplMaxHeap) dziedziczą po klasie abstrakcyjnej SplHeap i implementują metodę compare w inny sposób. SplMinHeap posortuje elementy od najmniejszego do największego, natomiast SplMaxHeap posortuje je odwrotnie. Wspólne cechy obu klas są zawarte w klasie abstrakcyjnej SplHeap, której dokumentację można znaleźć pod adresem http://ca2.php.net/manual/en/class.splheap.php. Zamiast tworzyć sztuczne przykłady klas abstrakcyjnych, zobaczmy, w jaki sposób są używane w SPL. Oto proste zastosowanie klasy SplMinHeap:

Wykonanie tego kodu zwróci następujący wynik: Adam Marcin Piotr

Imiona zostały posortowane alfabetycznie — ich kolejność jest inna, niż była przy wstawianiu. W dalszej części wyjaśnimy, w jaki sposób można wykorzystać obiekt klasy SplMaxHeap w pętli; potraktujemy go jak tablicę. Zwróćmy teraz uwagę na praktyczne techniki programowania obiektowego. Być może zastanawiasz się, jak sprawić, aby klasa była dostępna dla skryptu PHP. Klasy są z reguły pisane tak, aby mogły być wykorzystywane wielokrotnie. Oczywistą odpowiedzią jest utworzenie odrębnego pliku, który następnie może zostać dołączony do skryptu za pomocą dyrektywy require lub include, jednak ten sposób może szybko stać się kłopotliwy, kiedy liczba plików zacznie rosnąć. Okazuje się, że PHP wyposażone jest w narzędzie mające pomóc w rozwiązaniu tego problemu — jest to funkcja __autoload. Przyjmuje ona jako parametr nazwę klasy i będzie wywołana, kiedy PHP nie będzie mogło znaleźć odpowiedniej klasy w aktualnie wykonywanym skrypcie. Zasadniczo __autoload jest funkcją obsługującą przy wystąpieniu wyjątku „klasa nie została odnaleziona”. Do wyjątku tego wrócimy później. Przykład z listingu 1.2 może być przepisany w dwóch plikach (listing 1.3).

25

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

Listing 1.3. Listing 1.2 przepisany w dwóch plikach Plik listing1_3.php

Plik ACMEmanager.php: , ponieważ mogą być załadowane lub załączone w nagłówku pliku, zanim strona zostanie złożona. Wszystkie białe znaki pomiędzy znakami ?> a znakiem końca pliku będą wstawione na początku wynikowego kodu HTML strony. PHP radzi sobie z brakiem końcowych znaków ?>, więc dobrą praktyką jest pomijanie ich na końcu pliku. Jest to prawdopodobnie najczęstszy powód błędów typu „przesyłanie już się rozpoczęło”, występujących podczas stosowania funkcji header() przy przesyłaniu nagłówka HTTP do przeglądarki.

„Magiczne” funkcje Większość metod nazywanych zazwyczaj „magicznymi” funkcjami odnosi się do brakujących właściwości i metod niezdefiniowanych w klasie. Powodem tego jest szeroko stosowane definiowanie właściwości jako tabeli asocjacyjnej zamiast jako odrębnych zmiennych. Takie podejście jest proste w realizacji, łatwo rozszerzalne oraz wygodne w zarządzaniu, co przełożyło się na popularność definiowania właściwości jako tablicy. Bez „magicznych” funkcji nie byłoby łatwego dostępu do takich właściwości. Pierwsza para tych specjalnych metod warta wspomnienia to metody __get i __set.

Metody __get i __set Metoda __set jest wywoływana w momencie przypisania wartości do nieistniejącej właściwości. Metoda __get jest wywoływana w momencie odczytu wartości nieistniejącej właściwości (listing 1.4). Listing 1.4. Przykład wykorzystania funkcji __get i __set # Przykład wykorzystania funkcji __get i __set # Nieistniejąca właściwość "limit_predkosci" jest zapisywana i odczytywana.

27

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

W wyniku działania powyższego skryptu otrzymamy: Brak właściwości! Ograniczenie prędkości wynosi 100 km/h Metoda __isset() została wywołana.

Właściwość limit_predkosci nie jest zdefiniowana, jednak odwołanie do niej nie kończy się błędem, ponieważ w momencie odwołania wykonana została metoda __get. Metoda __set została natomiast wywołana w momencie przypisania wartości do nieistniejącej właściwości. Definiowanie wszystkich właściwości klasy jako tabeli asocjacyjnej i odwoływanie się do nich jak do odrębnych właściwości jest częstą praktyką. Taki sposób definiowania właściwości pozwala na łatwe rozwijanie klasy.

Metoda __isset Poza metodami __get i __set na listingu 1.4 zademonstrowano wykorzystanie funkcji __isset, która jest stosowana do sprawdzania, czy nieistniejąca właściwość, zazwyczaj definiowana jako tablica, została ustawiona (ma przypisaną wartość). Oczywiście dostępna jest także funkcja __unset. Jest ona wywoływana w momencie wywołania unset dla niezdefiniowanej właściwości. Metoda __isset jest także wywoływana podczas sprawdzania, czy zmienna nie jest pusta, za pomocą funkcji empty(). Funkcja empty() sprawdza, czy argument jest ustawiony oraz czy jego długość jest większa od 0. Zwraca prawdę, jeżeli argument nie jest ustawiony lub jego długość jest równa 0, w przeciwnym wypadku zwraca fałsz. Jeżeli argument zostanie ustawiony na pusty ciąg znaków, funkcja empty() zwróci prawdę.

Metoda __call Dla nieistniejących właściwości funkcja __call wywoływana jest w momencie odwołania się do nieistniejącej metody. Jak pokazuje doświadczenie, funkcja wykorzystywana jest raczej rzadko. Listing 1.5 przedstawia krótki przykład, obrazujący to w pełni. Listing 1.5. Funkcja __call jest wykonywana w momencie odwołania się do nieistniejącej metody

Wykonanie skryptu zwróci następujący wynik: nazwa:nieistniejaca_metoda 1 2 3

Metoda nieistniejaca_metoda oczywiście nie została zdefiniowana, jednak mimo to wywołanie jest poprawne.

28

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

Metoda __toString() Ostatnia opisywana tutaj „magiczna” funkcja, __toString(), jako jedyna nie ma nic wspólnego z nieistniejącymi elementami klasy. Wykorzystywana jest w momencie, kiedy obiekt jest konwertowany na ciąg znaków poprzez bezpośrednie rzutowanie lub pośrednio, poprzez przekazanie go jako parametru funkcji, która oczekuje argumentów łańcuchowych, np. print (listing 1.6). Listing 1.6. Przykład wykorzystania metody __toString

Wykonanie skryptu zwróci następujący wynik: element test2.

Wypisywana jest wartość zwracana przez metodę __toString. Funkcja jest wywoływana w momencie wykorzystania obiektu jak zmiennej łańcuchowej. Funkcja ta jest bardzo pożyteczna, gdy konieczne jest wyświetlenie złożonych obiektów zawierających nietypowe elementy, takie jak połączenia sieciowe lub bazodanowe albo inne obiekty binarne.

Kopiowanie, klonowanie oraz porównywanie obiektów Na początku tego rozdziału wyjaśniono, czym są klasy i w jaki sposób tworzyć i wykorzystywać złożone obiekty. Teraz przyszedł czas na przedstawienie niektórych aspektów wewnętrznej obsługi obiektów. Kiedy tworzony jest obiekt przy zastosowaniu dyrektywy w rodzaju $x=new class(....), zmienna $x jest referencją na obiekt. Co się stanie, kiedy wywołamy polecenie $x=$y? To bardzo proste — obiekt, na który dotychczas wskazywała zmienna $x, jest usuwany, wywoływany jest jego destruktor, a zmienna $x od tej chwili wskazuje na obiekt $y. Listing 1.7 przedstawia skrypt demonstrujący powyższe zachowanie. Listing 1.7. Wykonanie $x=$y

Wykonanie skryptu zwróci następujący wynik: Przypisywanie zmiennej: Usuwanie obiektu obiekt 1... Koniec skryptu Usuwanie obiektu obiekt 2...

Obiekt 1 jest usuwany z pamięci podczas przypisywania $x=$y. Dlaczego usunięty został obiekt 2? Odpowiedź na to pytanie jest bardzo prosta — destruktor wywoływany jest zawsze, gdy obiekt przestaje być potrzebny. Kiedy skrypt się kończy, wszystkie obiekty przestają być potrzebne i dla każdego z nich jest wywoływany jego destruktor. To powód umieszczenia przypisania pomiędzy dwoma poleceniami print. Ponadto zauważ, że destruktor wywoływany jest tylko raz, pomimo że do obiektu istnieją dwie referencje, $x i $y. Destruktor wywoływany jest raz dla obiektu, nie dla każdej referencji do niego. Ten sposób kopiowania obiektów jest nazywany płytkim kopiowaniem, ponieważ nie jest tworzona prawdziwa kopia obiektu, zmieniane są tylko referencje. Oprócz płytkiego kopiowania istnieje także kopiowanie głębokie, tworzące nowy obiekt. Głębokie kopiowanie wykonywane jest przy użyciu operatora clone. Przykład takiego kopiowania pokazano na listingu 1.8. Listing 1.8. Głębokie kopiowanie przy wykorzystaniu operatora clone

Głębokie kopiowanie ma miejsce w linii $x = clone $y. W momencie wykonywania tej linii tworzona jest nowa kopia obiektu $y i wywoływana jest funkcja __clone w celu ustawienia nowej kopii obiektu w sposób wymagany przez skrypt. Wynik działania skryptu wygląda następująco:

30

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

Obiekt obiekt 1 ma 0 kopii. Usuwanie obiektu obiekt 1... Obiekt obiekt 2:KLON ma 1 kopii. Obiekt obiekt 2 ma 0 kopii. Koniec skryptu, uruchamianie destruktorów. Usuwanie obiektu obiekt 2... Usuwanie obiektu obiekt 2:KLON...

Nowo utworzona kopia zapisana w zmiennej $x ma wartość właściwości obiekt 2:KLON i liczbę kopii ustawioną na 1 w rezultacie czynności, które zostały wykonane wewnątrz metody __clone. Zauważ także, że konstruktor został wywołany dwukrotnie — raz dla obiektu oryginalnego i raz dla kopii. Klonowanie nie jest używane tak często jak przypisanie przez referencję, jednak dobrze jest mieć taką możliwość. W jaki sposób porównywane są obiekty? Należy rozważyć kilka przypadków, zależnie od kryteriów porównania. Kiedy dokładnie nazwiemy dwie zmienne obiektowe $x i $y „równymi”? Są następujące trzy poprawne logicznie możliwości: • Obiekty tej samej klasy mają równe wartości dla wszystkich właściwości. • Obiekty są referencją do tego samego obiektu tej samej klasy. • Wykorzystywanych jest kilka innych niestandardowych kryteriów. Standardowy operator porównania == testuje pierwszy wariant. Wyrażenie $x==$y jest prawdziwe wtedy i tylko wtedy, gdy odpowiednie właściwości obu obiektów są sobie równe. Druga możliwość — czyli $x i $y są referencjami na ten sam obiekt — sprawdzana jest za pomocą specjalnego operatora === (trzy znaki równości pisane łącznie). Wyrażenie $x===$y jest prawdziwe wtedy i tylko wtedy, gdy obie zmienne są referencją na ten sam obiekt. Zwróć uwagę, że zwyczajowe przypisanie $x=$y spowoduje, że wyrażenie $x===$y będzie prawdziwe, klonowanie natomiast sprawi, że wyrażenie będzie fałszywe. Jeżeli nie została zdefiniowana niestandardowa metoda __clone, oryginalny obiekt i klon będą równe dla wyrażenia z wykorzystaniem operatora ==. Co możemy zrobić w trzecim przypadku, niestandardowej definicji równości? Musimy utworzyć niestandardową funkcję porównującą i porównać zwracane wartości. Podczas pisania funkcji przyjmujących argumenty konkretnych klas możliwe jest egzekwowanie typu zmiennej przekazywanej do funkcji poprzez podanie nazwy klasy przed formalną nazwą argumentu. Wygląda to w ten sposób: function funkcja_testowa(test3a $a) {….}

Wymagane jest tutaj, aby argument $a był typu test3a. Jest to możliwe wyłącznie dla typów obiektowych i tablicowych poprzez wstawienie słowa array zamiast nazwy klasy. PHP5 nadal jest słabo typowanym językiem i wymuszenie typów argumentów dla standardowych typów takich jak int nadal nie jest wspierane.

Interfejsy, iteratory i klasy abstrakcyjne Kolejnym standardowym typem w programowaniu obiektowym jest interfejs. Interfejs jest obiektem opisującym zestaw metod, które klasa może zaimplementować. Interfejs wygląda następująco: interface interf { public function f1($x,$y,...,); public function f2(....); …. public function fn(...); }

Zauważ, że kod metody nie jest wyspecyfikowany, wyszczególnione są tylko jej nazwa i argumenty. Klasa może zaimplementować interfejs w następujący sposób: class c extends klasaNadrzedna implements interf { (wszystkie funkcje wyszczególnione w interfejsie muszą zostać zaimplementowane) … )

31

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

Interfejsy mogą po sobie dziedziczyć jak klasy. Składnia jest identyczna: interface interf2 extends interf1 { function f1(...); }

Nowy interfejs interf2 będzie zawierał wszystkie funkcje z interfejsu interf1 oraz nowe, zdefiniowane w interf2 (listing 1.9). Listing 1.9. Przykład nowego interfejsu interf2

Zauważ, że znaki nowej linii nie są usuwane z linii i że musimy sprawdzać, czy linie nie są puste. Klasa SplFileObject mogłaby wyjść poza koniec pliku, gdybyśmy ominęli sprawdzanie pustych wierszy. Mimo to jest to klasa znacznie ułatwiająca pracę. Jedyną bardzo użyteczną funkcją, której brakuje w klasie SplFileObject, jest fputcsv, zwracająca tablice w formacie CSV. Można jednak z łatwością ją sobie napisać.

34

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

W bibliotece SPL jest wiele innych przydatnych klas i interfejsów. Pełny opis biblioteki SPL wykracza poza zakres niniejszej książki. Odpowiednią dokumentację możesz znaleźć pod adresem http://www.php.net/ manual/pl/book.spl.php. Istnieje także standardowy zestaw klas implementujących iterator dla kursorów i zapytań bazodanowych. Zestaw ten nazwano ADOdb. Pozwala on programiście wykorzystywać wyniki zapytań w pętlach foreach, podobnie jak pliki i tablice. Zestaw ADOdb będzie omówiony szczegółowo w dalszej części książki. Jaka jest różnica między klasami abstrakcyjnymi a interfejsami? Jedne i drugie wykorzystuje się jako szablony dla innych klas dziedziczących po nich lub implementujących je; klasa abstrakcyjna jest jednak dużo bardziej restrykcyjna i znacznie ściślej definiuje strukturę. Dodatkowo poza metodami abstrakcyjnymi klasy abstrakcyjne mogą mieć nieabstrakcyjne właściwości i metody — nawet metody ze słowem kluczowym final, które nie mogą być przeciążane.

Kontekst klasy i elementy statyczne Do tej pory pracowaliśmy wyłącznie z właściwościami i metodami, które są definiowane w kontekście obiektu — każdy obiekt posiadał własne właściwości i metody. Są jeszcze właściwości i metody działające w kontekście klasy. Oznacza to, że są wspólne dla wszystkich obiektów danej klasy. Problem, który próbujemy rozwiązać, jest następujący: w jaki sposób możemy policzyć wszystkie obiekty danej klasy utworzone w skrypcie. Oczywiście potrzebujemy licznika, który będzie działał raczej na poziomie klasy niż obiektu. Zmienne i metody zadeklarowane w kontekście klasy, nie w kontekście obiektu, nazywają się zmiennymi statycznymi (listing 1.12). Listing 1.12. Przykład zmiennych statycznych

Wykonanie skryptu zwróci następujący wynik: X: 1 obiekt został utworzony Y: 2 obiekty zostały utworzone Ponownie sprawdźmy zmienną x: X: 2 obiekty zostały utworzone Jeżeli odwołamy się do właściwości obiektu, PHP utworzy nową liczbę dla X... i zainicjuje ją na:0

35

ROZDZIAŁ 1. „ OBIEKTOWOŚĆ

Zmienna test4::$liczba_obiektow jest zmienną statyczną rezydującą w kontekście klasy. Kiedy została zwiększona do dwóch podczas tworzenia obiektu $y, zmiana była widoczna także dla obiektu $x. Jeżeli podjęta będzie próba odczytania zmiennej jako właściwości obiektu, tak jak w przypadku funkcji blad(), PHP utworzy nową publiczną właściwość o takiej nazwie. Wszystko stało się teraz bardziej zagmatwane. Fakt, że element klasy został oznaczony jako statyczny, nie ma nic wspólnego z jego widocznością. Mogą występować elementy statyczne typu public, private i protected, z takimi samymi restrykcjami jak przy właściwościach obiektu. Zwróć także uwagę, że do tej samej zmiennej odwoływaliśmy się zarówno poprzez self::$liczba_obiektow, jak i test4::$liczba_obiektow. Słowo kluczowe self jest skrótem dla „ta klasa” i zawsze dotyczy klasy, w której zostało wykorzystane. Innymi słowy, nie uwzględnia dziedziczenia — zawsze jest takie samo (listing 1.13). Listing 1.13. Słowo kluczowe self zawsze odnosi się do klasy, w której zostało zdefiniowane

Jeśli kod metody get_wlasciwosc w klasie B jest oznaczony jako komentarz, oba wiersze będą wyświetlały liczbę 4, ponieważ obie funkcje będą wywoływane w kontekście klasy A. Jeżeli nie będzie oznaczony jako komentarz, linia printf("B:%d\n", $y->get_wlasciwosc()); wyświetli liczbę 9. Zmienne klas najlepiej wywoływać poprzez ich nazwy. Takie odwołanie jest jednoznaczne i sprawia, że kod jest czytelniejszy. Oprócz właściwości statycznych istnieją metody statyczne. One także są wywoływane w kontekście klasy: class::metoda_statyczna(...). Należy wspomnieć, że brak jest jakiejkolwiek serializacji, leży ona całkowicie w gestii użytkownika.

Podsumowanie Z tego rozdziału dowiedziałeś się całkiem sporo o klasach i obiektach w PHP. Powinieneś już znać pojęcia: klasa, obiekt, metoda, właściwość, konstruktor, destruktor, dziedziczenie, przeciążenie, interfejs, klasa abstrakcyjna, metoda statyczna oraz iterator. Rozdział ten nie jest w żadnym wypadku kompletnym spisem elementów obiektowych w PHP5, zawiera jednak główne pojęcia i może być solidną podstawą dalszej nauki. Oficjalna dokumentacja zamieszczona pod adresem www.php.net jest doskonałym źródłem wiedzy i zawiera wszystko, co zostało pominięte w tym rozdziale.

36

ROZDZIAŁ 2 „„„

Wyjątki i referencje

W tym rozdziale przedstawimy wyjątki i referencje — dwa podstawowe aspekty nowoczesnego programowania obiektowego (OOP — Object-oriented programming). Wyjątki są zdarzeniami synchronicznymi. Słowo „synchroniczne” oznacza, że wyjątki występują w konsekwencji zdarzeń w kodzie, a nie zdarzeń zewnętrznych, takich jak sygnały. Kiedy na przykład operator stosuje kombinację klawiszy Ctrl+C, sygnał przesyłany jest do wykonywanego programu. Wyjątki są wykorzystywane do obsługi błędów w sposób uporządkowany i zgodny ze standardami. Kiedy program (lub jak w przypadku PHP — skrypt) próbuje wykonać dzielenie przez zero, zgłaszany jest wyjątek. Wyjątki mogą być zgłaszane (lub wywoływane) oraz przechwytywane. Wywołanie wyjątku oznacza przekierowanie kontroli programu do części kodu przeznaczonej do obsługi tych zdarzeń. Współczesne języki programowania, takie jak PHP, mają możliwość wykonania tego w logiczny i uporządkowany sposób.

Wyjątki Wyjątki są obiektami klasy Exception lub dowolnej klasy dziedziczącej po niej. Na pewno pamiętasz z poprzedniego rozdziału, że dziedziczenie jest hierarchicznym związkiem między klasami. Definicja klasy Exception zgodnie ze specyfikacją jest następująca: Exception { /* Właściwości */ protected string $message ; protected int $code ; protected string $file ; protected int $line ; /* Metody */ public __construct ([ string $message = "" [, int $code = 0 [, Exception $previous = NULL ]]] ) final public string getMessage ( void ) final public Exception getPrevious ( void ) final public int getCode ( void ) final public string getFile ( void ) final public int getLine ( void ) final public array getTrace ( void ) final public string getTraceAsString ( void ) public string __toString ( void ) final private void __clone ( void ) }

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

Wyjątki są zatem obiektami mieszczącymi przynajmniej powyższe informacje w momencie wystąpienia błędu, czyli zawierają: treść błędu, kod błędu, nazwę pliku oraz linię, w której wystąpił wyjątek. Wyjątki są bardzo przydatne podczas szukania i usuwania błędów w programach. Listing 2.1 przedstawia przykład. Listing 2.1. Przykład wyjątku

Skrypt wykonany z wiersza poleceń z innymi argumentami zwróci następujące wyniki: ./listing2_1.php 4 2 Wynik: 2.000000 Zmienna a:mój string ./listing2_1.php 4 A Błąd: wartość A nie jest liczbą!

38

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

./listing2_1.php 4 0 Wyjątek: Niedozwolone dzielenie przez zero.

Z punktu widzenia wyjątków ten niewielki skrypt zawiera sporo ważnych rzeczy. Tablica $argv jest predefiniowaną tablicą globalną z argumentami wiersza poleceń. Istnieje także predefiniowana zmienna globalna $argc zawierająca liczbę argumentów wiersza poleceń, jak w języku C. Teraz zwróćmy uwagę na wyjątki i ich składnię. Najpierw zdefiniowaliśmy klasę wyjątku, która ignoruje istniejącą strukturę klasy Exception i nie wywołuje nawet metody konstruktora klasy nadrzędnej. Nie jest to dobrą praktyką programistyczną i zostało tu przedstawione jedynie jako przykład. W konsekwencji nasza klasa nie ma metod getMessage oraz getCode, przez co jest trudniejsza w wykorzystaniu. Zwyczajowa składnia wyjątku nie odnosi się do naszej klasy, co może powodować problemy, jeżeli ktoś spróbuje na przykład wywołać metodę getMessage(). Następnie utworzyliśmy blok try, w którym wystąpił wyjątek. Pojawienie się wyjątku sprawdzane jest w blokach catch (zwanych także blokami obsługi wyjątków), występujących bezpośrednio po bloku try. Blok try nie jest zwykłym blokiem programu; zmienne zdefiniowane wewnątrz bloku try będą zdefiniowane także poza nim. Zmienna $a jest wyświetlana po wykonaniu pierwszej części, po dzieleniu 4 przez 2. Kolejną sprawą jest składnia instrukcji throw. W tej instrukcji „rzucany” jest wyjątek. Bloki obsługi błędów są bardzo podobne do funkcji przyjmujących jeden argument — obiekt wyjątku. Kolejność bloków obsługi błędów jest istotna. PHP przekaże wyjątek do pierwszego bloku obsługi przyjmującego wyjątek danego typu. Blok obsługi dla wyjątku klasy Exception musi zawsze być ostatni, ponieważ przechwyci wszystkie zgłaszane wyjątki dowolnego typu. Kiedy zgłaszany jest wyjątek, PHP znajduje pierwszy pasujący blok obsługi i wykorzystuje go. Gdyby blok obsługujący wyjątki typu Exception został utworzony przed blokiem obsługującym wyjątki typu WyjatekNieLiczba, to ten drugi nie zostałby nigdy wywołany. Bloki obsługi błędów lub bloki catch wyglądają jak funkcje. Podobieństwo nie jest przypadkowe. PHP posiada także „magiczną” metodę set_exception_handler, dzięki której możliwe jest ustawienie obsługi dla wszystkich nieprzechwyconych wyjątków. Przepiszmy skrypt z listingu 2.1 (listing 2.2). Listing 2.2. Przepisany skrypt z listingu 2.1

Wynik powyższego skryptu będzie identyczny z wynikiem działania skryptu z listingu 2.1. Blok obsługi wyjątków zadeklarowany przy wykorzystaniu funkcji set_exception_handler jest funkcją przyjmującą jeden argument typu Exception i wykonywaną po wszystkich innych blokach obsługi wyjątków. ./listing2_2.php 4 A Błąd: wartość A nie jest liczbą!

Powyższy kod pochodzi z bloku obsługi wyjątku WyjatekNieLiczba, a nie z bloku domyślnego. Jeżeli drugi argument zostałby zastąpiony przez 0 podczas wykonywania skryptu, otrzymalibyśmy wynik zgodny z poprzednim skryptem: ./listing2_2.php 4 0 Wyjątek: Niedozwolone dzielenie przez zero.

Teraz wykonany został domyślny blok obsługi wyjątków. Domyślna obsługa wyjątków jest szczególnie użyteczna podczas pracy z klasami napisanymi przez kogoś innego, takimi jak klasa SplFileObject z poprzedniego rozdziału. Jeśli pójdzie coś nie tak, obiekty tej klasy zgłoszą wyjątki typu Exception, analogicznie do ADOdb. „ UWAGA. Klasy z repozytorium PEAR zgłaszają wyjątki klasy PEAR_Exception w momencie wystąpienia błędu. Klasa PEAR_Exception posiada wszystkie elementy standardowej klasy Exception, wzbogacone o dodatkową zmienną $trace. PEAR_Exception spróbuje także pokazać stos wywołań, kiedy zostanie zgłoszony i przechwycony.

Listing 2.3 pokazuje przykład skryptu, który próbuje otworzyć nieistniejący plik, wykorzystując klasę SplFileObject. Zadeklarowany został także domyślny blok obsługi błędów, który przechwyci wyjątek zgłoszony przez klasę SplFileObject, pomimo że nie ma w kodzie jawnych bloków try { ..} catch {...}.

Listing 2.3. Przykład skryptu próbującego otworzyć nieistniejący plik przy wykorzystaniu klasy SplFileObject

40

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

Wykonanie skryptu zwróci następujący wynik: Exception: SplFileObject::__construct(nieistniejacy_plik.txt) [splfileobject.--construct]: failed to open ´stream: No such file or directory Plik:C:\ksiazka\Rozdzial02\listing2_3.php Linia:14

Przy korzystaniu z klas napisanych przez kogoś innego domyślny blok obsługi wyjątków może być bardzo użytecznym, chociaż niewymagającym narzędziem. Domyślny blok obsługi wyjątków przechwyci wszystkie nieprzechwycone w inny sposób wyjątki. Przeważnie służy on do kończenia działania programu oraz ułatwia proces identyfikacji błędów. Oczywiście, w pewnych sytuacjach programista może przeprowadzić specjalną obsługę i wykonać coś takiego: try { $file = new SplFileObject("nieistniejacy_plik.txt", "r"); } catch (Exception $e) { $plik=STDIN; }

Jeżeli wystąpi problem z otwarciem pliku do odczytu, zostaną zwrócone standardowe dane wejściowe. Nie będzie to obiekt klasy SplFileObject, a programista będzie musiał uporać się z ewentualnymi konsekwencjami. Ponieważ domyślny blok obsługi zostanie wykonany jako ostatni dla nieprzechwyconych wyjątków, nie ma żadnych przeszkód, aby dokładnie obsłużyć wyjątki i napisać własne bloki obsługi. Jest jeszcze jedna rzecz warta wspomnienia — zagnieżdżanie wyjątków. PHP nie wspiera zagnieżdżania, jeżeli także bloki try nie zostaną zagnieżdżone. Innymi słowy, w poniższej sytuacji obsługa dla ExcB nie zostanie wywołana, jeżeli wyjątek jest zgłoszony wewnątrz obsługi ExcA: class ExcA extends Exception {...} class ExcB extends Exception {...} try {... throw new ExcA(..) } catch(ExcA $e) { throw new ExcB(); } catch(ExcB $e) { // Nie zostanie wykonany, jeżeli wyjątek będzie zgłoszony wewnątrz ExcA. }

Jedynym sposobem na zagnieżdżanie wyjątków jest zagnieżdżenie bloków try. W kontekście zagnieżdżania wyjątków PHP5 nie różni się od Javy czy C++.

Referencje Kolejnym ważnym typem obiektów w PHP są referencje. Referencje w PHP nie są wskaźnikami. PHP w odróżnieniu od Perla nie ma typu referencyjnego, który może być wykorzystany do adresowania obiektów przez dereferencje. W PHP referencja oznacza inną nazwę dla obiektu. Przyjrzyjmy się skryptowi z listingu 2.4. Listing 2.4. W PHP referencje są obiektami

Wywołanie skryptu zwraca następujący wynik: Element X posiada właściwość 10 Element X posiada właściwość 5 1 2 3 4 5

Dla zmiennej obiektowej $x wartość została zmieniona przez operacje wewnątrz metody funkc, a dla tablicy $arr wartości nie zostały zmienione przez operacje wewnątrz pętli foreach. Dzieje się tak, ponieważ PHP przekazuje parametry przez kopiowanie. Oznacza to, że dla typów nieobiektowych, takich jak liczby, łańcuchy znaków czy tablice, tworzona jest nowa, identyczna kopia obiektu, dla obiektów natomiast tworzona jest referencja lub, inaczej mówiąc, nowa nazwa dla obiektu. Kiedy do metody funkc został przekazany argument $x typu test5, powstała nowa nazwa dla obiektu. Poprzez operacje na nowej zmiennej modyfikowaliśmy zawartość pierwotnego obiektu, a nowa zmienna była tylko nową nazwą dla obiektu już istniejącego. Więcej szczegółów znajdziesz w rozdziale 1. Pomimo że PHP w przeciwieństwie do Perla nie zapewnia bezpośredniego dostępu do referencji, nadal umożliwia w pewnym stopniu kontrolę nad sposobem kopiowania obiektów. Listing 2.5 przedstawia przykład kopiowania przez referencję. Listing 2.5. Kopiowanie przez referencję

Wywołanie skryptu zwróci wynik: Zwykłe przypisanie. x=2 Przypisanie przez referencję. x=3

42

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

Powyższy skrypt składa się z dwóch części — zwykłego przypisania oraz przypisania przez referencję. W pierwszej części podczas normalnego przypisania tworzona jest nowa kopia zmiennej $y. Kopia ta jest przypisywana do zmiennej $x, poprzednia zawartość zmiennej $x jest usuwana. Zwiększenie zmiennej $y nie miało żadnego wpływu na zmienną $x. W drugiej części przez przypisanie przez referencję poprzednia zawartość zmiennej $x także została usunięta, jednak zmienna stała się aliasem (referencją) zmiennej $y. Zwiększenie wartości zmiennej $y o jeden było widoczne także w zmiennej $x, która zwróciła 3 zamiast 2. Analogiczna operacja może także dotyczyć pętli. Na listingu 2.4 mieliśmy następujący fragment kodu: $arr = range(1, 5); foreach ($arr as $a) { $a*= 2; } foreach ($arr as $a) { print "$a\n";

Wynikiem były niezmienione liczby od 1 do 5. Zmieńmy teraz ten fragment, korzystając z operatora referencji &: $arr = range(1, 5); foreach ($arr as $a) { $a*= 2; } print_r($arr);

Wynikiem będzie zmieniona tablica: Array ( [0] [1] [2] [3] [4] )

=> => => => =>

2 4 6 8 10

Innymi słowy, dodając operator & do zmiennej $a, nie utworzyliśmy kopii elementu tablicy — inaczej niż przy wyrażeniu foreach($arr as $a), gdzie kopia była tworzona. Zamiast tego utworzyliśmy referencję do elementów tablicy, co oznacza, że wszystko, co zrobimy ze zmienną $a wewnątrz pętli, zmodyfikuje element tablicy, a nie jego kopię. Niemożliwe jest utworzenie referencji do funkcji. „ UWAGA. Gdy po referencji do tablicy wykonywana jest pętla, należy zachować szczególną ostrożność. Jeżeli kod zmieni tablicę, efekty mogą być nieprzewidywalne.

Możliwe jest jednakże zwrócenie referencji jako wyniku działania funkcji oraz przekazanie referencji jako parametru funkcji. Argumenty powinny być przekazywane do funkcji przez referencję, jeżeli funkcja może zmienić pierwotną zmienną. Składnia jest taka sama jak w przypadku pętli — zmienna przekazywana przez referencję jest poprzedzana ampersandem (&). Listing 2.6 przedstawia przykład. Listing 2.6. Możliwe jest zwracanie referencji jako wyniku działania funkcji oraz przekazywanie referencji do tej funkcji

Uruchomienie powyższego fragmentu kodu spowoduje wyświetlenie następującego wyniku: x=8 a=5 x=8 a=8

Kiedy została wywołana funkcja f1, nastąpiło przekazanie argumentu przez wartość. Polecenie print wewnątrz funkcji wyświetliło liczbę 8, jednak pierwotna zmienna nie uległa zmianie, pozostała ustawiona wartość 5. Kiedy nastąpiło wywołanie funkcji f2, pierwotna zmienna uległa modyfikacji. Widać to po ostatniej wyświetlonej wartości. Referencje można także zwracać jako wyniki funkcji. Nie powinno się tego stosować w celu zwiększenia wydajności, ponieważ PHP robi to automatycznie. Powtórzmy: referencja jest po prostu inną nazwą dla zmiennej. Referencje mogą być wykorzystane do obejścia zabezpieczenia widoczności zmiennej, ustawionego za pomocą słowa kluczowego private lub protected (listing 2.7). Listing 2.7. Referencje mogą być wykorzystane do obejścia zabezpieczenia widoczności zmiennej

Po wykonaniu skryptu wynik jest zgodny z oczekiwaniami: b=10 b=15 $a->get_x()=16

W tym przykładzie zmienna $b jest ustawiana jako referencja na $a->x, która jest prywatną właściwością klasy test6. Zostało to wykonane poprzez zwrócenie referencji w wyniku działania metody get_x(). Oczywiście

44

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

deklarowanie publicznej referencji do prywatnej właściwości przeczy celowi kontroli widoczności. Zwracanie wartości przez referencję jest rzadko stosowaną praktyką. Wykorzystywanie tej metody powinno być dobrze przemyślane — łatwo można zezwolić na niepowołany dostęp do referencji zwróconych przez funkcję.

Podsumowanie Z tego rozdziału dowiedziałeś się o wyjątkach i referencjach w PHP. Oba elementy funkcjonują także w innych nowoczesnych językach programowania. Celem wyjątków jest zapewnienie łatwego systemu obsługi błędów. Głównym zadaniem referencji jest zwiększenie szybkości wykonywania kodu oraz (sporadycznie) umożliwienie wykorzystania sztuczek programistycznych. Oba elementy języka są bardzo przydatne i mogą ułatwić pracę programiście. Obsługa wyjątków pozwala na sprawdzanie błędów w elegancki sposób, co zostanie zademonstrowane w rozdziale dotyczącym integracji z bazami danych.

45

ROZDZIAŁ 2. „ WYJĄTKI I REFERENCJE

46

ROZDZIAŁ 3 „„„

Mobilne PHP

Tworzenie aplikacji mobilnych staje się z roku na rok coraz popularniejsze. O zwiększenie udziału w rynku walczą iPhone, Android czy BlackBerry. Każdy producent smartfona potrzebuje aplikacji dla swojego urządzenia, by przyciągnąć jak najwięcej użytkowników. Ponadto istnieją tablety, takie jak iPad, PlayBook i Galaxy, oraz czytniki, np. Kindle czy Nook. Nawet standardowe telefony komórkowe mają przeglądarki i różne dodatki. Na każdym urządzeniu mobilnym posiadającym dostęp do internetu można przeglądać strony internetowe i uruchamiać aplikacje utworzone w technologii PHP. Dlatego potrzebny jest sposób sensownego prezentowania zawartości stron na mniejszych urządzeniach. Z tego rozdziału dowiesz się, jak rozpoznać urządzenie klienckie za pomocą żądania HTTP, poznasz WURFL i Tera-WURFL. Obecnie działają tysiące urządzeń mobilnych umożliwiających przeglądanie stron internetowych. Może się wydawać, że tworzenie oprogramowania dla starszych przeglądarek jest trudne, ale urządzenia mobilne są jeszcze mniej ustandaryzowane. Na szczęście są dostępne systemy pomocne w procesie tworzenia takiego oprogramowania. Mając na uwadze renderowanie na urządzenia mobilne, pokażemy, jak sprawić przy użyciu WALL, by znaczniki były bardziej abstrakcyjne, jak automatycznie zmieniać rozmiar obrazków i spowodować, by CSS był bardziej płynny. Zaprezentujemy także emulatory urządzeń, omówimy tworzenie aplikacji PHP na urządzenia z Androidem i program Flash Builder dla PHP.

Różnorodność urządzeń Podczas pracy z urządzeniami mobilnymi jednym z największych wyzwań jest zapewnienie czytelności strony po jej wyrenderowaniu. Przy tworzeniu aplikacji internetowych na komputery osobiste sprawdzamy najpopularniejsze przeglądarki, takie jak Chrome, Firefox, Safari, Opera czy Internet Explorer, i być może inne systemy, np. Windows XP, Windows 7, Linux bądź Mac OS X. Zapewnienie wsparcia dla różnych kombinacji przeglądarek i systemów może być pracochłonne. W przypadku urządzeń mobilnych renderowanie jest jeszcze mniej ustandaryzowane i dużo bardziej złożone. Na przykład prawie wszystkie współczesne komputery osobiste umożliwiają wyświetlanie tysięcy kolorów i zapewniają rozdzielczość minimum 800 na 600 pikseli. Jednakże telefony komórkowe, smartfony, tablety, czytniki e-booków i inne urządzenia mobilne mogą mieć ograniczoną paletę kolorów lub tylko skalę szarości. Rozmiary wyświetlaczy także znacznie się różnią. To są tylko trzy parametry — istnieją setki innych, którymi mogą się różnić poszczególne urządzenia. Omówimy kilka z tych parametrów w dalszej części tego rozdziału. W przeciwieństwie do tworzenia stron przeznaczonych dla komputerów stacjonarnych naiwne próby programowania dla każdego urządzenia oddzielnie są nierealne lub przynajmniej zajęłyby zbyt wiele czasu i pracy, niż ktokolwiek byłby skłonny na to poświęcić. Zamiast tego omówimy systemy pozwalające na określenie urządzenia i wyrenderowanie strony dynamicznie oraz płynne zmienianie stylów CSS.

ROZDZIAŁ 3. „ MOBILNE PHP

Rozpoznanie urządzenia Pierwszym krokiem różnicowania zawartości strony jest sprawdzenie, dla jakiego urządzenia ta strona będzie renderowana. Przeanalizujemy kilka technik pozwalających na ustalenie, jakie urządzenie jest używane.

Aplikacja kliencka U podstaw każdego systemu detekcji urządzeń leży nagłówek aplikacji klienckiej wysyłany w standardowym zapytaniu HTTP. W PHP możemy uzyskać dostęp do informacji o aplikacji klienckiej dzięki superglobalnej zmiennej serwerowej $_SERVER['HTTP_USER_AGENT']. Nagłówek takiej aplikacji może zawierać informacje o przeglądarce, silniku renderującym i systemie operacyjnym. Ma postać podobną do poniższego, wygenerowanego dla przeglądarki Firefox 4: Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0

Z tego nagłówka możemy wyczytać, że systemem operacyjnym klienta jest Windows, silnikiem renderującym jest Gecko, natomiast przeglądarką jest Firefox w wersji 4.0. „ UWAGA. Rozpoznawanie urządzeń nie jest pewne. Nagłówki dla dwóch różnych urządzeń mogą nie być unikalne, chociaż rzadko tak bywa; mogą także być fałszowane, co zostanie omówione w dalszej części rozdziału.

Wbudowane funkcje PHP PHP ma funkcję get_browser, która próbuje uzyskać informacje o wykorzystywanej przeglądarce. Funkcja działa na podstawie pliku browscap.ini. W tym kontekście jest jak prostsza, ograniczona wersja systemu WURFL, który będzie omówiony dalej. „ UWAGA. Ta funkcja wymaga zainstalowanego w systemie pliku browscap.ini oraz ustawienia ścieżki do niego w pliku php.ini, na przykład: browscap = "C:\twoja\sciezka\do\browscap.ini"

Więcej informacji o funkcji get_browser można uzyskać pod adresem http://php.net/manual/pl/function.get-browser.php, natomiast aktualne pliki browscap.ini pod adresem http://browsers.garykeith.com/downloads.asp.

Jeżeli pierwszy parametr będzie ustawiony na wartość null lub przekazany zostanie nagłówek aplikacji klienckiej, uzyskamy informacje o przeglądarce. Możemy także przekazać inny nagłówek, aby uzyskać informacje o nim. Drugi parametr jest opcjonalny. Ustawienie go na wartość true spowoduje zwrócenie wyniku w postaci tabeli zamiast domyślnego obiektu (listingi 3.1 i 3.2). Listing 3.1. Wykorzystanie funkcji get_browser

Listing 3.2. Wynik dla przeglądarki Chrome Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24

48

ROZDZIAŁ 3. „ MOBILNE PHP

array 'browser_name_regex' => string '§^.*$§' (length=6) 'browser_name_pattern' => string '*' (length=1) 'browser' => string 'Default Browser' (length=15) 'version' => string '0' (length=1) 'majorver' => string '0' (length=1) 'minorver' => string '0' (length=1) 'platform' => string 'unknown' (length=7) 'alpha' => string '' (length=0) 'beta' => string '' (length=0) 'win16' => string '' (length=0) 'win32' => string '' (length=0) 'win64' => string '' (length=0) 'frames' => string '1' (length=1) 'iframes' => string '' (length=0) 'tables' => string '1' (length=1) 'cookies' => string '' (length=0) 'backgroundsounds' => string '' (length=0) 'cdf' => string '' (length=0) 'vbscript' => string '' (length=0) 'javaapplets' => string '' (length=0) 'javascript' => string '' (length=0) 'activexcontrols' => string '' (length=0) 'isbanned' => string '' (length=0) 'ismobiledevice' => string '' (length=0) 'issyndicationreader' => string '' (length=0) 'crawler' => string '' (length=0) 'cssversion' => string '0' (length=1) 'supportscss' => string '' (length=0) 'aol' => string '' (length=0) 'aolversion' => string '0' (length=1)

Jak widać, funkcja nie zwraca żadnych informacji dla tej nowej przeglądarki. Dzieje się tak dlatego, że plik browscap.ini załączony do serwera WAMP (Windows, Apache, MySQL, PHP) ma już ponad rok. Rozwiązaniem problemu jest pobranie aktualnej wersji pliku. Może także być potrzebny restart serwera, jeżeli plik zostanie złożony w pamięci podręcznej. Po aktualizacji pliku otrzymamy dokładniejsze informacje, pokazane na listingu 3.3. Listing 3.3. Wynik dla przeglądarki Chrome po aktualizacji pliku browscap.ini Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.65 Safari/534.24 array 'browser_name_regex' => string '§^mozilla/5\.0 \(.*windows nt 6\.1.*wow64.*\) ´applewebkit/.*\(khtml, like gecko\).*chrome/11\..*safari/.*$§' (length=108) 'browser_name_pattern' => string 'Mozilla/5.0 (*Windows NT 6.1*WOW64*) AppleWebKit/* (KHTML, ´like Gecko)*Chrome/11.*Safari/*' (length=90) 'parent' => string 'Chrome 11.0' (length=11) 'platform' => string 'Win7' (length=4) 'win32' => string '' (length=0) 'win64' => string '1' (length=1) 'browser' => string 'Chrome' (length=6) 'version' => string '11.0' (length=4) 'majorver' => string '11' (length=2) 'frames' => string '1' (length=1) 'iframes' => string '1' (length=1) 'tables' => string '1' (length=1) 'cookies' => string '1' (length=1)

49

ROZDZIAŁ 3. „ MOBILNE PHP

'javascript' => string '1' (length=1) 'javaapplets' => string '1' (length=1) 'cssversion' => string '1' (length=1) 'minorver' => string '0' (length=1) 'alpha' => string '' (length=0) 'beta' => string '' (length=0) 'win16' => string '' (length=0) 'backgroundsounds' => string '' (length=0) 'vbscript' => string '' (length=0) 'activexcontrols' => string '' (length=0) 'isbanned' => string '' (length=0) 'ismobiledevice' => string '' (length=0) 'issyndicationreader' => string '' (length=0) 'crawler' => string '' (length=0) 'aolversion' => string '0' (length=1)Using Regex

Jeżeli zależy Ci na sprawdzeniu tylko kilku głównych urządzeń mobilnych, możesz wykorzystać wyrażenia regularne w celu przeszukania nagłówka aplikacji klienckiej. Na listingu 3.4 sprawdzamy, czy zapytanie przyszło z jednego z popularnych telefonów. Jeżeli łańcuch zostanie znaleziony, przekierowujemy żądanie do odrębnej strony przeznaczonej dla urządzeń mobilnych oraz ładujemy alternatywny szablon i arkusz stylów. Opcja /i w wyrażeniu regularnym (Regex) powoduje, że nasze zapytanie ignoruje wielkość znaków. Znak | oznacza „lub” — zostanie znaleziony zarówno łańcuch „iPhone”, jak i „iPad”, ale nie „iPod”. Podobnie będą znalezione „windows ce” oraz „windows phone”, ale nie „windows xp”. Zajrzyj do dodatku „Wyrażenia regularne”. Listing 3.4. Wykorzystanie wyrażeń regularnych w celu zweryfikowania urządzeń mobilnych

Aby wykryć więcej urządzeń, potrzebujemy znacznie większego wyrażenia regularnego. Możemy skorzystać z popularnej strony http://detectmobilebrowsers.com/, pozwalającej generować wyrażenie regularne w kilku różnych językach programowania i dla różnych frameworków. Wygenerowany skrypt przekieruje klienta na witrynę przeznaczoną dla urządzeń mobilnych. Listing 3.5 pokazuje przykładowy skrypt wygenerowany przez wyżej wymienioną stronę. Listing 3.5. Wyrażenie regularne wygenerowane przez stronę detectmobilebrowsers.com

To rozwiązanie będzie poprawne tylko w niektórych przypadkach. Aby uzyskać dokładniejsze wyniki oraz rozpoznać możliwości urządzenia, potrzebny jest zaawansowany system. Ten system to WURFL, omówiony w kolejnym podrozdziale.

Rozpoznawanie możliwości urządzenia System WURFL pozwala wyjść poza proste wykrywanie rodzaju urządzenia i ustalić, jakie są jego możliwości.

WURFL Wireless Universal Resource FiLe (WURFL) jest plikiem XML opracowanym przez Luca Passaniego, zawierającym informacje o możliwościach urządzeń mobilnych.

Wprowadzenie Aktualnie w pliku WURFL jest ponad pięćset różnych właściwości urządzeń mobilnych. Implementacje WURFL zostały opracowane w wielu językach i na wiele platform, włączając w to Javę i .NET. Dla PHP oficjalne API to The New PHP WURFL API, dostępne pod adresem http://wurfl.sourceforge.net/nphp/. Właściwości urządzeń są ułożone hierarchicznie. Jeżeli właściwość nie jest wyszczególniona dla danego modelu, to sprawdzany jest ogólniejszy typ urządzenia. Jeśli właściwość ponownie nie zostanie znaleziona, WURFL sprawdza kolejny ogólniejszy typ urządzenia i powtarza ten proces, dopóki nie dotrze do korzenia pliku. Struktura hierarchiczna oszczędza przestrzeń na dysku i przyspiesza wyszukiwanie. WURFL próbuje także wykorzystywać wersje pliku XML spakowaną za pomocą ZipArchiwe, pakietu dostępnego w PHP od wersji 5.2.0. Ponieważ wersja ZIP pliku ma aktualnie poniżej megabajta (MB), a wersja rozpakowana pliku ponad 16 MB, jest to duże usprawnienie. Niektóre użyteczne właściwości to rozdzielczość ekranu, kodeki i formaty lub wsparcie dla JavaScriptu, Javy czy Flasha. „ UWAGA. Plik XML jest tworzony głównie przez developerów i użytkowników, więc może zawierać błędy. Ponadto na rynek ciągle trafiają nowe urządzenia. Pomimo rozmiarów i kompletności pliku WURFL nie powinniśmy nigdy ufać mu w stu procentach. Jeżeli potrzebujesz szybko wykorzystać informacje o urządzeniu, możesz wyszczególnić jego właściwości oraz umieścić informacje o nim w głównym pliku XML. Jeżeli dokładność informacji ma kluczowe znaczenie, można użyć systemów o znacznie większej skuteczności.

Instalacja Na potrzeby wszystkich przykładów z tego rozdziału umieścimy bibliotekę WURFL w katalogu wurfl, który będzie się znajdował w głównym katalogu web jako ./wurfl/. Wykorzystamy standardowy plik konfiguracyjny, a obiekt WURFLManager będziemy za każdym razem pozyskiwać za pomocą kodu z listingu 3.6.

51

ROZDZIAŁ 3. „ MOBILNE PHP

Listing 3.6. Utworzenie obiektu WURFLManager: wurflSetup.php

Rozpoznawanie urządzeń za pomocą WURFL W naszym pierwszym przykładzie rozpoznawania urządzenia wyświetlimy stos urządzenia przy wykorzystaniu WURFL PHP API. Wyświetlimy hierarchię aplikacji klienckiej z zastosowaniem właściwości fallback oraz id (listing 3.7). Listing 3.7. Wyświetlenie stosu dla aplikacji klienckiej od szczegółowej do ogólnej

Poniżej znajduje się wynik działania skryptu na komputerze stacjonarnym dla przeglądarki Firefox 4: Stos Id: firefox_1 firefox generic_web_browser generic_xhtml generic

oraz dla przeglądarki Chrome: Stos Id: google_chrome_1 google_chrome generic_web_browser generic_xhtml generic

52

ROZDZIAŁ 3. „ MOBILNE PHP

„ UWAGA. Uruchomienie skryptu po raz pierwszy może zająć dużo czasu, ponieważ WURFL buduje bufor. Konieczne może być zwiększenie wartości dla dyrektywy max_execution_time w pliku php.ini.

Jeżeli chcemy emulować inne urządzenie, możemy wprowadzić inną zmienną serwerową zawierającą nagłówek aplikacji klienckiej. Zmodyfikowana wersja listingu 3.7 pokazana jest na listingu 3.8. Wynik skryptu przedstawiono na listingu 3.9. Listing 3.8. Emulowanie innego urządzenia — wprowadzenie innej zmiennej serwerowej

Listing 3.9. Wynik działania WURFL dla emulowanego iPhone’a 4 Stos ID: apple_iphone_ver4_sub405 apple_iphone_ver4 apple_iphone_ver3_1_3 apple_iphone_ver3_1_2 apple_iphone_ver3_1 apple_iphone_ver3 apple_iphone_ver2_2_1 apple_iphone_ver2_2 apple_iphone_ver2_1 apple_iphone_ver2 apple_iphone_ver1 apple_generic generic_xhtml generic

Rozpoznawanie i wyświetlanie właściwości urządzenia za pomocą WURFL Na listingu 3.10 pokazano dostępne grupy właściwości, które możemy sprawdzić. Wyświetlimy wszystkie dostępne właściwości dla grup display i css. Wynik pokazany jest na listingu 3.11. Listing 3.10. Wyświetlanie dostępnych grup atrybutów

Listing 3.11. Wynik działania skryptu z listingu 3.10 ajax bearer bugs cache chtml_ui css display drm flash_lite html_ui image_format j2me markup mms object_download pdf playback product_info rss security sms sound_format storage streaming transcoding wap_push wml_ui wta xhtml_ui

Aby wyświetlić listę wszystkich dostępnych właściwości, możemy zmodyfikować skrypt z listingu 3.10, tak by wykorzystywał metodę getCapabilitiesNameForGroup. Zmodyfikowany skrypt pokazany jest na listingu 3.12. Początkowa część wyniku widnieje na listingu 3.13. Listing 3.12. Wyświetlanie listy wszystkich właściwości, które mogą być sprawdzone

54

ROZDZIAŁ 3. „ MOBILNE PHP

Listing 3.13. Początek wyniku skryptu z listingu 3.12 ajax array 0 => 1 => 2 => 3 => 4 => 5 => 6 => 7 => 8 => bearer array 0 => 1 => 2 => 3 => 4 => …

string string string string string string string string string

'ajax_preferred_geoloc_api' (length=25) 'ajax_xhr_type' (length=13) 'ajax_support_getelementbyid' (length=27) 'ajax_support_event_listener' (length=27) 'ajax_manipulate_dom' (length=19) 'ajax_support_javascript' (length=23) 'ajax_support_inner_html' (length=23) 'ajax_manipulate_css' (length=19) 'ajax_support_events' (length=19)

string string string string string

'sdio' (length=4) 'wifi' (length=4) 'has_cellular_radio' (length=18) 'max_data_rate' (length=13) 'vpn' (length=3)

Możemy zmodyfikować skrypt z listingu 3.12 tak, aby wyświetlały się tylko niektóre właściwości urządzenia, by wspierane właściwości były oznaczone kolorem zielonym i znacznikami (renderowanymi przez encje HTML) oraz by niewspierane właściwości były oznaczone kolorem czerwonym i przekreśleniem (listing 3.14). Wynik pokazany jest na rysunku 3.1. Listing 3.14. Wyświetlanie właściwości urządzeń wraz z kolorowaniem



WALL jest super

Nagłówek

To będzie paragraf w HTML



  • A
  • B




  • 61

    ROZDZIAŁ 3. „ MOBILNE PHP

    Reagujący CSS Aby rozmieszczenie elementów na stronie było odpowiednie dla urządzenia, możemy zastosować pływające kontenery oraz zmieniać rozmiar zdjęć, jak pokazano powyżej. Możemy także wykorzystać arkusze przeznaczone specjalnie dla urządzeń mobilnych. Niedawnym usprawnieniem w CSS są zapytania o media. Właściwości, jakie można sprawdzić, to width, height, device-width, device-height, orientation, aspect-ratio, device-aspect-ratio, color, color-index, monochrome, resolution, scan i grid (listing 3.21). Listing 3.21. Przykładowe zapytania o media za pomocą CSS3 @media screen and (min-device-width:400px) and (max-device-width:600px){ /* ograniczenie szerokości urządzenia */ } @media screen and (orientation:landscape){ /* dobre dla urządzeń mogących działać w dwóch płaszczyznach, takich jak iPad i Kindle */ }

    Głębsza analiza CSS wyszłaby poza zakres tej książki, jednakże pod adresem http://www.netmagazine.com/ tutorials/adaptive-layouts-media-queries dostępny jest doskonały artykuł. Opisane tam techniki mogą usprawnić wyświetlanie stron na urządzeniach mobilnych. Więcej informacji dotyczących zapytań o media w CSS3 znajduje się pod adresem http://www.w3.org/TR/css3-mediaqueries/.

    Emulatory i SDK W ramach pomocy dla twórców mających ograniczony budżet, niepozwalający na zakup telefonów na potrzeby testów, oraz w celu ułatwienia pracy powstało wiele emulatorów i zestawów narzędzi dla programistów (Software Developer Kit — SDK) piszących aplikacje przeznaczone dla urządzeń mobilnych. Niektóre narzędzia emulują jedno urządzenie, inne kilka jednocześnie. Oto wybrane adresy, pod którymi są one dostępne: • Android: http://developer.android.com/guide/developing/tools/emulator.html • Apple: http://developer.apple.com/devcenter/ios/index.action • BlackBerry: http://www.blackberry.com/developers/downloads/simulators/ • Kindle: http://www.amazon.com/kdk/ • Opera Mini: http://www.opera.com/mobile/demo/ • Windows: http://create.msdn.com/en-us/resources/downloads

    Tworzenie dla systemu Android System Android wydany przez Google może uruchamiać aplikacje w Java i natywnym C. Projekt warstwy skryptów dla Androida (SL4A) dostępny pod adresem http://code.google.com/p/android-scripting/ pozwala na tworzenie aplikacji w językach skryptowych. Jednakże PHP aktualnie nie należy do wspieranych języków. Aby tworzyć aplikacje dla Androida w PHP, możemy wykorzystać projekt open source PHP for Android, dostępny pod adresem http://www.phpforandroid.net/. Narzędzie to oferuje nieoficjalne wsparcie dla PHP wewnątrz SL4A poprzez plik APK (Android Package).

    Adobe Flash Builder dla PHP Niedawno Zend ogłosiło połączenie sił z Adobe w celu wprowadzenia wsparcia dla PHP w aplikacji Flash Builder 4.5 (rysunek 3.3). Więcej informacji o Flash Builder dla PHP można znaleźć pod adresem http://www.zend.com/en/ products/studio/flash-builder-for-php/. Flash Builder dla PHP zawiera Zend Studio w zintegrowanym środowisku programistycznym (IDE). Jako frontend może być wykorzystany Flex, natomiast jako backend — PHP. 62

    ROZDZIAŁ 3. „ MOBILNE PHP

    Rysunek 3.3. Ogłoszenie dotyczące programu Flash Builder na stronie Zend IDE ma ułatwiać tworzenie kodu i zapewniać lepszą jego przenośność pomiędzy platformami mobilnymi. Może nawet skompilować kod Flex, tak aby był wykonywany natywnie na urządzeniach opartych na systemie iOS, takich jak iPhone i iPad.

    Kody QR Kody QR (Quick Response) są czymś w rodzaju dwuwymiarowego kodu kreskowego. Zostały wprowadzone w Japonii ponad dwadzieścia lat temu w celu katalogowania części samochodowych. Nowoczesne urządzenia mobilne z wbudowanymi aparatami fotograficznymi przyczyniły się do rozpowszechnienia tego rozwiązania. Kod QR zazwyczaj reprezentuje adres URL, ale może zawierać więcej tekstu. Pokażemy, w jaki sposób łatwo wygenerować kody QR za pomocą trzech różnych bibliotek. Dwie z nich, TCPDF i Google Chart API, są omówione dokładniej w rozdziale 10. Pierwsza biblioteka, za której pośrednictwem wygenerujemy kod QR, jest dostępna pod adresem http://www.tcpdf.org/. Za pomocą TCPDF możemy wygenerować kod QR jako PDF, nie możemy jednak generować kodów jako odrębnych plików graficznych. Zobacz listing 3.22 i rysunek 3.4 przedstawiający wygenerowany kod QR. Listing 3.22. Generowanie kodu QR w pliku PDF przy wykorzystaniu biblioteki TCPDF

    63

    ROZDZIAŁ 3. „ MOBILNE PHP

    Rysunek 3.4. Kod QR dla ciągu znaków „Witaj, świecie kodów QR”. Każda biblioteka powinna wygenerować taki sam obrazek Aby zapisać kod QR do pliku, możemy wykorzystać bibliotekę phpqrcode, dostępną pod adresem http://phpqrcode.sourceforge.net/index.php (listing 3.23). Listing 3.23. Generowanie kodów QR bezpośrednio do pliku lub przeglądarki za pośrednictwem phpqrcode

    Możemy także wykorzystać Google Chart API znajdujące się pod adresem http://code.google.com/p/gchartphp/ (listing 3.24). Listing 3.24. Generowanie kodów QR za pośrednictwem biblioteki qrcodephp

    Podsumowanie W tym rozdziale omówiliśmy rozpoznawanie urządzeń mobilnych i ich właściwości. Obecnie nie ma idealnego systemu wykrywania urządzeń, jednak to, co mamy, jest względnie niezawodne. Programista powinien być czujny i mieć aktualne pliki, niezależnie od tego, czy wykorzystuje browscap, WURFL, czy inny system. Pokazaliśmy także narzędzia do tworzenia abstrakcyjnego kodu, automatycznej zmiany rozmiarów obrazków oraz płynnej zmiany rozmiarów zawartości strony. Kiedy tylko jest to możliwe, używaj narzędzi, które wykonają pracę za Ciebie. Mogą one sprawdzić, jakie urządzenie zostało użyte i co ono potrafi; mogą też pomóc w ustaleniu, w jaki sposób przetransformować istniejące style, obrazki i kod. Automatyzacja i przydatne biblioteki powinny być stosowane we wszystkich dziedzinach tworzenia oprogramowania. Technologie mobilne ciągle się rozwijają, więc także i metody tworzenia oprogramowania szybko ulegają zmianie. Aby zostać dobrym twórcą oprogramowania dla urządzeń mobilnych, musisz przyswajać sobie dobre praktyki, poznawać najnowsze technologie oraz wchodzące na rynek SDK i API.

    64

    ROZDZIAŁ 4 „„„

    Media społecznościowe

    Media społecznościowe wykorzystują technologię na potrzeby społecznej interakcji i współpracy. Dwa najpopularniejsze portale społecznościowe, Twitter i Facebook, zrzeszają miliony użytkowników. Nakręcono nawet film o powstaniu Facebooka. Z kolei Twitter, który zaczął działać w roku 2006, stał się najpopularniejszą na świecie platformą mikroblogową. Pojawiły się już miliardy twittów (wiadomości mających mniej niż 140 znaków), wpisywanych przez internet lub za pośrednictwem SMS-ów. Facebook, nieprawdopodobnie szybko rozwijające się przedsięwzięcie Marka Zuckerberga, skupia na sobie powszechną uwagę — magazyn „Time” ogłosił Zuckerberga człowiekiem roku, film The Social Network ma wysoką oglądalność, w mediach nieustannie mówi się o portalu (często jest dyskutowana tematyka prywatności). Zarówno Facebook, jak i Twitter uwierzytelniają użytkowników za pomocą OAuth. W tym rozdziale będzie wyjaśnione, czym jest OAuth i jak się z nim połączyć. Twitter udostępnia trzy interfejsy programistyczne (API). Istnieje API publicznego wyszukiwania, GET wykorzystujący zapytania oraz dwa REST API, z których jedno dostarcza informacje o użytkownikach i akcjach wewnątrz sieci prywatnej, a drugie zapewnia strumieniowanie dużych wolumenów z niską latencją. Pokażemy tu, w jaki sposób używać publicznego oraz prywatnego API po wcześniejszym zalogowaniu. Na Twitterze możesz mieć przyjaciół zdefiniowanych jako osoby, które Cię śledzą (follow); podobnie Ty możesz śledzić ich. Pokażemy Ci, jak wygenerować listę przyjaciół z Twittera wraz z ich statusami. Omówimy także zaawansowane sposoby powiązania loginu z Twittera z uwierzytelnianiem na Twojej stronie przy wykorzystaniu bazy danych do przechowywania danych użytkowników. Przeanalizujemy ponadto zastosowanie bazy jako bufora służącego do ochrony przed zbyt dużą liczbą zapytań do Twittera. Facebook udostępnia dobrze zaprojektowane API i oficjalne PHP SDK. Dowiesz się z tego rozdziału, jak opracować nową aplikację na Facebooku, poznasz metodę uwierzytelniania oraz przykładowe zapytania wykonywane przez API.

    OAuth Nazwa „OAuth” jest skrótem od Open Authentication („otwarte uwierzytelnianie”). OAuth wykorzystuje klucze wygenerowane dla aplikacji, które są ważne przez dany okres. Uwierzytelnianie to zachodzi pomiędzy aplikacją kliencką a usługodawcą. Podstawowe etapy uwierzytelniania za pośrednictwem OAuth są następujące: 1. Aplikacja OAuth wysyła token klienta do usługodawcy (np. Facebooka lub Twittera) — w zamian odbiera tokeny żądania. 2. Użytkownik udziela żądanych uprawnień. 3. Do sprawdzenia zapytania o uprawnienia jest wykorzystywany URL zwrotny lub numer identyfikacyjny użytkownika (PIN).

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    4. Tokeny żądania i PIN są wymieniane na tokeny dostępu. 5. Użytkownik może korzystać z aplikacji z tokenami dostępu. „ UWAGA. Więcej informacji dotyczących OAuth można uzyskać pod adresem http://oauth.net/. Dobrym źródłem w Twitterze jest strona https://dev.twitter.com/docs/auth. Gdy powstawała ta książka, dwoma najpopularniejszymi modułami OAuth dla PHP były PECL OAuth i Zend_Oauth. Informacje dotyczące PECL OAuth można znaleźć pod adresem http://www.php.net/manual/en/book.oauth.php, natomiast o Zend_Oauth pod adresem http://framework.zend.com/manual/en/zend.oauth.html.

    Twitter zapewnia trzy mechanizmy dotyczące OAuth. Jeżeli potrzebujesz tylko połączyć się z kontem właściciela aplikacji, otrzymasz tokeny dostępowe, które można wykorzystać bezpośrednio. Dzięki temu będziesz mógł pominąć pierwsze cztery kroki wymienione powyżej. Jeżeli Twoja aplikacja pozwala wielu użytkownikom uzyskać dostęp do ich kont, możesz albo zastosować metodę sprawdzania numeru PIN dla aplikacji klienckich, albo zdefiniować stronę z odwołaniem zwrotnym, która wyeliminuje konieczność uwierzytelniania się użytkownika. Zajmiemy się tymi metodami w dalszej części tego rozdziału.

    Twitter API publicznego wyszukiwania Aby wyszukiwać tweety, nie musimy być uwierzytelniani. Zgodnie z dokumentacją Twittera, dostępną pod adresem https://dev.twitter.com/docs/api/1/get/search, adres URL wyszukiwania to http://search.twitter.com/search.format, natomiast przyjęte formaty to JSON i Atom. Można ustawić opcjonalne parametry, takie jak język, geokod, początkowy i końcowy interwał czasowy oraz miejsce. Zapytanie wyszukujące reprezentowane jest przez q. Wykorzystywana jest standardowa notacja Twittera — @ dla użytkowników, # dla tagów. Zapytanie http://search.twitter.com/search.json?q=montreal&lang=en&until=2010-10-21 zwróciłoby wszystkie posty ze słowem „montreal” napisane po angielsku utworzone przed 21 października 2010 r. Listing 4.1 przedstawia prosty formularz wyszukiwania postów na Twitterze. Listing 4.1. Przykład wyszukiwania twitter_get_search.php



    zapytanie:    





    Pierwsza część skryptu z listingu 4.1 wyświetla prosty formularz, zawierający pole tekstowe przeznaczone do wprowadzania zapytania oraz przycisk zatwierdzający wysłanie formularza. Kolejna część sprawdza zatwierdzenie formularza i koduje zapytanie. Następnie funkcja file_get_contents pobiera wynik z wygenerowanego adresu URL. Aby przekonwertować obiekt w formacie JSON na obiekt PHP, stosujemy funkcję json_dekode. Zostawiliśmy część kodu w postaci komentarza, który może posłużyć w zidentyfikowaniu dostępnych pól. Rezultat wykorzystywany jest w pętli, a jego elementy wyświetlane są w formie tabeli HTML. Zwróć uwagę na wywołanie error_reporting(E_ALL ^ E_NOTICE); na początku skryptu, które powoduje wyświetlenie wszystkich informacji o błędach poza zawiadomieniami (notice). To pomoże nam w znalezieniu błędu, gdyby coś poszło nie tak. Więcej informacji o JSON można znaleźć w rozdziale 15.

    Prywatne REST API W PHP napisano wiele bibliotek przeznaczonych do współpracy z API Twittera. Większość z tych rozwiązań wykorzystuje kombinację loginu i hasła jako metodę uwierzytelniania w celu połączenia. Od sierpnia 2010 r. Twitter używa do uwierzytelniania mechanizmu OAuth i nie obsługuje uwierzytelniania podstawowego. W związku z tym większość bibliotek do współpracy z Twitterem jest przestarzała lub wymaga aktualizacji. Powodem zmiany uwierzytelniania podstawowego na uwierzytelnianie OAuth była potrzeba zwiększenia bezpieczeństwa. Jedną z najczęściej stosowanych bibliotek współpracujących z API Twittera i OAuth jest biblioteka twitteroauth, dostępna pod adresem https://github.com/abraham/twitteroauth/downloads. W tym rozdziale będziemy korzystać właśnie z tej biblioteki. Biblioteka twitteroauth składa się z dwóch głównych plików, twitteroauth.php i oauth.php. Na potrzeby przykładów umieść oba pliki w katalogu /twitteroauth/ będącym podkatalogiem głównego katalogu web. Musisz także mieć zainstalowaną bibliotekę CURL dla PHP. Wymagane pliki będą się różniły w zależności od tego, jaki masz system. W systemie Windows biblioteka to php_curl.dll; w pliku php.ini musisz dodać lub włączyć linię extension=php_curl.dll. W przypadku Linuksa plik biblioteki to curl.so, a w php.ini niezbędna jest linia extension=php_curl.dll. Możesz także sprawdzić zainstalowane moduły przy wykorzystaniu komendy php –m w wierszu poleceń lub przez wywołanie funkcji php_info.

    Zakładanie konta na Twitterze Aby wykonywać przykłady z tego rozdziału, będziesz potrzebował konta na Twitterze. Rejestracja jest szybka i prosta, przeprowadza się ją pod adresem https://twitter.com/signup. Otrzymasz wiadomość e-mail z potwierdzeniem rejestracji. Po uaktywnieniu swojego konta przejdź do części dla developerów: http://dev. twitter.com/. Pod adresem http://dev.twitter.com/apps/new utworzymy nową aplikację do współpracy z OAuth (rysunek 4.1).

    67

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    Rysunek 4.1. Tworzenie nowej aplikacji „ UWAGA. Twitter wymaga, aby pole dotyczące strony aplikacji zostało wypełnione. Jeżeli testujesz aplikację lokalnie lub nie masz własnej strony, wpisz po prostu dowolny poprawny adres WWW, np. http://test.pl.

    Na potrzeby pierwszego przykładu zastosujemy poniższe ustawienia: Default Access Type: Read-only

    Dostępne są dwa typy aplikacji: „client” oraz „browser”. Aplikacja typu „browser” wykorzystuje publiczny adres odwołania zwrotnego; pod tym adresem są odbierane informacje w procesie uwierzytelniania. Aplikacja „client” nie wymaga zewnętrznego dostępu dla usługi OAuth, aby się z nią skomunikować. Zamiast tego przyznawany jest kod PIN, który użytkownik musi podać, aby zakończyć proces uwierzytelniania. Typ dostępu może zostać ustawiony na „read-only” (tylko odczyt — domyślnie) lub „read and write” (odczyt i zapis). Typ „read-only” pozwala na żądanie i odczytywanie informacji, a tryb „read and write” także na wysyłanie informacji z powrotem do aplikacji. Twitter wygeneruje klucz klienta i tajny token klienta, które będziemy wykorzystywać w naszych przykładach (rysunek 4.2). Większość przykładów z tego rozdziału wymaga wykorzystania tokenów użytkownika, więc dla wygody umieścimy je w zewnętrznym pliku (listing 4.2). Listing 4.2. Zdefiniowanie tokenów użytkownika w pliku twitter_config.php

    68

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    Rysunek 4.2. Wygenerowane przez Twitter tokeny użytkownika

    Uwierzytelnianie przy użyciu tokenu dostępu Na dole strony naszej aplikacji widnieje link tworzący token dostępu (Create my access token). Dzięki temu otrzymamy token dostępu i tajny token dostępu — będziemy mogli przeprowadzić uwierzytelnianie bez standardowych kroków OAuth (rysunek 4.3).

    Rysunek 4.3. Tokeny bezpośredniego dostępu dla użytkownika Dzięki tokenom możemy nawiązać połączenie za pośrednictwem biblioteki twitteroauth (listing 4.3). Listing 4.3. Proste uwierzytelnianie za pośrednictwem twitteroauth oraz tokenów dostępu — twitter_direct_access.php

    Powyższy skrypt ładuje bibliotekę twitteroauth i przekazuje token dostępu, tajny token dostępu oraz token użytkownika jako parametry. Musisz oczywiście wstawić prawdziwe wartości w miejsce TOKEN_DOSTEPU i TAJNY_TOKEN_DOSTEPU. Poprawne wykonanie powyższego skryptu spowoduje wyświetlenie linii: Witaj, bdanchilla!

    „ UWAGA. Ważne jest, aby chronić swoje tokeny użytkownika i tokeny dostępu przed osobami niepowołanymi.

    Uwierzytelnianie przy wykorzystaniu osobistego numeru identyfikacyjnego (PIN) W tym przykładzie założymy, że uwierzytelnić się próbuje inny użytkownik. W związku z tym nie mamy naszych tokenów dostępu. Do konstruktora twitteroauth przekażemy nasze tokeny klienta, otrzymamy tokeny żądania, a następnie przekierujemy żądanie do części deweloperskiej Twittera. Otrzymamy informację, że skrypt próbuje uzyskać dostęp do aplikacji, i pojawi się pytanie o akceptację lub odrzucenie dostępu. Oczywiście zaakceptujemy prośbę o uzyskanie dostępu i otrzymamy numer PIN. Wprowadzenie tego siedmiocyfrowego PIN-u w drugim skrypcie zakończy rejestrację. Te czynności wykonujemy tylko jeden raz. Metoda ta jest stosowana przy uwierzytelnianiu w niepublicznych skryptach, takich jak aplikacja stacjonarna, lub lokalnie, bez udostępnionej publicznej domeny. W bibliotece twitteroauth możemy wykorzystać PIN, przekazując go jako parametr do funkcji getAccessToken: function getAccessToken($oauth_verifier = FALSE);

    W celu uzyskania PIN-u musimy wymienić tokeny klienta na tokeny żądania, a następnie je zarejestrować. Kiedy już będziemy mieć PIN, musimy użyć go wraz z tokenami klienta do uzyskania tokenów dostępu. Gdy otrzymamy tokeny dostępu, będziemy mogli się uwierzytelnić i korzystać z API.

    Krok 1. Uzyskanie numeru PIN Listing 4.4. Rejestracja — twitter_registration.php

    70

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    Skrypt otrzyma tokeny żądania, które zostaną zapisane w zmiennej $_SESSION, i przekieruje nas na stronę zawierającą nasz numer PIN (rysunek 4.4).

    Rysunek 4.4. PIN podany po przekierowaniu na stronę rejestracji

    Krok 2. Sprawdzenie numeru PIN w celu uzyskania tokenów dostępu W celu uzyskania tokenów uruchom skrypt z listingu 4.5, przekazując PIN jako parametr GET. Listing 4.5. Sprawdzenie numeru PIN — twitter_pin_validation.php

    71

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    W skrypcie z listingu 4.5 wprowadziliśmy dodatkowe zabezpieczenie, sprawdzające, czy podany numer PIN jest prawidłowy. W przypadku poprawnego zadziałania skryptu otrzymamy informację: „Skrypt walidacji numeru PIN został uruchomiony”; w razie wystąpienia błędu wyświetli się stosowny komunikat. Błąd może być spowodowany brakiem numeru PIN, wprowadzeniem niepoprawnego numeru PIN lub zakończeniem czasu jego ważności. Skrypt ładuje tokeny zapisane podczas wykonywania skryptu z listingu 4.4. Tworzy nowy obiekt TwitterOAuth, tym razem przekazując tokeny żądania oraz dodatkowe parametry. Możemy następnie wywołać metodę getAccessToken, przekazując nasz PIN jako parametr. Otrzymamy tokeny dostępu. Na końcu zapisujemy uzyskane tokeny w sesji lub zwracany jest błąd w przypadku zakończenia ważności numeru PIN. „ UWAGA. Numer PIN wygenerowany za pomocą skryptu z listingu 4.5 ma określony czas ważności. Jeżeli wywołanie skryptu twitter_sprawdzenie_pin.php nastąpi zbyt późno, pojawi się komunikat o błędzie.

    Mimo że OAuth jest bezpieczniejsze niż standardowa autoryzacja oparta na kombinacji loginu i hasła, nadal należy zachować ostrożność. Jeżeli komuś uda się dotrzeć do Twoich tokenów dostępu, będzie mógł uzyskać dostęp do Twojego konta.

    Krok 3. Uwierzytelnianie przy zastosowaniu tokenów dostępu dla Twitter API Mamy już dostęp do tokenów, które zostały zapisane w sesji. Pozwolą nam one na uwierzytelnianie i użycie API (listing 4.6). Listing 4.6. Przykładowe wykorzystanie Twittera — twitter_usage.php

    Jeżeli uwierzytelnianie przebiegnie prawidłowo, otrzymamy następujący wynik: Witaj, bdanchilla! Wstawianie informacji o statusie.

    72

    ROZDZIAŁ 4. „ MEDIA SPOŁECZNOŚCIOWE

    Linia: $twitterOAuth->post( 'statuses/update', array( 'status' => "Wstawianie statusu…foobar." )

    powinna wstawić informację o statusie. Jeżeli jednak wejdziemy na nasze konto, zobaczymy, że nic nie zostało opublikowane. Dzieje się tak dlatego, że nasza aplikacja nie ma uprawnień do zapisu. Metody REST API są albo typu GET, albo typu POST. Metody typu GET odczytują dane. Metody typu POST zapisują dane. Większość naszych wywołań funkcji będzie dotyczyć odczytu danych i dlatego funkcje te będą wywoływane za pomocą GET. Edytowanie informacji, np. wystawianie nowego statusu lub śledzenie kogoś nowego, wymaga uprawnień do zapisu, czyli wywołania POST. Aby to poprawić, musimy przejść z powrotem na stronę dla developerów i zmienić dla naszej aplikacji domyślny typ dostępu z Read only na Read and Write (rysunek 4.5). Upewnij się, że zapisałeś zmiany w konfiguracji. „ UWAGA. Jeżeli zmieniasz typ aplikacji lub typ dostępu, może być konieczne usunięcie danych sesji.

    Rysunek 4.5. Modyfikacja typu dostępu dla aplikacji Uruchom ponownie poprzedni skrypt. Nowy status powinien zostać przekazany.

    Przykładowe wykorzystanie API — statusy przyjaciół W kolejnym przykładzie, pokazanym na listingu 4.7, wyświetlimy ostatnie statusy naszych przyjaciół. Połączymy się z API tak jak poprzednio. Następnie wywołamy statuses/friends, co zwróci ostatnie statusy naszych przyjaciół. Jest to zbliżone do przykładu wyszukiwania za pośrednictwem publicznego API, jednak pokazuje naszych przyjaciół, a nie wszystkie osoby. Wywołamy także shuffle($friends), aby lista przyjaciół była losowa. Listing 4.7. Wyświetlenie ostatniego statusu przyjaciół — friend_status.php

    Po wczytaniu dokumentu z listingu 14.3 zmienna $xml_obiekt reprezentuje element główny dokumentu — . Dokument jest reprezentowany przez obiekt SimpleXMLElement, dzięki czemu możemy przeiterować po elementach potomnych w pętli foreach. Wynik działania skryptu z listingu 14.3 jest następujący: typ: pies imie: reksio

    Listing 14.4 prezentuje przykład operacji na bardziej złożonym dokumencie XML. Listing 14.4. Bardziej złożony przykład — listing14_4.php

    Wynik działania skryptu jest następujący: reksio azor

    Większość kodu z listingu 14.4 to wykorzystanie składni heredoc do zapisania dokumentu XML w czytelny sposób. Właściwy kod wyszukujący odpowiednie wartości to zaledwie parę linii. SimpleXML jest wystarczająco sprytne, aby przeiterować po wszystkich elementach pies, nawet pomimo elementu kot wstawionego pomiędzy nie.

    Parsowanie XML z pliku Podczas wczytywania XML-a PHP zgłosi błąd wraz z pomocnym komunikatem, jeżeli dokument jest niepoprawny. Wiadomość może informować, że musisz zamknąć tag lub zamienić encję, wskaże także numer linii, w której występuje błąd (listing 14.5). Listing 14.5. Prosty komunikat PHP informujący o błędzie w dokumencie Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser error : ´attributes construct error in E:\xampp\htdocs\xml\zwierzeta.php on line 29

    Kolejne dwa przykłady dotyczą wczytania pliku XML widocznego na listingu 14.6. Niektóre z elementów XML mają atrybuty. Na listingu 14.7 pokażemy, w jaki sposób znajdować wartości atrybutów przy użyciu kolejnych wywołań SimpleXML. Następnie zaprezentujemy na listingu 14.10, jak znaleźć wartość atrybutów przy wykorzystaniu XPath, którego zadaniem jest uproszczenie wyszukiwania. Listing 14.6. Prosty dokument XHTML — template.xhtml



    290

    ROZDZIAŁ 14. „ XML

    tutaj byłby nagłówek

    tutaj byłoby menu

    lewa kolumna

    główna zawartość

    prawa kolumna

    tutaj byłaby stopka



    Pierwsze dwie linie na listingu 14.6 definiują wykorzystaną wersję XML-a oraz DOCTYPE i nie są wczytywane do obiektu SimpleXMLElement jako część drzewa. Elementem głównym jest element . Skrypt 14.7 przedstawia zastosowanie metod SimpleXML do znalezienia elementu mającego atrybut id="glowna_srodek". Listing 14.7. Znalezienie atrybutu o zadanej wartości

    Skrypt z listingu 14.7 znajdzie wszystkie elementy zawarte wewnątrz elementu oraz elementy bezpośrednio im podległe. Dla każdego elementu wartość atrybutu id porównywana jest z wartością szukaną glowna_srodek. Jeżeli są równe, wyświetlamy wartość elementu i kończymy działanie pętli. Wynik działania skryptu jest następujący: wartość elementu #glowna_srodek to: główna zawartość

    Nie możemy po prostu wyświetlić zmiennej $element wewnątrz funkcji czyElementMaId, ponieważ wtedy wyświetlony zostałby cały obiekt SimpleXMLElement. object(SimpleXMLElement)[10] public '@attributes' => array 'id' => string 'glowna_srodek' (length=13) 'class' => string 'test' (length=4) string ' główna zawartość ' (length=50)

    Musimy więc rzutować zwracaną wartość z typu Object na String (pamiętaj, że rzutowanie konwertuje zmienną z jednego typu na inny). Zwróć uwagę, że zwracane są także białe znaki, więc musimy wykorzystać funkcję trim(). Do pobrania atrybutów możemy zastosować funkcję SimpleXML, attributes(), która zwraca obiekt z atrybutami. var_dump($element->attributes()); object(SimpleXMLElement)[9] public '@attributes' => array 'id' => string 'glowna_srodek' (length=13) 'class' => string 'test' (length=4)

    Także w przypadku wartości $element->attributes()->id musimy wykonać rzutowanie — w przeciwnym razie znowu otrzymamy obiekt klasy SimpleXMLElement. Kod z listingu 14.7 nie jest do końca poprawny. Jeżeli zmianie ulegnie struktura dokumentu lub poziom zagłębień będzie wyższy niż dwa, identyfikator nie zostanie znaleziony. Mogłeś zauważyć, że dokumenty XHTML zachowują obiektowy model dokumentu (DOM) znany z HTML-u. Istniejące parsery i oprogramowanie pozwalające poruszać się po drzewie, takie jak XPath czy XQuery, znacznie ułatwiają znajdowanie zagnieżdżonych elementów. XPath jest składnikiem biblioteki SimpleXML, ale także biblioteki PHP DOM. Przy wykorzystaniu SimpleXML zapytanie XPath wywoływane jest za pomocą funkcji $simple_xml_object->xpath(). W bibliotece DOM zapytanie XPath wykonuje się za pomocą tworzonego obiektu DOMXPath, wywołując jego metodę query. Na listingu 14.10 pokazano, w jaki sposób znaleźć szukany atrybut przy wykorzystaniu XPath. Najpierw pokażemy jednak, jak znaleźć elementy wybierane na listingach 14.3 i 14.4 — zobacz listing 14.8. Listing 14.8. Wyszukiwanie elementu przy użyciu XPath

    Wynik działania skryptu: pies typ: pies imie: reksio

    W pierwszej części skryptu z listingu 14.8 wybieramy element , będący potomkiem elementu , wykorzystując selektor XPath typ. Zwrócona zostanie tablica pasujących do zapytania obiektów typu SimpleXMLElement. W drugiej części wybieramy wszystkie elementy potomne elementu przy użyciu selektora /zwierze/* — gwiazdka oznacza dziką kartę. Kiedy obiekty SimpleXMLElement zostaną zwrócone z funkcji xpath(), możemy wypisać ich nazwy przy zastosowaniu metody getName(). „ UWAGA. Pełna specyfikacja selektorów XPath dostępna jest pod adresem http://www.w3.org/TR/xpath/.

    Na listingu 14.9 pokazano, jak znaleźć dany element potomny niezależnie od jego elementu nadrzędnego. Listing demonstruje także, jak znaleźć element nadrzędny elementu w obiekcie SimpleXMLElement. Listing 14.9. Wyszukiwanie elementów potomnych i nadrzędnych przy wykorzystaniu XPath

    Wynik działania skryptu jest następujący: reksio (pies) bzik (kot) azor (pies)

    Za pomocą zapytania XPath — */imie — dopasowaliśmy element , niezależnie od tego, czy zawarty był wewnątrz elementu , czy . Aby pobrać element nadrzędny elementu z obiektu SimpleXMLElement, zastosowaliśmy zapytanie ... Zamiast tego mogliśmy wykorzystać zapytanie parent::*. Listing 14.10. Wyszukiwanie atrybutu o zadanej wartości przy zastosowaniu XPath



    296

    ROZDZIAŁ 14. „ XML

    Wired Top Stories http://www.wired.com/rss/index.xml Top Stories en-us Copyright 2007 CondeNet Inc. All rights reserved. Sun, 27 Feb 2011 16:07:00 GMT

    Wired.com

    2011-02-27T16:07:00Z en-us Copyright 2007 CondeNet Inc. All rights reserved.

    Peers Or Not? Comcast And Level 3 Slug It Out At FCC's Doorstep http://feeds.wired.com/~r/wired/index/~3/QJQ4vgGV4qM/ pierwszy opis Sun, 27 Feb 2011 16:07:00 GMT http://www.wired.com/epicenter/2011/02/comcast-level-fcc/ Matthew Lasar 2011-02-27T16:07:00Z http://www.wired.com/epicenter/2011/02/comcast-level-fcc/

    360 Cams, AutoCAD and Miles of Fiber: Building an Oscars Broadcast http://feeds.wired.com/~r/wired/index/~3/vFb527zZQ0U/ drugi opis Sun, 27 Feb 2011 00:19:00 GMT http://www.wired.com/underwire/2011/02/oscars-broadcast/ Terrence Russell 2011-02-27T00:19:00Z http://www.wired.com/underwire/2011/02/oscars-broadcast/ … … …

    Aby zmniejszyć objętość dokumentu, zawartość elementu description została zamieniona. Jak widać, dokument RSS to po prostu XML. Istnieje wiele bibliotek pozwalających na parsowanie wiadomości XML — w rozdziale 10. pokazaliśmy, w jaki sposób wykorzystać do tego bibliotekę SimplePie. Przy Twojej znajomości XML-a możesz jednak z łatwością sparsować go samodzielnie. Skrypt z listingu 14.14 buduje tabelę zawierającą podstawowe informacje z kanału RSS: tytuł przekierowujący do pełnego artykułu, imię i nazwisko twórcy dokumentu oraz datę publikacji. Zauważ, że element creator należy do przestrzeni nazw — pobieramy go za pomocą XPath. Wynik pokazany jest na rysunku 14.1. Listing 14.14. Parsowanie kanału RSS ze strony magazynu „Wired”

    Witaj, świecie

    Skrypt z listingu 14.15 tworzy element główny — zwierzeta — przypisuje do niego wartość oraz wywołuje metodę asXML zapisującą plik. Aby przetestować poprawność skryptu, wczytujemy zawartość zapisanego pliku, a następnie ją wyświetlamy. Upewnij się, że posiadasz uprawnienia do zapisu w lokalizacji, w której chcesz utworzyć plik. Na listingu 14.16, który jest nawiązaniem do skryptu z listingu 14.4, mamy dane o zwierzętach zapisane w tablicach; na ich podstawie chcemy utworzyć dokument XML. Listing 14.16. Tworzenie podstawowego dokumentu XML przy wykorzystaniu SimpleXML

    Na listingu 14.16 tworzymy element główny za pomocą polecenia new SimpleXMLElement('');. Aby zasilić nasz dokument od elementu głównego w dół, tworzymy elementy potomne, wywołując metodę addChild i przechowując referencję do nowego elementu. Korzystając z referencji, możemy dodać elementy potomne. Powtarzając ten proces, możemy utworzyć całe drzewo węzłów. Niestety, funkcja asXML nie formatuje w żaden sposób wynikowego XML-a — cała zawartość pojawia się w jednej linii. Aby to obejść i wyświetlić XML w ładniejszej formie, możemy wykorzystać klasę DOMDocument, którą omówimy w dalszej części rozdziału. $zwierzeta_dom = new DOMDocument('1.0'); $zwierzeta_dom->preserveWhiteSpace = false; $zwierzeta_dom->formatOutput = true; //zwraca DOMElement $zwierzeta_dom_xml = dom_import_simplexml($zwierzeta); $zwierzeta_dom_xml = $zwierzeta_dom->importNode($zwierzeta_dom_xml, true); $zwierzeta_dom_xml = $zwierzeta_dom->appendChild($zwierzeta_dom_xml); $zwierzeta_dom->save('zwierzeta_sformatowane.xml');

    Ten kod tworzy nowy obiekt klasy DOMDocument oraz ustawia go tak, aby formatował dokument. Następnie importujemy element SimpleXMLElement do nowego obiektu DOMElement. Rekurencyjnie wstawiamy węzły do dokumentu, a następnie zapisujemy sformatowany plik. Zamiana powyższego kodu w miejscu wywołania funkcji asXML z listingu 14.16 spowoduje powstanie czystego, zagnieżdżonego dokumentu:



    bzik brązowy tabby



    reksio brązowy beagle cross

    azor czarny

    300

    ROZDZIAŁ 14. „ XML

    lab cross



    „ UWAGA. SimpleXML może także importować obiekty DOM za pomocą funkcji simplexml_import_dom.

    Skrypt z listingu 14.17 wygeneruje przykładową wiadomość RSS z przestrzeniami nazw i atrybutami. Naszym celem jest uzyskanie dokumentu posiadającego następującą strukturę:

    Kanał RSS Briana Najnowsze wpisy na blogu Briana http://www.briandanchilla.com/wezel/feed Fri, 04 Feb 2011 00:11:08 +0000 Fri, 04 Feb 2011 08:25:00 +0000

    Udawany temat Udawany opis http://www.briandanchilla.com/udawany-link/ unikalnie generowany łańcuch znaków Fri, 04 Feb 2011 08:25:00 +0000



    Listing 14.17. Generowanie dokumentu RSS za pomocą SimpleXML

    Najważniejsze elementy powyższego kodu to ustawienie przestrzeni nazw w elemencie głównym, $rss_xml = new SimpleXMLElement(''), pobranie przestrzeni nazw, jeżeli nazwa klucza to pubDate, oraz wygenerowanie daty w formacie RFC 2822 dla klucza lastBuildDate.

    Zawartość pliku po uruchomieniu skryptu z listingu 14.17 będzie zbliżona do poniższej:



    a b c d Fri, 23 Dec 2011 16:35:14 +0100 e

    a2 b2 c2 d2 Fri, 23 Dec 2011 16:35:14 +0100 e2



    302

    ROZDZIAŁ 14. „ XML

    „ UWAGA. Więcej informacji dotyczących SimpleXML można znaleźć pod adresem http://php.net/manual/en/book. simplexml.php. Aby sprawdzić błędy w niepoprawnym pliku XML, możesz wykorzystać walidator dostępny online pod adresem http://validator.w3.org/check.

    DOMDocument Jak wspomniano na początku tego rozdziału, SimpleXML nie jest jedyną opcją, jeżeli chodzi o manipulowanie dokumentami XML w PHP. Innym popularnym rozszerzeniem jest DOM. Podczas formatowania dokumentu wynikowego mogliśmy zauważyć, że ma on kilka opcji bardziej zaawansowanych niż SimpleXML. DOMDocument ma większe możliwości, ale jak można się spodziewać, nie jest tak prosty w wykorzystaniu. W większości przypadków prawdopodobnie wybierzesz SimpleXML zamiast DOM. DOM ma jednak następujące zalety: • Stosuje się go do W3C DOM API — jeżeli znasz JavaScript, łatwiej nauczysz się DOM. • Wspiera parsowanie HTML. • Różnorodne typy węzłów XML umożliwiają lepszą kontrolę nad dokumentem. • Może dopisywać XML do istniejących dokumentów XML. • Ułatwia wprowadzanie zmian w istniejących dokumentach poprzez modyfikowanie lub usuwanie węzłów. • Daje większą kontrolę nad zawartością CDATA i nad komentarzami. W SimpleXML wszystkie węzły są jednakowe. Element wykorzystuje więc ten sam obiekt jako argument. DOM ma odrębne typy węzłów. Są to XML_ELEMENT_NODE, XML_ATTRIBUTE_NODE i XML_TEXT_NODE. W zależności od rodzaju węzła odpowiednie właściwości to tagName dla elementów, name i value dla atrybutów oraz nodeName i nodeValue dla tekstu. //tworzenie obiektu DOMDocument $dom_xml = new DOMDocument(); DOMDocument może wczytać XML z ciągu znaków lub pliku albo zaimportować obiekt SimpleXML. //z ciągu znaków $dom_xml->loadXML('ciąg znaków zawierający XML'); //z pliku $dom_xml->load('animals.xml'); // import obiektu SimpleXML $dom_element = dom_import_simplexml($simplexml); $dom_element = $dom_xml->importNode($dom_element, true); $dom_element = $dom_xml->appendChild($dom_element);

    Aby poruszać się w obrębie obiektu DOM, należy wywoływać metody obiektu takie jak: $dom_xml->item(0)->firstChild->nodeValue $dom_xml->childNodes $dom_xml->parentNode $dom_xml->getElementsByTagname('div');

    Dostępnych jest kilka funkcji zapisujących: save, saveHTML, saveHTMLFile i saveXML. DOMDokument udostępnia funkcję walidującą, pozwalającą na sprawdzenie poprawności dokumentu. Aby wykorzystać XPath, konieczne jest utworzenie nowego obiektu klasy DOMXPath. $xpath = new DOMXPath($dom_xml);

    303

    ROZDZIAŁ 14. „ XML

    Aby lepiej zilustrować różnicę pomiędzy rozszerzeniami SimpleXML i DOM, następne dwa przykłady wykorzystujące DOM są równoważne z przykładami demonstrującymi SimpleXML, pokazanymi wcześniej. Skrypt z listingu 14.18 wyświetla wszystkie imiona zwierząt wraz z typem zwierzęcia zapisanym w nawiasie. Jest alternatywą dla przykładu z listingu 14.9, który wykorzystywał SimpleXML. Listing 14.18. Wyszukiwanie elementów za pomocą DOM

    Zauważ, że na listingu 14.18 musieliśmy utworzyć obiekt klasy DOMXPath, a następnie wywołać jego metodę query. Na listingu 14.9 możemy bezpośrednio odwołać się do elementu nadrzędnego. Zauważ także, że na listingu 14.18 odwołujemy się do wartości i nazw węzłów poprzez parametry, natomiast na listingu 14.9 poprzez metody. Listing 14.19 pokazuje, w jaki sposób znaleźć element o określonej wartości, a następnie odwołać się do jego atrybutu. Skrypt jest odpowiednikiem skryptu z listingu 14.13. Listing 14.19. Wyszukiwanie elementu i wartości atrybutu za pomocą DOM



    bzik brązowy tabby



    reksio brązowy beagle cross

    azor czarny lab cross



    Wynik działania skryptu z listingu 15.6 pokazany jest na rysunku 15.6.

    Rysunek 15.6. Wynik działania skryptu z listingu 15.6, wykorzystującego Ajax do odczytania tekstu z pliku XML

    319

    ROZDZIAŁ 15. „ JSON I AJAX

    Najważniejszą linią na listingu 15.6 jest ta, w której przypisujemy tekst wynikowy w przypadku pomyślnego pobrania pliku: if (xhr.status==200){ //sukces //pobranie rezultatu jako zwykłego tekstu wiadomosc = "" + xhr.responseText + ""; }

    i wstawienie go jako innerHTML elementu o id równym wygenerowana_zawartosc: document.getElementById("wygenerowana_zawartosc").innerHTML = wiadomosc;

    Pobieramy zawartość pliku jako XML i parsujemy wartości odpowiednich elementów, tak aby otrzymać tylko imiona zwierząt (listing 15.8). Listing 15.8. Pobranie zawartości dokumentu XML XMLHttpRequest oraz odpowiednich wartości

    Przykład XHR

    Ajax pobrał tekst:

     



    Na listingu 15.8 wykorzystujemy JavaScript, aby pobrać dane XML zwrócone przez żądanie Ajax — xhr.responseXML — następnie parsujemy je, wyszukując wartości elementów . Wynik pokazany został na rysunku 15.7.

    Rysunek 15.7. Wynik działania skryptu z listingu 15.8, wykorzystującego Ajax do parsowania XML-a Jeżeli odwołamy się do pliku zapisanego jako HTML, wykorzystanie responseText zachowuje strukturę HTML (listing 15.9). Wynik działania skryptu pokazany został na rysunku 15.8. Listing 15.9. Pobranie HTML-u za pomocą obiektu XMLHttpRequest

    Przykład XHR — zwykły tekst zawierający HTML

    Ajax pobrał tekst zawierający HTML:

     



    321

    ROZDZIAŁ 15. „ JSON I AJAX

    Zawartość pliku sample_table.html jest następująca:
    TytułDataAutor
    testowakolumna
    a1
    b2
    c3


    Rysunek 15.8. Wynik działania skryptu 15.9, wykorzystującego Ajax do pobrania zawartości HTML

    API JavaScript wyższego poziomu API wyższego poziomu, takie jak jQuery, Prototype i YUI, zyskały ostatnio dużą popularność — częściowo dlatego, że ukrywają część szczegółów implementacji i sprawiają, że wykorzystanie skomplikowanych obiektów — takich jak XMLHttpRequest — staje się łatwiejsze. Oznacza to, że użytkownik biblioteki nie musi znać szczegółów bezpośredniego użycia obiektu XMLHttpRequest. Obiekt XMLHttpRequest jest jednak kluczowy w zrozumieniu tego, co się dzieje „pod maską”. Inne zalety tych bibliotek to znacznie łatwiejsza obsługa drzewa DOM i lepsza kompatybilność między przeglądarkami. Możemy wybierać z kilku bibliotek. Danchilla jest zwolennikiem biblioteki jQuery, która jest bez wątpienia najczęściej używaną biblioteką JavaScript. Jest ona wykorzystywana przez Google, Amazon, Twitter, wewnątrz Microsoft Visual Studio, przez IBM, w Drupal CMS (system zarządzania treścią), a także przez wiele innych stron i bibliotek — zobacz http://docs.jquery.com/Sites_Using_jQuery. Jeżeli nie spodoba Ci się jQuery, do dyspozycji masz jeszcze Dojo, YUI, Prototype, MooTools oraz script.aculo.us. Omówienie szczegółów powyższych API wykracza poza zakres tej książki. Wyjaśnimy jednak znaczenie wszystkich funkcji wykorzystywanych w przykładach.

    Przykłady jQuery W skrypcie z listingu 15.10 zawartość elementu

    po załadowaniu strony modyfikowana jest przy wykorzystaniu jQuery — skrypt jest równoważny z listingiem 15.5. Listing 15.10. Modyfikacja elementu

    po załadowaniu strony za pomocą jQuery

    Pierwszy przykład jQuery



    Oryginalna zawartość



    Na listingu 15.10 linia:

    ładuje bibliotekę jQuery z sieci CDN Google (Content Delivery Network). Można także podłączyć lokalną kopię biblioteki. W systemach produkcyjnych CDN-y są z reguły szybsze i bardziej niezawodne. Większość przeglądarek ma ograniczoną liczbę plików, które mogą być jednocześnie pobierane z domeny. Wykorzystanie zewnętrznego CDN-u usuwa jeden plik z kolejki ładowania strony. Zwiększa to wydajność i skraca czas ładowania strony. Zwróć uwagę na nazwę pliku — jquery.min.js — jest to wersja produkcyjna. W środowisku testowym podczas wyszukiwania błędów w kodzie lepiej wykorzystać wersję czytelną dla człowieka — jquery.js. Wywołanie funkcji $(document).ready jest standardowe dla skryptów jQuery. Zmienna $(document) reprezentuje cały dokument DOM i w dalszej części skryptu została skrócona do $(). Odwołanie do .ready powoduje wykonanie skryptu po załadowaniu dokumentu DOM. Dzięki temu możemy umieścić skrypt przed dokumentem, do którego odwołujemy się w skrypcie. Parametry Ajaksa są inicjalizowane i ustawiane za pomocą wywołania $.ajax(). Funkcja jako parametry przyjmuje sposób wykonania żądania (GET lub POST), adres URL oraz typ odpowiedzi. Definiuje także funkcje zwrotne wywoływane w przypadku sukcesu i niepowodzenia. Linia document.getElementsByTagName("p")[0].innerHTML z oryginalnego skryptu została zastąpiona linią $("p").html("jakieś dane"). Pierwsza część polecenia znajduje odpowiedni element

    za pomocą selektorów CSS, druga ustawia zawartość elementu. „ UWAGA. Zapis $("p") odpowiada wszystkim elementom

    w dokumencie. Jeżeli chcemy wybrać tylko pierwszą instancję elementu, tak jak na listingu 15.5, moglibyśmy zastosować funkcje wbudowane $("p").first(). Moglibyśmy także użyć selektorów CSS, np.: $("p:first") lub $("p:eq(0)").

    Wersja skryptu używająca jQuery jest krótsza niż wersja oryginalna, wykorzystująca obiekt XMLHttpRequest. W przypadku bardziej skomplikowanych skryptów wartość API wyższego poziomu, takich jak jQuery, uwydatnia się w jeszcze większym stopniu. Skrypt z listingu 15.11 jest równoważny ze skryptem z listingu 15.6, ładującym tekst z pliku XML. Listing 15.11. Wykorzystanie jQuery do załadowania tekstu z pliku XML

    Ładowanie tekstu z jQuery



    Ajax pobrał tekst:

     

    Gdybyśmy nie troszczyli się o potencjalne błędy, moglibyśmy przepisać kod z listingu 15.11 zwięźlej (listing 15.12). Listing 15.12. Zwięzła wersja kodu ładującego dane z pliku XML

    Ładowanie tekstu z jQuery



    Ajax pobrał tekst:

     

    324

    ROZDZIAŁ 15. „ JSON I AJAX

    Funkcja jQuery load()na listingu 15.12 wykorzystuje żądanie GET oraz „inteligentne zgadywanie” do zwrócenia tekstu. Następnie wstawia tekst do wybranego elementu. Funkcja jQuery wrap otacza zawartość elementu znacznikami. To pozwala nam na otoczenie załadowanego XML-a znacznikami ... Oprócz funkcji $.ajax, jQuery udostępnia funkcje $.get i $.post, pozwalające na wysłanie żądań GET i POST. Dzięki tym funkcjom jQuery próbuje odgadnąć odpowiedni wynik. Jeżeli odgaduje niepoprawnie, typ wyniku możemy określić sami. Dokładniejsze informacje możesz znaleźć w dokumentacji jQuery dostępnej pod adresem http://api.jquery.com/jQuery.get/. Zobacz listing 15.13. Listing 15.13. Wykorzystanie funkcji jQuery $.get i pobranie danych XML

    Ładowanie XML-a z jQuery



    Ajax pobrał text:

     

    Na listingu 15.13 funkcja $.get przyjmuje trzy parametry. Pierwszy z nich to żądany plik, drugi to funkcja zwrotna, w której przetwarzane są uzyskane dane, a trzeci to oczekiwany typ danych. Bez określenia xml jQuery wybrałby zwykły tekst. Do tej pory pokazaliśmy, jak wykorzystać obiekt XMLHttpRequest oraz w jaki sposób API wyższego poziomu, takie jak jQuery, ukrywają szczegóły implementacji i ułatwiają nam pracę. Teraz pokażemy przykład zastosowania formatu JSON (listing 15.14). Listing 15.14. Wyświetlenie danych JSON z tabeli PHP — json_example.php

    325

    ROZDZIAŁ 15. „ JSON I AJAX

    Skrypt z listingu 15.15 wykorzystuje jQuery do uzyskania wartości JSON z pliku PHP (listing 15.14) za pomocą żądania Ajax. Listing 15.15. Wykorzystanie $.getJSON i $.each

    Ładowanie danych JSON z jQuery



    JSON sparsowany przez Ajax:

     

    Wynik działania skryptu z listingu 15.15 znajduje się poniżej: JSON sparsowany przez Ajax: afryka goryl, żyrafa, słoń azja panda północna ameryka niedźwiedź, ryś, orka

    Na listingu 15.15 wykorzystaliśmy funkcję skrótową $.getJSON. Mogliśmy także zastosować $.get z opcją json jako trzecim argumentem. Użyliśmy również funkcji $.each, aby przeiterować po zwróconych obiektach JSON. Aby przypisać wartości klucz-wartość do zmiennych kontynent i zwierzęta, zdefiniowaliśmy funkcję zwrotną następująco: $.each(dane, function(kontynent, zwierzeta){

    326

    ROZDZIAŁ 15. „ JSON I AJAX

    Przesyłanie danych z Ajaksa do skryptu PHP W kolejnym przykładzie (listing 15.16) na stronie znajdują się dwa przyciski — Myśliwy i Ofiara. Po kliknięciu dowolnego z nich do skryptu PHP zostanie przesłane żądanie Ajax zawierające parametr ?typ=mysliwy lub ?typ=ofiara. Kiedy skrypt PHP otrzyma żądanie, wykorzysta przekazaną wartość do zwrócenia odpowiedniego zwierzęcia w formacie JSON. Listing 15.16. Plik PHP wybierający i wysyłający odpowiednie zwierzę w formacie JSON — predator_prey.php

    Na listingu 15.17 obsługujemy zdarzenie .click obydwóch przycisków poprzez wywołanie żądania Ajax .load. Plik predator_prey.php odbiera żądanie wraz z parametrem typ, po czym odsyła odpowiedź, którą wstawiamy do dokumentu. Wykorzystaliśmy funkcję array_rand do wygenerowania losowego indeksu wybranej tablicy, a następnie funkcję json_encode, aby zakodować wynik w formacie JSON. Listing 15.17. Plik HTML ładujący wynik żądania Ajax

    Przykład Myśliwy/Ofiara



    Myśliwy Ofiara

    Odpowiedź z PHP:

     

    Wynik działania skryptu z listingu 15.17 pokazany jest na rysunku 15.9.

    Rysunek 15.9. Wynik działania skryptu z listingu 15.17

    Prosty program graficzny Na listingu 15.18 zbudujemy prostą aplikację pozwalającą na rysowanie siatki komórek tabeli HTML i jQuery przy wykorzystaniu palety kolorów. Następnie dodamy możliwość zapisywania i wczytywania rysunku przy zastosowaniu PHP i Ajaksa. Listing 15.18. Aplikacja pozwalająca manipulować kolorami tła komórek tabeli

    Przykład z rysowaniem po siatce



    Paleta kolorów:

                 

    Rysuj!

    Konsola debugowania: 



    329

    ROZDZIAŁ 15. „ JSON I AJAX



    Kod CSS na listingu 15.18 zawiera polecenie margin-collapse: collapse dla tabeli z siatką — dzięki temu wewnętrzne obramowanie ma taką samą grubość jak zewnętrzne. Tworzymy paletę kolorów jako tabelę HTML. Mimo że podajemy wymiary, znak   pomaga upewnić się, że przeglądarka narysuje obramowania komórek. Bez modyfikacji DOM nasza siatka jest pusta. W funkcji jQuery .ready wykorzystujemy pętlę do dodania dziesięciu kolumn i dziesięciu wierszy do tabeli. Następnie definiujemy akcję wykonywaną po kliknięciu komórki palety: $("#paleta td").each( function( index ){ //przypisanie zdarzenia onClick $( this ).bind ( click", function(){

    W ciele funkcji zmieniamy zmienną aktywny_kolor oraz wskazujemy jej wartość w sekcji debugowania: function(){ aktywny_kolor = $(this).css("background-color"); $("#debug_kolor_palety").html("aktywny kolor palety to: " + "" + aktywny_kolor + ""); }

    Do komórek siatki przypisujemy zdarzenie, tak aby po każdym kliknięciu wartość właściwości background-color została zmieniona na zgodną z wartością zapisaną w zmiennej aktywny_kolor: $("#siatka td").each( function( index ){ //przypisanie zdarzenia onClick $( this ).bind ( "click", function(){ $(this).css("background-color", aktywny_kolor); } );

    Wynik pokazany został na rysunku 15.10. Nasz program działa, nie możemy jednak zapisać utworzonego obrazu. Jeśli wyjdziemy ze strony i do niej powrócimy, zawsze otrzymamy czystą siatkę. Zajmiemy się teraz tym problemem. „ UWAGA. Kolory tła w jQuery są zapisywane w nowszej formie, rgb(255, 0, 0), a nie w wartościach szesnastkowych, np. #ff0000. Nowy format jest częścią specyfikacji CSS3 i zawiera także kanał alfa — rgba. Wartości alfa pozwalają na łatwe regulowanie przezroczystości i niedługo będą wspierane przez większość przeglądarek.

    Utrzymanie stanu Aby zapisać zmiany wprowadzone za pośrednictwem Ajaksa, możemy dzięki PHP zapisać dane w bazie, zmiennej $_SESSION lub pliku. Kiedy przeładujemy stronę, będziemy mogli ustawić kolory siatki zgodnie z zapisanymi danymi. W naszym przykładzie wykorzystamy plik fizyczny. Możesz rozszerzyć przykład tak, aby zapisywał dane dla unikalnej sesji lub nazwy użytkownika, my jednak przechowamy tylko jeden zestaw danych.

    330

    ROZDZIAŁ 15. „ JSON I AJAX

    Rysunek 15.10. Siatka rysowania z listingu 15.18 Nie chcemy zapisywać rezultatu po każdej zmianie piksela — byłoby to bardzo wolne i pochłaniałoby wiele zasobów. Zamiast tego dodamy przycisk pozwalający na zapisanie danych w dowolnym momencie. Można także śledzić liczbę zmian pomiędzy poszczególnymi zapisami. Dzięki temu moglibyśmy utworzyć mechanizm automatycznego zapisu co każde 100 zmian pracujący w tle. To pomogłoby w zabezpieczeniu danych użytkownika bez konieczności wykonywania przez niego zapisów. Możemy również dodać przycisk czyszczący siatkę do stanu sprzed modyfikacji oraz usuwający zapisane dane (listing 15.19). Na listingach 15.20 i 15.21 zostały przedstawione odpowiednio: skrypt zapisujący odebrane dane do pliku XML i skrypt odczytujący zapisane dane. Listing 15.19. Plik HTML wyświetlający siatkę i wykonujący odwołania Ajax do skryptu PHP

    Przykład z rysowaniem po siatce



    Paleta kolorów:

                 
    Zapisz

    Rysuj!

    Konsola debugowania: 





    Listing 15.20. Skrypt PHP zapisujący przekazaną zmienną $_POST, zawierającą dane w formacie JSON — save_drawing.php

    333

    ROZDZIAŁ 15. „ JSON I AJAX

    Listing 15.21. Skrypt PHP ładujący zapisane dane — load_drawing.php

    Nasz nowy skrypt wyposażyliśmy w funkcję zapisu po kliknięciu przycisku Zapisz. Aby było to możliwe, został utworzony nowy obiekt JavaScriptu. Następnie dla każdej z komórek dodaliśmy obiekt zawierający wartość koloru tła. Po tej operacji do pliku save_drawing.php zostało wysłane żądanie POST. Musimy wykorzystać metodę POST, ponieważ przesyłane dane są zbyt długie dla metody GET. Wewnątrz skryptu PHP kodujemy zmienną $_POST na format JSON i zapisujemy w pliku (listing 15.22). Listing 15.22. Funkcja zapisująca naszego programu $("#zapisz").click(function(){ var koloryJson = new Object(); var i=0; $("#siatka td").each(function() { koloryJson[i] = $(this).css("background-color"); ++i; }); $.ajax( { type: "post", url: "save_drawing.php", dataType: "text", data: koloryJson, success: function(data) { $("#debug_wiadomosc").html("rysunek zapisany"); }, failure: function(){ $("#debug_wiadomosc").html( "Podczas próby zapisania rysunku nastąpił błąd"); } }); });

    Nasz obrazek jest już zapisany, możemy zatem załadować dane przy powtórnej wizycie. Aby to zrobić, wysyłamy żądanie $.getJSON do pliku load_drawing.php. Zwracana jest zawartość w formacie JSON zapisana przez nas w pliku. Wewnątrz jQuery iterujemy po wszystkich komórkach siatki i przypisujemy im odpowiednie kolory (listing 15.23). Wynik jest pokazany na rysunku 15.11. Listing 15.23. Funkcja ładująca naszego programu $.getJSON("load_drawing.php", function(dane){ $("#siatka td").each(function(indeks){ $(this).css("background-color", dane[indeks]); }); });

    Podczas pracy z Ajaksem warto korzystać z narzędzi pomagających w procesie debugowania. Rozszerzenie Firebug dla przeglądarki Firefox jest jednym z najlepszych narzędzi. W Firebugu dane Ajax są dostępne w zakładce Sieć/XHR. Bardzo użyteczne są również narzędzia przeglądarki Chrome.

    334

    ROZDZIAŁ 15. „ JSON I AJAX

    Rysunek 15.11. Nasz program z załadowanymi danymi, przyciskiem zapisu oraz podglądem w programie Firebug

    Podsumowanie W tym rozdziale wyjaśniliśmy, w jaki sposób żądania asynchroniczne pozwalają budować bogate, użyteczne i przyjemne strony. Jest to możliwe dzięki wstawieniu warstwy pośredniej — silnika Ajax — pomiędzy klientem a serwerem. Serwer otrzymuje mniej żądań związanych z aktualizacją warstwy prezentacji i wykonywane są odwołania nieblokujące strony podczas przesyłania danych. Najpopularniejszym językiem skryptowym pozwalającym na wysyłanie żądań Ajax jest JavaScript. Wykorzystanie API wyższego poziomu, takiego jak jQuery, może znacznie ułatwić i uprzyjemnić pracę z Ajaksem w porównaniu z bezpośrednią pracą z obiektem XMLHttpRequest. Formaty danych, które mogą być zastosowane podczas pracy z Ajaksem, to XML (omówiony w rozdziale 14.), JSON (omówiony w tym rozdziale), HTML i zwykły tekst. Ajax w tworzeniu współczesnych stron internetowych jest mieczem obosiecznym. Z jednej strony wprowadza możliwości interakcji ze stroną i przesyłania danych niedostępne w modelu klasycznym. Z drugiej jednak użytkownicy oczekują bogatych doznań. Aby sprostać tym oczekiwaniom, potrzeba wiele pracy. Aby zapewnić użytkownikowi dobre doznania (ang. User Experience — UX) z Ajaksem, twórca musi poznać kilka technologii; najważniejsze z nich to JavaScript, selektory DOM, JSON i XML. Powstają poza tym nowe techniki, takie jak odwrotny Ajax, związany z długotrwałymi połączeniami HTTP i przesyłaniem danych z serwera do klienta. Rola, jaką odgrywa Ajax w procesie tworzenia stron, będzie w przyszłości jeszcze większa.

    335

    ROZDZIAŁ 15. „ JSON I AJAX

    336

    ROZDZIAŁ 16 „„„

    Konkluzja

    Mamy nadzieję, że z przyjemnością czytałeś tę książkę oraz że zrobiłeś dobry użytek z informacji i linków zamieszczonych w każdym z rozdziałów. Bardzo się staraliśmy, aby publikacja ta była dla Ciebie przydatna, i mamy nadzieję, że będziesz do niej często zaglądał, że znajdzie się na Twoim biurku obok komputera, a nie na półce razem z innymi książkami programistycznymi. Oczywiście rozumiemy, że branża IT rozwija się z prędkością światła i że za kilka miesięcy wiele zawartych tu informacji będzie nieaktualnych. W związku z tym dodaliśmy ten rozdział — aby spróbować odpowiedzieć na niezadane jeszcze pytania związane z tworzeniem aplikacji internetowych. Jest to zbiór najlepszych znanych nam źródeł informacji dotyczących programowania, stanowiących świetny dodatkowy materiał, z którym możesz zapoznawać się podczas swojej ciągłej edukacji programistycznej — w szczególności jeżeli chodzi o programowanie PHP.

    Zasoby Najpierw chcielibyśmy zapoznać Cię z szeroką gamą zasobów dostępnych w internecie. Kolejne podrozdziały wyjaśniają, co możesz znaleźć na podanych stronach.

    www.php.net Tutaj znajdziesz dostępne do pobrania najświeższe wersje PHP, a także pełną dokumentację zawierającą przykłady, w tym przykłady i wyjaśnienia dodawane przez użytkowników. Dokumentację można łatwo przeszukiwać; jeżeli nie znajdziesz potrzebnych informacji pod danym hasłem, sugerowane są jego alternatywy. Poza wspomnianymi materiałami znajdziesz wiadomości o nadchodzących wydarzeniach związanych z PHP, takich jak konferencje, spotkania grup użytkowników, i oczywiście najnowsze linki, które według administratorów strony mogą być przydatne (rysunek 16.1). „ UWAGA. Jeżeli szukasz na stronie informacji dotyczących kodu, spróbuj wyszukiwania poprzez modyfikację adresu URL — dodaj nazwę funkcji na końcu adresu, np.:

    php.net/date W tym przypadku otworzy się strona dokumentacji dotycząca daty.

    ROZDZIAŁ 16. „ KONKLUZJA

    Rysunek 16.1. www.php.net

    www.zend.com Prawdopodobnie dużo czasu spędzisz na stronie Zend Corporation. Jest to samozwańcza „firma PHP”. Znajdziesz tutaj wiele narzędzi, jakie Zend opracował, aby pomóc zarówno w tworzeniu aplikacji PHP, jak i uruchamianiu ich na serwerze. Spoglądając na pełną listę produktów, zauważysz, że firma przyczynia się do rozwoju samego języka PHP. Poza produktami komercyjnymi oferowane są tu inne wartościowe narzędzia i materiały (rysunek 16.2).

    devzone.zend.pl Jest to strona siostrzana portalu Zend. Znajdziesz tutaj społeczność programistów chcących pomagać sobie nawzajem w sprawach związanych z PHP i użytkowaniem produktów firmy Zend. Są tu zamieszczane recenzje książek i reportaże z konferencji. Gdy naprawdę utkniesz w martwym punkcie, tutaj będziesz mógł porozmawiać z ekspertami. Każdy temat ma odrębne forum, podcasty, samouczki, artykuły, a nawet ścieżki do dokumentacji PHP (rysunek 16.3).

    www.phparch.com Kolejną polecaną stroną jest magazyn „php|architect”. Pod powyższym adresem możesz obejrzeć bezpłatny numer — jeżeli Ci się spodoba, za niewielką opłatą możesz zaprenumerować wersję PDF. W magazynie tym są publikowane bardzo wartościowe informacje przeznaczone dla programistów średnio zaawansowanych i zaawansowanych; omawiane tematy są z reguły związane z nowinkami technicznymi.

    338

    ROZDZIAŁ 16. „ KONKLUZJA

    Rysunek 16.2. www.zend.com

    Rysunek 16.3. devzone.zend.pl

    Konferencje W przyswajaniu wiedzy i umiejętności w zakresie PHP nie ma nic lepszego niż uczestnictwo w konferencji. Dzięki temu możesz się oderwać od codziennego stresu i skupić się na spotykaniu i poznawaniu innych programistów PHP, dyskutowaniu z nimi o życiu, wszechświecie i wszystkim innym. Społecznościowy aspekt tych spotkań jest równie ważny. Możesz wierzyć lub nie, ale na tego typu spotkaniach wymieniane są ogromne ilości informacji — nawet gdy pod koniec dnia popijasz z innymi uczestnikami spotkania napój w hotelowym barze. Naturalnie najważniejszym elementem konferencji jest prezentacja, jednak korzyści z pobocznych rozmów są niezaprzeczalne.

    339

    ROZDZIAŁ 16. „ KONKLUZJA

    Jeżeli masz duże doświadczenie w danym obszarze, możesz podzielić się nim podczas prelekcji. Gdy wystąpisz jako mówca, wkroczysz w inny wymiar życia konferencyjnego, którego niewiele osób ma szanse doświadczyć — poznasz znaczące osobistości świata PHP i zyskasz bezcenne kontakty z wartościowymi ludźmi. Oczywiście będziesz uważany za jednego z nich, ponieważ stałeś się prelegentem na konferencji i ekspertem w danej dziedzinie. Oto lista polecanych konferencji, w których powinieneś uczestniczyć, jeżeli tylko będziesz miał okazję (przedstawiamy je tu od najciekawszych, w razie gdybyś miał ograniczone fundusze): • ZendCon. Główna światowa konferencja PHP odbywająca się co roku, przeważnie w listopadzie. Z pewnością zobaczysz tutaj wielkie osobistości świata PHP i nawiążesz wartościowe kontakty. Właśnie na tej konferencji ogłasza się większość komunikatów i premier. Jeśli więc chcesz być jednym z pierwszych poinformowanych, postaraj się w niej uczestniczyć. • OSCON. Konferencja firmy O’Reilly dotycząca tworzenia aplikacji internetowych i oprogramowania open source. Są to dyskusje o tematyce znacznie szerszej niż PHP, jednak PHP zdecydowanie ma tutaj swoje miejsce. OSCON z reguły odbywa się w lipcu. • ConFoo. Jest to duża kanadyjska konferencja, wcześniej znana pod nazwą PHP Quebec, dotycząca nie tylko tematów związanych z PHP, jednak jej korzenie tkwią w obszarze związanym z tym językiem. • International PHP Conference. Zawsze odbywa się w Niemczech dwa razy do roku — wiosną i jesienią. Wiosenna konferencja przeważnie ma miejsce w Berlinie, natomiast jesienna organizowana jest w październiku w różnych miastach Niemiec. • Open Source India. Trzydniowa konferencja odbywająca się co roku, jesienią. Dotyczy oprogramowania open source, więc jak w przypadku OSCON, porusza się na niej tematy związane nie tylko z PHP. Jest to jedna z największych tego typu konferencji w Azji. Jeżeli chcesz nawiązać jakieś kontakty biznesowe w tej części świata, powinieneś postarać się wziąć udział w tym spotkaniu. „ UWAGA. Nie zapomnij zaglądać do sekcji dotyczącej konferencji na stronie php.net, ponieważ ciągle organizowane są nowe konferencje.

    Certyfikacja PHP Ostatnim tematem tego rozdziału jest wartość (lub domniemana wartość) certyfikatów PHP i to, jak trzeba się przygotować do testu. Na ten temat bardzo dużo się dyskutuje. Certyfikaty dostępne są od wersji 4.0 PHP (czerwiec 2004). Warto zauważyć, że trzech z czterech autorów tej książki posiada certyfikaty PHP. To może być dla Ciebie wskazówka dotycząca wartości certyfikacji. Zobaczmy, z czym się to wiąże. Egzamin organizowany jest przez Zend Corporation. Zend prosi ekspertów PHP z całego świata, aby zajęli miejsce w komisji przygotowującej pytania egzaminacyjne i odpowiedzi. Ma to przynajmniej dwie następujące zalety: 1. Test przygotowywany jest przez kilka grup lub firm, więc obejmuje zróżnicowane zagadnienia. 2. Dzięki temu, że test jest przygotowywany przez różnych ekspertów, nie będzie dotyczył wąskiej dziedziny PHP. Obecnie egzamin bazuje na wersji PHP 5.3 i jest uważany za nieznacznie trudniejszy niż ten z wersji 4.0. Liczba poprawnych odpowiedzi koniecznych do zdania egzaminu nie jest znana, jednak przypuszcza się, że kandydat musi uzyskać ich 60%. „ UWAGA. Czasami test jest oferowany bezpłatnie na niektórych konferencjach, między innymi na konferencji ZendCon. Kurs przygotowujący do egzaminu dostępny jest na tej samej konferencji. Jest to świetna okazja, aby bezpłatnie przystąpić do egzaminu.

    340

    ROZDZIAŁ 16. „ KONKLUZJA

    Test składa się z 70 losowo wybranych pytań, na które musisz udzielić odpowiedzi w ciągu 90 minut. Jest dwanaście różnych obszarów tematycznych, z których losowane są pytania — przystępując do testu, powinieneś doskonale znać każdy z nich. Dodatkowo powinieneś mieć od półtora roku do dwóch lat styczności z PHP w codziennej pracy, aby dysponować wystarczającym doświadczeniem praktycznym. Jeżeli zdasz egzamin, otrzymasz tytuł ZCE (Zend Certified Engineer) oraz podpisany certyfikat, gotowy do oprawienia w ramkę; będziesz mógł także oficjalnie posługiwać się tytułem ZCE. „ UWAGA. Na stronach www.zend.com i www.phparch.com dostępne są podręczniki i testy przygotowujące do egzaminu. Jeśli potrzebujesz dodatkowych materiałów do nauki, warto tam zajrzeć.

    Oto obszary tematyczne testu: • Podstawy PHP • Funkcje • Tablice • Programowanie zorientowane obiektowo (OOP) • Ciągi znaków i wyrażenia regularne • Projektowanie i teoria • Funkcje internetowe • Różnice pomiędzy PHP4 i PHP5 • Pliki, strumienie, sieci • XML i usługi sieciowe • Bazy danych • Bezpieczeństwo Czy warto się certyfikować? Absolutnie tak! Tytuł ZCE gwarantuje pewien poziom znajomości PHP i można znaleźć wiele dobrych ofert pracy, w których jest on wymagany. Dysponując certyfikatem, będziesz miał więcej pewności siebie, przydatnej podczas rozmowy z szefem na temat Twoich kompetencji i wyników.

    Podsumowanie W tym rozdziale przedstawiliśmy wybrane zasoby i materiały dostępne w sieci, wykraczające poza zakres tej książki. Rozpatrzyliśmy także zasadność ubiegania się o certyfikat PHP. Mamy nadzieję, że będziesz kontynuował naukę i nadal rozwijał swoją wiedzę na temat tego języka.

    341

    ROZDZIAŁ 16. „ KONKLUZJA

    342

    DODATEK „„„

    Wyrażenia regularne

    Dodatek ten zapozna Cię z wyrażeniami regularnymi. Jest to jednak tylko wprowadzenie — tematyka ta jest w istocie bardzo obszerna i traktują o niej całe książki. Dobrym przykładem jest Regular Expression Recipes Nathana A. Gooda (Apress 2004). Wyrażenia regularne (regex) są metodą dopasowywania ciągów znaków odpowiadających zadanym kryteriom. Ich koncepcja wywodzi się z teorii komputerów i oparta jest na automatach skończonych. Istnieje wiele wariacji wyrażeń regularnych różniących się od siebie w licznych aspektach. Dwa najczęściej wykorzystywane silniki wyrażeń regularnych to Posix oraz PCRE (Perl compatible regular expressions — wyrażenia regularne kompatybilne z Perl). W PHP zastosowano ten drugi silnik. Właściwie możesz wykorzystywać oba, jednak Posix został wycofany w wersji PHP 5.3 i późniejszych. Poniżej wymieniono podstawowe funkcje PHP implementujące silnik PCRE: • • • •

    preg_match preg_replace preg_split preg_grep

    Istnieją także inne funkcje, będące częścią „maszynerii” wyrażeń regularnych, jednak te cztery są najczęściej stosowane. Prefiks preg w nazwie każdej z nich oznacza Perl regular expression (wyrażenie regularne Perl) w przeciwieństwie do wyrażeń Posix nazywanych też extended regular expressions (rozszerzone wyrażenia regularne). Tak, były wersje funkcji rozpoczynające się od prefiksu ereg, jednak zostały wycofane w PHP 5.3. Dodatek składa się z dwóch części — pierwsza omawia składnię wyrażeń regularnych, druga przedstawia przykłady ich wykorzystania w skryptach PHP.

    Składnia wyrażeń regularnych Podstawowym składnikiem wyrażeń regularnych są metaznaki. Metaznaki poprzedzone znakiem lewego ukośnika (\) tracą swoje specjalne znaczenie. Tabela A.1 przedstawia listę metaznaków. Poza metaznakami są dostępne klasy znaków specjalnych przedstawione w tabeli A.2. Wyrażenie .* odpowiada dowolnemu znakowi. Wyrażenie ^.*3 odpowiada znakom od początku ciągu do ostatniej cyfry 3 w linii. To zachowanie może być zmienione; omówimy to w dalszej części dodatku, dotyczącej chciwości wyrażeń. Na razie zobaczmy więcej przykładów wyrażeń regularnych.

    PHP. ZAAWANSOWANE PROGRAMOWANIE

    Tabela A.1. Metaznaki i ich znaczenie Wyrażenie

    Znaczenie

    .

    Dowolny znak.

    *

    Zero lub więcej wystąpień znaku poprzedzającego znak *.

    ?

    Zero lub jedno wystąpienie znaku poprzedzającego znak ?. Powoduje także, że wyrażenie nie jest chciwe (wyjaśnienie różnicy pomiędzy „chciwym” i „niechciwym” wyrażeniem znajduje się w dalszej części dodatku). Znak ? jest również wykorzystywany do ustawiania opcji wewnętrznych.

    /

    Separator wyrażeń regularnych. Oznacza rozpoczęcie i zakończenie wyrażenia.

    +

    Co najmniej jedno wystąpienie znaku poprzedzającego znak +.

    [ ]

    Klasy znaków: [a-z] — wszystkie małe litery. [Ab9] odpowiada znakom A, b i 9. Możliwe jest także zanegowanie klasy znaków za pomocą znaku ^ umieszczonego na początku. ^[a-z] oznacza wszystkie znaki poza małymi literami.

    ^

    Początek linii.

    $

    Koniec linii.

    ( )

    Grupowanie — zostanie wyjaśnione w dalszej części dodatku.

    |

    Wyrażenie „lub” — rozdziela dwa podwyrażenia.

    { }

    Kwalifikatory. \d{3} oznacza „3 cyfry”, \s{1,5} oznacza „jeden, dwa, trzy, cztery lub pięć znaków spacji”, Z{1,} oznacza „jedna lub więcej liter Z” — jest to synonim wyrażenia Z+.

    Tabela A.2. Klasy znaków specjalnych Symbol klasy

    Znaczenie

    \d, \D

    Symbol \d pisany małą literą odpowiada liczbie. Symbol \D pisany dużą literą jest negacją i odpowiada znakom niebędącym liczbą.

    \s, \S

    Symbol \s pisany małą literą odpowiada znakowi spacji lub znakowi tabulacji. Symbol \D pisany dużą literą odpowiada znakom niebędącym znakiem spacji ani znakiem tabulacji.

    \w, \W

    Symbol \w pisany małą literą odpowiada dowolnym literom i cyfrom. Podobnie jak w poprzednich przypadkach, \W jest negacją i odpowiada znakom niebędącym literami ani cyframi.

    Przykłady wyrażeń regularnych Pierwszy przykład dotyczy miejsca i daty. Wiemy, że 8 czerwca 2012 roku w Warszawie będzie miało miejsce pewne ważne wydarzenie. Wzorzec odpowiadający zapisowi „Warszawa, 8 czerwca 2012” wyglądałby następująco: /[A-Z][a-z]{2,},\s\d{1,2}\s[a-z]{3,}\s\d{4}/

    Oznacza to: „Duża litera, po niej przynajmniej dwie małe litery i przecinek, następnie spacja, jedna lub dwie cyfry, spacja, przynajmniej trzy małe litery, spacja i na końcu dokładnie cztery cyfry reprezentujące rok”. Listing A.1 prezentuje fragment kodu pozwalający na testowanie wyrażeń regularnych. Listing A.1. Testowanie wyrażeń regularnych

    Zauważ, że zmienna $ciag z listingu A.1 ma na końcu kropkę. Wyrażenie regularne natomiast kończy się na \d{4} i nie pasuje do kropki na końcu ciągu znaków. Gdybyśmy chcieli to zmienić, moglibyśmy „zakotwiczyć” wyrażenie regularne na końcu linii, pisząc je w ten sposób: /[A-Z][a-z]{2,},\s\d{1,2}\s[a-z]{3,}\s\d{4}$/. Znak dolara dodany na końcu wyrażenia oznacza „koniec linii” — jeżeli po wyrażeniu wystąpią jakieś znaki, wyrażenie nie zostanie dopasowane. Mogliśmy także „zakotwiczyć” wyrażenie na początku linii, wykorzystując znak ^. Wyrażenie dopasowujące całą linię niezależnie od zawartości ma postać /^.*$/. Spójrzmy teraz na inny format daty, YYYY-MM-DD. Zadanie to sparsowanie daty i wyodrębnienie poszczególnych składowych. „ UWAGA. Można to wykonać za pośrednictwem funkcji date; to dobry przykład wewnętrznego działania niektórych funkcji PHP.

    Musimy sprawdzić, czy linia zawiera poprawną datę, ale także wyodrębnić rok, miesiąc i dzień. Aby to zrobić, trzeba wykorzystać grupy wyrażeń. Można o tym myśleć jak o podwyrażeniach ustawionych w kolejności sekwencji. Wyrażenie regularne, które pozwoli nam wykonać zadanie, wygląda następująco: /(\d{4})-(\d{2})-(\d{2})/

    Nawiasy wykorzystywane są do grupowania wyrażeń. Te grupy to podwyrażenia i można je traktować jako odrębne zmienne. Listing A.2 przedstawia wykonanie zadania za pomocą wbudowanej funkcji preg_match. Listing A.2. Dopasowanie grup za pomocą wbudowanej funkcji preg_match

    W powyższym skrypcie funkcja preg_match przyjmuje trzeci parametr, tablicę $dopasowania. Oto wynik działania skryptu: 0:-->2011-05-01 1:-->2011 2:-->05 3:-->01 Rok:2011 Miesiąc:05 Dzień:01

    Zerowy element tablicy $dopasowania zawiera ciąg pasujący do całego wyrażenia. To nie jest to samo co cały ciąg wejściowy. Każda kolejna grupa przedstawiona jest jako pozycja w tablicy. Zobaczmy kolejny, bardziej skomplikowany przykład. Sparsujmy adres URL. Ogólna forma adresu URL jest następująca:

    345

    PHP. ZAAWANSOWANE PROGRAMOWANIE

    http://nazwahosta:port/lokacja?argument=wartosc

    Oczywiście, może brakować dowolnej części wyrażenia. Wyrażenie parsujące adres URL w powyższej formie wygląda następująco: /^https?:\/\/[^:\/]+:?\d*\/[^?]*.*/

    Znalazło się w nim kilka nowych, wartych zauważenia elementów. Zacznijmy od części s? w ^http[s]?: — dzięki niej zostanie dopasowany zarówno ciąg rozpoczynający się od http:, jak i https:. Znak ^ kotwiczy wyrażenie do początku ciągu. Znak ? oznacza „żadne lub jedno wystąpienie poprzedniego wyrażenia”. Poprzednim wyrażeniem jest litera s — czyli „żadne lub jedno wystąpienie litery s”. Aby usunąć specjalne znaczenie znaków /, zostały one poprzedzone znakami \. W przypadku separatora wyrażeń regularnych PHP jest bardzo pobłażliwe. Pozwala na zamienienie go jakimkolwiek innym separatorem. PHP rozpozna nawiasy kwadratowe lub znak |, więc wyrażenie byłoby poprawne, gdyby zostało zapisane w formie [^https?://[^:/]+:?\d*/[^?]*.*] lub nawet przy użyciu znaku pipe |^https?://[^:/]:?\d*/[^?]*.*|. Sposobem na wyłączenie specjalnego znaczenia danego znaku jest poprzedzenie go znakiem \. Wyrażenia regularne są sprytne i potrafią „domyślić się” znaczenia znaków w zależności od kontekstu. Poprzedzanie znaku zapytania znakiem ucieczki w miejscu [^?]* było niepotrzebne, ponieważ z kontekstu wynika, że chodzi o klasę znaków innych niż znak zapytania. Powyższe nie odnosi się do separatora /:, który musieliśmy poprzedzić znakiem \. Jest jeszcze część wyrażenia [^:\/]+, która oznacza „co najmniej jeden znak inny niż dwukropek lub ukośnik”. To wyrażenie regularne pasuje także do bardziej skomplikowanych form adresu URL (listing A.3). Listing A.3. Wyrażenia regularne dla skomplikowanych adresów URL

    Wyodrębnijmy teraz adres hosta, port, katalog i argument z podanego ciągu, wykorzystując grupowanie, tak jak zrobiliśmy to na listingu A.2 (listing A.4). Listing A.4. Wyodrębnienie adresu hosta, portu, katalogu i argumentu

    Wykonany skrypt zwróci wynik: Host=>mojekonto.test.pl Port=>

    346

    DODATEK „ WYRAŻENIA REGULARNE

    Katalog=>logowanie/login Argumenty=>URI=http://

    Opcje wewnętrzne Wartość numeru portu nie była zawarta w adresie, więc nie został on wyodrębniony. Wszystko inne zostało pobrane poprawnie. Co by się stało, gdyby adres URL był zapisany wielkimi literami? HTTPS://mojekonto.test.pl/logowanie/login?URI=http://

    Taki adres nie będzie pasował, ponieważ aktualne wyrażenie przewiduje tylko małe litery. Ten adres jest jednak zupełnie poprawny i zostałby rozpoznany przez przeglądarkę. Jeżeli chcemy zezwolić na taką ewentualność, musimy zignorować wielkość liter w wyrażeniu regularnym. Możemy to osiągnąć poprzez ustawienie opcji ignorowania wielkości liter. Wyrażenie będzie teraz wyglądało następująco: [(?i)^https?://([^:/]+):?(\d*)/([^?]*)\??(.*)]

    Dla wszystkich znaków występujących po (?i) wielkość znaków będzie ignorowana. Wyrażenie Mladen (?i)g będzie pasowało do ciągów Mladen G oraz Mladen g, ale nie MLADEN G. Kolejną często wykorzystywaną opcją jest m — oznacza ona „wiele linii”. Bez tej opcji sprawdzanie wyrażenia będzie przerwane w momencie napotkania znaku nowej linii. To zachowanie może być zmienione poprzez ustawienie opcji (?m). W tym przypadku koniec parsowania nie nastąpi aż do końca ciągu. Znak dolara będzie pasował także do znaków nowej linii — chyba że zostanie ustawiona opcja D. Oznacza ona, że metaznak $ będzie pasował wyłącznie do znaku końca ciągu, a nie do znaków końca linii zawartych wewnątrz tego ciągu. Opcje mogą być grupowane. Użycie (?imD) na początku wyrażenia włączy wszystkie trzy opcje: ignorowanie wielkości liter, parsowanie wszystkich linii oraz „znak dolara pasuje tylko do końca ciągu”. Istnieje też alternatywa — tradycyjna notacja pozwalająca ustawić opcje globalne. W tym przypadku modyfikatory globalne wstawiane są na końcu wyrażenia, po ostatnim separatorze. Przy wykorzystaniu tej notacji nasze wyrażenie miałoby postać: [^https?://([^:/]+):?(\d*)/([^?]*)\??(.*)]i

    Zaletą nowej notacji jest to, że może być wykorzystana w dowolnym miejscu wyrażenia, oraz to, że efekty modyfikatora będą dotyczyły części wyrażenia za nim. W przypadku użycia modyfikatora na końcu wyrażenia jego efekty dotyczą całego wyrażenia. „ UWAGA. Pełna dokumentacja modyfikatorów globalnych dostępna jest pod adresem www.php.net/manual/en/reference.pcre.pattern.modifiers.php.

    Chciwość Standardowo wyrażenia regularne są chciwe. Oznacza to, że parser spróbuje dopasować jak największą część ciągu. Gdyby wyrażenie (123)+ było wykorzystane dla ciągu 123123123123123A, dopasowane zostałoby wszystko przed literą A. W kolejnym przykładzie sprawdzimy powyższą notację. Chodzi o to, aby dopasować wyłącznie znacznik img w linii kodu HTML. Pierwsza iteracja skryptu, która nie działa prawidłowo, jest pokazana na listingu A.5. Listing A.5. Niepoprawny skrypt wyszukujący znacznik img